diff --git a/WHATSNEW.md b/WHATSNEW.md index 522bc605e475837fe6c321c75a57d2fe086880dd..ed656f683a7c03dc708939991227ef9829dbd270 100644 --- a/WHATSNEW.md +++ b/WHATSNEW.md @@ -1,3 +1,7 @@ +New stuff in 1.7-dpr3 +====================== + + New stuff in 1.7-dpr2 ====================== diff --git a/assets/default/css/theme.css b/assets/default/css/theme.css index d004c4069706a8bc1d62e34fe19dd9850eaa3f9c..88c4898a80b62ae5be6ede550948a3e217fd3a8a 100644 --- a/assets/default/css/theme.css +++ b/assets/default/css/theme.css @@ -379,19 +379,33 @@ body { font-size: 15px; margin-left: 0; padding-left: 0; + border-top:1px solid #ddd; } #faq ol li { list-style: none; - margin: 0 0 10px 0; + margin: 0; + padding:0; color: #999; } #faq ol li a { - display: block; - height: 16px; + display:block; + padding:5px 0; + height:auto !important; + overflow:hidden; + margin:0; + border-bottom:1px solid #ddd; line-height: 16px; padding-left: 24px; background: url('../images/icons/page.png?1319579499') 0 50% no-repeat; } +#faq ol li a:hover { + background-color:#e9f5ff; +} + +.article-meta { + padding:5px; + background:#fafafa; +} /* Knowledgebase */ #kb { @@ -401,12 +415,21 @@ body { } #kb > li { - margin: 0 0 5px 0; - padding: 10px; - width: auto; - float: left; - clear: both; - list-style: none; + padding:10px; + height:auto !important; + overflow:hidden; + margin:0; + background:url(../images/kb_category_bg.png) bottom left repeat-x; + border-bottom:1px solid #ddd; +} + +#kb li i { + display:block; + width:32px; + height:32px; + float:left; + margin-right:6px; + background:url(../images/kb_large_folder.png) top left no-repeat; } #kb > li h4 { @@ -420,10 +443,51 @@ body { #kb > li h4 a { font-size: 14px; - padding-left: 24px; - background: url('../images/icons/page.png?1319579499') 0 50% no-repeat; } +#kb-search { + padding:10px 0; + overflow:hidden; +} + +#kb-search div { + clear:both; + overflow:hidden; + padding-top:5px; +} + +#kb-search #query { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; +} + +#kb-search #cid { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; + position:relative; + top:2px; +} + +#kb-search #topic-id { + margin:0; + display:inline-block; + float:left; + width:410px; +} + +#kb-search #searchSubmit { + margin:0; + display:inline-block; + float:left; + position:relative; + top:2px; +} #breadcrumbs { color: #333; @@ -644,6 +708,13 @@ a.refresh { font-size: 12px; padding: 5px; } + +#ticketThread table th span { + font-weight:normal; + color:#888; + padding-left:20px; +} + #ticketThread table td { padding: 5px; } diff --git a/assets/default/images/kb_category_bg.png b/assets/default/images/kb_category_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..174d675f4c491060a413232bdef7e0e9298df60e Binary files /dev/null and b/assets/default/images/kb_category_bg.png differ diff --git a/assets/default/images/kb_large_folder.png b/assets/default/images/kb_large_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..144fa828a3fc83613dd7a5b29368b6da290fd09d Binary files /dev/null and b/assets/default/images/kb_large_folder.png differ diff --git a/client.inc.php b/client.inc.php index b714e93b44bd587f4d10a2f292b2d4890bc63a3f..3b450e9e2491653ec44c65f346ef79758cc1d1a8 100644 --- a/client.inc.php +++ b/client.inc.php @@ -28,21 +28,12 @@ define('OSTCLIENTINC',TRUE); define('ASSETS_PATH',ROOT_PATH.'assets/default/'); - //Check the status of the HelpDesk. -if(!is_object($cfg) || !$cfg->getId() || $cfg->isHelpDeskOffline()) { +if(!is_object($cfg) || !$cfg->getId() || $cfg->isHelpDeskOffline() || $cfg->isUpgradePending()) { include('./offline.php'); exit; } -//Forced upgrade? Version mismatch. -if(defined('THIS_VERSION') && strcasecmp($cfg->getVersion(),THIS_VERSION)) { - die('System is offline for an upgrade.'); - exit; -} - - - /* include what is needed on client stuff */ require_once(INCLUDE_DIR.'class.client.php'); require_once(INCLUDE_DIR.'class.ticket.php'); diff --git a/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png b/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png new file mode 100644 index 0000000000000000000000000000000000000000..954e22dbd99e8c6dd7091335599abf2d10bf8003 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png differ diff --git a/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png b/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100644 index 0000000000000000000000000000000000000000..64ece5707d91a6edf9fad4bfcce0c4dbcafcf58d Binary files /dev/null and b/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png differ diff --git a/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png b/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..abdc01082bf3534eafecc5819d28c9574d44ea89 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png differ diff --git a/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png b/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..9b383f4d2eab09c0f2a739d6b232c32934bc620b Binary files /dev/null and b/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png differ diff --git a/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png b/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..a23baad25b1d1ff36e17361eab24271f2e9b7326 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png differ diff --git a/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png b/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..42ccba269b6e91bef12ad0fa18be651b5ef0ee68 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png b/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png new file mode 100644 index 0000000000000000000000000000000000000000..39d5824d6af5456f1e89fc7847ea3599ea5fd815 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png differ diff --git a/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png b/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..f1273672d253263b7564e9e21d69d7d9d0b337d9 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png differ diff --git a/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png b/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..359397acffdd84bd102f0e8a951c9d744f278db5 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png differ diff --git a/css/ui-lightness/images/ui-icons_222222_256x240.png b/css/ui-lightness/images/ui-icons_222222_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..b273ff111d219c9b9a8b96d57683d0075fb7871a Binary files /dev/null and b/css/ui-lightness/images/ui-icons_222222_256x240.png differ diff --git a/css/ui-lightness/images/ui-icons_228ef1_256x240.png b/css/ui-lightness/images/ui-icons_228ef1_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..a641a371afa0fbb08ba599dc7ddf14b9bfc3c84f Binary files /dev/null and b/css/ui-lightness/images/ui-icons_228ef1_256x240.png differ diff --git a/css/ui-lightness/images/ui-icons_ef8c08_256x240.png b/css/ui-lightness/images/ui-icons_ef8c08_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..85e63e9f604ce042d59eb06a8428eeb7cb7896c9 Binary files /dev/null and b/css/ui-lightness/images/ui-icons_ef8c08_256x240.png differ diff --git a/css/ui-lightness/images/ui-icons_ffd27a_256x240.png b/css/ui-lightness/images/ui-icons_ffd27a_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..e117effa3dca24e7978cfc5f8b967f661e81044f Binary files /dev/null and b/css/ui-lightness/images/ui-icons_ffd27a_256x240.png differ diff --git a/css/ui-lightness/images/ui-icons_ffffff_256x240.png b/css/ui-lightness/images/ui-icons_ffffff_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..42f8f992c727ddaa617da224a522e463df690387 Binary files /dev/null and b/css/ui-lightness/images/ui-icons_ffffff_256x240.png differ diff --git a/css/ui-lightness/jquery-ui-1.8.18.custom.css b/css/ui-lightness/jquery-ui-1.8.18.custom.css new file mode 100755 index 0000000000000000000000000000000000000000..d9e8e3a5a914d18948c9ebddfcb3b8d50929bd3a --- /dev/null +++ b/css/ui-lightness/jquery-ui-1.8.18.custom.css @@ -0,0 +1,354 @@ +/* + * jQuery UI CSS Framework 1.8.18 + * + * 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:before, .ui-helper-clearfix:after { content: ""; display: table; } +.ui-helper-clearfix:after { clear: both; } +.ui-helper-clearfix { zoom: 1; } +.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.18 + * + * 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=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Trebuchet MS, Tahoma, 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: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; } +.ui-widget-content a { color: #333333; } +.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } +.ui-widget-header a { color: #ffffff; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; 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 #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; } +.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; 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 #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top 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: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } +.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_ffffff_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_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: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); } +.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/* + * jQuery UI Datepicker 1.8.18 + * + * 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*/ +} diff --git a/include/ajax.config.php b/include/ajax.config.php index 7dcfd9972717e9c8cd5cb14a217b0e3b361dd9ee..fc9fb2c3fc8622108054052828b7e6bb9a42dcd6 100644 --- a/include/ajax.config.php +++ b/include/ajax.config.php @@ -19,7 +19,7 @@ if(!defined('INCLUDE_DIR')) die('!'); class ConfigAjaxAPI extends AjaxController { //config info UI might need. - function ui() { + function scp_ui() { global $thisstaff, $cfg; $config=array('ticket_lock_time'=>($cfg->getLockTime()*3600), diff --git a/include/ajax.reports.php b/include/ajax.reports.php index cee05471d2e15c82e1bc7163dd61494e63a3af39..16775eb4b1ffe4370bf0a4451ce935d55a3a8ae2 100644 --- a/include/ajax.reports.php +++ b/include/ajax.reports.php @@ -29,7 +29,9 @@ include_once(INCLUDE_DIR.'class.ticket.php'); class OverviewReportAjaxAPI extends AjaxController { function enumTabularGroups() { return $this->encode(array("dept"=>"Department", "topic"=>"Topics", - "staff"=>"Staff")); + # XXX: This will be relative to permissions based on the + # logged-in-staff. For basic staff, this will be 'My Stats' + "staff"=>"Staff")); } function getData() { @@ -51,6 +53,8 @@ class OverviewReportAjaxAPI extends AjaxController { "fields" => "T1.topic", "headers" => array('Help Topic') ), + # XXX: This will be relative to permissions based on the + # logged-in-staff "staff" => array( "table" => STAFF_TABLE, "pk" => 'staff_id', @@ -65,27 +69,43 @@ class OverviewReportAjaxAPI extends AjaxController { $res = db_query( 'SELECT ' . $info['fields'] . ',' - .' COUNT(A1.ticket_id) AS Opened,' - .' COUNT(A2.ticket_id) AS Closed,' - .' COUNT(A3.ticket_id) AS Reopened' + .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE + .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk'] + .' AND A1.status=\'open\') AS Open,' + .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE + .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk'] + .' AND (A1.staff_id > 0 OR A1.team_id > 0)' + .' AND A1.status=\'open\') AS Assigned,' + .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE + .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk'] + .' AND (A1.staff_id = 0 AND A1.team_id = 0)' + .' AND A1.status=\'open\') AS Unassigned,' + .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE + .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk'] + .' AND A1.isanswered = 0' + .' AND A1.status=\'open\') AS Unanswered,' + .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE + .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk'] + .' AND A1.isoverdue = 1' + .' AND A1.status=\'open\') AS Overdue,' + .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE + .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk'] + .' AND A1.status=\'closed\') AS Closed,' + .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE + .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk'] + .' AND A1.reopened is not null) AS Reopened,' + .'(SELECT FORMAT(AVG(DATEDIFF(A1.closed, A1.created)),1) FROM '.TICKET_TABLE + .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk'] + .' AND A1.status=\'closed\') AS ServiceTime' .' FROM ' . $info['table'] . ' T1' - .' LEFT JOIN ' . TICKET_EVENT_TABLE - . ' A1 ON (T1.' . $info['pk'] . ' = A1.' . $info['pk'] - .' AND A1.state=\'opened\' AND NOT A1.annulled)' - .' LEFT JOIN ' . TICKET_EVENT_TABLE - . ' A2 ON (T1.' . $info['pk'] . ' = A2.' . $info['pk'] - .' AND A2.state=\'closed\' AND NOT A2.annulled)' - .' LEFT JOIN ' . TICKET_EVENT_TABLE - . ' A3 ON (T1.' . $info['pk'] . ' = A3.' . $info['pk'] - .' AND A3.state=\'reopened\' AND NOT A3.annulled)' - .' GROUP BY '.$info['fields'] ); $rows = array(); while ($row = db_fetch_row($res)) { $rows[] = $row; } return array("columns" => array_merge($info['headers'], - array('Opened','Closed','Reopened')), + array('Open','Assigned','Unassigned','Unanswered', + 'Overdue','Closed','Reopened','Service Time')), "data" => $rows); } @@ -95,21 +115,23 @@ class OverviewReportAjaxAPI extends AjaxController { function downloadTabularData() { $data = $this->getData(); - $csv = array($data['columns']); - $csv = array_merge($csv, $data['data']); + $csv = '"' . implode('","',$data['columns']) . '"'; + foreach ($data['data'] as $row) + $csv .= "\n" . '"' . implode('","', $row) . '"'; Http::download( sprintf('%s-report.csv', $this->get('group', 'Department')), - Format::implode_array(',', "\n", $csv)); + 'text/csv', $csv); } function getPlotData() { - $start = $this->get('start', strtotime('last month')); - $stop = $this->get('stop', time()); + $start = strtotime($this->get('start', 'last month')); + $stop = strtotime($this->get('stop', 'now')); # Fetch all types of events over the timeframe $res = db_query('SELECT DISTINCT(state) FROM '.TICKET_EVENT_TABLE .' WHERE timestamp BETWEEN FROM_UNIXTIME('.db_input($start) - .') AND FROM_UNIXTIME('.db_input($stop).')'); + .') AND FROM_UNIXTIME('.db_input($stop) + .') ORDER BY 1'); $events = array(); while ($row = db_fetch_row($res)) $events[] = $row[0]; @@ -120,7 +142,9 @@ class OverviewReportAjaxAPI extends AjaxController { .' FROM '.TICKET_EVENT_TABLE .' WHERE timestamp BETWEEN FROM_UNIXTIME('.db_input($start) .') AND FROM_UNIXTIME('.db_input($stop) - .') GROUP BY state, DATE_FORMAT(timestamp, \'%Y-%m-%d\')'); + .') AND NOT annulled' + .' GROUP BY state, DATE_FORMAT(timestamp, \'%Y-%m-%d\')' + .' ORDER BY 2, 1'); # Initialize array of plot values $plots = array(); foreach ($events as $e) { $plots[$e] = array(); } @@ -133,18 +157,21 @@ class OverviewReportAjaxAPI extends AjaxController { # New time (and not the first), figure out which events did # not have any tickets associated for this time slot if ($time !== null) { - # Not the first record - foreach (array_diff($events, $slots) as $slot) { + # Not the first record -- add zeros all the arrays that + # did not have at least one entry for the timeframe + foreach (array_diff($events, $slots) as $slot) $plots[$slot][] = 0; - } } $slots = array(); $times[] = $time = $row_time; } # Keep track of states for this timeframe - if (!in_array($row[0], $slots)) $slots[] = $row[0]; + $slots[] = $row[0]; $plots[$row[0]][] = (int)$row[2]; } - return $this->encode(array("times" => $times, "plots" => $plots)); + foreach (array_diff($events, $slots) as $slot) + $plots[$slot][] = 0; + return $this->encode(array("times" => $times, "plots" => $plots, + "events"=>$events)); } } diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php index 458e430ea83192703bea52c026413af63c4edb63..f67581005194848131dbaf1c709b8c238c8e404a 100644 --- a/include/ajax.tickets.php +++ b/include/ajax.tickets.php @@ -20,11 +20,11 @@ include_once(INCLUDE_DIR.'class.ticket.php'); class TicketsAjaxAPI extends AjaxController { - function search() { + function lookup() { global $thisstaff; if(!is_numeric($_REQUEST['q'])) - return self::searchByEmail(); + return self::lookupByEmail(); $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25; @@ -53,7 +53,7 @@ class TicketsAjaxAPI extends AjaxController { return $this->json_encode($tickets); } - function searchByEmail() { + function lookupByEmail() { global $thisstaff; @@ -84,6 +84,100 @@ class TicketsAjaxAPI extends AjaxController { return $this->json_encode($tickets); } + function search() { + global $thisstaff; + + $result=array(); + $select = 'SELECT count(ticket.ticket_id) as tickets '; + $from = ' FROM '.TICKET_TABLE.' ticket '; + $where = ' WHERE 1 '; + + //Access control. + $where.=' AND ( ticket.staff_id='.db_input($thisstaff->getId()); + + if(($teams=$thisstaff->getTeams()) && count(array_filter($teams))) + $where.=' OR ticket.team_id IN('.implode(',', array_filter($teams)).')'; + + if(!$thisstaff->showAssignedOnly() && ($depts=$thisstaff->getDepts())) + $where.=' OR ticket.dept_id IN ('.implode(',', $depts).')'; + + $where.=' ) '; + + //Department + if($_REQUEST['deptId']) + $where.=' AND ticket.dept_id='.db_input($_REQUEST['deptId']); + + //Status + switch(strtolower($_REQUEST['status'])) { + case 'open'; + $where.=' AND ticket.status="open" '; + break; + case 'overdue': + $where.=' AND ticket.status="open" AND ticket.isoverdue=1 '; + break; + case 'closed': + $where.=' AND ticket.status="closed" '; + break; + } + + //Assignee + if($_REQUEST['assignee'] && strcasecmp($_REQUEST['status'], 'closed')) { + $id=preg_replace("/[^0-9]/", "", $_REQUEST['assignee']); + $assignee = $_REQUEST['assignee']; + $where.= ' AND ( '; + if($assignee[0]=='t') + $where.=' (ticket.team_id='.db_input($id). ' AND ticket.status="open") '; + elseif($assignee[0]=='s') + $where.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + else + $where.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + + if($_REQUEST['staffId'] && !$_REQUEST['status']) //Assigned TO + Closed By + $where.= ' OR (ticket.staff_id='.db_input($_REQUEST['staffId']). ' AND ticket.status="closed") '; + + $where.= ' ) '; + } elseif($_REQUEST['staffId']) { + $where.=' AND (ticket.staff_id='.db_input($_REQUEST['staffId']).' AND ticket.status="closed") '; + } + + //dates + $startTime =($_REQUEST['startDate'] && (strlen($_REQUEST['startDate'])>=8))?strtotime($_REQUEST['startDate']):0; + $endTime =($_REQUEST['endDate'] && (strlen($_REQUEST['endDate'])>=8))?strtotime($_REQUEST['endDate']):0; + if( ($startTime && $startTime>time()) or ($startTime>$endTime && $endTime>0)) + $startTime=$endTime=0; + + if($startTime) + $where.=' AND ticket.created>=FROM_UNIXTIME('.$startTime.')'; + + if($endTime) + $where.=' AND ticket.created<=FROM_UNIXTIME('.$endTime.')'; + + //Query + if($_REQUEST['query']) { + $queryterm=db_real_escape($_REQUEST['query'], false); + + $from.=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON (ticket.ticket_id=thread.ticket_id )'; + $where.=" AND ( ticket.email LIKE '%$queryterm%'" + ." OR ticket.name LIKE '%$queryterm%'" + ." OR ticket.subject LIKE '%$queryterm%'" + ." OR thread.title LIKE '%$queryterm%'" + ." OR thread.body LIKE '%$queryterm%'" + .' )'; + $groupby = 'GROUP BY ticket.ticket_id '; + } + + $sql="$select $from $where $groupby"; + if(($tickets=db_result(db_query($sql)))) { + $result['success'] =sprintf("Search criteria matched %s - <a href='tickets.php?%s'>view</a>", + ($tickets>1?"$tickets tickets":"$tickets ticket"), + str_replace(array('&', '&'), array('&', '&'), $_SERVER['QUERY_STRING'])); + } else { + $result['fail']='No tickets found matching your search criteria.'; + } + + return $this->json_encode($result); + } + function acquireLock($tid) { global $cfg,$thisstaff; diff --git a/include/class.config.php b/include/class.config.php index c51814bebc73aef1ae3a9052db364d2702798c04..626e11c9a0e3eb466046f3539b9ed16ecb7c0c7e 100644 --- a/include/class.config.php +++ b/include/class.config.php @@ -67,22 +67,35 @@ class Config { return !$this->isSystemOnline(); } + function isHelpDeskOnline() { + return $this->isSystemOnline(); + } + function isSystemOnline() { - return ($this->config['isonline']); + return ($this->config['isonline'] && !$this->isUpgradePending()); } - function isKnowledgebaseEnabled() { + function isUpgradePending() { + return (defined('SCHEMA_SIGNATURE') && strcasecmp($this->getSchemaSignature(), SCHEMA_SIGNATURE)); + } + function isKnowledgebaseEnabled() { require_once(INCLUDE_DIR.'class.faq.php'); return ($this->config['enable_kb'] && FAQ::countPublishedFAQs()); } function getVersion() { - return '1.7-DPR2'; + return THIS_VERSION; } function getSchemaSignature() { - return $this->config['schema_signature']; + + if($this->config['schema_signature']) + return $this->config['schema_signature']; + elseif($this->config['ostversion']) //old version 1.6 st. + return md5(strtoupper($this->config['ostversion'])); + + return null; } function setMysqlTZ($tz) { @@ -155,6 +168,10 @@ class Config { function showRelatedTickets() { return $this->config['show_related_tickets']; } + + function showNotesInline(){ + return $this->config['show_notes_inline']; + } function getClientTimeout() { return $this->getClientSessionTimeout(); @@ -300,7 +317,7 @@ class Config { } function canFetchMail() { - return ($this->config['enable_mail_fetch']); + return ($this->config['enable_mail_polling']); } function enableStaffIPBinding() { @@ -662,6 +679,7 @@ class Config { ',show_assigned_tickets='.db_input(isset($vars['show_assigned_tickets'])?1:0). ',show_answered_tickets='.db_input(isset($vars['show_answered_tickets'])?1:0). ',show_related_tickets='.db_input(isset($vars['show_related_tickets'])?1:0). + ',show_notes_inline='.db_input(isset($vars['show_notes_inline'])?1:0). ',hide_staff_name='.db_input(isset($vars['hide_staff_name'])?1:0); return (db_query($sql)); diff --git a/include/class.dept.php b/include/class.dept.php index 8bd575116a421dba88b82dd236243829aeadfc32..bf82b76526b7ce77abbdcdbaa213c939207ca4ad 100644 --- a/include/class.dept.php +++ b/include/class.dept.php @@ -47,6 +47,7 @@ class Dept { $this->id=$this->ht['dept_id']; $this->email=$this->sla=$this->manager=null; $this->getEmail(); //Auto load email struct. + $this->members=array(); return true; } @@ -88,6 +89,21 @@ class Dept { return $this->getNumStaff(); } + function getAvailableMembers(){ + + if(!$this->members && $this->getNumStaff()){ + $sql='SELECT m.staff_id FROM '.STAFF_TABLE.' m ' + .'WHERE m.dept_id='.db_input($this->getId()) + .' AND s.staff_id IS NOT NULL ' + .'ORDER BY s.lastname, s.firstname'; + if(($res=db_query($sql)) && db_num_rows($res)){ + while(list($id)=db_fetch_row($res)) + if($staff= Staff::lookup($id) && $staff->isAvailable()) + $this->members[]= $staff; + } + } + return $this->members; + } function getSLAId(){ return $this->ht['sla_id']; diff --git a/include/class.format.php b/include/class.format.php index f7b624d852b5dda8b6dc2e7eedf20a2ef13de5c3..a3461bf9d615c857382763c62b8ff49562352648 100644 --- a/include/class.format.php +++ b/include/class.format.php @@ -126,7 +126,7 @@ class Format { $text=preg_replace("/(^|[ \\n\\r\\t])(www\.([a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+)(\/[^\/ \\n\\r]*)*)/", '\\1<a href="l.php?url=http://\\2" target="_blank">\\2</a>', $text); $text=preg_replace("/(^|[ \\n\\r\\t])([_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,4})/", - '\\1<a href="l.php?url=mailto:\\2" target="_blank">\\2</a>', $text); + '\\1<a href="mailto:\\2" target="_blank">\\2</a>', $text); return $text; } diff --git a/include/class.knowledgebase.php b/include/class.knowledgebase.php index d8a64689168de48014011bf46c45e029056efdea..6bb67898f7a94f7b6f95c547b646241aa45c2699 100644 --- a/include/class.knowledgebase.php +++ b/include/class.knowledgebase.php @@ -55,9 +55,11 @@ class Knowledgebase { function publish() { $this->published = true; } function unpublish() { $this->published = false; } function setPublished($val) { $this->published = !!$val; } + function setEnabled($val) { $this->enabled = !!$val; } function setTitle($title) { $this->title = $title; } function setKeywords($words) { $this->keywords = $words; } function setAnswer($text) { $this->answer = $text; } + function setDepartment($id) { $this->department = $id; } /* -------------> Validation and Clean methods <------------ */ function validate(&$errors, $what=null) { diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php index 5f97775930f25da87f80261cc20b66cdad947b8f..f25d72b26236471dd6b14e365a1745067ffe6f3e 100644 --- a/include/class.mailfetch.php +++ b/include/class.mailfetch.php @@ -242,7 +242,7 @@ class MailFetcher { function getBody($mid) { $body =''; - if(!($body = $this->getpart($mid,'TEXT/PLAIN',$this->charset))) { + if(!($body = $this->getPart($mid,'TEXT/PLAIN',$this->charset))) { if(($body = $this->getPart($mid,'TEXT/HTML',$this->charset))) { //Convert tags of interest before we striptags $body=str_replace("</DIV><DIV>", "\n", $body); @@ -346,7 +346,7 @@ class MailFetcher { } - function fetchTickets($emailid,$max=20,$deletemsgs=false){ + function fetchTickets($emailid,$max=20,$deletemsgs=false,$archivefolder){ $nummsgs=imap_num_msg($this->mbox); //echo "New Emails: $nummsgs\n"; @@ -354,7 +354,7 @@ class MailFetcher { for($i=$nummsgs; $i>0; $i--){ //process messages in reverse. Latest first. FILO. if($this->createTicket($i,$emailid)){ imap_setflag_full($this->mbox, imap_uid($this->mbox,$i), "\\Seen", ST_UID); //IMAP only?? - if($deletemsgs) + if((!$archivefolder || !imap_mail_move($this->mbox,$i,$archivefolder)) && $deletemsgs) imap_delete($this->mbox,$i); $msgs++; $errors=0; //We are only interested in consecutive errors. @@ -384,7 +384,7 @@ class MailFetcher { $MAX_ERRORS=5; //Max errors before we start delayed fetch attempts - hardcoded for now. - $sql=' SELECT email_id,mail_host,mail_port,mail_protocol,mail_encryption,mail_delete,mail_errors,userid,userpass FROM '.EMAIL_TABLE. + $sql=' SELECT email_id,mail_host,mail_port,mail_protocol,mail_encryption,mail_delete,mail_archivefolder,mail_errors,userid,userpass FROM '.EMAIL_TABLE. ' WHERE mail_active=1 AND (mail_errors<='.$MAX_ERRORS.' OR (TIME_TO_SEC(TIMEDIFF(NOW(),mail_lasterror))>5*60) )'. ' AND (mail_lastfetch IS NULL OR TIME_TO_SEC(TIMEDIFF(NOW(),mail_lastfetch))>mail_fetchfreq*60) '; //echo $sql; @@ -396,7 +396,7 @@ class MailFetcher { $fetcher = new MailFetcher($row['userid'],Misc::decrypt($row['userpass'],SECRET_SALT), $row['mail_host'],$row['mail_port'],$row['mail_protocol'],$row['mail_encryption']); if($fetcher->connect()){ - $fetcher->fetchTickets($row['email_id'],$row['mail_fetchmax'],$row['mail_delete']?true:false); + $fetcher->fetchTickets($row['email_id'],$row['mail_fetchmax'],$row['mail_delete']?true:false,$row['mail_archivefolder']); $fetcher->close(); db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=0, mail_lastfetch=NOW() WHERE email_id='.db_input($row['email_id'])); }else{ diff --git a/include/class.staff.php b/include/class.staff.php index 0630a0fe514d391c90af98bd47fe06c7c3871422..00554157935ba0d82aa77596bf9c912f0fcf5ad5 100644 --- a/include/class.staff.php +++ b/include/class.staff.php @@ -220,7 +220,7 @@ class Staff { return $this->showAssignedOnly(); } - function isadmin() { + function isAdmin() { return ($this->ht['isadmin']); } @@ -261,7 +261,7 @@ class Staff { } function canManageTickets() { - return ($this->isadmin() + return ($this->isAdmin() || $this->canDeleteTickets() || $this->canCloseTickets()); } @@ -623,6 +623,7 @@ class Staff { .' ,dept_id='.db_input($vars['dept_id']) .' ,group_id='.db_input($vars['group_id']) .' ,timezone_id='.db_input($vars['timezone_id']) + .' ,daylight_saving='.db_input(isset($vars['daylight_saving'])?1:0) .' ,username='.db_input($vars['username']) .' ,firstname='.db_input($vars['firstname']) .' ,lastname='.db_input($vars['lastname']) diff --git a/include/class.sys.php b/include/class.sys.php index ab10cd99442fa640bd36a6a329b6cc27e18f1b7f..33b5c830407f1b56fb1ef8eff47657e1296bb97a 100644 --- a/include/class.sys.php +++ b/include/class.sys.php @@ -96,7 +96,7 @@ class Sys { function purgeLogs(){ global $cfg; - if($cfg && ($gp=$cfg->getLogGraceperiod()) && is_numeric($gp)) { + if($cfg && ($gp=$cfg->getLogGracePeriod()) && is_numeric($gp)) { $sql='DELETE FROM '.SYSLOG_TABLE.' WHERE DATE_ADD(created, INTERVAL '.$gp.' MONTH)<=NOW()'; db_query($sql); } diff --git a/include/class.team.php b/include/class.team.php index 7aada43a3b13a6529822ef8a764ba958b7f838d8..b3f996d28fc658ed03d5e458679fc97953de000b 100644 --- a/include/class.team.php +++ b/include/class.team.php @@ -200,7 +200,6 @@ class Team { $sql='SET updated=NOW(),isenabled='.db_input($vars['isenabled']). ',name='.db_input($vars['name']). - ',isenabled='.db_input($vars['isenabled']). ',noalerts='.db_input(isset($vars['noalerts'])?$vars['noalerts']:0). ',notes='.db_input($vars['notes']); diff --git a/include/class.template.php b/include/class.template.php index ef53d7ed59ff1c404e525f2d903107118b923709..36d9b2f4845d3ca14ad564c9a8c829c11b9ab083 100644 --- a/include/class.template.php +++ b/include/class.template.php @@ -28,11 +28,12 @@ class Template { if(!$id && !($id=$this->getId())) return false; - + $sql='SELECT tpl.*,count(dept.tpl_id) as depts ' .' FROM '.EMAIL_TEMPLATE_TABLE.' tpl ' .' LEFT JOIN '.DEPT_TABLE.' dept USING(tpl_id) ' - .' WHERE tpl_id='.db_input($id); + .' WHERE tpl.tpl_id='.db_input($id) + .' GROUP BY tpl.tpl_id'; if(!($res=db_query($sql))|| !db_num_rows($res)) return false; diff --git a/include/class.ticket.php b/include/class.ticket.php index 8eca918fbb101b71f02276b930e62b1bde35a3b1..6a27d981bb24bdc7f05a6c8adec30615f0f7ed24 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -75,18 +75,25 @@ class Ticket{ $sql='SELECT ticket.*, topic.topic as helptopic, lock_id, dept_name, priority_desc ' .' ,count(attach.attach_id) as attachments ' - .' ,count(DISTINCT message.msg_id) as messages ' - .' ,count(DISTINCT response.response_id) as responses ' - .' ,count(DISTINCT note.note_id) as notes ' + .' ,count(DISTINCT message.id) as messages ' + .' ,count(DISTINCT response.id) as responses ' + .' ,count(DISTINCT note.id) as notes ' .' FROM '.TICKET_TABLE.' ticket ' .' LEFT JOIN '.DEPT_TABLE.' dept ON (ticket.dept_id=dept.dept_id) ' - .' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (ticket.priority_id=pri.priority_id) ' - .' LEFT JOIN '.TOPIC_TABLE.' topic ON (ticket.topic_id=topic.topic_id) ' - .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON (ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW()) ' - .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (ticket.ticket_id=attach.ticket_id) ' - .' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id) ' - .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id) ' - .' LEFT JOIN '.TICKET_NOTE_TABLE.' note ON (ticket.ticket_id=note.ticket_id ) ' + .' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (' + .'ticket.priority_id=pri.priority_id) ' + .' LEFT JOIN '.TOPIC_TABLE.' topic ON (' + .'ticket.topic_id=topic.topic_id) ' + .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON (' + .'ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW()) ' + .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (' + .'ticket.ticket_id=attach.ticket_id) ' + .' LEFT JOIN '.TICKET_THREAD_TABLE.' message ON (' + ."ticket.ticket_id=message.ticket_id AND message.thread_type = 'M') " + .' LEFT JOIN '.TICKET_THREAD_TABLE.' response ON (' + ."ticket.ticket_id=response.ticket_id AND response.thread_type = 'R') " + .' LEFT JOIN '.TICKET_THREAD_TABLE.' note ON ( ' + ."ticket.ticket_id=note.ticket_id AND note.thread_type = 'N') " .' WHERE ticket.ticket_id='.db_input($id) .' GROUP BY ticket.ticket_id'; @@ -437,9 +444,10 @@ class Ticket{ function getLastRespondent() { $sql ='SELECT resp.staff_id ' - .' FROM '.TICKET_RESPONSE_TABLE.' resp ' + .' FROM '.TICKET_THREAD_TABLE.' resp ' .' LEFT JOIN '.STAFF_TABLE. ' USING(staff_id) ' .' WHERE resp.ticket_id='.db_input($this->getId()).' AND resp.staff_id>0 ' + .' AND resp.thread_type="R"' .' ORDER BY resp.created DESC LIMIT 1'; if(!($res=db_query($sql)) || !db_num_rows($res)) @@ -457,8 +465,9 @@ class Ticket{ return $this->lastmsgdate; //for old versions...XXX: still needed???? - $sql='SELECT created FROM '.TICKET_MESSAGE_TABLE + $sql='SELECT created FROM '.TICKET_THREAD_TABLE .' WHERE ticket_id='.db_input($this->getId()) + ." AND thread_type = 'M'" .' ORDER BY created DESC LIMIT 1'; if(($res=db_query($sql)) && db_num_rows($res)) list($this->lastmsgdate)=db_fetch_row($res); @@ -475,8 +484,9 @@ class Ticket{ if($this->lastrespdate) return $this->lastrespdate; - $sql='SELECT created FROM '.TICKET_RESPONSE_TABLE + $sql='SELECT created FROM '.TICKET_THREAD_TABLE .' WHERE ticket_id='.db_input($this->getId()) + .' AND thread_type="R"' .' ORDER BY created DESC LIMIT 1'; if(($res=db_query($sql)) && db_num_rows($res)) list($this->lastrespdate)=db_fetch_row($res); @@ -517,63 +527,67 @@ class Ticket{ return $this->ht['notes']; } - function getNotes($order='') { + function getMessages() { + return $this->getThreadByType('M'); + } - if(!$order || !in_array($order, array('DESC','ASC'))) - $order='DESC'; + function getResponses($msgId=0) { + return $this->getThreadByType('R', $msgID); + } - $sql ='SELECT note.*, count(DISTINCT attach.attach_id) as attachments ' - .' FROM '.TICKET_NOTE_TABLE.' note ' - .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach - ON (note.ticket_id=attach.ticket_id AND note.note_id=attach.ref_id AND ref_type="N") ' - .' WHERE note.ticket_id='.db_input($this->getId()) - .' GROUP BY note.note_id ' - .' ORDER BY note.created '.$order; + function getNotes() { + return $this->getThreadByType('N'); + } - $notes=array(); - if(($res=db_query($sql)) && db_num_rows($res)) - while($rec=db_fetch_array($res)) - $notes[]=$rec; + function getClientThread() { + return $this->getThreadwithoutNotes(); + } - return $notes; + function getThreadWithNotes() { + return $this->getThread(true); + } + + function getThreadWithoutNotes() { + return $this->getThread(false); } - function getMessages() { + function getThread($includeNotes=false, $order='') { - $sql='SELECT msg.msg_id, msg.created, msg.message ' - .' ,count(DISTINCT attach.attach_id) as attachments, count( DISTINCT resp.response_id) as responses ' - .' FROM '.TICKET_MESSAGE_TABLE.' msg ' - .' LEFT JOIN '.TICKET_RESPONSE_TABLE. ' resp ON(resp.msg_id=msg.msg_id) ' - .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach - ON (msg.ticket_id=attach.ticket_id AND msg.msg_id=attach.ref_id AND ref_type="M") ' - .' WHERE msg.ticket_id='.db_input($this->getId()) - .' GROUP BY msg.msg_id ' - .' ORDER BY msg.created ASC '; + $treadtypes=array('M', 'R'); // messages and responses. + if($includeNotes) //Include notes?? + $treadtypes[] = 'N'; - $messages=array(); - if(($res=db_query($sql)) && db_num_rows($res)) - while($rec=db_fetch_array($res)) - $messages[] = $rec; - - return $messages; + return $this->getThreadbyType($treadtypes, $order); } + + function getThreadByType($type, $order='ASC') { - function getResponses($msgId) { + if(!$order || !in_array($order, array('DESC','ASC'))) + $order='ASC'; - $sql='SELECT resp.*, count(DISTINCT attach.attach_id) as attachments ' - .' FROM '.TICKET_RESPONSE_TABLE. ' resp ' + $sql='SELECT thread.* ' + .' ,count(DISTINCT attach.attach_id) as attachments ' + .' FROM '.TICKET_THREAD_TABLE.' thread ' .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach - ON (resp.ticket_id=attach.ticket_id AND resp.response_id=attach.ref_id AND ref_type="R") ' - .' WHERE resp.ticket_id='.db_input($this->getId()) - .' GROUP BY resp.response_id ' - .' ORDER BY resp.created'; + ON (thread.ticket_id=attach.ticket_id + AND thread.id=attach.ref_id + AND thread.thread_type=attach.ref_type) ' + .' WHERE thread.ticket_id='.db_input($this->getId()); + + if($type && is_array($type)) + $sql.=" AND thread.thread_type IN('".implode("','", $type)."')"; + else + $sql.=' AND thread.thread_type='.db_input($type); + + $sql.=' GROUP BY thread.id ' + .' ORDER BY thread.created '.$order; - $responses=array(); + $thread=array(); if(($res=db_query($sql)) && db_num_rows($res)) - while($rec= db_fetch_array($res)) - $responses[] = $rec; - - return $responses; + while($rec=db_fetch_array($res)) + $thread[] = $rec; + + return $thread; } function getAttachments($refId=0, $type=null) { @@ -654,10 +668,14 @@ class Ticket{ //Set staff ID...assign/unassign/release (id can be 0) function setStaffId($staffId){ - $sql='UPDATE '.TICKET_TABLE.' SET updated=NOW(), staff_id='.db_input($staffId) - .' WHERE ticket_id='.db_input($this->getId()); + $sql='UPDATE '.TICKET_TABLE.' SET updated=NOW(), staff_id='.db_input($staffId) + .' WHERE ticket_id='.db_input($this->getId()); - return (db_query($sql) && db_affected_rows()); + if (db_query($sql) && db_affected_rows()) { + $this->staff_id = $staffId; + return true; + } + return false; } function setSLAId($slaId) { @@ -769,7 +787,7 @@ class Ticket{ $sql.=' WHERE ticket_id='.db_input($this->getId()); - $this->track('closed'); + $this->logEvent('closed'); return (db_query($sql) && db_affected_rows()); } @@ -783,7 +801,7 @@ class Ticket{ //TODO: log reopen event here - $this->track('reopened'); + $this->logEvent('reopened', 'closed'); return (db_query($sql) && db_affected_rows()); } @@ -873,7 +891,7 @@ class Ticket{ $msg=sprintf('Max open tickets (%d) reached for %s ', $cfg->getMaxOpenTickets(), $this->getEmail()); sys::log(LOG_WARNING, 'Max. Open Tickets Limit ('.$this->getEmail().')', $msg); - if(!$sendNotice || !$cfg->sendOverlimitNotice()) return true; + if(!$sendNotice || !$cfg->sendOverLimitNotice()) return true; //Send notice to user. $dept = $this->getDept(); @@ -953,7 +971,7 @@ class Ticket{ $email=$cfg->getDefaultEmail(); if($email) { - $email->send($this->getEMail(),$subj,$body); + $email->send($this->getEmail(),$subj,$body); } } @@ -996,12 +1014,12 @@ class Ticket{ $recipients=array(); //Assigned staff or team... if any // Assigning a ticket to a team when already assigned to staff disables alerts to the team (!)) - if($cfg->alertStaffONAssign() && $this->getStaffId()) + if($cfg->alertStaffONAssignment() && $this->getStaffId()) $recipients[]=$this->getStaff(); elseif($this->getTeamId() && ($team=$this->getTeam())) { - if($cfg->alertTeamMembersOnAssignment() && ($members=$team->getMembers())) + if($cfg->alertTeamMembersONAssignment() && ($members=$team->getMembers())) $recipients+=$members; - elseif($cfg->alertTeamLeadOnAssignment() && ($lead=$team->getTeamLead())) + elseif($cfg->alertTeamLeadONAssignment() && ($lead=$team->getTeamLead())) $recipients[]=$lead; } //Send the alerts. @@ -1128,8 +1146,8 @@ class Ticket{ if(!db_query($sql) || !db_affected_rows()) return false; + $this->logEvent('overdue'); $this->onOverdue($whine); - $this->track('overdue'); return true; } @@ -1150,6 +1168,7 @@ class Ticket{ $this->reopen(); $this->reload(); //reload - new dept!! + $this->logEvent('transferred'); //Send out alerts if enabled AND requested if(!$alert || !$cfg->alertONTransfer() || !($dept=$this->getDept())) return true; //no alerts!! @@ -1196,7 +1215,6 @@ class Ticket{ } } - $this->track('transferred'); return true; } @@ -1209,8 +1227,8 @@ class Ticket{ return false; $this->onAssign($note, $alert); + $this->logEvent('assigned'); - $this->track('assigned'); return true; } @@ -1228,8 +1246,8 @@ class Ticket{ $this->setStaffId(0); $this->onAssign($note, $alert); + $this->logEvent('assigned'); - $this->track('assigned'); return true; } @@ -1270,18 +1288,18 @@ class Ticket{ } //Insert message from client - function postMessage($msg,$source='',$msgid=NULL,$headers='',$newticket=false){ + function postMessage($msg,$source='',$emsgid=null,$headers='',$newticket=false){ global $cfg; if(!$this->getId()) return 0; # XXX: Refuse auto-response messages? (via email) XXX: No - but kill our auto-responder. - $sql='INSERT INTO '.TICKET_MESSAGE_TABLE.' SET created=NOW() ' + $sql='INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW()' + .' ,thread_type="M" ' .' ,ticket_id='.db_input($this->getId()) - .' ,messageId='.db_input($msgid) - .' ,message='.db_input(Format::striptags($msg)) //Tags/code stripped...meaning client can not send in code..etc - .' ,headers='.db_input($headers) //Raw header. + # XXX: Put Subject header into the 'title' field + .' ,body='.db_input(Format::striptags($msg)) //Tags/code stripped...meaning client can not send in code..etc .' ,source='.db_input($source?$source:$_SERVER['REMOTE_ADDR']) .' ,ip_address='.db_input($_SERVER['REMOTE_ADDR']); @@ -1289,6 +1307,15 @@ class Ticket{ $this->setLastMsgId($msgid); + if ($emsgid !== null) { + $sql='INSERT INTO '.TICKET_EMAIL_INFO_TABLE + .' SET message_id='.db_input($msgid) + .', email_mid='.db_input($emsgid) + .', headers='.db_input($headers); + + if (!db_query($sql)) return 0; + } + if($newticket) return $msgid; //Our work is done... $autorespond = true; @@ -1353,12 +1380,13 @@ class Ticket{ if($errors) return 0; - $sql='INSERT INTO '.TICKET_RESPONSE_TABLE.' SET created=NOW() ' + $sql='INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW() ' + .' ,thread_type="R"' .' ,ticket_id='.db_input($this->getId()) - .' ,msg_id='.db_input($vars['msgId']) - .' ,response='.db_input(Format::striptags($vars['response'])) + .' ,pid='.db_input($vars['msgId']) + .' ,body='.db_input(Format::striptags($vars['response'])) .' ,staff_id='.db_input($thisstaff->getId()) - .' ,staff_name='.db_input($thisstaff->getName()) + .' ,poster='.db_input($thisstaff->getName()) .' ,ip_address='.db_input($thisstaff->getIP()); if(!db_query($sql) || !($respId=db_insert_id())) @@ -1386,16 +1414,17 @@ class Ticket{ $this->onResponse(); //do house cleaning.. $this->reload(); - $dept = $this->getDept(); /* email the user?? - if disabled - the bail out */ if(!$alert) return $respId; + $dept = $this->getDept(); + if(!($tpl = $dept->getTemplate())) $tpl= $cfg->getDefaultTemplate(); - if(!($email=$cfg->getAlertEmail())) - $email =$cfg->getDefaultEmail(); + if(!$dept || !($email=$dept->getEmail())) + $email = $cfg->getDefaultEmail(); if($tpl && ($msg=$tpl->getReplyMsgTemplate()) && $email) { $body=$this->replaceTemplateVars($msg['body']); @@ -1430,20 +1459,32 @@ class Ticket{ if(!$cfg || !$cfg->logTicketActivity()) return 0; - return $this->postNote($title,$note,false,'system'); + return $this->postNote($title,$note,false,'System'); } // History log -- used for statistics generation (pretty reports) - function track($state, $staff=null) { + function logEvent($state, $annul=null, $staff=null) { global $thisstaff; if ($staff === null) { if ($thisstaff) $staff=$thisstaff->getUserName(); else $staff='SYSTEM'; # XXX: Security Violation ? } + # Annul previous entries if requested (for instance, reopening a + # ticket will annul an 'closed' entry). This will be useful to + # easily prevent repeated statistics. + if ($annul) { + db_query('UPDATE '.TICKET_EVENT_TABLE.' SET annulled=1' + .' WHERE ticket_id='.db_input($this->getId()) + .' AND state='.db_input($annul)); + } - return db_query('INSERT INTO '.TICKET_HISTORY_TABLE + return db_query('INSERT INTO '.TICKET_EVENT_TABLE .' SET ticket_id='.db_input($this->getId()) + .', staff_id='.db_input($this->getStaffId()) + .', team_id='.db_input($this->getTeamId()) + .', dept_id='.db_input($this->getDeptId()) + .', topic_id='.db_input($this->getTopicId()) .', timestamp=NOW(), state='.db_input($state) .', staff='.db_input($staff)) && db_affected_rows() == 1; @@ -1453,12 +1494,13 @@ class Ticket{ function postNote($title,$note,$alert=true,$poster='') { global $thisstaff,$cfg; - $sql= 'INSERT INTO '.TICKET_NOTE_TABLE.' SET created=NOW() '. + $sql= 'INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW() '. + ',thread_type="N"'. ',ticket_id='.db_input($this->getId()). ',title='.db_input(Format::striptags($title)). - ',note='.db_input(Format::striptags($note)). + ',body='.db_input(Format::striptags($note)). ',staff_id='.db_input($thisstaff?$thisstaff->getId():0). - ',source='.db_input(($poster || !$thisstaff)?$poster:$thisstaff->getName()); + ',poster='.db_input(($poster || !$thisstaff)?$poster:$thisstaff->getName()); //echo $sql; if(!db_query($sql) || !($id=db_insert_id())) return false; @@ -1560,9 +1602,7 @@ class Ticket{ if(!db_query($sql) || !db_affected_rows()) return false; - db_query('DELETE FROM '.TICKET_MESSAGE_TABLE.' WHERE ticket_id='.db_input($this->getId())); - db_query('DELETE FROM '.TICKET_RESPONSE_TABLE.' WHERE ticket_id='.db_input($this->getId())); - db_query('DELETE FROM '.TICKET_NOTE_TABLE.' WHERE ticket_id='.db_input($this->getId())); + db_query('DELETE FROM '.TICKET_THREAD_TABLE.' WHERE ticket_id='.db_input($this->getId())); $this->deleteAttachments(); return true; @@ -1678,8 +1718,9 @@ class Ticket{ return 0; $sql='SELECT ticket.ticket_id FROM '.TICKET_TABLE. ' ticket '. - ' LEFT JOIN '.TICKET_MESSAGE_TABLE.' msg USING(ticket_id) '. - ' WHERE messageId='.db_input($mid).' AND email='.db_input($email); + ' LEFT JOIN '.TICKET_THREAD_TABLE.' msg USING(ticket_id) '. + ' INNER JOIN '.TICKET_EMAIL_INFO_TABLE.' emsg ON (msg.id = emsg.message_id) '. + ' WHERE email_mid='.db_input($mid).' AND email='.db_input($email); $id=0; if(($res=db_query($sql)) && db_num_rows($res)) list($id)=db_fetch_row($res); @@ -1962,6 +2003,9 @@ class Ticket{ && ($client->getNumOpenTickets()==$cfg->getMaxOpenTickets())) { $ticket->onOpenLimit(($autorespond && strcasecmp($origin, 'staff'))); } + + /* Start tracking ticket lifecycle events */ + $ticket->logEvent('created'); /* Phew! ... time for tea (KETEPA) */ diff --git a/include/client/faq.inc.php b/include/client/faq.inc.php index c944f8316f58fb1b1ff59854bb7a63c05d505de5..65f770e9673083d2474d2a9eb260771492541d41 100644 --- a/include/client/faq.inc.php +++ b/include/client/faq.inc.php @@ -6,7 +6,7 @@ $category=$faq->getCategory(); ?> <h1>Frequently Asked Questions</h1> <div id="breadcrumbs"> - <a href="index.php">All Categories</a> + <a href="index.php">All Categories</a> » <a href="faq.php?cid=<? echo $category->getId(); ?>"><? echo $category->getName(); ?></a> </div> <div style="width:700;padding-top:2px; float:left;"> @@ -23,7 +23,8 @@ if($faq->getNumAttachments()) { ?> <div><span class="faded"><b>Attachments:</b></span> <?php echo $faq->getAttachmentsLinks(); ?></div> <? }?> -<div><span class="faded"><b>Help Topics:</b></span> + +<div class="article-meta"><span class="faded"><b>Help Topics:</b></span> <?php echo ($topics=$faq->getHelpTopics())?implode(', ',$topics):' '; ?> </div> </p> diff --git a/include/client/knowledgebase.inc.php b/include/client/knowledgebase.inc.php index 83484e95de818d732a67fed39b980fd5e9262e95..d8f402e7b5d191b224dc638b54f3a3177bddce85 100644 --- a/include/client/knowledgebase.inc.php +++ b/include/client/knowledgebase.inc.php @@ -3,61 +3,53 @@ if(!defined('OSTCLIENTINC')) die('Access Denied'); ?> <h1>Frequently Asked Questions</h1> -<form action="index.php" method="get" style="padding-top:15px;"> +<form action="index.php" method="get" id="kb-search"> <input type="hidden" name="a" value="search"> - <table border="0" cellspacing="0" cellpadding="3"> - <tr> - <td width="440"> - <input id="query" type="text" size="20" name="q" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> - <select name="cid"> - <option value="">— All Categories —</option> - <?php - $sql='SELECT category_id, name, count(faq.category_id) as faqs ' - .' FROM '.FAQ_CATEGORY_TABLE.' cat ' - .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) ' - .' WHERE cat.ispublic=1 AND faq.ispublished=1 ' - .' GROUP BY cat.category_id ' - .' HAVING faqs>0 ' - .' ORDER BY cat.name DESC '; - if(($res=db_query($sql)) && db_num_rows($res)) { - while($row=db_fetch_array($res)) - echo sprintf('<option value="%d" %s>%s (%d)</option>', - $row['category_id'], - ($_REQUEST['cid'] && $row['category_id']==$_REQUEST['cid']?'selected="selected"':''), - $row['name'], - $row['faqs']); - } - ?> - </select> - </td> - <td width="100" rowspan="2" style="text-align:left;vertical-align: middle;"> - <input id="searchSubmit" type="submit" value="Search"> - </td> - </tr> - <tr> - <td width="400"> - <select name="topicId" style="width:350px;"> - <option value="">— All Help Topics —</option> - <?php - $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs ' - .' FROM '.TOPIC_TABLE.' ht ' - .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) ' - .' WHERE ht.ispublic=1 ' - .' GROUP BY ht.topic_id ' - .' HAVING faqs>0 ' - .' ORDER BY ht.topic DESC '; - if(($res=db_query($sql)) && db_num_rows($res)) { - while($row=db_fetch_array($res)) - echo sprintf('<option value="%d" %s>%s (%d)</option>', - $row['topic_id'], - ($_REQUEST['topicId'] && $row['topic_id']==$_REQUEST['topicId']?'selected="selected"':''), - $row['topic'], $row['faqs']); - } - ?> - </select> - </td> - </tr> - </table> + <div> + <input id="query" type="text" size="20" name="q" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> + <select name="cid" id="cid"> + <option value="">— All Categories —</option> + <?php + $sql='SELECT category_id, name, count(faq.category_id) as faqs ' + .' FROM '.FAQ_CATEGORY_TABLE.' cat ' + .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) ' + .' WHERE cat.ispublic=1 AND faq.ispublished=1 ' + .' GROUP BY cat.category_id ' + .' HAVING faqs>0 ' + .' ORDER BY cat.name DESC '; + if(($res=db_query($sql)) && db_num_rows($res)) { + while($row=db_fetch_array($res)) + echo sprintf('<option value="%d" %s>%s (%d)</option>', + $row['category_id'], + ($_REQUEST['cid'] && $row['category_id']==$_REQUEST['cid']?'selected="selected"':''), + $row['name'], + $row['faqs']); + } + ?> + </select> + <input id="searchSubmit" type="submit" value="Search"> + </div> + <div> + <select name="topicId" id="topic-id"> + <option value="">— All Help Topics —</option> + <?php + $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs ' + .' FROM '.TOPIC_TABLE.' ht ' + .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) ' + .' WHERE ht.ispublic=1 ' + .' GROUP BY ht.topic_id ' + .' HAVING faqs>0 ' + .' ORDER BY ht.topic DESC '; + if(($res=db_query($sql)) && db_num_rows($res)) { + while($row=db_fetch_array($res)) + echo sprintf('<option value="%d" %s>%s (%d)</option>', + $row['topic_id'], + ($_REQUEST['topicId'] && $row['topic_id']==$_REQUEST['topicId']?'selected="selected"':''), + $row['topic'], $row['faqs']); + } + ?> + </select> + </div> </form> <hr> <div> @@ -100,9 +92,10 @@ if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search. echo '<div>Click on the category to browse FAQs.</div> <ul id="kb">'; while($row=db_fetch_array($res)) { - + echo sprintf(' <li> + <i></i> <h4><a href="faq.php?cid=%d">%s (%d)</a></h4> %s </li>',$row['category_id'], diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php index a360217167bde83dedcb4decb339677e3c5370d6..7719ec74a7ef2a58babcae7112a0d2cb05caa92e 100644 --- a/include/client/tickets.inc.php +++ b/include/client/tickets.inc.php @@ -59,13 +59,12 @@ if($search) { $queryterm=db_real_escape($_REQUEST['q'],false); //escape the term ONLY...no quotes. $qwhere.=' AND ( ' ." ticket.subject LIKE '%$queryterm%'" - ." OR message.message LIKE '%$queryterm%'" - ." OR response.response LIKE '%$queryterm%'" + ." OR thread.body LIKE '%$queryterm%'" .' ) '; $deep_search=true; //Joins needed for search - $qfrom.=' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id )' - .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id )'; + $qfrom.=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON (' + .'ticket.ticket_id=thread.ticket_id AND thread.thread_type IN ("M","R"))'; } } diff --git a/include/client/view.inc.php b/include/client/view.inc.php index e720ed96bffa58c5d7321e7fe2544c7829a86678..debddc4ed4713aeb3dec50b48e1fcb5bfe2f9ccc 100644 --- a/include/client/view.inc.php +++ b/include/client/view.inc.php @@ -59,46 +59,25 @@ if(!$dept || !$dept->isPublic()) <span class="Icon thread">Ticket Thread</span> <div id="ticketThread"> <?php -if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) { - - foreach($messages as $message) {?> - - <table class="message" cellspacing="0" cellpadding="1" width="800" border="0"> - - <tr><th><?php echo Format::db_datetime($message['created']); ?></th></tr> - - <tr><td><?php echo Format::display($message['message']); ?></td></tr> - +if($ticket->getThreadCount() && ($thread=$ticket->getClientThread())) { + $threadType=array('M' => 'message', 'R' => 'response'); + foreach($thread as $entry) { + //Making sure internal notes are not displayed due to backend MISTAKES! + if(!$threadType[$entry['thread_type']]) continue; + $poster = $entry['poster']; + if($entry['thread_type']=='R' && $cfg->hideStaffName()) + $poster = ' '; + ?> + <table class="<?php echo $threadType[$entry['thread_type']]; ?>" cellspacing="0" cellpadding="1" width="800" border="0"> + <tr><th><?php echo Format::db_datetime($entry['created']); ?> <span><?php echo $poster; ?></span></th></tr> + <tr><td><?php echo Format::display($entry['body']); ?></td></tr> <?php - - if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['msg_id'],'M'))) { ?> - + if($entry['attachments'] && ($links=$ticket->getAttachmentsLinks($entry['id'], $entry['thread_type']))) { ?> <tr><td class="info"><?php echo $links; ?></td></tr> - <?php - } ?> - </table> - <?php - if($message['responses'] && ($responses=$ticket->getResponses($message['msg_id']))) { - foreach($responses as $resp) { - $staff=$cfg->hideStaffName()?'staff':Format::htmlchars($resp['staff_name']); - ?> - <table class="response" cellspacing="0" cellpadding="1" width="100%" border="0"> - <tr> - <th><?php echo Format::db_datetime($resp['created']);?> - <?php echo $staff; ?></th> - </tr> - <tr><td><?php echo Format::display($resp['response']); ?></td></tr> - <?php - if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['response_id'],'R'))) {?> - <tr><td class="info"><?php echo $links; ?></td></tr> - <?php - }?> - </table> - <? - } - } + <?php } } ?> diff --git a/include/staff/api.inc.php b/include/staff/api.inc.php deleted file mode 100644 index 21eac469162af3d2cc9652d8e8255f230ee18460..0000000000000000000000000000000000000000 --- a/include/staff/api.inc.php +++ /dev/null @@ -1,147 +0,0 @@ -<?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); - - -$info['phrase']=($errors && $_POST['phrase'])?Format::htmlchars($_POST['phrase']):$cfg->getAPIPassphrase(); -$select='SELECT * '; -$from='FROM '.API_KEY_TABLE; -$where=''; -$sortOptions=array('date'=>'created','ip'=>'ipaddr'); -$orderWays=array('DESC'=>'DESC','ASC'=>'ASC'); -//Sorting options... -if($_REQUEST['sort']) { - $order_column =$sortOptions[$_REQUEST['sort']]; -} - -if($_REQUEST['order']) { - $order=$orderWays[$_REQUEST['order']]; -} -$order_column=$order_column?$order_column:'ipaddr'; -$order=$order?$order:'ASC'; -$order_by=" ORDER BY $order_column $order "; - -$total=db_count('SELECT count(*) '.$from.' '.$where); -$pagelimit=1000;//No limit. TODO: Add limit. -$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); -$pageNav->setURL('admin.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); -$query="$select $from $where $order_by"; -//echo $query; -$result = db_query($query); -$showing=db_num_rows($result)?$pageNav->showing():''; -$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting.. -$deletable=0; -?> -<div class="msg">API Keys</div> -<hr> -<div><b><?php echo $showing; ?></b></div> - <table width="100%" border="0" cellspacing=1 cellpadding=2> - <form action="admin.php?t=api" method="POST" name="api" onSubmit="return checkbox_checker(document.forms['api'],1,0);"> - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='mass_process'> - <tr><td> - <table border="0" cellspacing=0 cellpadding=2 class="dtable" align="center" width="100%"> - <tr> - <th width="7px"> </th> - <th>API Key</th> - <th width="10" nowrap>Active</th> - <th width="100" nowrap> IP Address</th> - <th width="150" nowrap> - <a href="admin.php?t=api&sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Create Date <?php echo $negorder; ?>">Created</a></th> - </tr> - <?php - $class = 'row1'; - $total=0; - $active=$inactive=0; - $sids=($errors && is_array($_POST['ids']))?$_POST['ids']:null; - if($result && db_num_rows($result)): - $dtpl=$cfg->getDefaultTemplateId(); - while ($row = db_fetch_array($result)) { - $sel=false; - $disabled=''; - if($row['isactive']) - $active++; - else - $inactive++; - - if($sids && in_array($row['id'],$sids)){ - $class="$class highlight"; - $sel=true; - } - ?> - <tr class="<?php echo $class; ?>" id="<?php echo $row['id']; ?>"> - <td width=7px> - <input type="checkbox" name="ids[]" value="<?php echo $row['id']; ?>" <?php echo $sel?'checked':''; ?> - onClick="highLight(this.value,this.checked);"> - <td> <?php echo $row['apikey']; ?></td> - <td><?php echo $row['isactive']?'<b>Yes</b>':'No'; ?></td> - <td> <?php echo $row['ipaddr']; ?></td> - <td> <?php echo Format::db_datetime($row['created']); ?></td> - </tr> - <?php - $class = ($class =='row2') ?'row1':'row2'; - } //end of while. - else: //nothin' found!! ?> - <tr class="<?php echo $class; ?>"><td colspan=5><b>Query returned 0 results</b> <a href="admin.php?t=templates">Index list</a></td></tr> - <?php - endif; ?> - - </table> - </td></tr> - <?php - if(db_num_rows($result)>0): //Show options.. - ?> - <tr> - <td align="center"> - <?php - if($inactive) { ?> - <input class="button" type="submit" name="enable" value="Enable" - onClick='return confirm("Are you sure you want to ENABLE selected keys?");'> - <?php - } - if($active){ ?> - - <input class="button" type="submit" name="disable" value="Disable" - onClick='return confirm("Are you sure you want to DISABLE selected keys?");'> - <?php } ?> - - <input class="button" type="submit" name="delete" value="Delete" - onClick='return confirm("Are you sure you want to DELETE selected keys?");'> - </td> - </tr> - <?php - endif; - ?> - </form> - </table> - <br/> - <div class="msg">Add New IP</div> - <hr> - <div> - Add a new IP address. <font class="error"><?php echo $errors['ip']; ?></font> - <form action="admin.php?t=api" method="POST" > - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='add'> - New IP: - <input name="ip" size=30 value="<?php echo ($errors['ip'])?Format::htmlchars($_REQUEST['ip']):''; ?>" /> - <font class="error">* </font> - <input class="button" type="submit" name="add" value="Add"> - </form> - </div> - <br/> - <div class="msg">API Passphrase</div> - <hr> - <div> - Passphrase must be at least 3 words. Required to generate the api keys.<br/> - <form action="admin.php?t=api" method="POST" > - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='update_phrase'> - Phrase: - <input name="phrase" size=50 value="<?php echo Format::htmlchars($info['phrase']); ?>" /> - <font class="error">* <?php echo $errors['phrase']; ?></font> - <input class="button" type="submit" name="update" value="Submit"> - </form> - <br/><br/> - <div><i>Please note that changing the passprase does NOT invalidate existing keys. To regerate a key you need to delete and readd it.</i></div> - </div> - diff --git a/include/staff/apikey.inc.php b/include/staff/apikey.inc.php index 5a82ee39bf264a821de957a779c0a73087f78bd9..7bcac1cb03e257feb855fbf0436769b8b3a3650e 100644 --- a/include/staff/apikey.inc.php +++ b/include/staff/apikey.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($api && $_REQUEST['a']!='add'){ diff --git a/include/staff/apikeys.inc.php b/include/staff/apikeys.inc.php index d7063c749ce92c04cddc36f20902b88181ab51d4..3deccb941222f8d771eb120ea90ab7e27557203c 100644 --- a/include/staff/apikeys.inc.php +++ b/include/staff/apikeys.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT * FROM '.API_KEY_TABLE.' WHERE 1'; diff --git a/include/staff/attachment.inc.php b/include/staff/attachment.inc.php index 17819867e69a458517e7c312075c07ffe3eeb06c..5951b87c0b0788767b34c98d1a7290a7c1debcdd 100644 --- a/include/staff/attachment.inc.php +++ b/include/staff/attachment.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); //Get the config info. $config=($errors && $_POST)?Format::input($_POST):$cfg->getConfig(); ?> diff --git a/include/staff/banlist.inc.php b/include/staff/banlist.inc.php index ecef00ba4325e18339b4f733d82a34b38466b950..430b51f4835bbf7038941109621774b409485b2e 100644 --- a/include/staff/banlist.inc.php +++ b/include/staff/banlist.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin() || !$filter) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$filter) die('Access Denied'); $qstr=''; $select='SELECT rule.* '; diff --git a/include/staff/banrule.inc.php b/include/staff/banrule.inc.php index bd28d19dea8368b395122beeb861045205d7ddff..0560b4a4d6268961220dad69de5d7b73617afec2 100644 --- a/include/staff/banrule.inc.php +++ b/include/staff/banrule.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; diff --git a/include/staff/department.inc.php b/include/staff/department.inc.php index fa32ec2795d1ab1635fa126ab639a5d1259f3258..521cee9bf9e9eb7446420c26c4e0ab03a1c3ad69 100644 --- a/include/staff/department.inc.php +++ b/include/staff/department.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($dept && $_REQUEST['a']!='add'){ diff --git a/include/staff/departments.inc.php b/include/staff/departments.inc.php index 805b7ec20706c7cbbfa1bb2dd331068aa3bc8154..71b702a0676cff5f6824c933fc458882fff9e991 100644 --- a/include/staff/departments.inc.php +++ b/include/staff/departments.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT dept.dept_id,dept_name,email.email_id,email.email,email.name as email_name,ispublic,count(staff.staff_id) as users '. diff --git a/include/staff/editticket.inc.php b/include/staff/editticket.inc.php deleted file mode 100644 index 20accf0e4d70883861b51e2c6518fa6bce060cdc..0000000000000000000000000000000000000000 --- a/include/staff/editticket.inc.php +++ /dev/null @@ -1,142 +0,0 @@ -<?php -if(!defined('OSTSCPINC') || !is_object($ticket) || !is_object($thisstaff) || !$thisstaff->isStaff()) die('Access Denied'); - -if(!($thisstaff->canEditTickets() || ($thisstaff->isManager() && $ticket->getDeptId()==$thisstaff->getDeptId()))) die('Access Denied. Perm error.'); - -if($_POST && $errors){ - $info=Format::input($_POST); -}else{ - $info=array('email'=>$ticket->getEmail(), - 'name' =>$ticket->getName(), - 'phone'=>$ticket->getPhone(), - 'phone_ext'=>$ticket->getPhoneExt(), - 'pri'=>$ticket->getPriorityId(), - 'topicId'=>$ticket->getTopicId(), - 'topic'=>$ticket->getHelpTopic(), - 'subject' =>$ticket->getSubject(), - 'duedate' =>$ticket->getDueDate()?(Format::userdate('m/d/Y',Misc::db2gmtime($ticket->getDueDate()))):'', - 'time'=>$ticket->getDueDate()?(Format::userdate('G:i',Misc::db2gmtime($ticket->getDueDate()))):'', - ); - /*Note: Please don't make me explain how dates work - it is torture. Trust me! */ -} - -?> -<div width="100%"> - <?php if($errors['err']) { ?> - <p align="center" id="errormessage"><?php echo $errors['err']; ?></p> - <?php }elseif($msg) { ?> - <p align="center" class="infomessage"><?php echo $msg; ?></p> - <?php }elseif($warn) { ?> - <p class="warnmessage"><?php echo $warn; ?></p> - <?php } ?> -</div> -<table width="100%" border="0" cellspacing=1 cellpadding=2> - <form action="tickets.php?id=<?php echo $ticket->getId(); ?>" method="post"> - <input type='hidden' name='id' value='<?php echo $ticket->getId(); ?>'> - <input type='hidden' name='a' value='update'> - <tr><td align="left" colspan=2 class="msg"> - Update Ticket #<?php echo $ticket->getExtId(); ?> (<a href="tickets.php?id=<?php echo $ticket->getId(); ?>" style="color:black;">View Ticket</a>)<br></td></tr> - <tr> - <td align="left" nowrap width="120"><b>Email Address:</b></td> - <td> - <input type="text" id="email" name="email" size="25" value="<?php echo $info['email']; ?>"> - <font class="error"><b>*</b> <?php echo $errors['email']; ?></font> - </td> - </tr> - <tr> - <td align="left" ><b>Full Name:</b></td> - <td> - <input type="text" id="name" name="name" size="25" value="<?php echo $info['name']; ?>"> - <font class="error"><b>*</b> <?php echo $errors['name']; ?></font> - </td> - </tr> - <tr> - <td align="left"><b>Subject:</b></td> - <td> - <input type="text" name="subject" size="35" value="<?php echo $info['subject']; ?>"> - <font class="error">* <?php echo $errors['subject']; ?></font> - </td> - </tr> - <tr> - <td align="left">Telephone:</td> - <td><input type="text" name="phone" size="25" value="<?php echo $info['phone']; ?>"> - Ext <input type="text" name="phone_ext" size="6" value="<?php echo $info['phone_ext']; ?>"> - <font class="error"> <?php echo $errors['phone']; ?></font></td> - </tr> - <tr height=1px><td align="left" colspan=2 > </td></tr> - <tr> - <td align="left" valign="top">Due Date:</td> - <td> - <i>Time is based on your time zone (GM <?php echo $thisstaff->getTZoffset(); ?>)</i> <font class="error"> <?php echo $errors['time']; ?></font><br> - <input id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('duedate')); return false;"><img src='images/cal.png'border=0 alt=""></a> - - <?php - $min=$hr=null; - if($info['time']) - list($hr,$min)=explode(':',$info['time']); - echo Misc::timeDropdown($hr,$min,'time'); - ?> - <font class="error"> <?php echo $errors['duedate']; ?></font> - </td> - </tr> - <?php - $sql='SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE.' ORDER BY priority_urgency DESC'; - if(($priorities=db_query($sql)) && db_num_rows($priorities)){ ?> - <tr> - <td align="left">Priority:</td> - <td> - <select name="pri"> - <?php - while($row=db_fetch_array($priorities)){ ?> - <option value="<?php echo $row['priority_id']; ?>" <?php echo $info['pri']==$row['priority_id']?'selected':''; ?> ><?php echo $row['priority_desc']; ?></option> - <?php } ?> - </select> - </td> - </tr> - <?php } ?> - - <?php - $services= db_query('SELECT topic_id,topic,isactive FROM '.TOPIC_TABLE.' ORDER BY topic'); - if($services && db_num_rows($services)){ ?> - <tr> - <td align="left" valign="top">Help Topic:</td> - <td> - <select name="topicId"> - <option value="0" selected >None</option> - <?php if(!$info['topicId'] && $info['topic']){ //old helptopic ?> - <option value="0" selected ><?php echo $info['topic']; ?> (deleted)</option> - <?php - } - while (list($topicId,$topic,$active) = db_fetch_row($services)){ - $selected = ($info['topicId']==$topicId)?'selected':''; - $status=$active?'Active':'Inactive'; - ?> - <option value="<?php echo $topicId; ?>"<?php echo $selected; ?>><?php echo $topic; ?> (<?php echo $status; ?>)</option> - <?php - } ?> - </select> - (optional)<font class="error"> <?php echo $errors['topicId']; ?></font> - </td> - </tr> - <?php - } ?> - <tr> - <td align="left" valign="top"><b>Internal Note:</b></td> - <td> - <i>Reasons for the edit.</i><font class="error"><b>* <?php echo $errors['note']; ?></b></font><br/> - <textarea name="note" cols="45" rows="5" wrap="soft"><?php echo $info['note']; ?></textarea></td> - </tr> - <tr height=2px><td align="left" colspan=2 > </td></tr> - <tr> - <td></td> - <td> - <input class="button" type="submit" name="submit_x" value="Update Ticket"> - <input class="button" type="reset" value="Reset"> - <input class="button" type="button" name="cancel" value="Cancel" onClick='window.location.href="tickets.php?id=<?php echo $ticket->getId(); ?>"'> - </td> - </tr> - </form> -</table> - diff --git a/include/staff/email.inc.php b/include/staff/email.inc.php index 4f2d695b09304c4dcd5fc850e32ede734c514bbf..2fd2b8857494c64c061524a5bd294e4433299ee4 100644 --- a/include/staff/email.inc.php +++ b/include/staff/email.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($email && $_REQUEST['a']!='add'){ diff --git a/include/staff/emails.inc.php b/include/staff/emails.inc.php index 65d34d7b9bfb0b10acd983bfe41e5671932d3060..8d5f221177051e484fcaff4457c5f9f60bffbc99 100644 --- a/include/staff/emails.inc.php +++ b/include/staff/emails.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT email.*,dept.dept_name as department,priority_desc as priority '. diff --git a/include/staff/filter.inc.php b/include/staff/filter.inc.php index 91f74501661cda00d97aada035b28559a9961d41..6f8cce2c41a1e6acd8f4810b3cdc7e643a9a4471 100644 --- a/include/staff/filter.inc.php +++ b/include/staff/filter.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $matches=array('name'=>"Sender's Name",'email'=>"Sender's Email",'subject'=>'Email Subject','body'=>'Email Body/Text','header'=>'Email Header'); $match_types=array('equal'=>'Equal','not_equal'=>'Not Equal','contains'=>'Contains','dn_contain'=>'Does Not Contain'); diff --git a/include/staff/filters.inc.php b/include/staff/filters.inc.php index fb8a48d268a7705d5eb3a49b4076a6dcdb3b0b17..b5534bdde77a12ffe88a8f2362046c5d2e64fce2 100644 --- a/include/staff/filters.inc.php +++ b/include/staff/filters.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT filter.*,count(rule.id) as rules '. diff --git a/include/staff/group.inc.php b/include/staff/group.inc.php index 87921a63cb18aad7a2c73ab73ab5a2c7fb3d8acd..afb574f5f3cea7ff161dc34e90c05fa77f955b51 100644 --- a/include/staff/group.inc.php +++ b/include/staff/group.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($group && $_REQUEST['a']!='add'){ diff --git a/include/staff/groups.inc.php b/include/staff/groups.inc.php index 15b9b6610916c203cdf25e902228dd8d5281ba5a..ed5e3638a8d0528908584ddfad5320d885a38e4d 100644 --- a/include/staff/groups.inc.php +++ b/include/staff/groups.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; diff --git a/include/staff/header.inc.php b/include/staff/header.inc.php index 58d4f28dcdf77cbe3fa184e8a4979982b01de0fe..46722948c5aae7309c921623dfeaa57aa2c32a0b 100644 --- a/include/staff/header.inc.php +++ b/include/staff/header.inc.php @@ -14,19 +14,20 @@ </style> <![endif]--> <script type="text/javascript" src="../js/jquery-1.7.2.min.js"></script> - <script type="text/javascript" src="./js/calendar.js"></script> + <script type="text/javascript" src="../js/jquery-ui-1.8.18.custom.min.js"></script> <script type="text/javascript" src="./js/tips.js"></script> <script type="text/javascript" src="./js/nicEdit.js"></script> <script type="text/javascript" src="./js/bootstrap-typeahead.js"></script> <script type="text/javascript" src="./js/scp.js"></script> <link rel="stylesheet" href="./css/scp.css" media="screen"> <link rel="stylesheet" href="./css/typeahead.css" media="screen"> + <link type="text/css" href="../css/ui-lightness/jquery-ui-1.8.18.custom.css" rel="stylesheet" /> </head> <body> <div id="container"> <div id="header"> <a href="index.php" id="logo">osTicket - Customer Support System</a> - <p id="info">Welcome back, <strong><?php echo $thisstaff->getUsername(); ?></strong> + <p id="info">Howdy, <strong><?php echo $thisstaff->getUserName(); ?></strong> <?php if($thisstaff->isAdmin() && !defined('ADMINPAGE')) { ?> | <a href="admin.php">Admin Panel</a> diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php index ad9f808bcfd6afedfabec510dda920ca2abaae0a..c0fdcd34010266a802bbffdd3f31c741c36f0b9a 100644 --- a/include/staff/helptopic.inc.php +++ b/include/staff/helptopic.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($topic && $_REQUEST['a']!='add'){ diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php index 27ffde9bdacac59c2687b30b5046dde4255b1537..b3d58c777517753e02b41d1aaa703ed6e5500c01 100644 --- a/include/staff/helptopics.inc.php +++ b/include/staff/helptopics.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT topic.*,dept.dept_name as department,priority_desc as priority '. diff --git a/include/staff/kb-categories.inc.php b/include/staff/kb-categories.inc.php index 0ab8b03fc1e6326eac435768954c049dc0b3aa64..eb673a735678e3ebd867f3019b34443822a4b178 100644 --- a/include/staff/kb-categories.inc.php +++ b/include/staff/kb-categories.inc.php @@ -3,59 +3,51 @@ if(!defined('OSTSTAFFINC') || !$thisstaff) die('Access Denied'); ?> <h2>Frequently Asked Questions</h2> -<form id="kbSearch" action="kb.php" method="get" style="padding-top:15px;"> +<form id="kbSearch" action="kb.php" method="get"> <input type="hidden" name="a" value="search"> - <table border="0" cellspacing="0" cellpadding="3"> - <tr> - <td width="440"> - <input id="query" type="text" size="20" name="q" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> - <select name="cid"> - <option value="">— All Categories —</option> - <?php - $sql='SELECT category_id, name, count(faq.category_id) as faqs ' - .' FROM '.FAQ_CATEGORY_TABLE.' cat ' - .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) ' - .' GROUP BY cat.category_id ' - .' HAVING faqs>0 ' - .' ORDER BY cat.name DESC '; - if(($res=db_query($sql)) && db_num_rows($res)) { - while($row=db_fetch_array($res)) - echo sprintf('<option value="%d" %s>%s (%d)</option>', - $row['category_id'], - ($_REQUEST['cid'] && $row['category_id']==$_REQUEST['cid']?'selected="selected"':''), - $row['name'], - $row['faqs']); - } - ?> - </select> - </td> - <td width="100" rowspan="2"> - <input id="searchSubmit" type="submit" value="Search"> - </td> - </tr> - <tr> - <td width="400"> - <select name="topicId" style="width:350px;"> - <option value="">— All Help Topics —</option> - <?php - $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs ' - .' FROM '.TOPIC_TABLE.' ht ' - .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) ' - .' GROUP BY ht.topic_id ' - .' HAVING faqs>0 ' - .' ORDER BY ht.topic DESC '; - if(($res=db_query($sql)) && db_num_rows($res)) { - while($row=db_fetch_array($res)) - echo sprintf('<option value="%d" %s>%s (%d)</option>', - $row['topic_id'], - ($_REQUEST['topicId'] && $row['topic_id']==$_REQUEST['cid']?'selected="selected"':''), - $row['topic'], $row['faqs']); - } - ?> - </select> - </td> - </tr> - </table> + <div> + <input id="query" type="text" size="20" name="q" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> + <select name="cid" id="cid"> + <option value="">— All Categories —</option> + <?php + $sql='SELECT category_id, name, count(faq.category_id) as faqs ' + .' FROM '.FAQ_CATEGORY_TABLE.' cat ' + .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) ' + .' GROUP BY cat.category_id ' + .' HAVING faqs>0 ' + .' ORDER BY cat.name DESC '; + if(($res=db_query($sql)) && db_num_rows($res)) { + while($row=db_fetch_array($res)) + echo sprintf('<option value="%d" %s>%s (%d)</option>', + $row['category_id'], + ($_REQUEST['cid'] && $row['category_id']==$_REQUEST['cid']?'selected="selected"':''), + $row['name'], + $row['faqs']); + } + ?> + </select> + <input id="searchSubmit" type="submit" value="Search"> + </div> + <div> + <select name="topicId" style="width:350px;" id="topic-id"> + <option value="">— All Help Topics —</option> + <?php + $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs ' + .' FROM '.TOPIC_TABLE.' ht ' + .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) ' + .' GROUP BY ht.topic_id ' + .' HAVING faqs>0 ' + .' ORDER BY ht.topic DESC '; + if(($res=db_query($sql)) && db_num_rows($res)) { + while($row=db_fetch_array($res)) + echo sprintf('<option value="%d" %s>%s (%d)</option>', + $row['topic_id'], + ($_REQUEST['topicId'] && $row['topic_id']==$_REQUEST['cid']?'selected="selected"':''), + $row['topic'], $row['faqs']); + } + ?> + </select> + </div> </form> <hr> <div> @@ -96,7 +88,7 @@ if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search. echo '<div>Click on the category to browse FAQs.</div> <ul id="kb">'; while($row=db_fetch_array($res)) { - + echo sprintf(' <li> <h4><a href="kb.php?cid=%d">%s (%d)</a> - <span>%s</span></h4> diff --git a/include/staff/kb-category.inc.php b/include/staff/kb-category.inc.php index 619aa6205fd8db22e0a3060d5e23b495162b5e10..e7013192e995738c2f9be4f249c3292acac9ab53 100644 --- a/include/staff/kb-category.inc.php +++ b/include/staff/kb-category.inc.php @@ -11,23 +11,23 @@ if(!defined('OSTSTAFFINC') || !$category || !$thisstaff) die('Access Denied'); <div> <strong><?php echo $category->getName() ?></strong> <span>(<?php echo $category->isPublic()?'Public':'Internal'; ?>)</span> - <br> - <div class="faded"> Last updated <?php echo Format::db_daydatetime($category->getUpdateDate()); ?></div> + <time>Last updated <?php echo Format::db_daydatetime($category->getUpdateDate()); ?></time> </div> -<p> +<div class="cat-desc"> <?php echo Format::safe_html($category->getDescription()); ?> -</p> +</div> <?php if($thisstaff->canManageFAQ()) { - echo sprintf('<a href="categories.php?id=%d" class="Icon editCategory">Edit Category</a> - | <a href="categories.php" class="Icon deleteCategory">Delete Category</a> - | <a href="faq.php?cid=%d&a=add" class="Icon newFAQ">Add New FAQ</a>', + echo sprintf('<div class="cat-manage-bar"><a href="categories.php?id=%d" class="Icon editCategory">Edit Category</a> + <a href="categories.php" class="Icon deleteCategory">Delete Category</a> + <a href="faq.php?cid=%d&a=add" class="Icon newFAQ">Add New FAQ</a></div>', $category->getId(), $category->getId()); -} +} else { ?> <hr> <?php +} $sql='SELECT faq.faq_id, question, ispublished, count(attach.file_id) as attachments ' .' FROM '.FAQ_TABLE.' faq ' @@ -39,7 +39,7 @@ if(($res=db_query($sql)) && db_num_rows($res)) { <ol>'; while($row=db_fetch_array($res)) { echo sprintf(' - <li><a href="faq.php?id=%d" class="previewfaq">%s</a> - <span>%s</span></li>', + <li><a href="faq.php?id=%d" class="previewfaq">%s <span>- %s</span></a></li>', $row['faq_id'],$row['question'],$row['ispublished']?'Published':'Internal'); } echo ' </ol> diff --git a/include/staff/newticket.inc.php b/include/staff/newticket.inc.php deleted file mode 100644 index 42afb7c3e07ac579516750ac60b9826a19d0eb4e..0000000000000000000000000000000000000000 --- a/include/staff/newticket.inc.php +++ /dev/null @@ -1,224 +0,0 @@ -<?php -if(!defined('OSTSCPINC') || !is_object($thisstaff) || !$thisstaff->isStaff()) die('Access Denied'); -$info=($_POST && $errors)?Format::input($_POST):array(); //on error...use the post data -?> -<div width="100%"> - <?php if($errors['err']) { ?> - <p align="center" id="errormessage"><?php echo $errors['err']; ?></p> - <?php }elseif($msg) { ?> - <p align="center" class="infomessage"><?php echo $msg; ?></p> - <?php }elseif($warn) { ?> - <p class="warnmessage"><?php echo $warn; ?></p> - <?php } ?> -</div> -<table width="80%" border="0" cellspacing=1 cellpadding=2> - <form action="tickets.php" method="post" enctype="multipart/form-data"> - <input type='hidden' name='a' value='open'> - <tr><td align="left" colspan=2>Please fill in the form below to open a new ticket.</td></tr> - <tr> - <td align="left" nowrap width="20%"><b>Email Address:</b></td> - <td> - <input type="text" id="email" name="email" size="25" value="<?php echo $info['email']; ?>"> - <font class="error"><b>*</b> <?php echo $errors['email']; ?></font> - <?php if($cfg->notifyONNewStaffTicket()) { ?> - - <input type="checkbox" name="alertuser" <?php echo (!$errors || $info['alertuser'])? 'checked': ''; ?>>Send alert to user. - <?php } ?> - </td> - </tr> - <tr> - <td align="left" ><b>Full Name:</b></td> - <td> - <input type="text" id="name" name="name" size="25" value="<?php echo $info['name']; ?>"> - <font class="error"><b>*</b> <?php echo $errors['name']; ?></font> - </td> - </tr> - <tr> - <td align="left">Telephone:</td> - <td><input type="text" name="phone" size="25" value="<?php echo $info['phone']; ?>"> - Ext <input type="text" name="phone_ext" size="6" value="<?php echo $info['phone_ext']; ?>"> - <font class="error"> <?php echo $errors['phone']; ?></font></td> - </tr> - <tr height=2px><td align="left" colspan=2 > </td</tr> - <tr> - <td align="left"><b>Ticket Source:</b></td> - <td> - <select name="source"> - <option value="" selected >Select Source</option> - <option value="Phone" <?php echo ($info['source']=='Phone')?'selected':''; ?>>Phone</option> - <option value="Email" <?php echo ($info['source']=='Email')?'selected':''; ?>>Email</option> - <option value="Other" <?php echo ($info['source']=='Other')?'selected':''; ?>>Other</option> - </select> - <font class="error"><b>*</b> <?php echo $errors['source']; ?></font> - </td> - </tr> - <tr> - <td align="left"><b>Department:</b></td> - <td> - <select name="deptId"> - <option value="" selected >Select Department</option> - <?php - $services= db_query('SELECT dept_id,dept_name FROM '.DEPT_TABLE.' ORDER BY dept_name'); - while (list($deptId,$dept) = db_fetch_row($services)){ - $selected = ($info['deptId']==$deptId)?'selected':''; ?> - <option value="<?php echo $deptId; ?>"<?php echo $selected; ?>><?php echo $dept; ?></option> - <?php - } ?> - </select> - <font class="error"><b>*</b> <?php echo $errors['deptId']; ?></font> - </td> - </tr> - <tr> - <td align="left"><b>Subject:</b></td> - <td> - <input type="text" name="subject" size="35" value="<?php echo $info['subject']; ?>"> - <font class="error">* <?php echo $errors['subject']; ?></font> - </td> - </tr> - <tr> - <td align="left" valign="top"><b>Issue Summary:</b></td> - <td> - <i>Visible to client/customer.</i><font class="error"><b>* <?php echo $errors['issue']; ?></b></font><br/> - <?php - $sql='SELECT canned_id,title FROM '.CANNED_TABLE.' WHERE isenabled=1'; - - if(($res=db_query($sql)) && db_num_rows($res)) { - ?> - Premade: - <select id="canned" name="canned" - onChange="getCannedResponse(this.options[this.selectedIndex].value,this.form,'issue');this.selectedIndex='0';" > - <option value="0" selected="selected">Select a premade reply/issue</option> - <?php while(list($cannedId,$title)=db_fetch_row($res)) { ?> - <option value="<?php echo $cannedId; ?>" ><?php echo Format::htmlchars($title); ?></option> - <?php } ?> - </select> <label><input type='checkbox' value='1' name=append checked="true" />Append</label> - <?php } ?> - <textarea name="issue" cols="55" rows="8" wrap="soft"><?php echo $info['issue']; ?></textarea></td> - </tr> - <?php if($cfg->canUploadFiles()) { - ?> - <tr> - <td>Attachment:</td> - <td> - <input type="file" name="attachment"><font class="error"> <?php echo $errors['attachment']; ?></font> - </td> - </tr> - <?php } ?> - <tr> - <td align="left" valign="top">Internal Note:</td> - <td> - <i>Optional Internal note(s).</i><font class="error"><b> <?php echo $errors['note']; ?></b></font><br/> - <textarea name="note" cols="55" rows="5" wrap="soft"><?php echo $info['note']; ?></textarea></td> - </tr> - - <tr> - <td align="left" valign="top">Due Date:</td> - <td> - <i>Time is based on your time zone (GM <?php echo $thisstaff->getTZoffset(); ?>)</i> <font class="error"> <?php echo $errors['time']; ?></font><br> - <input id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('duedate')); return false;"><img src='images/cal.png'border=0 alt=""></a> - - <?php - $min=$hr=null; - if($info['time']) - list($hr,$min)=explode(':',$info['time']); - echo Misc::timeDropdown($hr,$min,'time'); - ?> - <font class="error"> <?php echo $errors['duedate']; ?></font> - </td> - </tr> - <?php - $sql='SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE.' ORDER BY priority_urgency DESC'; - if(($priorities=db_query($sql)) && db_num_rows($priorities)){ ?> - <tr> - <td align="left">Priority:</td> - <td> - <select name="pri"> - <?php - $info['pri']=$info['pri']?$info['pri']:$cfg->getDefaultPriorityId(); - while($row=db_fetch_array($priorities)){ ?> - <option value="<?php echo $row['priority_id']; ?>" <?php echo $info['pri']==$row['priority_id']?'selected':''; ?> ><?php echo $row['priority_desc']; ?></option> - <?php } ?> - </select> - </td> - </tr> - <?php } ?> - <?php - $services= db_query('SELECT topic_id,topic FROM '.TOPIC_TABLE.' WHERE isactive=1 ORDER BY topic'); - if($services && db_num_rows($services)){ ?> - <tr> - <td align="left" valign="top">Help Topic:</td> - <td> - <select name="topicId"> - <option value="" selected >Select One</option> - <?php - while (list($topicId,$topic) = db_fetch_row($services)){ - $selected = ($info['topicId']==$topicId)?'selected':''; ?> - <option value="<?php echo $topicId; ?>"<?php echo $selected; ?>><?php echo $topic; ?></option> - <?php - } ?> - </select> - <font class="error"> <?php echo $errors['topicId']; ?></font> - </td> - </tr> - <?php - } ?> - <tr> - <td>Assign To:</td> - <td> - <select id="staffId" name="staffId"> - <option value="0" selected="selected">-Assign To Staff-</option> - <?php - //TODO: make sure the user's group is also active....DO a join. - $sql=' SELECT staff_id,CONCAT_WS(", ",lastname,firstname) as name FROM '.STAFF_TABLE.' WHERE isactive=1 AND onvacation=0 '; - $depts= db_query($sql.' ORDER BY lastname,firstname '); - while (list($staffId,$staffName) = db_fetch_row($depts)){ - $selected = ($info['staffId']==$staffId)?'selected':''; ?> - <option value="<?php echo $staffId; ?>"<?php echo $selected; ?>><?php echo $staffName; ?></option> - <?php - } ?> - </select><font class='error'> <?php echo $errors['staffId']; ?></font> - - <input type="checkbox" name="alertstaff" <?php echo (!$errors || $info['alertstaff'])? 'checked': ''; ?>>Send alert to assigned staff. - </td> - </tr> - <tr> - <td>Signature:</td> - <td> <?php - $appendStaffSig=$thisstaff->appendMySignature(); - $info['signature']=!$info['signature']?'none':$info['signature']; //change 'none' to 'mine' to default to staff signature. - ?> - <div style="margin-top: 2px;"> - <label><input type="radio" name="signature" value="none" checked > None</label> - <?php if($appendStaffSig) { ?> - <label> <input type="radio" name="signature" value="mine" <?php echo $info['signature']=='mine'?'checked':''; ?> > My signature</label> - <?php } ?> - <label><input type="radio" name="signature" value="dept" <?php echo $info['signature']=='dept'?'checked':''; ?> > Dept Signature (if any)</label> - </div> - </td> - </tr> - <tr height=2px><td align="left" colspan=2 > </td</tr> - <tr> - <td></td> - <td> - <input class="button" type="submit" name="submit_x" value="Submit Ticket"> - <input class="button" type="reset" value="Reset"> - <input class="button" type="button" name="cancel" value="Cancel" onClick='window.location.href="tickets.php"'> - </td> - </tr> - </form> -</table> -<script type="text/javascript"> - - var options = { - script:"ajax.php?api=tickets&f=searchbyemail&limit=10&", - varname:"input", - json: true, - shownoresults:false, - maxresults:10, - callback: function (obj) { document.getElementById('email').value = obj.id; document.getElementById('name').value = obj.info; return false;} - }; - var autosug = new bsn.AutoSuggest('email', options); -</script> - diff --git a/include/staff/preference.inc.php b/include/staff/preference.inc.php index d956d011dff2c15ad87c7e023f69303a87034353..054d592a7555f8d16f436f9cc5c9c66a91b6f27b 100644 --- a/include/staff/preference.inc.php +++ b/include/staff/preference.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); //Get the config info. $config=($errors && $_POST)?Format::input($_POST):Format::htmlchars($cfg->getConfig()); diff --git a/include/staff/settings-tickets.inc.php b/include/staff/settings-tickets.inc.php index bcf7347a74cf6d5bf5e9c60cfbe1b28729bbaffd..5ada80f48bca4edfb7221e6916aa5e46efb85d94 100644 --- a/include/staff/settings-tickets.inc.php +++ b/include/staff/settings-tickets.inc.php @@ -1,140 +1,148 @@ -<form action="settings.php?t=tickets" method="post" id="save"> -<input type="hidden" name="t" value="tickets" > -<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2"> - <thead> - <tr> - <th colspan="2"> - <h4>Ticket Settings and Options</h4> - <em>Global ticket settings and options.</em> - </th> - </tr> - </thead> - <tbody> - <tr><td width="220" class="required">Ticket IDs:</td> - <td> - <input type="radio" name="random_ticket_ids" value="0" <?php echo !$config['random_ticket_ids']?'checked="checked"':''; ?> /> - Sequential - <input type="radio" name="random_ticket_ids" value="1" <?php echo $config['random_ticket_ids']?'checked="checked"':''; ?> /> - Random <em>(highly recommended)</em> - </td> - </tr> - - <tr> - <td width="180" class="required"> - Default SLA: - </td> - <td> - <select name="default_sla_id"> - <option value="0">— None —</option> - <?php - $sql='SELECT id,name FROM '.SLA_TABLE.' sla ORDER by name'; - if(($res=db_query($sql)) && db_num_rows($res)){ - while(list($id,$name)=db_fetch_row($res)){ - $selected=($config['default_sla_id'] && $id==$config['default_sla_id'])?'selected="selected"':''; - echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name); - } - } - ?> - </select> - <span class="error">* <?php echo $errors['default_sla_id']; ?></span> - </td> - </tr> - <tr> - <td width="180" class="required">Default Priority:</td> - <td> - <select name="default_priority_id"> +<form action="settings.php?t=tickets" method="post" id="save"> +<input type="hidden" name="t" value="tickets" > +<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2"> + <thead> + <tr> + <th colspan="2"> + <h4>Ticket Settings and Options</h4> + <em>Global ticket settings and options.</em> + </th> + </tr> + </thead> + <tbody> + <tr><td width="220" class="required">Ticket IDs:</td> + <td> + <input type="radio" name="random_ticket_ids" value="0" <?php echo !$config['random_ticket_ids']?'checked="checked"':''; ?> /> + Sequential + <input type="radio" name="random_ticket_ids" value="1" <?php echo $config['random_ticket_ids']?'checked="checked"':''; ?> /> + Random <em>(highly recommended)</em> + </td> + </tr> + + <tr> + <td width="180" class="required"> + Default SLA: + </td> + <td> + <select name="default_sla_id"> + <option value="0">— None —</option> <?php - $priorities= db_query('SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE); - while (list($id,$tag) = db_fetch_row($priorities)){ ?> - <option value="<?php echo $id; ?>"<?php echo ($config['default_priority_id']==$id)?'selected':''; ?>><?php echo $tag; ?></option> + $sql='SELECT id,name FROM '.SLA_TABLE.' sla ORDER by name'; + if(($res=db_query($sql)) && db_num_rows($res)){ + while(list($id,$name)=db_fetch_row($res)){ + $selected=($config['default_sla_id'] && $id==$config['default_sla_id'])?'selected="selected"':''; + echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name); + } + } + ?> + </select> + <span class="error">* <?php echo $errors['default_sla_id']; ?></span> + </td> + </tr> + <tr> + <td width="180" class="required">Default Priority:</td> + <td> + <select name="default_priority_id"> <?php - } ?> - </select> - <span class="error">* <?php echo $errors['default_priority_id']; ?></span> - </td> - </tr> - <tr> - <td width="180">Web Tickets Priority</td> - <td> - <input type="checkbox" name="allow_priority_change" value="1" <?php echo $config['allow_priority_change'] ?'checked="checked"':''; ?>> - <em>(Allow user to overwrite/set priority)</em> - </td> - </tr> - <tr> - <td width="180">Emailed Tickets Priority</td> - <td> - <input type="checkbox" name="use_email_priority" value="1" <?php echo $config['use_email_priority'] ?'checked="checked"':''; ?> > - <em>(Use email priority when available)</em> - </td> - </tr> - <tr> - <td width="180">Show Related Tickets</td> - <td> - <input type="checkbox" name="show_related_tickets" value="1" <?php echo $config['show_related_tickets'] ?'checked="checked"':''; ?> > - <em>(Show all related tickets on user login - otherwise access is restricted to one ticket view per login)</em> - </td> - </tr> - <tr> - <td>Human Verification:</td> - <td> - <input type="checkbox" name="enable_captcha" <?php echo $config['enable_captcha']?'checked="checked"':''; ?>> - Enable CAPTCHA on new web tickets.<em>(requires GDLib)</em> <font class="error"> <?php echo $errors['enable_captcha']; ?></font><br/> - </td> - </tr> - <tr> - <td>Maximum <b>Open</b> Tickets:</td> - <td> - <input type="text" name="max_open_tickets" size=4 value="<?php echo $config['max_open_tickets']; ?>"> - per email/user. <em>(Helps with spam and email flood control - enter 0 for unlimited)</em> - </td> - </tr> - <tr> - <td>Ticket Auto-lock Time:</td> - <td> - <input type="text" name="autolock_minutes" size=4 value="<?php echo $config['autolock_minutes']; ?>"> - <font class="error"><?php echo $errors['autolock_minutes']; ?></font> - <em>(Minutes to lock a ticket on activity - enter 0 to disable locking)</em> - </td> - </tr> - <tr> - <td>Reopened Tickets:</td> - <td> - <input type="checkbox" name="auto_assign_reopened_tickets" <?php echo $config['auto_assign_reopened_tickets']?'checked="checked"':''; ?>> - Auto-assign reopened tickets to the last available respondent. - </td> - </tr> - <tr> - <td>Assigned Tickets:</td> - <td> - <input type="checkbox" name="show_assigned_tickets" <?php echo $config['show_assigned_tickets']?'checked="checked"':''; ?>> - Show assigned tickets on open queue. - </td> - </tr> - <tr> - <td>Answered Tickets:</td> - <td> - <input type="checkbox" name="show_answered_tickets" <?php echo $config['show_answered_tickets']?'checked="checked"':''; ?>> - Show answered tickets on open queue. - </td> - </tr> - <tr> - <td>Ticket Activity Log:</td> - <td> - <input type="checkbox" name="log_ticket_activity" <?php echo $config['log_ticket_activity']?'checked="checked"':''; ?>> - Log ticket activity as internal notes. - </td> - </tr> - <tr> - <td>Staff Identity Masking:</td> - <td> - <input type="checkbox" name="hide_staff_name" <?php echo $config['hide_staff_name']?'checked="checked"':''; ?>> - Hide staff's name on responses. - </td> - </tr> - </tbody> -</table> -<p style="padding-left:250px;"> - <input class="button" type="submit" name="submit" value="Save Changes"> - <input class="button" type="reset" name="reset" value="Reset Changes"> -</p> -</form> + $priorities= db_query('SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE); + while (list($id,$tag) = db_fetch_row($priorities)){ ?> + <option value="<?php echo $id; ?>"<?php echo ($config['default_priority_id']==$id)?'selected':''; ?>><?php echo $tag; ?></option> + <?php + } ?> + </select> + <span class="error">* <?php echo $errors['default_priority_id']; ?></span> + </td> + </tr> + <tr> + <td width="180">Web Tickets Priority</td> + <td> + <input type="checkbox" name="allow_priority_change" value="1" <?php echo $config['allow_priority_change'] ?'checked="checked"':''; ?>> + <em>(Allow user to overwrite/set priority)</em> + </td> + </tr> + <tr> + <td width="180">Emailed Tickets Priority</td> + <td> + <input type="checkbox" name="use_email_priority" value="1" <?php echo $config['use_email_priority'] ?'checked="checked"':''; ?> > + <em>(Use email priority when available)</em> + </td> + </tr> + <tr> + <td width="180">Show Related Tickets</td> + <td> + <input type="checkbox" name="show_related_tickets" value="1" <?php echo $config['show_related_tickets'] ?'checked="checked"':''; ?> > + <em>(Show all related tickets on user login - otherwise access is restricted to one ticket view per login)</em> + </td> + </tr> + <tr> + <td width="180">Show Notes Inline</td> + <td> + <input type="checkbox" name="show_notes_inline" value="1" <?php echo $config['show_notes_inline'] ?'checked="checked"':''; ?> > + <em>(Show internal notes inline)</em> + </td> + </tr> + <tr> + <td>Human Verification:</td> + <td> + <input type="checkbox" name="enable_captcha" <?php echo $config['enable_captcha']?'checked="checked"':''; ?>> + Enable CAPTCHA on new web tickets.<em>(requires GDLib)</em> <font class="error"> <?php echo $errors['enable_captcha']; ?></font><br/> + </td> + </tr> + <tr> + <td>Maximum <b>Open</b> Tickets:</td> + <td> + <input type="text" name="max_open_tickets" size=4 value="<?php echo $config['max_open_tickets']; ?>"> + per email/user. <em>(Helps with spam and email flood control - enter 0 for unlimited)</em> + </td> + </tr> + <tr> + <td>Ticket Auto-lock Time:</td> + <td> + <input type="text" name="autolock_minutes" size=4 value="<?php echo $config['autolock_minutes']; ?>"> + <font class="error"><?php echo $errors['autolock_minutes']; ?></font> + <em>(Minutes to lock a ticket on activity - enter 0 to disable locking)</em> + </td> + </tr> + <tr> + <td>Reopened Tickets:</td> + <td> + <input type="checkbox" name="auto_assign_reopened_tickets" <?php echo $config['auto_assign_reopened_tickets']?'checked="checked"':''; ?>> + Auto-assign reopened tickets to the last available respondent. + </td> + </tr> + <tr> + <td>Assigned Tickets:</td> + <td> + <input type="checkbox" name="show_assigned_tickets" <?php echo $config['show_assigned_tickets']?'checked="checked"':''; ?>> + Show assigned tickets on open queue. + </td> + </tr> + <tr> + <td>Answered Tickets:</td> + <td> + <input type="checkbox" name="show_answered_tickets" <?php echo $config['show_answered_tickets']?'checked="checked"':''; ?>> + Show answered tickets on open queue. + </td> + </tr> + <tr> + <td>Ticket Activity Log:</td> + <td> + <input type="checkbox" name="log_ticket_activity" <?php echo $config['log_ticket_activity']?'checked="checked"':''; ?>> + Log ticket activity as internal notes. + </td> + </tr> + <tr> + <td>Staff Identity Masking:</td> + <td> + <input type="checkbox" name="hide_staff_name" <?php echo $config['hide_staff_name']?'checked="checked"':''; ?>> + Hide staff's name on responses. + </td> + </tr> + </tbody> +</table> +<p style="padding-left:250px;"> + <input class="button" type="submit" name="submit" value="Save Changes"> + <input class="button" type="reset" name="reset" value="Reset Changes"> +</p> +</form> + diff --git a/include/staff/slaplan.inc.php b/include/staff/slaplan.inc.php index 91d896d639d688813389ed0582ecd800beb2a842..70db620e84d83dc66a53cf6c08e1d97ea2b31f24 100644 --- a/include/staff/slaplan.inc.php +++ b/include/staff/slaplan.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($sla && $_REQUEST['a']!='add'){ diff --git a/include/staff/slaplans.inc.php b/include/staff/slaplans.inc.php index 5dea61f69b8ccaeaec3b84411185fbe4a26da886..b8997b6a34be75b697624384e0e39006c5c16feb 100644 --- a/include/staff/slaplans.inc.php +++ b/include/staff/slaplans.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT * FROM '.SLA_TABLE.' sla WHERE 1'; diff --git a/include/staff/staff.inc.php b/include/staff/staff.inc.php index 8883397f51fe86c6b46c5207a099ad33ec50ec31..39651227105158adcadf5283517589ff8dc52ce8 100644 --- a/include/staff/staff.inc.php +++ b/include/staff/staff.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; @@ -210,7 +210,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); </tr> <tr> <td width="180" class="required"> - User Default Time Zone: + Staff's Time Zone: </td> <td> <select name="timezone_id" id="timezone_id"> @@ -228,6 +228,16 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <span class="error">* <?php echo $errors['timezone_id']; ?></span> </td> </tr> + <tr> + <td width="180"> + Daylight Saving: + </td> + <td> + <input type="checkbox" name="daylight_saving" value="1" <?php echo $info['daylight_saving']?'checked="checked"':''; ?>> + Observe daylight saving + <em>(Current Time: <strong><?php echo Format::date($cfg->getDateTimeFormat(),Misc::gmtime(),$info['tz_offset'],$info['daylight_saving']); ?></strong>)</em> + </td> + </tr> <tr> <td width="180"> Limited Access: diff --git a/include/staff/staffmembers.inc.php b/include/staff/staffmembers.inc.php index aa41b1bbf4a00a6143bb8bd0961d8a8ab4a801b0..b01e3387ff28da3e2f8e419b4e728293fe851254 100644 --- a/include/staff/staffmembers.inc.php +++ b/include/staff/staffmembers.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $select='SELECT staff.*,CONCAT_WS(" ",firstname,lastname) as name, grp.group_name, dept.dept_name as dept,count(m.team_id) as teams '; $from='FROM '.STAFF_TABLE.' staff '. diff --git a/include/staff/syslogs.inc.php b/include/staff/syslogs.inc.php index 482dd429c3738faea83e49df05a09c8dd391a7e2..e0f5d2098717dfd360b16fce6959b4a222fd241b 100644 --- a/include/staff/syslogs.inc.php +++ b/include/staff/syslogs.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; if($_REQUEST['type']) { @@ -45,9 +45,10 @@ if( ($startTime && $startTime>time()) or ($startTime>$endTime && $endTime>0)){ $qstr.='&endDate='.urlencode($_REQUEST['endDate']); } } -$sortOptions=array('title'=>'log.title','type'=>'log_type','ip'=>'log.ip_address','date'=>'log.created','created'=>'log.created','updated'=>'log.updated'); +$sortOptions=array('id'=>'log.log_id', 'title'=>'log.title','type'=>'log_type','ip'=>'log.ip_address' + ,'date'=>'log.created','created'=>'log.created','updated'=>'log.updated'); $orderWays=array('DESC'=>'DESC','ASC'=>'ASC'); -$sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'date'; +$sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'id'; //Sorting options... if($sort && $sortOptions[$sort]) { $order_column =$sortOptions[$sort]; @@ -87,13 +88,9 @@ else <form action="syslogs.php" method="get"> <div style="padding-left:2px;"> <b>Date Span</b>: - From <input class="dp" id="sd" size=15 name="startDate" value="<?php echo Format::htmlchars($_REQUEST['startDate']); ?>" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('sd')); return false;"><img src='images/cal.png'border=0 alt=""></a> + From <input class="dp" id="sd" size=15 name="startDate" value="<?php echo Format::htmlchars($_REQUEST['startDate']); ?>" autocomplete=OFF> to - <input class="dp" id="ed" size=15 name="endDate" value="<?php echo Format::htmlchars($_REQUEST['endDate']); ?>" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF > - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('ed')); return false;"><img src='images/cal.png'border=0 alt=""></a> + <input class="dp" id="ed" size=15 name="endDate" value="<?php echo Format::htmlchars($_REQUEST['endDate']); ?>" autocomplete=OFF> Type: <select name='type'> diff --git a/include/staff/team.inc.php b/include/staff/team.inc.php index 7f8c409decba5de347d3cac28b848ce3ad78fa44..51b06ce2d1fa51344dbef35258a72cc68ddbf60b 100644 --- a/include/staff/team.inc.php +++ b/include/staff/team.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($team && $_REQUEST['a']!='add'){ diff --git a/include/staff/teams.inc.php b/include/staff/teams.inc.php index 1aa6dc4ed0554692b67449970caf0d799673f709..ab3a2f58d4a88e94ea4d08653b853352d37be680 100644 --- a/include/staff/teams.inc.php +++ b/include/staff/teams.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT team.*,count(m.staff_id) as members,CONCAT_WS(" ",lead.firstname,lead.lastname) as team_lead '. diff --git a/include/staff/template.inc.php b/include/staff/template.inc.php index 15881945e369c2fa541163008b3c9f4c9ce2352f..ac5c09a744879021e7286f116dc91e18a26df95f 100644 --- a/include/staff/template.inc.php +++ b/include/staff/template.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; diff --git a/include/staff/templates.inc.php b/include/staff/templates.inc.php index 7f82f656f12cafe984de35ff205eb62bfef2b1a7..f60e3b010ec7efe053fd1a73df1cefe9366b9daa 100644 --- a/include/staff/templates.inc.php +++ b/include/staff/templates.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT tpl.*,count(dept.tpl_id) as depts '. diff --git a/include/staff/ticket-edit.inc.php b/include/staff/ticket-edit.inc.php index db80cf2f73fc53853905be23eaa6430e7eefd1de..7bbf0921e5ed97a076e0dc5df4aa61dde44e27fb 100644 --- a/include/staff/ticket-edit.inc.php +++ b/include/staff/ticket-edit.inc.php @@ -139,18 +139,17 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo()); Due Date: </td> <td> - <input id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" size="10" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('duedate')); return false;"><img src='images/cal.png'border=0 alt=""></a> + <input class="dp" id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" size="12" autocomplete=OFF> <?php $min=$hr=null; if($info['time']) - list($hr,$min)=explode(':',$info['time']); - echo Misc::timeDropdown($hr,$min,'time'); + list($hr, $min)=explode(':', $info['time']); + + echo Misc::timeDropdown($hr, $min, 'time'); ?> <font class="error"> <?=$errors['duedate']?> <?php echo $errors['time']; ?></font> - <em>Time is based on your time zone (GM <?php echo $thisstaff->getTZoffset(); ?>)</em> + <em>Time is based on your time zone (GMT <?php echo $thisstaff->getTZoffset(); ?>)</em> </td> </tr> <tr> diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php index 4ec32b3423abb2c4fa424552ec4b6730a8418e9a..680fbad151ba038104410a3a778f3371841d4ed1 100644 --- a/include/staff/ticket-open.inc.php +++ b/include/staff/ticket-open.inc.php @@ -203,18 +203,17 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); Due Date: </td> <td> - <input id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" size="10" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('duedate')); return false;"><img src='images/cal.png'border=0 alt=""></a> + <input class="dp" id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" size="12" autocomplete=OFF> <?php $min=$hr=null; if($info['time']) - list($hr,$min)=explode(':',$info['time']); - echo Misc::timeDropdown($hr,$min,'time'); + list($hr, $min)=explode(':', $info['time']); + + echo Misc::timeDropdown($hr, $min, 'time'); ?> <font class="error"> <?=$errors['duedate']?> <?php echo $errors['time']; ?></font> - <em>Time is based on your time zone (GM <?php echo $thisstaff->getTZoffset(); ?>)</em> + <em>Time is based on your time zone (GMT <?php echo $thisstaff->getTZoffset(); ?>)</em> </td> </tr> <tr> diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index 33f46eadd443ccf0cda94867d0e54a924b73e30e..a299b04fc1afcbe5039ba45809e655378f4d8cac 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -171,11 +171,21 @@ if($ticket->isOverdue()) </tr> </table> <div class="clear" style="padding-bottom:10px;"></div> +<?php +$tcount = $ticket->getThreadCount(); +if($cfg->showNotesInline()) + $tcount+= $ticket->getNumNotes(); +?> <ul id="threads"> - <li><a class="active" id="toggle_ticket_thread" href="#">Ticket Thread (<?php echo $ticket->getThreadCount(); ?>)</a></li> + <li><a class="active" id="toggle_ticket_thread" href="#">Ticket Thread (<?php echo $tcount; ?>)</a></li> + <?php + if(!$cfg->showNotesInline()) {?> <li><a id="toggle_notes" href="#">Internal Notes (<?php echo $ticket->getNumNotes(); ?>)</a></li> + <?php + }?> </ul> - +<?php +if(!$cfg->showNotesInline()) { ?> <div id="ticket_notes"> <?php /* Internal Notes */ @@ -189,18 +199,18 @@ if($ticket->isOverdue()) <?php echo sprintf('%s <em>posted by <b>%s</b></em>', Format::htmlchars($note['title']), - Format::htmlchars($note['source'])); + Format::htmlchars($note['poster'])); ?> </th> <th class="date" width="300"><?php echo Format::db_datetime($note['created']); ?></th> </tr> <tr> <td colspan="2"> - <?php echo Format::htmlchars($note['note']); ?> + <?php echo Format::display($note['body']); ?> </td> </tr> <?php - if($note['attachments'] && ($links=$ticket->getAttachmentsLinks($note['note_id'],'N'))) {?> + if($note['attachments'] && ($links=$ticket->getAttachmentsLinks($note['id'],'N'))) {?> <tr> <td class="info" colspan="2"><?php echo $links; ?></td> </tr> @@ -213,45 +223,32 @@ if($ticket->isOverdue()) echo "<p>No internal notes found.</p>"; }?> </div> +<?php +} ?> <div id="ticket_thread"> <?php - /* -------- Messages & Responses -------------*/ - if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) { - foreach($messages as $message) {?> - <table class="message" cellspacing="0" cellpadding="1" width="940" border="0"> - <tr><th><?php echo Format::db_datetime($message['created']); ?></th></tr> - <tr><td><?php echo Format::display($message['message']); ?></td></tr> + $threadTypes=array('M'=>'message','R'=>'response', 'N'=>'note'); + /* -------- Messages & Responses & Notes (if inline)-------------*/ + if(($thread=$ticket->getThread($cfg->showNotesInline()))) { + foreach($thread as $entry) { + ?> + <table class="<?php echo $threadTypes[$entry['thread_type']]; ?>" cellspacing="0" cellpadding="1" width="940" border="0"> + <tr> + <th width="200"><?php echo Format::db_datetime($entry['created']);?></th> + <th width="440"><span><?php echo Format::htmlchars($entry['title']); ?></span></th> + <th width="300" class="tmeta"><?php echo Format::htmlchars($entry['poster']); ?></th></tr> + <tr><td colspan=2><?php echo Format::display($entry['body']); ?></td></tr> <?php - if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['msg_id'],'M'))) {?> + if($entry['attachments'] && ($links=$ticket->getAttachmentsLinks($entry['id'], $entry['thread_type']))) {?> <tr> - <td class="info"><?php echo $links; ?></td> + <td class="info" colspan=2><?php echo $links; ?></td> </tr> <?php }?> </table> <?php - /* --------- Responses ------------ */ - if($message['responses'] && ($responses=$ticket->getResponses($message['msg_id']))) { - foreach($responses as $resp) {?> - <table class="response" cellspacing="0" cellpadding="1" width="100%" border="0"> - <tr> - <th><?php echo Format::db_datetime($resp['created']); ?> - <?php echo Format::htmlchars($resp['staff_name']); ?></th> - </tr> - <tr> - <td><?php echo Format::display($resp['response']); ?></td> - </tr> - <?php - if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['response_id'],'R'))) {?> - <tr> - <td class="info"><?php echo $links; ?></td> - </tr> - <?php - }?> - </table> - <?php - } - } - $msgId=$message['msg_id']; + if($entry['thread_type']=='M') + $msgId=$entry['id']; } } else { echo '<p>Error fetching ticket thread - get technical help.</p>'; diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php index 67d270c3f033e0db98e901d66b09fdcabf5247c6..bd4801c445cadc40677b3dcdb3bf163b280abfc8 100644 --- a/include/staff/tickets.inc.php +++ b/include/staff/tickets.inc.php @@ -42,6 +42,7 @@ switch(strtolower($_REQUEST['status'])){ //Status is overloaded case 'assigned': $status='open'; $staffId=$thisstaff->getId(); + $results_type='My Tickets'; break; case 'answered': $status='open'; @@ -97,9 +98,6 @@ $deep_search=false; if($search): $qstr.='&a='.urlencode($_REQUEST['a']); $qstr.='&t='.urlencode($_REQUEST['t']); - if(isset($_REQUEST['advance_search'])){ //advance search box! - $qstr.='&advance_search=Search'; - } //query if($searchTerm){ @@ -108,6 +106,8 @@ if($search): if(is_numeric($searchTerm)){ $qwhere.=" AND ticket.ticketID LIKE '$queryterm%'"; }elseif(strpos($searchTerm,'@') && Validator::is_email($searchTerm)){ //pulling all tricks! + # XXX: What about searching for email addresses in the body of + # the thread message $qwhere.=" AND ticket.email='$queryterm'"; }else{//Deep search! //This sucks..mass scan! search anything that moves! @@ -117,33 +117,50 @@ if($search): $qwhere.=" AND ( ticket.email LIKE '%$queryterm%'". " OR ticket.name LIKE '%$queryterm%'". " OR ticket.subject LIKE '%$queryterm%'". - " OR note.title LIKE '%$queryterm%'". - " OR MATCH(message.message) AGAINST('$queryterm')". - " OR MATCH(response.response) AGAINST('$queryterm')". - " OR MATCH(note.note) AGAINST('$queryterm')". + " OR thread.title LIKE '%$queryterm%'". + " OR MATCH(thread.body) AGAINST('$queryterm')". ' ) '; }else{ $qwhere.=" AND ( ticket.email LIKE '%$queryterm%'". " OR ticket.name LIKE '%$queryterm%'". " OR ticket.subject LIKE '%$queryterm%'". - " OR message.message LIKE '%$queryterm%'". - " OR response.response LIKE '%$queryterm%'". - " OR note.note LIKE '%$queryterm%'". - " OR note.title LIKE '%$queryterm%'". + " OR thread.body LIKE '%$queryterm%'". + " OR thread.title LIKE '%$queryterm%'". ' ) '; } } } //department - if($_REQUEST['dept'] && in_array($_REQUEST['dept'],$thisstaff->getDepts())) { + if($_REQUEST['deptId'] && in_array($_REQUEST['deptId'],$thisstaff->getDepts())) { //This is dept based search..perm taken care above..put the sucker in. - $qwhere.=' AND ticket.dept_id='.db_input($_REQUEST['dept']); - $qstr.='&dept='.urlencode($_REQUEST['dept']); + $qwhere.=' AND ticket.dept_id='.db_input($_REQUEST['deptId']); + $qstr.='&deptId='.urlencode($_REQUEST['deptId']); } - //Teams - if($_REQUEST['team'] && ($thisuser->isadmin() || in_array($_REQUEST['team'],$thisuser->getTeams()))) { - $qwhere.=' AND ticket.team_id='.db_input($_REQUEST['team']); - $qstr.='&team='.urlencode($_REQUEST['team']); + + //Assignee + if($_REQUEST['assignee'] && strcasecmp($_REQUEST['status'], 'closed')) { + $id=preg_replace("/[^0-9]/", "", $_REQUEST['assignee']); + $assignee = $_REQUEST['assignee']; + $qstr.='&assignee='.urlencode($_REQUEST['assignee']); + $qwhere.= ' AND ( '; + + if($assignee[0]=='t') + $qwhere.=' (ticket.team_id='.db_input($id). ' AND ticket.status="open") '; + elseif($assignee[0]=='s') + $qwhere.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + else + $qwhere.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + + + if($_REQUEST['staffId'] && !$_REQUEST['status']) { //Assigned TO + Closed By + $qwhere.= ' OR (ticket.staff_id='.db_input($_REQUEST['staffId']). ' AND ticket.status="closed") '; + $qstr.='&staffId='.urlencode($_REQUEST['staffId']); + } + + $qwhere.= ' ) '; + } elseif($_REQUEST['staffId']) { + $qwhere.=' AND (ticket.staff_id='.db_input($_REQUEST['staffId']).' AND ticket.status="closed") '; + $qstr.='&staffId='.urlencode($_REQUEST['staffId']); } //dates @@ -163,7 +180,7 @@ if($search): $qwhere.=' AND ticket.created<=FROM_UNIXTIME('.$endTime.')'; $qstr.='&endDate='.urlencode($_REQUEST['endDate']); } -} + } endif; @@ -206,9 +223,7 @@ $qfrom=' FROM '.TICKET_TABLE.' ticket '. $sjoin=''; if($search && $deep_search) { - $sjoin=' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id )' - .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id )' - .' LEFT JOIN '.TICKET_NOTE_TABLE.' note ON (ticket.ticket_id=note.ticket_id ) '; + $sjoin=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON (ticket.ticket_id=thread.ticket_id )'; } $qgroup=' GROUP BY ticket.ticket_id'; @@ -222,9 +237,7 @@ $pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&ord //ADD attachment,priorities, lock and other crap $qselect.=' ,count(attach.attach_id) as attachments ' - .' ,count(DISTINCT message.msg_id) as messages ' - .' ,count(DISTINCT response.response_id) as responses ' - .' ,count(DISTINCT note.note_id) as notes ' + .' ,count(DISTINCT thread.id) as thread_count ' .' ,IF(ticket.reopened is NULL,IF(ticket.lastmessage is NULL,ticket.created,ticket.lastmessage),ticket.reopened) as effective_date ' .' ,CONCAT_WS(" ", staff.firstname, staff.lastname) as staff, team.name as team ' .' ,IF(staff.staff_id IS NULL,team.name,CONCAT_WS(" ", staff.lastname, staff.firstname)) as assigned '; @@ -233,9 +246,7 @@ $qfrom.=' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (ticket.priority_id=pri.pri .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON (ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW() AND tlock.staff_id!='.db_input($thisstaff->getId()).') ' .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (ticket.ticket_id=attach.ticket_id) ' - .' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id) ' - .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id) ' - .' LEFT JOIN '.TICKET_NOTE_TABLE.' note ON (ticket.ticket_id=note.ticket_id ) ' + .' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON ( ticket.ticket_id=thread.ticket_id) ' .' LEFT JOIN '.STAFF_TABLE.' staff ON (ticket.staff_id=staff.staff_id) ' .' LEFT JOIN '.TEAM_TABLE.' team ON (ticket.team_id=team.team_id) '; @@ -245,17 +256,18 @@ $hash = md5($query); $_SESSION['search_'.$hash] = $query; $res = db_query($query); $showing=db_num_rows($res)?$pageNav->showing():""; -if(!$results_type) { - $results_type=($search)?'Search Results':ucfirst($status).' Tickets'; -} -$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting.. +if(!$results_type) + $results_type = ucfirst($status).' Tickets'; -$basic_display=!isset($_REQUEST['advance_search'])?true:false; +if($search) + $results_type.= ' (Search Results)'; + +$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting.. //YOU BREAK IT YOU FIX IT. ?> <!-- SEARCH FORM START --> -<div id='basic' style="display:<?php echo $basic_display?'block':'none'; ?>"> +<div id='basic_search'> <form action="tickets.php" method="get"> <input type="hidden" name="a" value="search"> <table> @@ -263,6 +275,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; <td><input type="text" id="basic-ticket-search" name="query" size=30 value="<?php echo Format::htmlchars($_REQUEST['query']); ?>" autocomplete="off" autocorrect="off" autocapitalize="off"></td> <td><input type="submit" name="basic_search" class="button" value="Search"></td> + <td> <a href="" id="go-advanced">[advanced]</a></td> </tr> </table> </form> @@ -300,7 +313,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; title="Sort By Status <?php echo $negorder; ?>">Status</a></th> <?php } else { ?> - <th width="60" <?=$pri_sort?>> + <th width="60" <?php echo $pri_sort;?>> <a <?php echo $pri_sort; ?> href="tickets.php?sort=pri&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Priority <?php echo $negorder; ?>">Priority</a></th> <?php @@ -310,15 +323,18 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; <th width="150"> <a <?php echo $assignee_sort; ?> href="tickets.php?sort=assignee&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Assignee <?php echo $negorder;?>">Assigned To</a></th> - <?}elseif(!strcasecmp($status,'closed')){?> + <?php + } elseif(!strcasecmp($status,'closed')) { ?> <th width="150"> <a <?php echo $staff_sort; ?> href="tickets.php?sort=staff&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Closing Staff Name <?php echo $negorder; ?>">Closed By</a></th> - <?}else{?> + <?php + } else { ?> <th width="150"> - <a <?=$dept_sort?> href="tickets.php?sort=dept&order=<?=$negorder?><?=$qstr?>" - title="Sort By Department <?=$negorder?>">Department</a></th> - <?}?> + <a <?php echo $dept_sort; ?> href="tickets.php?sort=dept&order=<?php echo $negorder;?><?php echo $qstr; ?>" + title="Sort By Department <?php echo $negorder; ?>">Department</a></th> + <?php + } ?> </tr> </thead> <tbody> @@ -347,7 +363,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; } $tid=$row['ticketID']; $subject = Format::truncate($row['subject'],40); - $threadcount=$row['messages']+$row['responses']; + $threadcount=$row['thread_count']; if(!strcasecmp($row['status'],'open') && !$row['isanswered'] && !$row['lock_id']) { $tid=sprintf('<b>%s</b>',$tid); } @@ -449,3 +465,89 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; } ?> </form> </div> +<div id="overlay"></div> +<div style="display:none;" id="advanced-search"> + <h3>Advanced Ticket Search</h3> + <a class="close" href="">×</a> + <form action="tickets.php" method="post" id="search" name="search"> + <input type="hidden" name="a" value="search"> + <fieldset class="query"> + <label for="query">Keyword:</label> + <input type="input" id="query" name="query" size="20"> <em>Optional</em> + </fieldset> + <fieldset> + <label for="status">Status:</label> + <select id="status" name="status"> + <option value="">— Any Status —</option> + <option value="open">Open</option> + <option value="overdue">Overdue</option> + <option value="closed">Closed</option> + </select> + <label for="deptId">Dept:</label> + <select id="deptId" name="deptId"> + <option value="">— All Departments —</option> + <?php + if(($mydepts = $thisstaff->getDepts()) && ($depts=Dept::getDepartments())) { + foreach($depts as $id =>$name) { + if(!in_array($id, $mydepts)) continue; + echo sprintf('<option value="%d">%s</option>', $id, $name); + } + } + ?> + </select> + </fieldset> + <fieldset class="owner"> + <label for="assignee">Assigned To:</label> + <select id="assignee" name="assignee"> + <option value="0">— Anyone —</option> + <?php + if(($users=Staff::getStaffMembers())) { + echo '<OPTGROUP label="Staff Members ('.count($users).')">'; + foreach($users as $id => $name) { + $k="s$id"; + echo sprintf('<option value="%s">%s</option>', $k, $name); + } + echo '</OPTGROUP>'; + } + + if(($teams=Team::getTeams())) { + echo '<OPTGROUP label="Teams ('.count($teams).')">'; + foreach($teams as $id => $name) { + $k="t$id"; + echo sprintf('<option value="%s">%s</option>', $k, $name); + } + echo '</OPTGROUP>'; + } + ?> + </select> + <label for="staffId">Closed By:</label> + <select id="staffId" name="staffId"> + <option value="0">— Anyone —</option> + <?php + if(($users=Staff::getStaffMembers())) { + foreach($users as $id => $name) + echo sprintf('<option value="%d">%s</option>', $id, $name); + } + ?> + </select> + </fieldset> + <fieldset class="date_range"> + <label>Date Range:</label> + <input class="dp" type="input" size="20" name="startDate"> + <span>TO</span> + <input class="dp" type="input" size="20" name="endDate"> + </fieldset> + <p> + <span class="buttons"> + <input type="submit" value="Search"> + <input type="reset" value="Reset"> + <input type="button" value="Cancel" class="close"> + </span> + <span class="spinner"> + <img src="./images/ajax-loader.gif" width="16" height="16"> + </span> + </p> + </form> + <div id="result-count"> + </div> +</div> diff --git a/include/staff/topic.inc.php b/include/staff/topic.inc.php index 6504c5443200a4a3bd82624fec18c27c0ff3ea24..f0f895409d99ebd2c39c4013572b1ee455887090 100644 --- a/include/staff/topic.inc.php +++ b/include/staff/topic.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $info=($_POST && $errors)?Format::input($_POST):array(); //Re-use the post info on error...savekeyboards.org if($topic && $_REQUEST['a']!='new'){ diff --git a/js/jquery-ui-1.8.18.custom.min.js b/js/jquery-ui-1.8.18.custom.min.js new file mode 100755 index 0000000000000000000000000000000000000000..81486fc8e6f8a32d847668911188813b107536de --- /dev/null +++ b/js/jquery-ui-1.8.18.custom.min.js @@ -0,0 +1,21 @@ +/*! + * jQuery UI 1.8.18 + * + * 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,b){function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;if(!b.href||!g||f.nodeName.toLowerCase()!=="map")return!1;h=a("img[usemap=#"+g+"]")[0];return!!h&&d(h)}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}a.ui=a.ui||{};a.ui.version||(a.extend(a.ui,{version:"1.8.18",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(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=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):b=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"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a.each(["Width","Height"],function(c,d){function h(b,c,d,f){a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)});return c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){if(c===b)return g["inner"+d].call(this);return this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){if(typeof b!="number")return g["outer"+d].call(this,b);return this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!!d&&!!a.element[0].parentNode)for(var e=0;e<d.length;e++)a.options[d[e][0]]&&d[e][1].apply(a.element,c)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(b,c){if(a(b).css("overflow")==="hidden")return!1;var d=c&&c==="left"?"scrollLeft":"scrollTop",e=!1;if(b[d]>0)return!0;b[d]=1,e=b[d]>0,b[d]=0;return e},isOverAxis:function(a,b,c){return a>b&&a<b+c},isOver:function(b,c,d,e,f,g){return a.ui.isOverAxis(b,d,f)&&a.ui.isOverAxis(c,e,g)}}))})(jQuery);/* + * jQuery UI Datepicker 1.8.18 + * + * 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 + * + * Depends: + * jquery.ui.core.js + */(function($,undefined){function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);!c.length||c.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(c){var d=$(c.target).closest(b);!$.datepicker._isDisabledDatepicker(instActive.inline?a.parent()[0]:instActive.input[0])&&!!d.length&&(d.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),d.addClass("ui-state-hover"),d.hasClass("ui-datepicker-prev")&&d.addClass("ui-datepicker-prev-hover"),d.hasClass("ui-datepicker-next")&&d.addClass("ui-datepicker-next-hover"))})}function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,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:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,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:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}$.extend($.ui,{datepicker:{version:"1.8.18"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){extendRemove(this._defaults,a||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);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(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a))},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$('<span class="'+this._appendClass+'">'+c+"</span>"),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('<button type="button"></button>').addClass(this._triggerClass).html(g==""?f:$("<img/>").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){$.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=a[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(a[0])):$.datepicker._showDatepicker(a[0]);return!1})}},_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 d=function(a){var b=0,c=0;for(var d=0;d<a.length;d++)a[d].length>b&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(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=$(a);c.hasClass(this.markerClassName)||(c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block"))},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$('<input type="text" id="'+g+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>'),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f);return this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="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)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})}},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return!0;return!1},_getInst:function(a){try{return $.data(a,PROP_NAME)}catch(b){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(a,b,c){var d=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?$.extend({},$.datepicker._defaults):d?b=="all"?$.extend({},d.settings):this._get(d,b):null;var e=b||{};typeof b=="string"&&(e={},e[b]=c);if(d){this._curInst==d&&this._hideDatepicker();var f=this._getDateDatepicker(a,!0),g=this._getMinMaxDate(d,"min"),h=this._getMinMaxDate(d,"max");extendRemove(d.settings,e),g!==null&&e.dateFormat!==undefined&&e.minDate===undefined&&(d.settings.minDate=this._formatDate(d,g)),h!==null&&e.dateFormat!==undefined&&e.maxDate===undefined&&(d.settings.maxDate=this._formatDate(d,h)),this._attachments($(a),d),this._autoSize(d),this._setDate(d,f),this._updateAlternate(d),this._updateDatepicker(d)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){var b=this._getInst(a);b&&this._updateDatepicker(b)},_setDateDatepicker:function(a,b){var c=this._getInst(a);c&&(this._setDate(c,b),this._updateDatepicker(c),this._updateAlternate(c))},_getDateDatepicker:function(a,b){var c=this._getInst(a);c&&!c.inline&&this._setDateFromField(c,b);return c?this._getDate(c):null},_doKeyDown:function(a){var b=$.datepicker._getInst(a.target),c=!0,d=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=!0;if($.datepicker._datepickerShowing)switch(a.keyCode){case 9:$.datepicker._hideDatepicker(),c=!1;break;case 13:var e=$("td."+$.datepicker._dayOverClass+":not(."+$.datepicker._currentClass+")",b.dpDiv);e[0]&&$.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,e[0]);var f=$.datepicker._get(b,"onSelect");if(f){var g=$.datepicker._formatDate(b);f.apply(b.input?b.input[0]:null,[g,b])}else $.datepicker._hideDatepicker();return!1;case 27:$.datepicker._hideDatepicker();break;case 33:$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 34:$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 35:(a.ctrlKey||a.metaKey)&&$.datepicker._clearDate(a.target),c=a.ctrlKey||a.metaKey;break;case 36:(a.ctrlKey||a.metaKey)&&$.datepicker._gotoToday(a.target),c=a.ctrlKey||a.metaKey;break;case 37:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?1:-1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 38:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,-7,"D"),c=a.ctrlKey||a.metaKey;break;case 39:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?-1:1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 40:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,7,"D"),c=a.ctrlKey||a.metaKey;break;default:c=!1}else a.keyCode==36&&a.ctrlKey?$.datepicker._showDatepicker(this):c=!1;c&&(a.preventDefault(),a.stopPropagation())},_doKeyPress:function(a){var b=$.datepicker._getInst(a.target);if($.datepicker._get(b,"constrainInput")){var c=$.datepicker._possibleChars($.datepicker._get(b,"dateFormat")),d=String.fromCharCode(a.charCode==undefined?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||d<" "||!c||c.indexOf(d)>-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(a){$.datepicker.log(a)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if(!$.datepicker._isDisabledDatepicker(a)&&$.datepicker._lastInput!=a){var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){e|=$(this).css("position")=="fixed";return!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a));var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+$(document).scrollLeft(),i=document.documentElement.clientHeight+$(document).scrollTop();b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0);return b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=$.data(a,PROP_NAME))&&this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=this,f=function(){$.datepicker._tidyDialog(b),e._curInst=null};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,f):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,f),c||f(),this._datepickerShowing=!1;var g=this._get(b,"onClose");g&&g.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!!$.datepicker._curInst){var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);this._isDisabledDatepicker(d[0])||(this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e))},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[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(d)},_selectDay:function(a,b,c,d){var e=$(a);if(!$(d).hasClass(this._unselectableClass)&&!this._isDisabledDatepicker(e[0])){var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).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){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.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"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();b.setMonth(0),b.setDate(1);return Math.floor(Math.round((c-b)/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 d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1<a.length&&a.charAt(s+1)==b;c&&s++;return c},o=function(a){var c=n(a),d=a=="@"?14:a=="!"?20:a=="y"&&c?4:a=="o"?3:2,e=new RegExp("^\\d{1,"+d+"}"),f=b.substring(r).match(e);if(!f)throw"Missing number at position "+r;r+=f[0].length;return parseInt(f[0],10)},p=function(a,c,d){var e=$.map(n(a)?d:c,function(a,b){return[[b,a]]}).sort(function(a,b){return-(a[1].length-b[1].length)}),f=-1;$.each(e,function(a,c){var d=c[1];if(b.substr(r,d.length).toLowerCase()==d.toLowerCase()){f=c[0],r+=d.length;return!1}});if(f!=-1)return f+1;throw"Unknown name at position "+r},q=function(){if(b.charAt(r)!=a.charAt(s))throw"Unexpected literal at position "+r;r++},r=0;for(var s=0;s<a.length;s++)if(m)a.charAt(s)=="'"&&!n("'")?m=!1:q();else switch(a.charAt(s)){case"d":k=o("d");break;case"D":p("D",e,f);break;case"o":l=o("o");break;case"m":j=o("m");break;case"M":j=p("M",g,h);break;case"y":i=o("y");break;case"@":var t=new Date(o("@"));i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"!":var t=new Date((o("!")-this._ticksTo1970)/1e4);i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"'":n("'")?q():m=!0;break;default:q()}if(r<b.length)throw"Extra/unparsed characters found in date: "+b.substring(r);i==-1?i=(new Date).getFullYear():i<100&&(i+=(new Date).getFullYear()-(new Date).getFullYear()%100+(i<=d?0:-100));if(l>-1){j=1,k=l;for(;;){var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},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 d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+1<a.length&&a.charAt(m+1)==b;c&&m++;return c},i=function(a,b,c){var d=""+b;if(h(a))while(d.length<c)d="0"+d;return d},j=function(a,b,c,d){return h(a)?d[b]:c[b]},k="",l=!1;if(b)for(var m=0;m<a.length;m++)if(l)a.charAt(m)=="'"&&!h("'")?l=!1:k+=a.charAt(m);else switch(a.charAt(m)){case"d":k+=i("d",b.getDate(),2);break;case"D":k+=j("D",b.getDay(),d,e);break;case"o":k+=i("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864e5),3);break;case"m":k+=i("m",b.getMonth()+1,2);break;case"M":k+=j("M",b.getMonth(),f,g);break;case"y":k+=h("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case"@":k+=b.getTime();break;case"!":k+=b.getTime()*1e4+this._ticksTo1970;break;case"'":h("'")?k+="'":l=!0;break;default:k+=a.charAt(m)}return k},_possibleChars:function(a){var b="",c=!1,d=function(b){var c=e+1<a.length&&a.charAt(e+1)==b;c&&e++;return c};for(var e=0;e<a.length;e++)if(c)a.charAt(e)=="'"&&!d("'")?c=!1:b+=a.charAt(e);else switch(a.charAt(e)){case"d":case"m":case"y":case"@":b+="0123456789";break;case"D":case"M":return null;case"'":d("'")?b+="'":c=!0;break;default:b+=a.charAt(e)}return b},_get:function(a,b){return a.settings[b]!==undefined?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),d=a.lastVal=a.input?a.input.val():null,e,f;e=f=this._getDefaultDate(a);var g=this._getFormatConfig(a);try{e=this.parseDate(c,d,g)||f}catch(h){this.log(h),d=b?"":d}a.selectedDay=e.getDate(),a.drawMonth=a.selectedMonth=e.getMonth(),a.drawYear=a.selectedYear=e.getFullYear(),a.currentDay=d?e.getDate():0,a.currentMonth=d?e.getMonth():0,a.currentYear=d?e.getFullYear():0,this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var d=function(a){var b=new Date;b.setDate(b.getDate()+a);return b},e=function(b){try{return $.datepicker.parseDate($.datepicker._get(a,"dateFormat"),b,$.datepicker._getFormatConfig(a))}catch(c){}var d=(b.toLowerCase().match(/^c/)?$.datepicker._getDate(a):null)||new Date,e=d.getFullYear(),f=d.getMonth(),g=d.getDate(),h=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,i=h.exec(b);while(i){switch(i[2]||"d"){case"d":case"D":g+=parseInt(i[1],10);break;case"w":case"W":g+=parseInt(i[1],10)*7;break;case"m":case"M":f+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f));break;case"y":case"Y":e+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f))}i=h.exec(b)}return new Date(e,f,g)},f=b==null||b===""?c:typeof b=="string"?e(b):typeof b=="number"?isNaN(b)?c:d(b):new Date(b.getTime());f=f&&f.toString()=="Invalid Date"?c:f,f&&(f.setHours(0),f.setMinutes(0),f.setSeconds(0),f.setMilliseconds(0));return this._daylightSavingAdjust(f)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&p<l?l:p;while(this._daylightSavingAdjust(new Date(o,n,1))>p)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._adjustDate('#"+a.id+"', -"+i+", 'M');\""+' title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>":e?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._adjustDate('#"+a.id+"', +"+i+", 'M');\""+' title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>":e?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+dpuuid+'.datepicker._hideDatepicker();">'+this._get(a,"closeText")+"</button>",x=d?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?w:"")+(this._isInRange(a,v)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._gotoToday('#"+a.id+"');\""+">"+u+"</button>":"")+(c?"":w)+"</div>":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L<g[0];L++){var M="";this.maxRows=4;for(var N=0;N<g[1];N++){var O=this._daylightSavingAdjust(new Date(o,n,a.selectedDay)),P=" ui-corner-all",Q="";if(j){Q+='<div class="ui-datepicker-group';if(g[1]>1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+P+'">'+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'</div><table class="ui-datepicker-calendar"><thead>'+"<tr>";var R=z?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="<th"+((S+y+6)%7>=5?' class="ui-datepicker-week-end"':"")+">"+'<span title="'+A[T]+'">'+C[T]+"</span></th>"}Q+=R+"</tr></thead><tbody>";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z<X;Z++){Q+="<tr>";var _=z?'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(Y)+"</td>":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Y<l||m&&Y>m;_+='<td class="'+((S+y+6)%7>=5?" ui-datepicker-week-end":"")+(bb?" ui-datepicker-other-month":"")+(Y.getTime()==O.getTime()&&n==a.selectedMonth&&a._keyEvent||J.getTime()==Y.getTime()&&J.getTime()==O.getTime()?" "+this._dayOverClass:"")+(bc?" "+this._unselectableClass+" ui-state-disabled":"")+(bb&&!G?"":" "+ba[1]+(Y.getTime()==k.getTime()?" "+this._currentClass:"")+(Y.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!bb||G)&&ba[2]?' title="'+ba[2]+'"':"")+(bc?"":' onclick="DP_jQuery_'+dpuuid+".datepicker._selectDay('#"+a.id+"',"+Y.getMonth()+","+Y.getFullYear()+', this);return false;"')+">"+(bb&&!G?" ":bc?'<span class="ui-state-default">'+Y.getDate()+"</span>":'<a class="ui-state-default'+(Y.getTime()==b.getTime()?" ui-state-highlight":"")+(Y.getTime()==k.getTime()?" ui-state-active":"")+(bb?" ui-priority-secondary":"")+'" href="#">'+Y.getDate()+"</a>")+"</td>",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+"</tr>"}n++,n>11&&(n=0,o++),Q+="</tbody></table>"+(j?"</div>"+(g[0]>0&&N==g[1]-1?'<div class="ui-datepicker-row-break"></div>':""):""),M+=Q}K+=M}K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':""), +a._keyEvent=!1;return K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='<div class="ui-datepicker-title">',m="";if(f||!i)m+='<span class="ui-datepicker-month">'+g[b]+"</span>";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+dpuuid+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" "+">";for(var p=0;p<12;p++)(!n||p>=d.getMonth())&&(!o||p<=e.getMonth())&&(m+='<option value="'+p+'"'+(p==b?' selected="selected"':"")+">"+h[p]+"</option>");m+="</select>"}k||(l+=m+(f||!i||!j?" ":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+='<span class="ui-datepicker-year">'+c+"</span>";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+dpuuid+".datepicker._selectMonthYear('#"+a.id+"', this, 'Y');\" "+">";for(;t<=u;t++)a.yearshtml+='<option value="'+t+'"'+(t==c?' selected="selected"':"")+">"+t+"</option>";a.yearshtml+="</select>",l+=a.yearshtml,a.yearshtml=null}}l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?" ":"")+m),l+="</div>";return l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&b<c?c:b;e=d&&e>d?d:e;return e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_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,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth()));return this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.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,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));return this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)})},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.18",window["DP_jQuery_"+dpuuid]=$})(jQuery); \ No newline at end of file diff --git a/login.php b/login.php index 044d74644785f32a0f79bae76e6c4309fd473b2a..48dc9ec4aea9a5ab7c427cacc30b17c8005944b5 100644 --- a/login.php +++ b/login.php @@ -45,7 +45,7 @@ if($_POST && (!empty($_POST['lemail']) && !empty($_POST['lticket']))): //At this point we know the ticket is valid. //TODO: 1) Check how old the ticket is...3 months max?? 2) Must be the latest 5 tickets?? //Check the email given. - if($ticket->getId() && strcasecmp($ticket->getEMail(),$email)==0){ + if($ticket->getId() && strcasecmp($ticket->getEmail(),$email)==0){ //valid match...create session goodies for the client. $user = new ClientSession($email,$ticket->getId()); $_SESSION['_client']=array(); //clear. diff --git a/main.inc.php b/main.inc.php index bb997ebd6cb5d1d98d30136a66c55bd8a79008a7..0bfcf903a91866cd9c046f3d90020e3539cd935a 100644 --- a/main.inc.php +++ b/main.inc.php @@ -54,8 +54,8 @@ /*############## Do NOT monkey with anything else beyond this point UNLESS you really know what you are doing ##############*/ #Current version && schema signature (Changes from version to version) - define('THIS_VERSION','1.7-DPR2'); //Shown on admin panel - define('SCHEMA_SIGNATURE','ssddsdsd'); //MD5 signature of the db schema. (used to trigger upgrades) + define('THIS_VERSION','1.7-DPR3'); //Shown on admin panel + define('SCHEMA_SIGNATURE','c2d2fabfdf15e1632f00850ffb361558'); //MD5 signature of the db schema. (used to trigger upgrades) #load config info $configfile=''; @@ -135,14 +135,13 @@ define('CANNED_ATTACHMENT_TABLE',TABLE_PREFIX.'canned_attachment'); define('TICKET_TABLE',TABLE_PREFIX.'ticket'); - define('TICKET_NOTE_TABLE',TABLE_PREFIX.'ticket_note'); - define('TICKET_MESSAGE_TABLE',TABLE_PREFIX.'ticket_message'); - define('TICKET_RESPONSE_TABLE',TABLE_PREFIX.'ticket_response'); + define('TICKET_THREAD_TABLE',TABLE_PREFIX.'ticket_thread'); define('TICKET_ATTACHMENT_TABLE',TABLE_PREFIX.'ticket_attachment'); define('TICKET_PRIORITY_TABLE',TABLE_PREFIX.'ticket_priority'); define('PRIORITY_TABLE',TICKET_PRIORITY_TABLE); define('TICKET_LOCK_TABLE',TABLE_PREFIX.'ticket_lock'); - define('TICKET_HISTORY_TABLE',TABLE_PREFIX.'ticket_history'); + define('TICKET_EVENT_TABLE',TABLE_PREFIX.'ticket_event'); + define('TICKET_EMAIL_INFO_TABLE',TABLE_PREFIX.'ticket_email_info'); define('EMAIL_TABLE',TABLE_PREFIX.'email'); define('EMAIL_TEMPLATE_TABLE',TABLE_PREFIX.'email_template'); diff --git a/scp/admin.inc.php b/scp/admin.inc.php index a580fa6986b87661b039419bcf178e5ae46ad12e..5f6f5e7633422251ca7bbf8960f69461a8afbc35 100644 --- a/scp/admin.inc.php +++ b/scp/admin.inc.php @@ -15,34 +15,29 @@ **********************************************************************/ require('staff.inc.php'); //Make sure config is loaded and the staff is set and of admin type -if(!$cfg or !$thisstaff or !$thisstaff->isadmin()){ +if(!$cfg or !$thisstaff or !$thisstaff->isAdmin()){ header('Location: index.php'); require('index.php'); // just in case! exit; } //Some security related warnings - bitch until fixed!!! :) -if(defined('THIS_VERSION') && strcasecmp($cfg->getVersion(),THIS_VERSION)) { - $sysnotice=sprintf('The script is version %s while the database is version %s.',THIS_VERSION,$cfg->getVersion()); - if(file_exists('../setup/')) - $sysnotice.=' Possibly caused by incomplete <a href="../setup/upgrade.php">upgrade</a>.'; - $errors['err']=$sysnotice; -}elseif(!$cfg->isHelpDeskOffline()) { - if(file_exists('../setup/')){ - $sysnotice='Please take a minute to delete <strong>setup/install</strong> directory for security reasons.'; - }else{ - - if(CONFIG_FILE && file_exists(CONFIG_FILE) && is_writable(CONFIG_FILE)) { +if($cfg->isUpgradePending()) { + $errors['err']=$sysnotice='System upgrade is pending <a href="../setup/upgrade.php">Upgrade Now</a>'; +} elseif(!$cfg->isHelpDeskOffline()) { + + if(file_exists('../setup/')) { + $sysnotice='Please take a minute to delete <strong>setup/install</strong> directory (../setup/) for security reasons.'; + } elseif(CONFIG_FILE && file_exists(CONFIG_FILE) && is_writable(CONFIG_FILE)) { //Confirm for real that the file is writable by group or world. clearstatcache(); //clear the cache! $perms = @fileperms(CONFIG_FILE); if(($perms & 0x0002) || ($perms & 0x0010)) { $sysnotice=sprintf('Please change permission of config file (%s) to remove write access. e.g <i>chmod 644 %s</i>', - basename(CONFIG_FILE),basename(CONFIG_FILE)); + basename(CONFIG_FILE), basename(CONFIG_FILE)); } - } - } + if(!$sysnotice && ini_get('register_globals')) $sysnotice='Please consider turning off register globals if possible'; } diff --git a/scp/ajax.php b/scp/ajax.php index fac8a088f6a5ede0cc29c9488da06d2463b03a8f..2310fc67ae9102ab1df3865b45c816ae26595cb0 100644 --- a/scp/ajax.php +++ b/scp/ajax.php @@ -43,7 +43,14 @@ $dispatcher = patterns('', url_get('^ticket_variables', 'ticket_variables') )), url('^/config/', patterns('ajax.config.php:ConfigAjaxAPI', - url_get('^ui', 'ui') + url_get('^ui', 'scp_ui') + )), + url('^/report/overview/', patterns('ajax.reports.php:OverviewReportAjaxAPI', + # Send + url_get('^graph$', 'getPlotData'), + url_get('^table/groups$', 'enumTabularGroups'), + url_get('^table/export$', 'downloadTabularData'), + url_get('^table$', 'getTabularData') )), url('^/report/overview/', patterns('ajax.reports.php:OverviewReportAjaxAPI', # Send @@ -52,12 +59,13 @@ $dispatcher = patterns('', url_get('^table$', 'getTabularData') )), url_get('^/users$', array('ajax.users.php:UsersAjaxAPI', 'search')), - url_get('^/tickets$', array('ajax.tickets.php:TicketsAjaxAPI', 'search')), - url('^/ticket/', patterns('ajax.tickets.php:TicketsAjaxAPI', + url('^/tickets/', patterns('ajax.tickets.php:TicketsAjaxAPI', url_get('^(?P<tid>\d+)/preview', 'previewTicket'), url_get('^(?P<tid>\d+)/lock', 'acquireLock'), url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/renew', 'renewLock'), - url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/release', 'releaseLock') + url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/release', 'releaseLock'), + url_get('^lookup', 'lookup'), + url_get('^search', 'search') )) ); diff --git a/scp/banlist.php b/scp/banlist.php index 1ef580a5746e7666c7aebf4f72e364acb30456ea..b56d05c6d07b28b2536127abe9a5b3be6330cb69 100644 --- a/scp/banlist.php +++ b/scp/banlist.php @@ -68,7 +68,7 @@ if($_POST && !$errors && $filter){ }else{ $count=count($_POST['ids']); if($_POST['enable']){ - $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=1 WHERE filter_id='.db_input($filter->getID()). + $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=1 WHERE filter_id='.db_input($filter->getId()). ' AND id IN ('.implode(',',$_POST['ids']).')'; if(db_query($sql) && ($num=db_affected_rows())){ if($num==$count) @@ -79,7 +79,7 @@ if($_POST && !$errors && $filter){ $errors['err']='Unable to enable selected emails'; } }elseif($_POST['disable']){ - $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=0 WHERE filter_id='.db_input($filter->getID()). + $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=0 WHERE filter_id='.db_input($filter->getId()). ' AND id IN ('.implode(',',$_POST['ids']).')'; if(db_query($sql) && ($num=db_affected_rows())) { if($num==$count) diff --git a/scp/css/bootstrap.css b/scp/css/bootstrap.css new file mode 100644 index 0000000000000000000000000000000000000000..27de4b50704514f22930e034d004b27a707c35ea --- /dev/null +++ b/scp/css/bootstrap.css @@ -0,0 +1,4983 @@ +/*! + * Bootstrap v2.0.4 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +audio:not([controls]) { + display: none; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +a:hover, +a:active { + outline: 0; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + max-width: 100%; + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +#map_canvas img { + max-width: none; +} + +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} + +button, +input { + *overflow: visible; + line-height: normal; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 28px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} + +a { + color: #0088cc; + text-decoration: none; +} + +a:hover { + color: #005580; + text-decoration: underline; +} + +.row { + margin-left: -20px; + *zoom: 1; +} + +.row:before, +.row:after { + display: table; + content: ""; +} + +.row:after { + clear: both; +} + +[class*="span"] { + float: left; + margin-left: 20px; +} + +.container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.span12 { + width: 940px; +} + +.span11 { + width: 860px; +} + +.span10 { + width: 780px; +} + +.span9 { + width: 700px; +} + +.span8 { + width: 620px; +} + +.span7 { + width: 540px; +} + +.span6 { + width: 460px; +} + +.span5 { + width: 380px; +} + +.span4 { + width: 300px; +} + +.span3 { + width: 220px; +} + +.span2 { + width: 140px; +} + +.span1 { + width: 60px; +} + +.offset12 { + margin-left: 980px; +} + +.offset11 { + margin-left: 900px; +} + +.offset10 { + margin-left: 820px; +} + +.offset9 { + margin-left: 740px; +} + +.offset8 { + margin-left: 660px; +} + +.offset7 { + margin-left: 580px; +} + +.offset6 { + margin-left: 500px; +} + +.offset5 { + margin-left: 420px; +} + +.offset4 { + margin-left: 340px; +} + +.offset3 { + margin-left: 260px; +} + +.offset2 { + margin-left: 180px; +} + +.offset1 { + margin-left: 100px; +} + +.row-fluid { + width: 100%; + *zoom: 1; +} + +.row-fluid:before, +.row-fluid:after { + display: table; + content: ""; +} + +.row-fluid:after { + clear: both; +} + +.row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 28px; + margin-left: 2.127659574%; + *margin-left: 2.0744680846382977%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} + +.row-fluid .span12 { + width: 99.99999998999999%; + *width: 99.94680850063828%; +} + +.row-fluid .span11 { + width: 91.489361693%; + *width: 91.4361702036383%; +} + +.row-fluid .span10 { + width: 82.97872339599999%; + *width: 82.92553190663828%; +} + +.row-fluid .span9 { + width: 74.468085099%; + *width: 74.4148936096383%; +} + +.row-fluid .span8 { + width: 65.95744680199999%; + *width: 65.90425531263828%; +} + +.row-fluid .span7 { + width: 57.446808505%; + *width: 57.3936170156383%; +} + +.row-fluid .span6 { + width: 48.93617020799999%; + *width: 48.88297871863829%; +} + +.row-fluid .span5 { + width: 40.425531911%; + *width: 40.3723404216383%; +} + +.row-fluid .span4 { + width: 31.914893614%; + *width: 31.8617021246383%; +} + +.row-fluid .span3 { + width: 23.404255317%; + *width: 23.3510638276383%; +} + +.row-fluid .span2 { + width: 14.89361702%; + *width: 14.8404255306383%; +} + +.row-fluid .span1 { + width: 6.382978723%; + *width: 6.329787233638298%; +} + +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} + +.container:before, +.container:after { + display: table; + content: ""; +} + +.container:after { + clear: both; +} + +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} + +.container-fluid:before, +.container-fluid:after { + display: table; + content: ""; +} + +.container-fluid:after { + clear: both; +} + +p { + margin: 0 0 9px; +} + +p small { + font-size: 11px; + color: #999999; +} + +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-family: inherit; + font-weight: bold; + color: inherit; + text-rendering: optimizelegibility; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} + +h1 { + font-size: 30px; + line-height: 36px; +} + +h1 small { + font-size: 18px; +} + +h2 { + font-size: 24px; + line-height: 36px; +} + +h2 small { + font-size: 18px; +} + +h3 { + font-size: 18px; + line-height: 27px; +} + +h3 small { + font-size: 14px; +} + +h4, +h5, +h6 { + line-height: 18px; +} + +h4 { + font-size: 14px; +} + +h4 small { + font-size: 12px; +} + +h5 { + font-size: 12px; +} + +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} + +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} + +.page-header h1 { + line-height: 1; +} + +ul, +ol { + padding: 0; + margin: 0 0 9px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +ul { + list-style: disc; +} + +ol { + list-style: decimal; +} + +li { + /* line-height: 18px; */ +} + +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +dl { + margin-bottom: 18px; +} + +dt, +dd { + line-height: 18px; +} + +dt { + font-weight: bold; + line-height: 17px; +} + +dd { + margin-left: 9px; +} + +.dl-horizontal dt { + float: left; + width: 120px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dl-horizontal dd { + margin-left: 130px; +} + +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +.muted { + color: #999999; +} + +abbr[title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} + +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 18px; + font-style: normal; + line-height: 18px; +} + +small { + font-size: 100%; +} + +cite { + font-style: normal; +} + +code, +pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +code { + padding: 2px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} + +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12.025px; + line-height: 18px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +pre.prettyprint { + margin-bottom: 18px; +} + +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +form { + margin: 0 0 18px; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +legend small { + font-size: 13.5px; + color: #999999; +} + +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} + +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +label { + display: block; + margin-bottom: 5px; +} + +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; +} + +input, +textarea { + width: 210px; +} + +textarea { + height: auto; +} + +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: #ffffff; + border: 1px solid #cccccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} + +textarea:focus, +input[type="text"]:focus, +input[type="password"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="date"]:focus, +input[type="month"]:focus, +input[type="time"]:focus, +input[type="week"]:focus, +input[type="number"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="color"]:focus, +.uneditable-input:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); +} + +input[type="radio"], +input[type="checkbox"] { + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; +} + +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; +} + +.uneditable-textarea { + width: auto; + height: auto; +} + +select, +input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} + +select { + width: 220px; + border: 1px solid #bbb; +} + +select[multiple], +select[size] { + height: auto; +} + +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.radio, +.checkbox { + min-height: 18px; + padding-left: 18px; +} + +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} + +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} + +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} + +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} + +.input-mini { + width: 60px; +} + +.input-small { + width: 90px; +} + +.input-medium { + width: 150px; +} + +.input-large { + width: 210px; +} + +.input-xlarge { + width: 270px; +} + +.input-xxlarge { + width: 530px; +} + +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} + +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} + +input, +textarea, +.uneditable-input { + margin-left: 0; +} + +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 930px; +} + +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 850px; +} + +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 770px; +} + +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 690px; +} + +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 610px; +} + +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 530px; +} + +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 450px; +} + +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 370px; +} + +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 290px; +} + +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 210px; +} + +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 130px; +} + +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 50px; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eeeeee; + border-color: #ddd; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + +.control-group.warning > label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} + +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} + +.control-group.warning .checkbox:focus, +.control-group.warning .radio:focus, +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} + +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} + +.control-group.error > label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} + +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} + +.control-group.error .checkbox:focus, +.control-group.error .radio:focus, +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} + +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} + +.control-group.success > label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} + +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; + border-color: #468847; +} + +.control-group.success .checkbox:focus, +.control-group.success .radio:focus, +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} + +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} + +input:focus:required:invalid, +textarea:focus:required:invalid, +select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} + +input:focus:required:invalid:focus, +textarea:focus:required:invalid:focus, +select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} + +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #e5e5e5; + *zoom: 1; +} + +.form-actions:before, +.form-actions:after { + display: table; + content: ""; +} + +.form-actions:after { + clear: both; +} + +.uneditable-input { + overflow: hidden; + white-space: nowrap; + cursor: not-allowed; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); +} + +:-moz-placeholder { + color: #999999; +} + +:-ms-input-placeholder { + color: #999999; +} + +::-webkit-input-placeholder { + color: #999999; +} + +.help-block, +.help-inline { + color: #555555; +} + +.help-block { + display: block; + margin-bottom: 9px; +} + +.help-inline { + display: inline-block; + *display: inline; + padding-left: 5px; + vertical-align: middle; + *zoom: 1; +} + +.input-prepend, +.input-append { + margin-bottom: 5px; +} + +.input-prepend input, +.input-append input, +.input-prepend select, +.input-append select, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + position: relative; + margin-bottom: 0; + *margin-left: 0; + vertical-align: middle; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.input-prepend input:focus, +.input-append input:focus, +.input-prepend select:focus, +.input-append select:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + z-index: 2; +} + +.input-prepend .uneditable-input, +.input-append .uneditable-input { + border-left-color: #ccc; +} + +.input-prepend .add-on, +.input-append .add-on { + display: inline-block; + width: auto; + height: 18px; + min-width: 16px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + vertical-align: middle; + background-color: #eeeeee; + border: 1px solid #ccc; +} + +.input-prepend .add-on, +.input-append .add-on, +.input-prepend .btn, +.input-append .btn { + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend .active, +.input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} + +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} + +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-append .uneditable-input { + border-right-color: #ccc; + border-left-color: #eee; +} + +.input-append .add-on:last-child, +.input-append .btn:last-child { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} + +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + *display: inline; + margin-bottom: 0; + *zoom: 1; +} + +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} + +.form-search label, +.form-inline label { + display: inline-block; +} + +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} + +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} + +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + +.control-group { + margin-bottom: 9px; +} + +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} + +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} + +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + content: ""; +} + +.form-horizontal .control-group:after { + clear: both; +} + +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 160px; + *margin-left: 0; +} + +.form-horizontal .controls:first-child { + *padding-left: 160px; +} + +.form-horizontal .help-block { + margin-top: 9px; + margin-bottom: 0; +} + +.form-horizontal .form-actions { + padding-left: 160px; +} + +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +.table { + width: 100%; + margin-bottom: 18px; +} + +.table th, +.table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table th { + font-weight: bold; +} + +.table thead th { + vertical-align: bottom; +} + +.table caption + thead tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapsed; + border-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} + +.table-bordered caption + thead tr:first-child th, +.table-bordered caption + tbody tr:first-child th, +.table-bordered caption + tbody tr:first-child td, +.table-bordered colgroup + thead tr:first-child th, +.table-bordered colgroup + tbody tr:first-child th, +.table-bordered colgroup + tbody tr:first-child td, +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} + +.table-bordered thead:first-child tr:first-child th:first-child, +.table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered thead:first-child tr:first-child th:last-child, +.table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-bordered thead:last-child tr:last-child th:first-child, +.table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.table-bordered thead:last-child tr:last-child th:last-child, +.table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; +} + +.table-striped tbody tr:nth-child(odd) td, +.table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} + +.table tbody tr:hover td, +.table tbody tr:hover th { + background-color: #f5f5f5; +} + +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} + +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} + +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} + +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} + +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} + +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} + +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} + +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} + +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} + +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} + +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} + +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} + +table .span13 { + float: none; + width: 1004px; + margin-left: 0; +} + +table .span14 { + float: none; + width: 1084px; + margin-left: 0; +} + +table .span15 { + float: none; + width: 1164px; + margin-left: 0; +} + +table .span16 { + float: none; + width: 1244px; + margin-left: 0; +} + +table .span17 { + float: none; + width: 1324px; + margin-left: 0; +} + +table .span18 { + float: none; + width: 1404px; + margin-left: 0; +} + +table .span19 { + float: none; + width: 1484px; + margin-left: 0; +} + +table .span20 { + float: none; + width: 1564px; + margin-left: 0; +} + +table .span21 { + float: none; + width: 1644px; + margin-left: 0; +} + +table .span22 { + float: none; + width: 1724px; + margin-left: 0; +} + +table .span23 { + float: none; + width: 1804px; + margin-left: 0; +} + +table .span24 { + float: none; + width: 1884px; + margin-left: 0; +} + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +} + +[class^="icon-"]:last-child, +[class*=" icon-"]:last-child { + *margin-left: 0; +} + +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} + +.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + background-position: -384px -120px; +} + +.icon-folder-open { + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.icon-hdd { + background-position: 0 -144px; +} + +.icon-bullhorn { + background-position: -24px -144px; +} + +.icon-bell { + background-position: -48px -144px; +} + +.icon-certificate { + background-position: -72px -144px; +} + +.icon-thumbs-up { + background-position: -96px -144px; +} + +.icon-thumbs-down { + background-position: -120px -144px; +} + +.icon-hand-right { + background-position: -144px -144px; +} + +.icon-hand-left { + background-position: -168px -144px; +} + +.icon-hand-up { + background-position: -192px -144px; +} + +.icon-hand-down { + background-position: -216px -144px; +} + +.icon-circle-arrow-right { + background-position: -240px -144px; +} + +.icon-circle-arrow-left { + background-position: -264px -144px; +} + +.icon-circle-arrow-up { + background-position: -288px -144px; +} + +.icon-circle-arrow-down { + background-position: -312px -144px; +} + +.icon-globe { + background-position: -336px -144px; +} + +.icon-wrench { + background-position: -360px -144px; +} + +.icon-tasks { + background-position: -384px -144px; +} + +.icon-filter { + background-position: -408px -144px; +} + +.icon-briefcase { + background-position: -432px -144px; +} + +.icon-fullscreen { + background-position: -456px -144px; +} + +.dropup, +.dropdown { + position: relative; +} + +.dropdown-toggle { + *margin-bottom: -3px; +} + +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; + opacity: 0.3; + filter: alpha(opacity=30); +} + +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +.dropdown:hover .caret, +.open .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 4px 0; + margin: 1px 0 0; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 8px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu li > a:hover, +.dropdown-menu .active > a, +.dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} + +.open { + *z-index: 1000; +} + +.open > .dropdown-menu { + display: block; +} + +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: "\2191"; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} + +.well-large { + padding: 24px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.btn { + display: inline-block; + *display: inline; + padding: 4px 10px 4px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 13px; + line-height: 18px; + *line-height: 20px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #f5f5f5; + *background-color: #e6e6e6; + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #cccccc; + *border: 0; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-bottom-color: #b3b3b3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; + *background-color: #d9d9d9; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + *background-color: #d9d9d9; + /* Buttons in IE7 don't get borders, so darken on hover */ + + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-color: #e6e6e6; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.btn-large [class^="icon-"] { + margin-top: 1px; +} + +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} + +.btn-small [class^="icon-"] { + margin-top: -1px; +} + +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} + +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn { + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} + +.btn-primary { + background-color: #0074cc; + *background-color: #0055cc; + background-image: -ms-linear-gradient(top, #0088cc, #0055cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0055cc); + background-image: -o-linear-gradient(top, #0088cc, #0055cc); + background-image: -moz-linear-gradient(top, #0088cc, #0055cc); + background-image: linear-gradient(top, #0088cc, #0055cc); + background-repeat: repeat-x; + border-color: #0055cc #0055cc #003580; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0055cc; + *background-color: #004ab3; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #004099 \9; +} + +.btn-warning { + background-color: #faa732; + *background-color: #f89406; + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; + *background-color: #df8505; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + background-color: #da4f49; + *background-color: #bd362f; + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; + *background-color: #a9302a; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + background-color: #5bb75b; + *background-color: #51a351; + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; + *background-color: #499249; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + background-color: #49afcd; + *background-color: #2f96b4; + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; + *background-color: #2a85a0; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + background-color: #414141; + *background-color: #222222; + background-image: -ms-linear-gradient(top, #555555, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222)); + background-image: -webkit-linear-gradient(top, #555555, #222222); + background-image: -o-linear-gradient(top, #555555, #222222); + background-image: -moz-linear-gradient(top, #555555, #222222); + background-image: linear-gradient(top, #555555, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #222222; + *background-color: #151515; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} + +button.btn, +input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +.btn-group { + position: relative; + *margin-left: .3em; + *zoom: 1; +} + +.btn-group:before, +.btn-group:after { + display: table; + content: ""; +} + +.btn-group:after { + clear: both; +} + +.btn-group:first-child { + *margin-left: 0; +} + +.btn-group + .btn-group { + margin-left: 5px; +} + +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} + +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-group > .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group > .btn:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.btn-group > .btn.large:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group > .dropdown-toggle { + *padding-top: 4px; + padding-right: 8px; + *padding-bottom: 4px; + padding-left: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group > .btn-mini.dropdown-toggle { + padding-right: 5px; + padding-left: 5px; +} + +.btn-group > .btn-small.dropdown-toggle { + *padding-top: 4px; + *padding-bottom: 4px; +} + +.btn-group > .btn-large.dropdown-toggle { + padding-right: 12px; + padding-left: 12px; +} + +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group.open .btn.dropdown-toggle { + background-color: #e6e6e6; +} + +.btn-group.open .btn-primary.dropdown-toggle { + background-color: #0055cc; +} + +.btn-group.open .btn-warning.dropdown-toggle { + background-color: #f89406; +} + +.btn-group.open .btn-danger.dropdown-toggle { + background-color: #bd362f; +} + +.btn-group.open .btn-success.dropdown-toggle { + background-color: #51a351; +} + +.btn-group.open .btn-info.dropdown-toggle { + background-color: #2f96b4; +} + +.btn-group.open .btn-inverse.dropdown-toggle { + background-color: #222222; +} + +.btn .caret { + margin-top: 7px; + margin-left: 0; +} + +.btn:hover .caret, +.open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.btn-mini .caret { + margin-top: 5px; +} + +.btn-small .caret { + margin-top: 6px; +} + +.btn-large .caret { + margin-top: 6px; + border-top-width: 5px; + border-right-width: 5px; + border-left-width: 5px; +} + +.dropup .btn-large .caret { + border-top: 0; + border-bottom: 5px solid #000000; +} + +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + color: #c09853; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.alert-heading { + color: inherit; +} + +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-danger, +.alert-error { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} + +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} + +.alert-block p + p { + margin-top: 5px; +} + +.nav { + margin-bottom: 18px; + margin-left: 0; + list-style: none; +} + +.nav > li > a { + display: block; +} + +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} + +.nav > .pull-right { + float: right; +} + +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} + +.nav li + .nav-header { + margin-top: 9px; +} + +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} + +.nav-list [class^="icon-"] { + margin-right: 2px; +} + +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 8px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.nav-tabs, +.nav-pills { + *zoom: 1; +} + +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} + +.nav-tabs:after, +.nav-pills:after { + clear: both; +} + +.nav-tabs > li, +.nav-pills > li { + float: left; +} + +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} + +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +.nav-tabs > li { + margin-bottom: -1px; +} + +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 18px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.nav-pills > .active > a, +.nav-pills > .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li > a { + margin-right: 0; +} + +.nav-tabs.nav-stacked { + border-bottom: 0; +} + +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.nav-tabs.nav-stacked > li > a:hover { + z-index: 2; + border-color: #ddd; +} + +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} + +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} + +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; +} + +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.nav-tabs .dropdown-toggle .caret, +.nav-pills .dropdown-toggle .caret { + margin-top: 6px; + border-top-color: #0088cc; + border-bottom-color: #0088cc; +} + +.nav-tabs .dropdown-toggle:hover .caret, +.nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} + +.nav-tabs .active .dropdown-toggle .caret, +.nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} + +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} + +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} + +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover { + border-color: #999999; +} + +.tabbable { + *zoom: 1; +} + +.tabbable:before, +.tabbable:after { + display: table; + content: ""; +} + +.tabbable:after { + clear: both; +} + +.tab-content { + overflow: auto; +} + +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} + +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} + +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.tabs-below > .nav-tabs > li > a:hover { + border-top-color: #ddd; + border-bottom-color: transparent; +} + +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} + +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} + +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} + +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.tabs-left > .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} + +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} + +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} + +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.tabs-right > .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} + +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} + +.navbar { + *position: relative; + *z-index: 2; + margin-bottom: 18px; + overflow: visible; +} + +.navbar-inner { + min-height: 40px; + padding-right: 20px; + padding-left: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} + +.navbar .container { + width: auto; +} + +.nav-collapse.collapse { + height: auto; +} + +.navbar { + color: #999999; +} + +.navbar .brand:hover { + text-decoration: none; +} + +.navbar .brand { + display: block; + float: left; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #999999; +} + +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; +} + +.navbar .navbar-link { + color: #999999; +} + +.navbar .navbar-link:hover { + color: #ffffff; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 5px; +} + +.navbar .btn-group .btn { + margin: 0; +} + +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} + +.navbar-form:before, +.navbar-form:after { + display: table; + content: ""; +} + +.navbar-form:after { + clear: both; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 5px; +} + +.navbar-form input, +.navbar-form select { + display: inline-block; + margin-bottom: 0; +} + +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} + +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} + +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} + +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} + +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + background-color: #626262; + border: 1px solid #151515; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} + +.navbar-search .search-query:-moz-placeholder { + color: #cccccc; +} + +.navbar-search .search-query:-ms-input-placeholder { + color: #cccccc; +} + +.navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} + +.navbar-search .search-query:focus, +.navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + outline: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-right: 0; + padding-left: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.navbar-fixed-top { + top: 0; +} + +.navbar-fixed-bottom { + bottom: 0; +} + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} + +.navbar .nav.pull-right { + float: right; +} + +.navbar .nav > li { + display: block; + float: left; +} + +.navbar .nav > li > a { + float: none; + padding: 9px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar .btn { + display: inline-block; + padding: 4px 10px 4px; + margin: 5px 5px 6px; + line-height: 18px; +} + +.navbar .btn-group { + padding: 5px 5px 6px; + margin: 0; +} + +.navbar .nav > li > a:hover { + color: #ffffff; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav .active > a, +.navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} + +.navbar .divider-vertical { + width: 1px; + height: 40px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} + +.navbar .nav.pull-right { + margin-right: 0; + margin-left: 10px; +} + +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-right: 5px; + margin-left: 5px; + background-color: #2c2c2c; + *background-color: #222222; + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-image: -moz-linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} + +.navbar .btn-navbar:hover, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + background-color: #222222; + *background-color: #151515; +} + +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #080808 \9; +} + +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + +.navbar .dropdown-menu:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.navbar .dropdown-menu:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-left: 6px solid transparent; + content: ''; +} + +.navbar-fixed-bottom .dropdown-menu:before { + top: auto; + bottom: -7px; + border-top: 7px solid #ccc; + border-bottom: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.navbar-fixed-bottom .dropdown-menu:after { + top: auto; + bottom: -6px; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.navbar .nav li.dropdown .dropdown-toggle .caret, +.navbar .nav li.dropdown.open .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar .nav li.dropdown.active .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + background-color: transparent; +} + +.navbar .nav li.dropdown.active > .dropdown-toggle:hover { + color: #ffffff; +} + +.navbar .pull-right .dropdown-menu, +.navbar .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar .pull-right .dropdown-menu:before, +.navbar .dropdown-menu.pull-right:before { + right: 12px; + left: auto; +} + +.navbar .pull-right .dropdown-menu:after, +.navbar .dropdown-menu.pull-right:after { + right: 13px; + left: auto; +} + +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + list-style: none; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.breadcrumb li { + display: inline-block; + *display: inline; + text-shadow: 0 1px 0 #ffffff; + *zoom: 1; +} + +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} + +.breadcrumb .active a { + color: #333333; +} + +.pagination { + height: 36px; + margin: 18px 0; +} + +.pagination ul { + display: inline-block; + *display: inline; + margin-bottom: 0; + margin-left: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + *zoom: 1; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.pagination li { + display: inline; +} + +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} + +.pagination a:hover, +.pagination .active a { + background-color: #f5f5f5; +} + +.pagination .active a { + color: #999999; + cursor: default; +} + +.pagination .disabled span, +.pagination .disabled a, +.pagination .disabled a:hover { + color: #999999; + cursor: default; + background-color: transparent; +} + +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} + +.pager { + margin-bottom: 18px; + margin-left: 0; + text-align: center; + list-style: none; + *zoom: 1; +} + +.pager:before, +.pager:after { + display: table; + content: ""; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} + +.pager .next a { + float: right; +} + +.pager .previous a { + float: left; +} + +.pager .disabled a, +.pager .disabled a:hover { + color: #999999; + cursor: default; + background-color: #fff; +} + +.modal-open .dropdown-menu { + z-index: 2050; +} + +.modal-open .dropdown.open { + *z-index: 2050; +} + +.modal-open .popover { + z-index: 2060; +} + +.modal-open .tooltip { + z-index: 2070; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + width: 560px; + margin: -250px 0 0 -280px; + overflow: auto; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.modal.fade { + top: -25%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -ms-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; +} + +.modal.fade.in { + top: 50%; +} + +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} + +.modal-header .close { + margin-top: 2px; +} + +.modal-body { + max-height: 400px; + padding: 15px; + overflow-y: auto; +} + +.modal-form { + margin-bottom: 0; +} + +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + content: ""; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} + +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} + +.tooltip { + position: absolute; + z-index: 1020; + display: block; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.tooltip.top { + margin-top: -2px; +} + +.tooltip.right { + margin-left: 2px; +} + +.tooltip.bottom { + margin-top: 2px; +} + +.tooltip.left { + margin-left: -2px; +} + +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top: 5px solid #000000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; + border-left: 5px solid transparent; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-right: 5px solid #000000; + border-bottom: 5px solid transparent; +} + +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} + +.popover.top { + margin-top: -5px; +} + +.popover.right { + margin-left: 5px; +} + +.popover.bottom { + margin-top: 5px; +} + +.popover.left { + margin-left: -5px; +} + +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top: 5px solid #000000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} + +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-right: 5px solid #000000; + border-bottom: 5px solid transparent; +} + +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; + border-left: 5px solid transparent; +} + +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} + +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} + +.popover-inner { + width: 280px; + padding: 3px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} + +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} + +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.popover-content p, +.popover-content ul, +.popover-content ol { + margin-bottom: 0; +} + +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} + +.thumbnails:before, +.thumbnails:after { + display: table; + content: ""; +} + +.thumbnails:after { + clear: both; +} + +.row-fluid .thumbnails { + margin-left: 0; +} + +.thumbnails > li { + float: left; + margin-bottom: 18px; + margin-left: 20px; +} + +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} + +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} + +.thumbnail > img { + display: block; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; +} + +.label, +.badge { + font-size: 10.998px; + font-weight: bold; + line-height: 14px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; +} + +.label { + padding: 1px 4px 2px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.badge { + padding: 1px 9px 2px; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} + +a.label:hover, +a.badge:hover { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label-important, +.badge-important { + background-color: #b94a48; +} + +.label-important[href], +.badge-important[href] { + background-color: #953b39; +} + +.label-warning, +.badge-warning { + background-color: #f89406; +} + +.label-warning[href], +.badge-warning[href] { + background-color: #c67605; +} + +.label-success, +.badge-success { + background-color: #468847; +} + +.label-success[href], +.badge-success[href] { + background-color: #356635; +} + +.label-info, +.badge-info { + background-color: #3a87ad; +} + +.label-info[href], +.badge-info[href] { + background-color: #2d6987; +} + +.label-inverse, +.badge-inverse { + background-color: #333333; +} + +.label-inverse[href], +.badge-inverse[href] { + background-color: #1a1a1a; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-ms-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +.progress { + height: 18px; + margin-bottom: 18px; + overflow: hidden; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress .bar { + width: 0; + height: 18px; + font-size: 12px; + color: #ffffff; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress-striped .bar { + background-color: #149bdf; + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} + +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} + +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} + +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} + +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-warning .bar { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); +} + +.progress-warning.progress-striped .bar { + background-color: #fbb450; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.accordion { + margin-bottom: 18px; +} + +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.accordion-heading { + border-bottom: 0; +} + +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +.accordion-toggle { + cursor: pointer; +} + +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} + +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel .item > img { + display: block; + line-height: 1; +} + +.carousel .active, +.carousel .next, +.carousel .prev { + display: block; +} + +.carousel .active { + left: 0; +} + +.carousel .next, +.carousel .prev { + position: absolute; + top: 0; + width: 100%; +} + +.carousel .next { + left: 100%; +} + +.carousel .prev { + left: -100%; +} + +.carousel .next.left, +.carousel .prev.right { + left: 0; +} + +.carousel .active.left { + left: -100%; +} + +.carousel .active.right { + left: 100%; +} + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-caption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + color: #ffffff; +} + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #eeeeee; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; + color: inherit; +} + +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; + color: inherit; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} diff --git a/scp/css/scp.css b/scp/css/scp.css index 90fd975fd8c8272be307a8a986cad77bdd02a2d5..aa6ca4782492783d221fef0c6b18fe412f3cbcd5 100644 --- a/scp/css/scp.css +++ b/scp/css/scp.css @@ -1,1072 +1,1305 @@ -body { - background:#eee; - font-family:arial, helvetica, sans-serif; - font-size:10pt; - color:#000; - margin:0; - padding:0; -} - -a { - color:#E65524; - text-decoration:none; -} - -.centered { - text-align:center; -} - -.clear { - clear:both; -} - -.faded { - color:#666; -} - -.strike { text-decoration:line-through; color:red; } - -#canned_attachments label { padding:3px; padding-right:10px; } - - -#breadcrumbs { - color: #333; - margin-bottom: 15px; -} - -#breadcrumbs a { - color: #555; -} - -#msg_notice { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #0a0; background: url('../images/icons/ok.png?1300763726') 10px 50% no-repeat #e0ffe0; } - -#msg_warning { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #f26522; background: url('../images/icons/alert.png?1307823786') 10px 50% no-repeat #ffffdd; } - -#msg_error { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #a00; background: url('../images/icons/error.png') 10px 50% no-repeat #fff0f0; } - - -#container { - width:960px; - margin:0 auto 20px auto; -} - -#header { - height:76px; - background:url(../images/header-bg.png) top left repeat-x; - border-left:1px solid #aaa; - border-right:1px solid #aaa; -} - -#logo { - display:block; - float:left; - width:190px; - height:76px; - text-decoration:none; - outline:none; - text-indent:-9999px; - background:url(../images/ost-logo.png) top left no-repeat; -} - -#header p { - display:block; - width:430px; - float:right; - margin:10px; - background:#eee; - border:1px solid #ccc; - padding:8px; - text-align:center; -} - -#nav, #sub_nav { - clear:both; - margin:0; - padding:0 20px; - height:26px; - line-height:26px; - border-left:1px solid #aaa; - border-right:1px solid #aaa; -} - -#nav .active, #sub_nav li { - margin:0; - padding:0; - list-style:none; - display:inline; -} - -#nav { - background:#eee; - padding-top:4px; - z-index:200; - border-top:1px solid #ddd; - border-bottom:1px solid #c5d9ec; -} - -#nav .active a, #nav .inactive { - display:block; - float:left; - width:115px; - height:26px; - color:#555; - text-align:center; - font-weight:bold; - margin-top:1px; - margin-right:5px; - position:relative; -} - -#nav .inactive a { - color:#555; - display:block; -} - -#nav .active a { - background:url(../images/tab-bg.png) top left no-repeat; - color:#004a80; -} - -#nav .inactive ul { - display:none; - width:230px; - background:#fbfbfb; - margin:0; - padding:0; - position:relative; - z-index:500; - border-bottom:1px solid #ccc; - border-left:1px solid #ccc; - border-right:1px solid #ccc; -} - -#nav .inactive li { - display:block; - margin:0; - padding:0 5px; - list-style:none; - text-align:left; -} - -#nav .inactive:hover { - background:url(../images/tab-bg.png) bottom left no-repeat; -} - -#nav .inactive:hover ul { - display:block; - -moz-box-shadow: 3px 3px 3px #ccc; - -webkit-box-shadow: 3px 3px 3px #ccc; - box-shadow: 3px 3px 3px #ccc; -} - -.ieshadow { - width:230px; - background:#000; - filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30); - -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30)"; - zoom: 1; - z-index:300; - position:absolute; - top:24px; - left:0; -} - -#nav .inactive li { - background:#fbfbfb; -} - -#nav .inactive li a { - padding-left:24px; - background-position:0 50%; - background-repeat:no-repeat; - font-weight:normal; - background-color:#fbfbfb; -} - -#nav .inactive li a:hover { - color:#E65524; -} - -#sub_nav { - background:#f7f7f7; - border-bottom:1px solid #bebebe; -} - -#sub_nav a { - display:block; - float:left; - margin-right:10px; - padding:0 10px 0 21px; - background-position:0 50%; - background-repeat:no-repeat; - color:#000; -} - -#sub_nav a:hover { - color:#E65524; -} - -#sub_nav a.active { - font-weight:bold; -} - -#sub_nav .open { background-image:url(../images/icons/open.gif) } -#sub_nav .answered { background-image:url(../images/icons/answered.gif) } -#sub_nav .mine { background-image:url(../images/icons/mine.gif) } -#sub_nav .closed { background-image:url(../images/icons/closed.gif) } -#sub_nav .new { background-image:url(../images/icons/new.gif) } - -a.test { background-image:url(../images/icons/open.gif) } - -a.Ticket { background:url(../images/icons/open_tickets.gif) } -a.assignedTickets { background:url(../images/icons/assigned_tickets.gif) } -a.overdueTickets { background:url(../images/icons/overdue_tickets.gif) } -a.answeredTickets { background:url(../images/icons/answered_tickets.gif) } -a.closedTickets { background:url(../images/icons/closed_tickets.gif) } -a.newTicket { background:url(../images/icons/new_ticket.gif) } - -a.premade { background:url(../images/icons/premade_reply.gif) } -a.newPremade { background:url(../images/icons/new_premade_reply.gif) } - -a.kb { background:url(../images/icons/kb.gif) } -a.kb-categories { background:url(../images/icons/kb-categories.gif) } -a.canned { background:url(../images/icons/canned.gif) } - -a.staff { background:url(../images/icons/list_groups.gif) } -a.user { background:url(../images/icons/list_users.gif) } -a.userPref { background:url(../images/icons/user_preferences.gif) } -a.userPasswd { background:url(../images/icons/change_password.gif) } - -a.preferences { background:url(../images/icons/settings.gif) } -a.attachment { background:url(../images/icons/attachment.gif ) } -a.api { background:url(../images/icons/api.png) } -a.newapi { background:url(../images/icons/new_api.png) } - -a.sla { background:url(../images/icons/slas.png) } -a.newsla { background:url(../images/icons/new_sla.png) } - -a.logs { background:url(../images/icons/logs.gif) } - -a.emails { background:url(../images/icons/emails.png) } -a.newEmail { background:url(../images/icons/new_email.png) } - -a.emailTemplates { background:url(../images/icons/email_templates.png) } -a.newEmailTemplate { background:url(../images/icons/new_email_template.png) } - -a.emailFilters { background:url(../images/icons/email_filters.png) } -a.newEmailFilter { background:url(../images/icons/new_email_filter.png) } - -a.emailSettings { background:url(../images/icons/emails.png) } -a.emailDiagnostic { background:url(../images/icons/email_diagnostic.gif) } -a.banList { background:url(../images/icons/ban_list.gif) } - -a.users { background:url(../images/icons/list_users.gif) } -a.newuser { background:url(../images/icons/new_user.gif) } -a.groups { background:url(../images/icons/list_groups.gif) } -a.teams { background:url(../images/icons/teams.gif) } -a.newgroup { background:url(../images/icons/new_group.gif) } - -a.helpTopics { background:url(../images/icons/help_topics.png) } -a.newHelpTopic { background:url(../images/icons/new_help_topic.png) } - -a.departments { background:url(../images/icons/list_departments.gif) } -a.newDepartment { background:url(../images/icons/new_department.gif) } - - -/* Generic CSS based Icons. use=> <tag class="Icon iconname">text</tag> */ - -.Icon { - width: auto; - padding-left:20px; - background-position: left center; - background-repeat: no-repeat; -} - - -a.Icon { background-repeat: no-repeat;} - - -a.Icon:hover { - text-decoration: underline; -} - - -.Icon.newstaff { background:url(../images/icons/new_user.gif) 0 0 no-repeat; } -.Icon.newteam { background:url(../images/icons/new_team.gif) 0 0 no-repeat; } - -.Icon.Ticket { background:url(../images/icons/ticket.gif) 0 2px no-repeat; } -.Icon.webTicket { background:url(../images/icons/ticket_source_web.gif) 0 0 no-repeat; } -.Icon.emailTicket { background:url(../images/icons/ticket_source_email.gif) 0 0 no-repeat; } -.Icon.phoneTicket { background:url(../images/icons/ticket_source_phone.gif) 0 0 no-repeat; } -.Icon.otherTicket { background:url(../images/icons/ticket_source_other.gif) 0 0 no-repeat; } -.Icon.overdueTicket { background:url(../images/icons/overdue_ticket.gif) 0 0 no-repeat; } -.Icon.assignedTicket { background:url(../images/icons/assigned_ticket.gif) 0 0 no-repeat; } -.Icon.lockedTicket { background:url(../images/icons/locked_ticket.gif) 0 0 no-repeat; } -.Icon.editTicket { background-image: url(../images/icons/edit_ticket.png); } - -.Icon.newCategory { background-image: url(../images/icons/new_category.png); } -.Icon.editCategory { background-image: url(../images/icons/edit_category.png); } -.Icon.deleteCategory { background-image: url(../images/icons/delete_category.png); } -.Icon.newFAQ { background-image: url(../images/icons/new_faq.png); } -.Icon.newReply { background-image: url(../images/icons/new_reply.png); } - -.Icon.file { background-image: url(../images/icons/file.gif); } -.Icon.refresh { background-image: url(../images/icons/refresh.gif); } -.Icon.note { - font-weight: bold; - font-size: 1em; - background-image: url(../images/icons/note.gif); -} - -.Icon.thread { - font-weight: bold; - font-size: 1em; - background-image: url(../images/icons/thread.gif); -} - - -.Icon.debugLog { background:url(../images/icons/log_debug.gif) 0 2px no-repeat; } -.Icon.alertLog { background:url(../images/icons/log_alert.gif) 0 2px no-repeat; } -.Icon.errorLog { background:url(../images/icons/log_error.gif) 0 2px no-repeat; } - - - -#content { - clear:both; - border:1px solid #aaa; - border-top:none; - border-bottom:3px solid #bbb; - padding:10px 10px 20px 10px; - background:#fff; -} - -#content a { - color:#184E81; -} - -#footer { - clear:both; - padding:10px; - text-align:center; - font-size:9pt; -} - -table { vertical-align:top; } - -table.list { - clear:both; - background:#ccc; - margin: 2px 0; - border-bottom: 1px solid #ccc; - font-family:arial, helvetica, sans-serif; - font-size:10pt; -} - -table.list caption { - text-align:left; - padding:5px; - background:#929292; - color:#fff; - font-weight:bold; -} - -table.list thead th { - background-color:#eee; - color:#000; - text-align:left; - vertical-align:top; -} - -table.list th a { - - text-decoration:none; - color:#000; -} - -table.list thead th a { padding: 3px; display: block; color: #000; background: url('../images/asc_desc.gif') 100% 50% no-repeat; } - -table.list thead th a.asc { background: url('../images/asc.gif') 100% 50% no-repeat #cfe6ff; } -table.list thead th a.desc { background: url('../images/desc.gif') 100% 50% no-repeat #cfe6ff; } -table.list tbody td { - background:#fff; - border:1px solid #fff; - padding:1px; - vertical-align:top; -} - -table.list tbody td { background: #fff; padding: 1px; padding-left:2px; vertical-align: top; } -table.list tbody tr.odd td { background-color: #f0faff; } -table.list tbody tr:hover td { background: #ffe; } -table.list tbody tr.odd:hover td { background: #ffd; } - -table.list tfoot td { - background:#eee; - padding: 2px; -} - -table.list tbody td.webticket, table.list tbody tr.row1 td.webticket { - text-indent:20px; - background:url(../images/icons/ticket_source_web.gif) 0 50% no-repeat #fff; -} - -table.list tbody td.emailticket, table.list tbody tr.row1 td.emailticket { - text-indent:20px; - background:url(../images/icons/ticket_source_email.gif) 0 50% no-repeat; -} - -table.list tbody td.phoneticket, table.list tbody tr.row1 td.phoneticket { - text-indent:20px; - background:url(../images/icons/ticket_source_phone.gif) 0 50% no-repeat; -} - -table.list tbody td.otherticket, table.list tbody tr.row1 td.otherticket { - text-indent:20px; - background:url(../images/icons/ticket_source_other.gif) 0 50% no-repeat; -} - -a.refresh { - display:block; - float:right; - width:auto; - height:16px; - line-height:16px; - padding:2px 5px 2px 2px; - background-position:2px 50%; - background-repeat:no-repeat; - padding-left:24px; - margin-left:10px; - margin-bottom: 2px; - border:1px solid #aaa; - background-image:url(../images/icons/refresh.gif); -} - -a.edit, a.print { - display:block; - float:right; - width:auto; - height:16px; - line-height:16px; - padding:2px 5px 2px 2px; - background-position:2px 50%; - background-repeat:no-repeat; - padding-left:24px; - margin-left:10px; - border:1px solid #aaa; - background-image:url(../images/icons/edit_ticket.png); -} - -a.print { - background-image:url(../images/icons/printer.gif); -} - -.btn { - padding:3px 10px; - background:url(../images/btn_bg.png) top left repeat-x #ccc; - border:1px solid #777; - color:#000; -} - -.button { padding:1px 5px; margin-right:10px; color:#777; font-weight:bold;} - -.btn_sm { - padding:2px 5px; - font-size:9pt; - background:url(../images/btn_sm_bg.png) top left repeat-x #f90; - border:1px solid #777; - color:#fff; - font-weight:bold; -} - -.btn:hover, .btn_sm:hover { - background-position: bottom left; -} - -.search label { - display:block; - line-height:25px; - height:25px; -} - -.search input[type=text] { - height:23px; - line-height:23px; - border:1px solid #aaa; - background:#fff; - padding:2px; -} - -.form_table { - margin-top:3px; - border-left:1px solid #ddd; - border-right:1px solid #ddd; -} - -.form_table td { - border-bottom:1px solid #ddd; -} - - -.form_table td.multi-line { - vertical-align:top; -} - -.form_table input[type=text], .form_table input[type=password], .form_table textarea { - background:#fff; - border:1px solid #aaa; -} - -.form_table input[type=radio], .form_table input[type=checkbox] { - position:relative; - top:3px; - margin-left:0; - padding-left:0; -} - -.form_table .required { - font-weight:bold; -} - -.form_table em { - font-weight:normal; - color:#666; -} - -.error { - color:#f00; -} - -.form_table .error input { - border:1px solid #f00; -} - -.form_table th { - text-align:left; - border:1px solid #ccc; - background:#eee; - padding:0; -} - -.form_table th h4 { - margin:0; - padding:5px; - color:#fff; - background:#929292; -} - -.form_table th em { - display:block; - padding:5px; - color:#000; -} - -.settings_table { - margin-top:2px; - border-left:1px solid #ddd; - border-right:1px solid #ddd; -} - -.settings_table td { - border-bottom:1px solid #ddd; -} - -.settings_table input[type=radio], .settings_table input[type=checkbox] { - margin-left:0; - padding-left:0; -} - -#content .settings_table th h4 a { - display:block; - color:#fff; -} - -.settings_table h4 a span { - font-size:12pt; - line-height:14px; - display:inline-block; - width:14px; - height:14px; - overflow:hidden; - text-align:center; - color:#444; - background:#ccc; - position:relative; - top:2px; -} - -h2 { - margin:0; - padding:0; - font-size:12pt; - color:#0A568E; -} - -h2 span { color:#000; } - -h3 { - margin:10px 0 0 0; - padding:5px 0; - font-size:10pt; - color:#444; -} - -.ticket_info th { - text-align:left; -} - -.ticket_info { - background:#F4FAFF; -} - -.right_align { text-align:right; } - -h2 .reload { - display:inline-block; - width:16px; - height:16px; - background:url(../images/icons/refresh.gif) top left no-repeat; - outline:none; - text-indent:-9999px; -} - -#assigned_message { - margin:10px 0; - padding:5px 5px 5px 30px; - background:url(../images/icons/assigned_ticket.gif) 5px 50% no-repeat #ffd; - border:1px solid #f90; -} - - - - -#ticket_actions { - padding:5px; - background:#eee; - border:1px solid #aaa; - border-bottom:none; - margin:0; -} - -#threads { - margin:0; - padding:5px 10px 0 10px; - border:1px solid #aaa; - background:#F4FAFF; - height:30px; -} - -#threads li { - list-style:none; - margin:0; - padding:0; - display:inline; -} - -#threads li a { - display:block; - width:auto; - float:left; - height:30px; - line-height:30px; - border-top:1px solid #F4FAFF; - padding:0 10px 0 32px; - margin-right:10px; -} - -#threads li a.active { - height:29px; - background-color:#fff; - border:1px solid #aaa; - border-bottom:none; - border-top:2px solid #ed9100; - font-weight:bold; -} - -#toggle_ticket_thread { - background:url(../images/icons/open.gif) 10px 50% no-repeat; -} - -#toggle_notes { - background:url(../images/icons/note.gif) 10px 50% no-repeat; -} - -#latest_notes { - margin:10px 0; - padding:10px; - background:#ffe; - border:1px solid #e7e765; -} - -#latest_notes h3 { - margin:0 0 10px 0; - padding:0; - font-size:11pt; -} - -#latest_notes h3 span, #latest_notes h3 a { - color:#777; - font-weight:normal; - text-decoration:none; - font-size:10pt; -} - -#latest_notes ul { - margin:0 20px; - padding:0; -} - -#latest_notes ul li { - margin:0; - padding:0 0 10px 0; - list-style:none; -} - -#latest_notes em { - color:#777; -} - -#ticket_thread table { - margin-top:10px; - border:1px solid #aaa; - border-bottom:2px solid #aaa; -} - -#ticket_notes table { - margin-top:10px; - border:1px solid #ddd; - border-bottom:2px solid #ddd; -} - -#ticket_thread table th, #ticket_notes table th { - text-align:left; - border-bottom:1px solid #aaa; - font-size:10pt; - padding:5px; -} - -#ticket_notes table th { - text-align:left; - border-bottom:1px solid #ddd; - font-size:10pt; - padding:5px; - background:#F4FAFF; -} - -#ticket_notes table th em { - font-weight:normal; - font-size:10pt; - color:#666; -} - -#ticket_thread .message th { - background:#C3D9FF; -} - -#ticket_notes .date { - font-weight:normal; - font-size:10pt; - color:#888; - text-align:right; -} - -#ticket_thread .response th { - background:#FFE0B3; -} - -#ticket_thread table td, #ticket_notes table td { - padding:5px; -} - -#ticket_notes td { - background:#f9f9f9; -} - -#ticket_thread .info, #ticket_notes .info { - padding:5px; - background:#F4FAFF; - height:16px; - line-height:16px; -} - -#ticket_notes .info { - background:#f9f9f9; -} - -#response_options { - margin-top:30px; -} - -#response_options form { - padding:0 10px; -} - -#response_options ul { - padding:4px 0 0 190px; - margin:0; - text-align:center; - height:29px; - border-bottom:1px solid #aaa; - background:#eef3f8; -} - -#response_options li { - margin:0; - padding:0; - display:inline; - list-style:none; -} - -#response_options li a { - width:130px; - font-weight:bold; - padding:5px; - height:18px; - line-height:20px; - color:#444; - display:block; - float:left; - outline:none; - position:relative; - top:0; - background:#fbfbfb; - border:1px solid #eee; - border-bottom:none; -} - -#response_options .reply_tab.tell { - color:#a00 !important; - background-image:url(../images/reminder.png); - background-position:12px 50%; - background-repeat:no-repeat; -} - -#response_options li a.active { - height:18px; - color:#184E81; - background-color:#f9f9f9; - border:1px solid #aaa; - border-top:2px solid #81a9d7; - border-bottom:none; -} - -#response_options form { - padding:10px 5px; - background:#f9f9f9; - border:1px solid #aaa; - border-top:none; -} - -#response_options table { - width:928px; -} - -#response_options td { - vertical-align:top; -} - -#response_options textarea { - width:760px !important; -} - -#response_options input[type=text], #response_options textarea { - border:1px solid #aaa; - background:#fff; -} - -.attachments .uploads div { - display:inline-block; - padding-right:20px; -} - - - -.file { - display:inline-block; - padding-left:20px; - margin-right:20px; - background:url(../images/icons/file.gif) 0 50% no-repeat; -} - -.expander { - line-height:14px; - display:inline-block; - width:12px; - height:12px; - overflow:hidden; - text-align:center; - color:#aaa; - position:relative; -} - -/** Popup Tool Tips and Content **/ - -.tip_box { - display:block; - height:30px; - position:absolute; - z-index:1000; -} - -.tip_arrow { - display:block; - position:absolute; - top:5px; - left:-11px; - width:12px; - z-index:700; -} - -.tip_content { - height:auto !important; - height:20px; - min-height:20px; - padding:10px 5px 5px 5px; - border:1px solid #666; - background:#fff; - -moz-border-radius:5px; - -webkit-border-radius:5px; - border-radius:5px; - -moz-box-shadow: 3px 3px 3px #666; - -webkit-box-shadow: 3px 3px 3px #666; - box-shadow: 3px 3px 3px #666; - z-index:500; - position:absolute; - top:0; - left:-1px; - width:auto !important; - width:300px; -} - -.tip_content hr { - - color: #ddd; - background-color: #ddd; - height: 1px; - border: 0; - padding: 0; - margin: 0.2em 0; - width: 100%; -} - -.tip_close { - position:absolute; - left:100%; - top:0; - margin-left:-12px; -} - -.tip_shadow { - display:none; - background:#000; - filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60); - -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60)"; - zoom: 1; - position:absolute; - z-index:200; - top:0; - left:0; - width:auto !important; - width:310px; -} - -.tip_menu { - margin:10px 0 0 0; - padding:5px 0; - border-top:1px solid #aaa; - height:16px; - font-size:9pt; -} - -.tip_menu li { - display:inline; - list-style:none; - margin:0; - padding:0; -} - -.tip_menu li a { - display:block; - width:auto; - _width:0; - float:left; - padding:0 10px; - border-right:1px solid #ddd; - color:#666; -} - -.tip_menu li a:hover { - color:#E76C74; -} - -.tip_content form { - display:none; - line-height:24px; -} - -.tip_content select, .tip_content textarea { - width:295px; -} - -.tip_content textarea { - padding:0; - border:1px solid #aaa; - background:#fff; -} - -.tip_content form p { - margin:0; - width:auto !important; - width:295px; - text-align:right; - line-height:24px; -} - -/* Knowledgebase */ -#kb { - margin: 2px 0; - padding: 0; - overflow: hidden; -} - -#kb > li { - margin: 0 0 5px 0; - padding: 0 10px; - width: auto; - float: left; - clear: both; -} - -#kb > li h4 { - padding-bottom:3px; - margin-bottom:3px; -} - -#kb > li h4 span { - color:#666; -} - -#kb > li h4 a { - font-size: 14px; -} - -#faq { - clear: both; - margin: 0; - padding: 5 0 10px 5px; -} -#faq ol { - font-size: 15px; - margin-left: 0; - padding-left: 0; -} -#faq ol li { - list-style: none; - margin: 0 0 10px 0; - color: #999; -} -#faq ol li a { - display: inline; - height: 16px; - line-height: 16px; - padding-left: 24px; - background: url('../images/icons/page.png') 0 50% no-repeat; -} +body { + background:#eee; + font-family:arial, helvetica, sans-serif; + font-size:10pt; + color:#000; + margin:0; + padding:0; +} + +a { + color:#E65524; + text-decoration:none; +} + +.centered { + text-align:center; +} + +.clear { + clear:both; +} + +.faded { + color:#666; +} + +.strike { text-decoration:line-through; color:red; } + +#canned_attachments label { padding:3px; padding-right:10px; } + + +#breadcrumbs { + color: #333; + margin-bottom: 15px; +} + +#breadcrumbs a { + color: #555; +} + +#msg_notice { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #0a0; background: url('../images/icons/ok.png?1300763726') 10px 50% no-repeat #e0ffe0; } + +#msg_warning { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #f26522; background: url('../images/icons/alert.png?1307823786') 10px 50% no-repeat #ffffdd; } + +#msg_error { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #a00; background: url('../images/icons/error.png') 10px 50% no-repeat #fff0f0; } + + +#container { + width:960px; + margin:0 auto 20px auto; +} + +#header { + height:76px; + background:url(../images/header-bg.png) top left repeat-x; + border-left:1px solid #aaa; + border-right:1px solid #aaa; +} + +#logo { + display:block; + float:left; + width:190px; + height:76px; + text-decoration:none; + outline:none; + text-indent:-9999px; + background:url(../images/ost-logo.png) top left no-repeat; +} + +#header p { + display:block; + width:430px; + float:right; + margin:10px; + background:#eee; + border:1px solid #ccc; + padding:8px; + text-align:center; +} + +#nav, #sub_nav { + clear:both; + margin:0; + padding:0 20px; + height:26px; + line-height:26px; + border-left:1px solid #aaa; + border-right:1px solid #aaa; +} + +#nav .active, #sub_nav li { + margin:0; + padding:0; + list-style:none; + display:inline; +} + +#nav { + background:#eee; + padding-top:4px; + z-index:200; + border-top:1px solid #ddd; + border-bottom:1px solid #c5d9ec; +} + +#nav .active a, #nav .inactive { + display:block; + float:left; + width:115px; + height:26px; + color:#555; + text-align:center; + font-weight:bold; + margin-top:1px; + margin-right:5px; + position:relative; +} + +#nav .inactive a { + color:#555; + display:block; +} + +#nav .active a { + background:url(../images/tab-bg.png) top left no-repeat; + color:#004a80; +} + +#nav .inactive ul { + display:none; + width:230px; + background:#fbfbfb; + margin:0; + padding:0; + position:relative; + z-index:500; + border-bottom:1px solid #ccc; + border-left:1px solid #ccc; + border-right:1px solid #ccc; +} + +#nav .inactive li { + display:block; + margin:0; + padding:0 5px; + list-style:none; + text-align:left; +} + +#nav .inactive:hover { + background:url(../images/tab-bg.png) bottom left no-repeat; +} + +#nav .inactive:hover ul { + display:block; + -moz-box-shadow: 3px 3px 3px #ccc; + -webkit-box-shadow: 3px 3px 3px #ccc; + box-shadow: 3px 3px 3px #ccc; +} + +.ieshadow { + width:230px; + background:#000; + filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30); + -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30)"; + zoom: 1; + z-index:300; + position:absolute; + top:24px; + left:0; +} + +#nav .inactive li { + background:#fbfbfb; +} + +#nav .inactive li a { + padding-left:24px; + background-position:0 50%; + background-repeat:no-repeat; + font-weight:normal; + background-color:#fbfbfb; +} + +#nav .inactive li a:hover { + color:#E65524; +} + +#sub_nav { + background:#f7f7f7; + border-bottom:1px solid #bebebe; +} + +#sub_nav a { + display:block; + float:left; + margin-right:10px; + padding:0 10px 0 21px; + background-position:0 50%; + background-repeat:no-repeat; + color:#000; +} + +#sub_nav a:hover { + color:#E65524; +} + +#sub_nav a.active { + font-weight:bold; +} + +#sub_nav .open { background-image:url(../images/icons/open.gif) } +#sub_nav .answered { background-image:url(../images/icons/answered.gif) } +#sub_nav .mine { background-image:url(../images/icons/mine.gif) } +#sub_nav .closed { background-image:url(../images/icons/closed.gif) } +#sub_nav .new { background-image:url(../images/icons/new.gif) } + +a.test { background-image:url(../images/icons/open.gif) } + +a.Ticket { background:url(../images/icons/open_tickets.gif) } +a.assignedTickets { background:url(../images/icons/assigned_tickets.gif) } +a.overdueTickets { background:url(../images/icons/overdue_tickets.gif) } +a.answeredTickets { background:url(../images/icons/answered_tickets.gif) } +a.closedTickets { background:url(../images/icons/closed_tickets.gif) } +a.newTicket { background:url(../images/icons/new_ticket.gif) } + +a.premade { background:url(../images/icons/premade_reply.gif) } +a.newPremade { background:url(../images/icons/new_premade_reply.gif) } + +a.kb { background:url(../images/icons/kb.gif) } +a.kb-categories { background:url(../images/icons/kb-categories.gif) } +a.canned { background:url(../images/icons/canned.gif) } + +a.staff { background:url(../images/icons/list_groups.gif) } +a.user { background:url(../images/icons/list_users.gif) } +a.userPref { background:url(../images/icons/user_preferences.gif) } +a.userPasswd { background:url(../images/icons/change_password.gif) } + +a.preferences { background:url(../images/icons/settings.gif) } +a.attachment { background:url(../images/icons/attachment.gif ) } +a.api { background:url(../images/icons/api.png) } +a.newapi { background:url(../images/icons/new_api.png) } + +a.sla { background:url(../images/icons/slas.png) } +a.newsla { background:url(../images/icons/new_sla.png) } + +a.logs { background:url(../images/icons/logs.gif) } + +a.emails { background:url(../images/icons/emails.png) } +a.newEmail { background:url(../images/icons/new_email.png) } + +a.emailTemplates { background:url(../images/icons/email_templates.png) } +a.newEmailTemplate { background:url(../images/icons/new_email_template.png) } + +a.emailFilters { background:url(../images/icons/email_filters.png) } +a.newEmailFilter { background:url(../images/icons/new_email_filter.png) } + +a.emailSettings { background:url(../images/icons/emails.png) } +a.emailDiagnostic { background:url(../images/icons/email_diagnostic.gif) } +a.banList { background:url(../images/icons/ban_list.gif) } + +a.users { background:url(../images/icons/list_users.gif) } +a.newuser { background:url(../images/icons/new_user.gif) } +a.groups { background:url(../images/icons/list_groups.gif) } +a.teams { background:url(../images/icons/teams.gif) } +a.newgroup { background:url(../images/icons/new_group.gif) } + +a.helpTopics { background:url(../images/icons/help_topics.png) } +a.newHelpTopic { background:url(../images/icons/new_help_topic.png) } + +a.departments { background:url(../images/icons/list_departments.gif) } +a.newDepartment { background:url(../images/icons/new_department.gif) } + + +/* Generic CSS based Icons. use=> <tag class="Icon iconname">text</tag> */ + +.Icon { + width: auto; + padding-left:20px; + background-position: left center; + background-repeat: no-repeat; +} + + +a.Icon { background-repeat: no-repeat;} + + +a.Icon:hover { + text-decoration: underline; +} + + +.Icon.newstaff { background:url(../images/icons/new_user.gif) 0 0 no-repeat; } +.Icon.newteam { background:url(../images/icons/new_team.gif) 0 0 no-repeat; } + +.Icon.Ticket { background:url(../images/icons/ticket.gif) 0 2px no-repeat; } +.Icon.webTicket { background:url(../images/icons/ticket_source_web.gif) 0 0 no-repeat; } +.Icon.emailTicket { background:url(../images/icons/ticket_source_email.gif) 0 0 no-repeat; } +.Icon.phoneTicket { background:url(../images/icons/ticket_source_phone.gif) 0 0 no-repeat; } +.Icon.otherTicket { background:url(../images/icons/ticket_source_other.gif) 0 0 no-repeat; } +.Icon.overdueTicket { background:url(../images/icons/overdue_ticket.gif) 0 0 no-repeat; } +.Icon.assignedTicket { background:url(../images/icons/assigned_ticket.gif) 0 0 no-repeat; } +.Icon.lockedTicket { background:url(../images/icons/locked_ticket.gif) 0 0 no-repeat; } +.Icon.editTicket { background-image: url(../images/icons/edit_ticket.png); } + +.Icon.newCategory { background-image: url(../images/icons/new_category.png); } +.Icon.editCategory { background-image: url(../images/icons/edit_category.png); } +.Icon.deleteCategory { background-image: url(../images/icons/delete_category.png); } +.Icon.newFAQ { background-image: url(../images/icons/new_faq.png); } +.Icon.newReply { background-image: url(../images/icons/new_reply.png); } + +.Icon.file { background-image: url(../images/icons/file.gif); } +.Icon.refresh { background-image: url(../images/icons/refresh.gif); } +.Icon.note { + font-weight: bold; + font-size: 1em; + background-image: url(../images/icons/note.gif); +} + +.Icon.thread { + font-weight: bold; + font-size: 1em; + background-image: url(../images/icons/thread.gif); +} + + +.Icon.debugLog { background:url(../images/icons/log_debug.gif) 0 2px no-repeat; } +.Icon.alertLog { background:url(../images/icons/log_alert.gif) 0 2px no-repeat; } +.Icon.errorLog { background:url(../images/icons/log_error.gif) 0 2px no-repeat; } + + + +#content { + clear:both; + border:1px solid #aaa; + border-top:none; + border-bottom:3px solid #bbb; + padding:10px 10px 20px 10px; + background:#fff; +} + +#content a { + color:#184E81; +} + +#footer { + clear:both; + padding:10px; + text-align:center; + font-size:9pt; +} + +table { vertical-align:top; } + +table.list { + clear:both; + background:#ccc; + margin: 2px 0; + border-bottom: 1px solid #ccc; + font-family:arial, helvetica, sans-serif; + font-size:10pt; +} + +table.list caption { + text-align:left; + padding:5px; + background:#929292; + color:#fff; + font-weight:bold; +} + +table.list thead th { + background-color:#eee; + color:#000; + text-align:left; + vertical-align:top; +} + +table.list th a { + + text-decoration:none; + color:#000; +} + +table.list thead th a { padding: 3px; display: block; color: #000; background: url('../images/asc_desc.gif') 100% 50% no-repeat; } + +table.list thead th a.asc { background: url('../images/asc.gif') 100% 50% no-repeat #cfe6ff; } +table.list thead th a.desc { background: url('../images/desc.gif') 100% 50% no-repeat #cfe6ff; } +table.list tbody td { + background:#fff; + border:1px solid #fff; + padding:1px; + vertical-align:top; +} + +table.list tbody td { background: #fff; padding: 1px; padding-left:2px; vertical-align: top; } +table.list tbody tr.odd td { background-color: #f0faff; } +table.list tbody tr:hover td { background: #ffe; } +table.list tbody tr.odd:hover td { background: #ffd; } + +table.list tfoot td { + background:#eee; + padding: 2px; +} + +table.list tbody td.webticket, table.list tbody tr.row1 td.webticket { + text-indent:20px; + background:url(../images/icons/ticket_source_web.gif) 0 50% no-repeat #fff; +} + +table.list tbody td.emailticket, table.list tbody tr.row1 td.emailticket { + text-indent:20px; + background:url(../images/icons/ticket_source_email.gif) 0 50% no-repeat; +} + +table.list tbody td.phoneticket, table.list tbody tr.row1 td.phoneticket { + text-indent:20px; + background:url(../images/icons/ticket_source_phone.gif) 0 50% no-repeat; +} + +table.list tbody td.otherticket, table.list tbody tr.row1 td.otherticket { + text-indent:20px; + background:url(../images/icons/ticket_source_other.gif) 0 50% no-repeat; +} + +a.refresh { + display:block; + float:right; + width:auto; + height:16px; + line-height:16px; + padding:2px 5px 2px 2px; + background-position:2px 50%; + background-repeat:no-repeat; + padding-left:24px; + margin-left:10px; + margin-bottom: 2px; + border:1px solid #aaa; + background-image:url(../images/icons/refresh.gif); +} + +a.edit, a.print { + display:block; + float:right; + width:auto; + height:16px; + line-height:16px; + padding:2px 5px 2px 2px; + background-position:2px 50%; + background-repeat:no-repeat; + padding-left:24px; + margin-left:10px; + border:1px solid #aaa; + background-image:url(../images/icons/edit_ticket.png); +} + +a.print { + background-image:url(../images/icons/printer.gif); +} + +.btn { + padding:3px 10px; + background:url(../images/btn_bg.png) top left repeat-x #ccc; + border:1px solid #777; + color:#000; +} + +.button { padding:1px 5px; margin-right:10px; color:#777; font-weight:bold;} + +.btn_sm { + padding:2px 5px; + font-size:9pt; + background:url(../images/btn_sm_bg.png) top left repeat-x #f90; + border:1px solid #777; + color:#fff; + font-weight:bold; +} + +.btn:hover, .btn_sm:hover { + background-position: bottom left; +} + +.search label { + display:block; + line-height:25px; + height:25px; +} + +.search input[type=text] { + height:23px; + line-height:23px; + border:1px solid #aaa; + background:#fff; + padding:2px; +} + +.form_table { + margin-top:3px; + border-left:1px solid #ddd; + border-right:1px solid #ddd; +} + +.form_table td { + border-bottom:1px solid #ddd; +} + + +.form_table td.multi-line { + vertical-align:top; +} + +.form_table input[type=text], .form_table input[type=password], .form_table textarea { + background:#fff; + border:1px solid #aaa; +} + +.form_table input[type=radio], .form_table input[type=checkbox] { + position:relative; + top:3px; + margin-left:0; + padding-left:0; +} + +.form_table .required { + font-weight:bold; +} + +.form_table em { + font-weight:normal; + color:#666; +} + +.error { + color:#f00; +} + +.form_table .error input { + border:1px solid #f00; +} + +.form_table th { + text-align:left; + border:1px solid #ccc; + background:#eee; + padding:0; +} + +.form_table th h4 { + margin:0; + padding:5px; + color:#fff; + background:#929292; +} + +.form_table th em { + display:block; + padding:5px; + color:#000; +} + +.settings_table { + margin-top:2px; + border-left:1px solid #ddd; + border-right:1px solid #ddd; +} + +.settings_table td { + border-bottom:1px solid #ddd; +} + +.settings_table input[type=radio], .settings_table input[type=checkbox] { + margin-left:0; + padding-left:0; +} + +#content .settings_table th h4 a { + display:block; + color:#fff; +} + +.settings_table h4 a span { + font-size:12pt; + line-height:14px; + display:inline-block; + width:14px; + height:14px; + overflow:hidden; + text-align:center; + color:#444; + background:#ccc; + position:relative; + top:2px; +} + +h2 { + margin:0; + padding:0; + font-size:12pt; + color:#0A568E; +} + +h2 span { color:#000; } + +h3 { + margin:10px 0 0 0; + padding:5px 0; + font-size:10pt; + color:#444; +} + +.ticket_info th { + text-align:left; +} + +.ticket_info { + background:#F4FAFF; +} + +.right_align { text-align:right; } + +h2 .reload { + display:inline-block; + width:16px; + height:16px; + background:url(../images/icons/refresh.gif) top left no-repeat; + outline:none; + text-indent:-9999px; +} + +#assigned_message { + margin:10px 0; + padding:5px 5px 5px 30px; + background:url(../images/icons/assigned_ticket.gif) 5px 50% no-repeat #ffd; + border:1px solid #f90; +} + + + + +#ticket_actions { + padding:5px; + background:#eee; + border:1px solid #aaa; + border-bottom:none; + margin:0; +} + +#threads { + margin:0; + padding:5px 10px 0 10px; + border:1px solid #aaa; + background:#F4FAFF; + height:30px; +} + +#threads li { + list-style:none; + margin:0; + padding:0; + display:inline; +} + +#threads li a { + display:block; + width:auto; + float:left; + height:30px; + line-height:30px; + border-top:1px solid #F4FAFF; + padding:0 10px 0 32px; + margin-right:10px; +} + +#threads li a.active { + height:29px; + background-color:#fff; + border:1px solid #aaa; + border-bottom:none; + border-top:2px solid #ed9100; + font-weight:bold; +} + +#toggle_ticket_thread { + background:url(../images/icons/open.gif) 10px 50% no-repeat; +} + +#toggle_notes { + background:url(../images/icons/note.gif) 10px 50% no-repeat; +} + +#ticket_thread table { + margin-top:10px; + border:1px solid #aaa; + border-bottom:2px solid #aaa; +} + +#ticket_notes table { + margin-top:10px; + border:1px solid #ddd; + border-bottom:2px solid #ddd; +} + +#ticket_thread table th, #ticket_notes table th { + text-align:left; + border-bottom:1px solid #aaa; + font-size:10pt; + padding:5px; +} + +#ticket_notes table th { + text-align:left; + border-bottom:1px solid #ddd; + font-size:10pt; + padding:5px; + background:#F4FAFF; +} + +#ticket_notes table th em { + font-weight:normal; + font-size:10pt; + color:#666; +} + +#ticket_notes .date { + font-weight:normal; + font-size:10pt; + color:#888; + text-align:right; +} + +#ticket_thread table th.tmeta { + font-weight:bold; + font-size:10pt; + color:#888; + text-align:right; + padding-right:15px; +} + +#ticket_thread table th span { + font-weight:normal; + font-size:10pt; + color:#888; + padding-left:5px; +} + +#ticket_thread .message th { + background:#C3D9FF; +} + +#ticket_thread .response th { + background:#FFE0B3; +} + +#ticket_thread .note th { + background:#FFE; +} + +#ticket_thread table td, #ticket_notes table td { + padding:5px; +} + +#ticket_notes td { + background:#f9f9f9; +} + +#ticket_thread .info, #ticket_notes .info { + padding:5px; + background:#F4FAFF; + height:16px; + line-height:16px; +} + +#ticket_notes .info { + background:#f9f9f9; +} + +#response_options { + margin-top:30px; +} + +#response_options form { + padding:0 10px; +} + +#response_options ul { + padding:4px 0 0 190px; + margin:0; + text-align:center; + height:29px; + border-bottom:1px solid #aaa; + background:#eef3f8; +} + +#response_options li { + margin:0; + padding:0; + display:inline; + list-style:none; +} + +#response_options li a { + width:130px; + font-weight:bold; + padding:5px; + height:18px; + line-height:20px; + color:#444; + display:block; + float:left; + outline:none; + position:relative; + top:0; + background:#fbfbfb; + border:1px solid #eee; + border-bottom:none; +} + +#response_options .reply_tab.tell { + color:#a00 !important; + background-image:url(../images/reminder.png); + background-position:12px 50%; + background-repeat:no-repeat; +} + +#response_options li a.active { + height:18px; + color:#184E81; + background-color:#f9f9f9; + border:1px solid #aaa; + border-top:2px solid #81a9d7; + border-bottom:none; +} + +#response_options form { + padding:10px 5px; + background:#f9f9f9; + border:1px solid #aaa; + border-top:none; +} + +#response_options table { + width:928px; +} + +#response_options td { + vertical-align:top; +} + +#response_options textarea { + width:760px !important; +} + +#response_options input[type=text], #response_options textarea { + border:1px solid #aaa; + background:#fff; +} + +.attachments .uploads div { + display:inline-block; + padding-right:20px; +} + + + +.file { + display:inline-block; + padding-left:20px; + margin-right:20px; + background:url(../images/icons/file.gif) 0 50% no-repeat; +} + +.expander { + line-height:14px; + display:inline-block; + width:12px; + height:12px; + overflow:hidden; + text-align:center; + color:#aaa; + position:relative; +} + +/** Popup Tool Tips and Content **/ + +.tip_box { + display:block; + height:30px; + position:absolute; + z-index:1000; +} + +.tip_arrow { + display:block; + position:absolute; + top:5px; + left:-11px; + width:12px; + z-index:700; +} + +.tip_content { + height:auto !important; + height:20px; + min-height:20px; + padding:10px 5px 5px 5px; + border:1px solid #666; + background:#fff; + -moz-border-radius:5px; + -webkit-border-radius:5px; + border-radius:5px; + -moz-box-shadow: 3px 3px 3px #666; + -webkit-box-shadow: 3px 3px 3px #666; + box-shadow: 3px 3px 3px #666; + z-index:500; + position:absolute; + top:0; + left:-1px; + width:auto !important; + width:300px; +} + +.tip_content hr { + + color: #ddd; + background-color: #ddd; + height: 1px; + border: 0; + padding: 0; + margin: 0.2em 0; + width: 100%; +} + +.tip_close { + position:absolute; + left:100%; + top:0; + margin-left:-12px; +} + +.tip_shadow { + display:none; + background:#000; + filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60); + -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60)"; + zoom: 1; + position:absolute; + z-index:200; + top:0; + left:0; + width:auto !important; + width:310px; +} + +.tip_menu { + margin:10px 0 0 0; + padding:5px 0; + border-top:1px solid #aaa; + height:16px; + font-size:9pt; +} + +.tip_menu li { + display:inline; + list-style:none; + margin:0; + padding:0; +} + +.tip_menu li a { + display:block; + width:auto; + _width:0; + float:left; + padding:0 10px; + border-right:1px solid #ddd; + color:#666; +} + +.tip_menu li a:hover { + color:#E76C74; +} + +.tip_content form { + display:none; + line-height:24px; +} + +.tip_content select, .tip_content textarea { + width:295px; +} + +.tip_content textarea { + padding:0; + border:1px solid #aaa; + background:#fff; +} + +.tip_content form p { + margin:0; + width:auto !important; + width:295px; + text-align:right; + line-height:24px; +} + +/* Knowledgebase */ +/* Knowledgebase */ +#kb { + margin: 2px 0; + padding: 5px; + overflow: hidden; +} + +#kb li { + padding:10px 10px 10px 46px; + height:auto !important; + overflow:hidden; + margin:0; + background-image:url(../images/kb_large_folder.png), url(../images/kb_category_bg.png); + background-position:0 50%, bottom left; + background-repeat:no-repeat, repeat-x; + border-bottom:1px solid #ddd; +} + + +#kb li h4 { + padding-bottom:3px; + margin:0 0 3px 0; +} + +#kb li h4 span { + color:#666; + font-weight:normal; +} + +#kb li h4 a { + font-size: 14px; +} + +#kbSearch { + padding:10px 0; + overflow:hidden; +} + +#kbSearch div { + clear:both; + overflow:hidden; + padding-top:5px; +} + +#kbSearch #query { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; +} + +#kbSearch #cid { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; + position:relative; + top:2px; +} + +#kbSearch #topic-id { + margin:0; + display:inline-block; + float:left; + width:410px; +} + +#kbSearch #searchSubmit { + margin:0; + display:inline-block; + float:left; + position:relative; + top:2px; +} + +#faq { + clear: both; + margin: 0; + padding: 5 0 10px 5px; +} +#faq ol { + font-size: 15px; + margin-left: 0; + padding-left: 0; +} +#faq ol li { + list-style: none; + margin: 0; + padding:5px 0; + color: #999; + border-bottom:1px solid #ddd; +} + +#faq ol li a { + display: inline; + height: 16px; + font-size:13px; + line-height: 16px; + padding-left: 24px; + background: url('../images/icons/page.png') 0 50% no-repeat; +} + +#faq ol li a span { + font-weight:normal; + color:#777; +} + +#faq ol li:hover { + background-color:#e9f5ff; +} + +time { + display:inline-block; + float:right; + color:#777; +} + +.cat-desc { + padding-top:5px; + padding-bottom:25px; +} + +.cat-manage-bar { + background:#e3f5ff; + padding:5px; + border-bottom:1px solid #777; +} + +.cat-manage-bar a { + display:inline-block; + margin-right:20px; +} + +/* Advanced Ticket Search */ + +#overlay { + background:#000; + position:absolute; + display:none; + z-index:1000; +} + +#advanced-search, #advanced-search * { + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} + +#advanced-search { + position:absolute; + padding:1em; + width:640px; + height:360px; + background:#fff; + border:1px solid #2a67ac; + display:none; + z-index:1200; +} + +#advanced-search h3 { + color:#2a67ac; + font-size:20px; + margin:0; + padding:0; + display:inline-block; +} + +#advanced-search a.close { + display:inline-block; + float:right; + font-size:16px; + color:#777; +} + +#advanced-search form { + clear:both; + padding:2em 0 1em 0; + width:100%; +} + +#advanced-search div.closed_by, #advanced-search span.spinner { + display:none; +} + +#advanced-search fieldset { + margin:0; + padding:0.25em 0; + border:none; + overflow:hidden; +} + +#advanced-search label { + width:100px; + display:inline-block; + text-align:right; + padding:10px; +} + +#advanced-search fieldset input { + border:1px solid #ccc; + background:#fff; +} + +#advanced-search fieldset select { + width:170px; + display:inline-block; +} + +#advanced-search fieldset span { + width:50px; + display:inline-block; + text-align:center; + color:#777; + font-size:0.75em; +} + +#advanced-search .query input { + width:350px; +} + +#advanced-search .date_range input { + width:175px; +} + +#advanced-search .date_range i { + display:inline-block; + margin-left:3px; + position:relative; + top:5px; + width:16px; + height:16px; + background:url(../images/cal.png) bottom left no-repeat; +} + +#advanced-search fieldset.sorting select { + width:130px; +} + +#advanced-search p { + text-align:center; +} + +#advanced-search input[type="submit"], +#advanced-search input[type="reset"], +#advanced-search input[type="button"] +{ + display:inline-block; + margin:0; + height:24px; + line-height:24px; + font-weight:bold; + border:1px solid #666666; + padding:0 10px; + background: url('../images/grey_btn_bg.png?1312910883') top left repeat-x; + color: #333; +} + +#advanced-search input[type="reset"], #advanced-search input[type="button"] { + opacity:0.7; +} + +#advanced-search input[type=submit]:hover, #advanced-search input[type=submit]:active, +#advanced-search input[type=reset]:hover, #advanced-search input[type=reset]:active { + background-position:bottom left; +} + +#result-count div { + padding:5px 10px; + text-align:left; + font-weight:bold; + width:100%; + margin:0 auto; +} + +#result-count .success { + background:#e3ffd8; + border:1px solid #0a0; +} + +#result-count .fail { + background:#ffd8d8; + border:1px solid #a00; +} + +/* Custom css for datepicker */ +.ui-datepicker-trigger { + display:inline-block; + border:0; + padding:0; + margin-left:2px; + position:relative; + top:5px; + width:16px; + height:16px; + background:inherit; +} diff --git a/scp/dashboard.php b/scp/dashboard.php index 0551639566396dea6544b361b22a41b7b21ce0db..fd276a2d49f4ee32dde0de8101d97baaa63bc123 100644 --- a/scp/dashboard.php +++ b/scp/dashboard.php @@ -17,6 +17,360 @@ require('staff.inc.php'); $nav->setTabActive('dashboard'); require(STAFFINC_DIR.'header.inc.php'); //require(STAFFINC_DIR.$page); -echo "Staff's dashboard"; +?> + +<script type="text/javascript" src="js/raphael-min.js"></script> +<script type="text/javascript" src="js/g.raphael.js"></script> +<script type="text/javascript" src="js/g.line-min.js"></script> +<script type="text/javascript" src="js/g.dot-min.js"></script> +<script type="text/javascript" src="js/bootstrap-tab.js"></script> + +<link rel="stylesheet" type="text/css" href="css/bootstrap.css"/> + +<style type="text/css"> +#line-chart-here { + padding: 0.4em; + margin-bottom: 1em; + border-radius: 0.3em; + border: 0.2em solid #ccc; +background: rgb(246,248,249); /* Old browsers */ +background: -moz-linear-gradient(top, rgba(246,248,249,1) 0%, +rgba(229,235,238,1) 50%, rgba(215,222,227,1) 51%, rgba(245,247,249,1) 100%); +/* FF3.6+ */ +background: -webkit-gradient(linear, left top, left bottom, +color-stop(0%,rgba(246,248,249,1)), color-stop(50%,rgba(229,235,238,1)), +color-stop(51%,rgba(215,222,227,1)), color-stop(100%,rgba(245,247,249,1))); +/* Chrome,Safari4+ */ +background: -webkit-linear-gradient(top, rgba(246,248,249,1) +0%,rgba(229,235,238,1) 50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1) +100%); /* Chrome10+,Safari5.1+ */ +background: -o-linear-gradient(top, rgba(246,248,249,1) +0%,rgba(229,235,238,1) 50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1) +100%); /* Opera 11.10+ */ +background: -ms-linear-gradient(top, rgba(246,248,249,1) +0%,rgba(229,235,238,1) 50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1) +100%); /* IE10+ */ +background: linear-gradient(top, rgba(246,248,249,1) 0%,rgba(229,235,238,1) +50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1) 100%); /* W3C */ +filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f6f8f9', +endColorstr='#f5f7f9',GradientType=0 ); /* IE6-9 */ +} +#line-chart-here tspan { + font-family: Monaco; + font-size: 8pt; +} +#line-chart-legend { + margin: 0.6em; + line-height: 140%; +} +span.label.disabled { + opacity: 0.5; + background-color: #555 !important; +} +span.label { + cursor: pointer; +} +</style> + +<form class="well form-inline" id="timeframe-form"> + <label> + Report timeframe: + <input type="text" class="dp input-medium search-query" + name="start" placeholder="Last month"/> + </label> + <button class="btn" type="submit">Refresh</button> +</form> + +<!-- Create a graph and fetch some data to create pretty dashboard --> + +<div style="position:relative"> + <div id="line-chart-here" style="height:300px"></div> + <div style="position:absolute;right:0;top:0" id="line-chart-legend"></div> +</div> + +<script type="text/javascript"> + var r, previous_data; + + function refresh() { + $('#line-chart-here').empty(); + $('#line-chart-legend').empty(); + var r = new Raphael('line-chart-here'); + var width = $('#line-chart-here').width() + var height = $('#line-chart-here').height() + $.ajax({ + method: 'GET', + url: 'ajax.php/report/overview/graph', + data: ((this.start && this.start.value) ? {'start': this.start.value} : {}), + dataType: 'json', + success: function(json) { + var previous_data = json, + times = [], + smtimes = Array.prototype.concat.apply([], json.times), + plots = [], + max = 0, + steps = 0, + primes = [2,3,5,7,9]; + + // Convert the timestamp to number of whole days after the + // unix epoch, and try and find an exact multiple of the + // number of days across the query that is less than 13 for + // the number of dates to place across the bottom. + for (key in smtimes) { + smtimes[key] = Math.floor(smtimes[key] / 86400); + } + steps = smtimes[smtimes.length-1] - smtimes[0] + 1; + while (steps > 12) { + for (var i in primes) { + if (steps % primes[i] === 0) { + steps /= primes[i]; + break; + } + } + } + for (key in json.events) { + e = json.events[key]; + if (json.plots[e] === undefined) continue; + $('<span>').append(e) + .attr({class:'label','style':'margin-left:0.5em'}) + .appendTo($('#line-chart-legend')); + $('<br>').appendTo('#line-chart-legend'); + times.push(smtimes); + plots.push(json.plots[e]); + max = Math.max(max, Math.max.apply(Math, json.plots[e])); + } + console.log(json.times, smtimes, steps, max); + m = r.linechart(10, 10, width - 80, height - 20, + times, plots, { + gutter: 10, + width: 1.6, + nostroke: false, + shade: false, + axis: "0 0 1 1", + axisxstep: steps, + axisystep: max, + symbol: "circle", + smooth: false + }).hoverColumn(function () { + this.tags = r.set(); + var slots = []; + + for (var i = 0, ii = this.y.length; i < ii; i++) { + if (this.values[i] === 0) continue; + if (this.symbols[i].node.style.display == "none") continue; + var angle = 160; + for (var j = 0, jj = slots.length; j < jj; j++) { + if (slots[j][0] == this.x && slots[j][1] == this.y[i]) { + angle = 20; + break; + } + } + slots.push([this.x, this.y[i]]); + this.tags.push(r.tag(this.x, this.y[i], + this.values[i], angle, + 10).insertBefore(this).attr([ + { fill: '#eee' }, + { fill: this.symbols[i].attr('fill') }])); + } + }, function () { + this.tags && this.tags.remove(); + }); + // Change axis labels from Unix epoch + $('tspan', $('#line-chart-here')).each(function(e) { + var text = this.firstChild.textContent; + if (parseInt(text) > 10000) + this.firstChild.textContent = + $.datepicker.formatDate('mm-dd-yy', + new Date(parseInt(text) * 86400000)); + }); + // Dear aspiring API writers, please consider making [easy] + // things simpler than this... + $('span.label').each(function(i, e) { + e = $(e); + e.click(function() { + e.toggleClass('disabled'); + if (e.hasClass('disabled')) { + m.symbols[i].hide(); + m.lines[i].hide(); + } else { + m.symbols[i].show(); + m.lines[i].show(); + } + }); + }); + $('span.label', '#line-chart-legend').css( + 'background-color', function(i) { + return Raphael.color(m.symbols[i][0].attr('fill')).hex; + }); + } + }); + return false; + } + $(refresh); + $('#timeframe-form').submit(refresh); + + function refresh_dots() { + var width = $('#line-chart-here').width() + $.ajax({ + method: 'GET', + url: 'ajax.php/report/overview/graph', + data: {'start': "May-01-2012"}, + dataType: 'json', + success: function(json) { + var xs = [], ys = [], data = [], axisx = [], axisy = [], y = 0; + for (var key in json.plots) { + y++; + axisy.push(key); + for (var x in json.plots[key]) { + xs.push(parseInt(x)); + ys.push(y); + data.push(json.plots[key][x]); + } + } + width = Math.min(json.times.length * 75 + 50, width - 50); + r.dotchart(10, 10 , width, 200, xs, ys, data, { + symbol: "o", max: 10, heat: true, axis: "0 0 1 1", + axisxstep: json.times.length-1, + axisystep: axisy.length-1, + axisxlabels: json.times, axisxtype: " ", + axisytype: " ", axisylabels: axisy + }).hover( + function () { + this.marker = this.marker + || r.tag(this.x, this.y, this.value, 0, this.r + 2) + .insertBefore(this); + this.marker.show(); + }, + function () { + this.marker && this.marker.hide(); + }); + } + }); + } + //$(refresh_dots); + +</script> + +<ul class="nav nav-tabs" id="tabular-navigation"> +</ul> + +<div id="table-here"></div> + +<script type="text/javascript"> + + $(function() { + $('tabular-navigation').tab(); + }); + + // Add tabs for the tabular display + $(function() { + $.ajax({ + url: 'ajax.php/report/overview/table/groups', + dataType: 'json', + success: function(json) { + var first=true; + for (key in json) { + $('#tabular-navigation') + .append($('<li>').attr((first) ? {class:"active"} : {}) + .append($('<a>') + .click(build_table) + .attr({'table-group':key,'href':'#'}) + .append(json[key]))); + first=false; + } + build_table.apply($('#tabular-navigation li:first-child a')) + } + }); + }); + + function build_table(e) { + $('#table-here').empty(); + $(this).tab('show'); + var group = $(this).attr('table-group') + $.ajax({ + method: 'GET', + dataType: 'json', + url: 'ajax.php/report/overview/table', + data: {group: group}, + success: function(json) { + var q = $('<table>').attr({class:'table table-condensed table-striped'}); + var h = $('<tr>').appendTo($('<thead>').appendTo(q)); + var pagesize = 25; + for (var c in json.columns) + h.append($('<th>').append(json.columns[c])); + for (var i in json.data) { + if (i % pagesize === 0) + b = $('<tbody>').attr({'page':i/pagesize+1}).appendTo(q); + row = json.data[i]; + tr = $('<tr>').appendTo(b); + for (var j in row) + tr.append($('<td>').append(row[j])); + } + $('#table-here').append(q); + + // ----------------------> Pagination <--------------------- + function goabs(e) { + $('tbody', q).addClass('hide'); + if (e.target) { + page = e.target.text; + $('tbody[page='+page+']', q).removeClass('hide'); + } else { + e.removeClass('hide'); + page = e.attr('page') + } + enable_next_prev(page); + } + function goprev() { + current = $('tbody:not(.hide)', q).attr('page'); + page = Math.max(1, parseInt(current) - 1); + goabs($('tbody[page='+page+']', q)); + } + function gonext() { + current = $('tbody:not(.hide)', q).attr('page'); + page = Math.min(Math.floor(json.data.length / pagesize) + 1, + parseInt(current) + 1); + goabs($('tbody[page='+page+']', q)); + } + function enable_next_prev(page) { + $('#table-here div.pagination li[page]').removeClass('active'); + $('#table-here div.pagination li[page='+page+']').addClass('active'); + + if (page == 1) $('#report-page-prev').addClass('disabled'); + else $('#report-page-prev').removeClass('disabled'); + + if (page == Math.floor(json.data.length / pagesize) + 1) + $('#report-page-next').addClass('disabled'); + else $('#report-page-next').removeClass('disabled'); + } + + var p = $('<ul>') + .appendTo($('<div>').attr({'class':'pagination'}) + .appendTo($('#table-here'))); + $('<a>').click(goprev).attr({'href':'#'}) + .append('«').appendTo($('<li>').attr({'id':'report-page-prev'}) + .appendTo(p)); + $('tbody', q).each(function() { + page = $(this).attr('page'); + $('<a>').click(goabs).attr({'href':'#'}).append(page) + .appendTo($('<li>').attr({'page':page}) + .appendTo(p)); + }); + $('<a>').click(gonext).attr({'href':'#'}) + .append('»').appendTo($('<li>').attr({'id':'report-page-next'}) + .appendTo(p)); + + // ------------------------> Export <----------------------- + $('<a>').attr({'href':'ajax.php/report/overview/table/export?group=' + +group}).append('Export') + .appendTo($('<li>') + .appendTo(p)); + + gonext(); + } + }); + return false; + } +</script> + +<? include(STAFFINC_DIR.'footer.inc.php'); ?> diff --git a/scp/images/ajax-loader.gif b/scp/images/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..d42f72c723644bbf8cf8d6e1b7ff0bea7ddd305a Binary files /dev/null and b/scp/images/ajax-loader.gif differ diff --git a/scp/images/kb_category_bg.png b/scp/images/kb_category_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..174d675f4c491060a413232bdef7e0e9298df60e Binary files /dev/null and b/scp/images/kb_category_bg.png differ diff --git a/scp/images/kb_large_folder.png b/scp/images/kb_large_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..144fa828a3fc83613dd7a5b29368b6da290fd09d Binary files /dev/null and b/scp/images/kb_large_folder.png differ diff --git a/scp/js/bootstrap-tab.js b/scp/js/bootstrap-tab.js new file mode 100644 index 0000000000000000000000000000000000000000..d87f35099aef8414b4e86055798f55be23508862 --- /dev/null +++ b/scp/js/bootstrap-tab.js @@ -0,0 +1,135 @@ +/* ======================================================== + * bootstrap-tab.js v2.0.4 + * http://twitter.github.com/bootstrap/javascript.html#tabs + * ======================================================== + * Copyright 2012 Twitter, 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. + * ======================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* TAB CLASS DEFINITION + * ==================== */ + + var Tab = function ( element ) { + this.element = $(element) + } + + Tab.prototype = { + + constructor: Tab + + , show: function () { + var $this = this.element + , $ul = $this.closest('ul:not(.dropdown-menu)') + , selector = $this.attr('data-target') + , previous + , $target + , e + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + if ( $this.parent('li').hasClass('active') ) return + + previous = $ul.find('.active a').last()[0] + + e = $.Event('show', { + relatedTarget: previous + }) + + $this.trigger(e) + + if (e.isDefaultPrevented()) return + + $target = $(selector) + + this.activate($this.parent('li'), $ul) + this.activate($target, $target.parent(), function () { + $this.trigger({ + type: 'shown' + , relatedTarget: previous + }) + }) + } + + , activate: function ( element, container, callback) { + var $active = container.find('> .active') + , transition = callback + && $.support.transition + && $active.hasClass('fade') + + function next() { + $active + .removeClass('active') + .find('> .dropdown-menu > .active') + .removeClass('active') + + element.addClass('active') + + if (transition) { + element[0].offsetWidth // reflow for transition + element.addClass('in') + } else { + element.removeClass('fade') + } + + if ( element.parent('.dropdown-menu') ) { + element.closest('li.dropdown').addClass('active') + } + + callback && callback() + } + + transition ? + $active.one($.support.transition.end, next) : + next() + + $active.removeClass('in') + } + } + + + /* TAB PLUGIN DEFINITION + * ===================== */ + + $.fn.tab = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('tab') + if (!data) $this.data('tab', (data = new Tab(this))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.tab.Constructor = Tab + + + /* TAB DATA-API + * ============ */ + + $(function () { + $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { + e.preventDefault() + $(this).tab('show') + }) + }) + +}(window.jQuery); \ No newline at end of file diff --git a/scp/js/calendar.js b/scp/js/calendar.js deleted file mode 100644 index 3a9c87601147e6e97b6990cdf5f23be16ee1e8c1..0000000000000000000000000000000000000000 --- a/scp/js/calendar.js +++ /dev/null @@ -1,254 +0,0 @@ -/* - Tiny DHTML Calendar - - Stolen somewhere online....add credit. - - */ - -function getObj(objID) -{ - if (document.getElementById) {return document.getElementById(objID);} - else if (document.all) {return document.all[objID];} - else if (document.layers) {return document.layers[objID];} -} - -function checkClick(e) { - e?evt=e:evt=event; - CSE=evt.target?evt.target:evt.srcElement; - if (getObj('fc')) - if (!isChild(CSE,getObj('fc'))) - getObj('fc').style.display='none'; -} - -function isChild(s,d) { - while(s) { - if (s==d) - return true; - s=s.parentNode; - } - return false; -} - -function Left(obj) -{ - var curleft = 0; - if (obj.offsetParent) - { - while (obj.offsetParent) - { - curleft += obj.offsetLeft - obj = obj.offsetParent; - } - } - else if (obj.x) - curleft += obj.x; - - - return curleft; -} - -function Top(obj) -{ - var curtop = 0; - if (obj.offsetParent) - { - while (obj.offsetParent) - { - curtop += obj.offsetTop - obj = obj.offsetParent; - } - } - else if (obj.y) - curtop += obj.y; - return curtop; -} - -document.write('<table id="fc" style="position:absolute;border-collapse:collapse;background:#FFFFFF;border:1px solid #ABABAB;display:none" cellpadding=2>'); -document.write('<tr><td style="cursor:pointer" onclick="csubm()"><img src="images/arrowleftmonth.gif"></td><td colspan=5 id="mns" align="center" style="font:bold 13px Arial;text-align:center"></td><td align="right" style="cursor:pointer" onclick="caddm()"><img src="images/arrowrightmonth.gif"></td></tr>'); -document.write('<tr><td align=center style="background:#ABABAB;font:12px Arial">S</td><td align=center style="background:#ABABAB;font:12px Arial">M</td><td align=center style="background:#ABABAB;font:12px Arial">T</td><td align=center style="background:#ABABAB;font:12px Arial">W</td><td align=center style="background:#ABABAB;font:12px Arial">T</td><td align=center style="background:#ABABAB;font:12px Arial">F</td><td align=center style="background:#ABABAB;font:12px Arial">S</td></tr>'); -for(var kk=1;kk<=6;kk++) { - document.write('<tr>'); - for(var tt=1;tt<=7;tt++) { - num=7 * (kk-1) - (-tt); - document.write('<td id="v' + num + '" style="width:18px;height:18px"> </td>'); - } - document.write('</tr>'); -} -document.write('</table>'); - -document.all?document.attachEvent('onclick',checkClick):document.addEventListener('click',checkClick,false); - - -// Calendar script -var now = new Date; -var sccm=now.getMonth(); -var sccy=now.getFullYear(); -var ccm=now.getMonth(); -var ccy=now.getFullYear(); - -var updobj; - -function calendar(ielem) { - - if(ielem) { - ielem.select(); - lcs(ielem); - } -} - - -function lcs(ielem) { - updobj=ielem; - getObj('fc').style.left=Left(ielem)+'px'; - getObj('fc').style.top=Top(ielem)+ielem.offsetHeight+'px'; - getObj('fc').style.display=''; - - // First check date is valid - curdt=ielem.value; - curdtarr=curdt.split('/'); - isdt=true; - for(var k=0;k<curdtarr.length;k++) { - if (isNaN(curdtarr[k])) - isdt=false; - } - if (isdt&(curdtarr.length==3)) { - ccm=curdtarr[0]-1; - ccy=curdtarr[2]; - prepcalendar(curdtarr[1],curdtarr[0]-1,curdtarr[2]); - } - -} - -function evtTgt(e) -{ - var el; - if(e.target)el=e.target; - else if(e.srcElement)el=e.srcElement; - if(el.nodeType==3)el=el.parentNode; // defeat Safari bug - return el; -} -function EvtObj(e){if(!e)e=window.event;return e;} -function cs_over(e) { - evtTgt(EvtObj(e)).style.background='#FFCC66'; -} -function cs_out(e) { - evtTgt(EvtObj(e)).style.background='#C4D3EA'; -} -function cs_click(e) { - updobj.value=calvalarr[evtTgt(EvtObj(e)).id.substring(1,evtTgt(EvtObj(e)).id.length)]; - getObj('fc').style.display='none'; - -} - -var mn=new Array('JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC'); -var mnn=new Array('31','28','31','30','31','30','31','31','30','31','30','31'); -var mnl=new Array('31','29','31','30','31','30','31','31','30','31','30','31'); -var calvalarr=new Array(42); - -function f_cps(obj) { - obj.style.background='#C4D3EA'; - obj.style.font='10px Arial'; - obj.style.color='#333333'; - obj.style.textAlign='center'; - obj.style.textDecoration='none'; - obj.style.border='1px solid #6487AE'; - obj.style.cursor='pointer'; -} - -function f_cpps(obj) { - obj.style.background='#C4D3EA'; - obj.style.font='10px Arial'; - obj.style.color='#ABABAB'; - obj.style.textAlign='center'; - obj.style.textDecoration='line-through'; - obj.style.border='1px solid #6487AE'; - obj.style.cursor='default'; -} - -function f_hds(obj) { - obj.style.background='#FFF799'; - obj.style.font='bold 10px Arial'; - obj.style.color='#333333'; - obj.style.textAlign='center'; - obj.style.border='1px solid #6487AE'; - obj.style.cursor='pointer'; -} - -// day selected -function prepcalendar(hd,cm,cy) { - now=new Date(); - sd=now.getDate(); - td=new Date(); - td.setDate(1); - td.setFullYear(cy); - td.setMonth(cm); - cd=td.getDay(); - getObj('mns').innerHTML=mn[cm]+ ' ' + cy; - marr=((cy%4)==0)?mnl:mnn; - for(var d=1;d<=42;d++) { - f_cps(getObj('v'+parseInt(d))); - if ((d >= (cd -(-1))) && (d<=cd-(-marr[cm]))) { - dip=((d-cd < sd)&&(cm==sccm)&&(cy==sccy)); - htd=((hd!='')&&(d-cd==hd)); - if (0 && dip) - f_cpps(getObj('v'+parseInt(d))); - else if (htd) - f_hds(getObj('v'+parseInt(d))); - else - f_cps(getObj('v'+parseInt(d))); - - getObj('v'+parseInt(d)).onmouseover=cs_over; - getObj('v'+parseInt(d)).onmouseout=cs_out; - getObj('v'+parseInt(d)).onclick=cs_click; - - getObj('v'+parseInt(d)).innerHTML=d-cd; - calvalarr[d]=''+(cm-(-1))+'/'+(d-cd)+'/'+cy; - } - else { - getObj('v'+d).innerHTML=' '; - getObj('v'+parseInt(d)).onmouseover=null; - getObj('v'+parseInt(d)).onmouseout=null; - getObj('v'+parseInt(d)).style.cursor='default'; - } - } -} - -prepcalendar('',ccm,ccy); -//getObj('fc'+cc).style.visibility='hidden'; - -function caddm() { - marr=((ccy%4)==0)?mnl:mnn; - - ccm+=1; - if (ccm>=12) { - ccm=0; - ccy++; - } - cdayf(); - prepcalendar('',ccm,ccy); -} - -function csubm() { - marr=((ccy%4)==0)?mnl:mnn; - - ccm-=1; - if (ccm<0) { - ccm=11; - ccy--; - } - cdayf(); - prepcalendar('',ccm,ccy); -} - -function cdayf() { - - return; - - if ((ccy>sccy)|((ccy==sccy)&&(ccm>=sccm))) - return; - else { - ccy=sccy; - ccm=sccm; - cfd=scfd; - } -} diff --git a/scp/js/g.dot-min.js b/scp/js/g.dot-min.js new file mode 100644 index 0000000000000000000000000000000000000000..4ba3af656f1657824c229b5e6a1fa97502162b8a --- /dev/null +++ b/scp/js/g.dot-min.js @@ -0,0 +1,7 @@ +/*! + * g.Raphael 0.5 - Charting library, based on Raphaël + * + * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com) + * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. + */ +(function(){var b=function(g,f,e,d){return"hsb("+[Math.min((1-g/f)*0.4,1),e||0.75,d||0.75]+")"};function a(e,N,M,d,j,B,A,t,I){var v=this;function U(g){+g[0]&&(g[0]=v.axis(N+s,M+s,d-2*s,E,p,I.axisxstep||Math.floor((d-2*s)/20),2,I.axisxlabels||null,I.axisxtype||"t",null,e));+g[1]&&(g[1]=v.axis(N+d-s,M+j-s,j-2*s,D,o,I.axisystep||Math.floor((j-2*s)/20),3,I.axisylabels||null,I.axisytype||"t",null,e));+g[2]&&(g[2]=v.axis(N+s,M+j-s+H,d-2*s,E,p,I.axisxstep||Math.floor((d-2*s)/20),0,I.axisxlabels||null,I.axisxtype||"t",null,e));+g[3]&&(g[3]=v.axis(N+s-H,M+j-s,j-2*s,D,o,I.axisystep||Math.floor((j-2*s)/20),1,I.axisylabels||null,I.axisytype||"t",null,e))}I=I||{};var z=v.snapEnds(Math.min.apply(Math,B),Math.max.apply(Math,B),B.length-1),E=z.from,p=z.to,s=I.gutter||10,L=v.snapEnds(Math.min.apply(Math,A),Math.max.apply(Math,A),A.length-1),D=L.from,o=L.to,C=Math.max(B.length,A.length,t.length),w=e[I.symbol]||"circle",J=e.set(),u=e.set(),G=I.max||100,r=Math.max.apply(Math,t),q=[],Q=Math.sqrt(r/Math.PI)*2/G;for(var S=0;S<C;S++){q[S]=Math.min(Math.sqrt(t[S]/Math.PI)*2/Q,G)}s=Math.max.apply(Math,q.concat(s));var F=e.set(),H=Math.max.apply(Math,q);if(I.axis){var n=(I.axis+"").split(/[,\s]+/);U.call(v,n);var T=[],V=[];for(var S=0,K=n.length;S<K;S++){var W=n[S].all?n[S].all.getBBox()[["height","width"][S%2]]:0;T[S]=W+s;V[S]=W}s=Math.max.apply(Math,T.concat(s));for(var S=0,K=n.length;S<K;S++){if(n[S].all){n[S].remove();n[S]=1}}U.call(v,n);for(var S=0,K=n.length;S<K;S++){if(n[S].all){F.push(n[S].all)}}J.axis=F}var P=(d-s*2)/((p-E)||1),O=(j-s*2)/((o-D)||1);for(var S=0,K=A.length;S<K;S++){var h=e.raphael.is(w,"array")?w[S]:w,m=N+s+(B[S]-E)*P,l=M+j-s-(A[S]-D)*O;h&&q[S]&&u.push(e[h](m,l,q[S]).attr({fill:I.heat?b(q[S],H):v.colors[0],"fill-opacity":I.opacity?q[S]/G:1,stroke:"none"}))}var f=e.set();for(var S=0,K=A.length;S<K;S++){var m=N+s+(B[S]-E)*P,l=M+j-s-(A[S]-D)*O;f.push(e.circle(m,l,H).attr(v.shim));I.href&&I.href[S]&&f[S].attr({href:I.href[S]});f[S].r=+q[S].toFixed(3);f[S].x=+m.toFixed(3);f[S].y=+l.toFixed(3);f[S].X=B[S];f[S].Y=A[S];f[S].value=t[S]||0;f[S].dot=u[S]}J.covers=f;J.series=u;J.push(u,F,f);J.hover=function(i,g){f.mouseover(i).mouseout(g);return this};J.click=function(g){f.click(g);return this};J.each=function(k){if(!e.raphael.is(k,"function")){return this}for(var g=f.length;g--;){k.call(f[g])}return this};J.href=function(x){var k;for(var g=f.length;g--;){k=f[g];if(k.X==x.x&&k.Y==x.y&&k.value==x.value){k.attr({href:x.href})}}};return J}var c=function(){};c.prototype=Raphael.g;a.prototype=new c;Raphael.fn.dotchart=function(e,k,g,d,j,i,f,h){return new a(this,e,k,g,d,j,i,f,h)}})(); \ No newline at end of file diff --git a/scp/js/g.line-min.js b/scp/js/g.line-min.js new file mode 100644 index 0000000000000000000000000000000000000000..39b4682280c65fd388afeb8514c4e37e1b4cc1ed --- /dev/null +++ b/scp/js/g.line-min.js @@ -0,0 +1,7 @@ +/*! + * g.Raphael 0.5 - Charting library, based on Raphaël + * + * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com) + * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. + */ +(function(){function a(g,n){var f=g.length/n,h=0,e=f,m=0,i=[];while(h<g.length){e--;if(e<0){m+=g[h]*(1+e);i.push(m/f);m=g[h++]*-e;e+=f}else{m+=g[h++]}}return i}function d(f,e,p,n,k,j){var h=(p-f)/2,g=(k-p)/2,q=Math.atan((p-f)/Math.abs(n-e)),o=Math.atan((k-p)/Math.abs(n-j));q=e<n?Math.PI-q:q;o=j<n?Math.PI-o:o;var i=Math.PI/2-((q+o)%(Math.PI*2))/2,s=h*Math.sin(i+q),m=h*Math.cos(i+q),r=g*Math.sin(i+o),l=g*Math.cos(i+o);return{x1:p-s,y1:n+m,x2:p+r,y2:n+l}}function b(f,P,O,e,h,A,z,J){var s=this;J=J||{};if(!f.raphael.is(A[0],"array")){A=[A]}if(!f.raphael.is(z[0],"array")){z=[z]}var q=J.gutter||10,B=Math.max(A[0].length,z[0].length),t=J.symbol||"",S=J.colors||s.colors,v=null,p=null,ad=f.set(),T=[];for(var ac=0,L=z.length;ac<L;ac++){B=Math.max(B,z[ac].length)}var ae=f.set();for(ac=0,L=z.length;ac<L;ac++){if(J.shade){ae.push(f.path().attr({stroke:"none",fill:S[ac],opacity:J.nostroke?1:0.3}))}if(z[ac].length>e-2*q){z[ac]=a(z[ac],e-2*q);B=e-2*q}if(A[ac]&&A[ac].length>e-2*q){A[ac]=a(A[ac],e-2*q)}}var W=Array.prototype.concat.apply([],A),U=Array.prototype.concat.apply([],z),u=s.snapEnds(Math.min.apply(Math,W),Math.max.apply(Math,W),A[0].length-1),E=u.from,o=u.to,N=s.snapEnds(Math.min.apply(Math,U),Math.max.apply(Math,U),z[0].length-1),C=N.from,n=N.to,Z=(e-q*2)/((o-E)||1),V=(h-q*2)/((n-C)||1);var G=f.set();if(J.axis){var m=(J.axis+"").split(/[,\s]+/);+m[0]&&G.push(s.axis(P+q,O+q,e-2*q,E,o,J.axisxstep||Math.floor((e-2*q)/20),2,f));+m[1]&&G.push(s.axis(P+e-q,O+h-q,h-2*q,C,n,J.axisystep||Math.floor((h-2*q)/20),3,f));+m[2]&&G.push(s.axis(P+q,O+h-q,e-2*q,E,o,J.axisxstep||Math.floor((e-2*q)/20),0,f));+m[3]&&G.push(s.axis(P+q,O+h-q,h-2*q,C,n,J.axisystep||Math.floor((h-2*q)/20),1,f))}var M=f.set(),aa=f.set(),r;for(ac=0,L=z.length;ac<L;ac++){if(!J.nostroke){M.push(r=f.path().attr({stroke:S[ac],"stroke-width":J.width||2,"stroke-linejoin":"round","stroke-linecap":"round","stroke-dasharray":J.dash||""}))}var g=Raphael.is(t,"array")?t[ac]:t,H=f.set();T=[];for(var ab=0,w=z[ac].length;ab<w;ab++){var l=P+q+((A[ac]||A[0])[ab]-E)*Z,k=O+h-q-(z[ac][ab]-C)*V;(Raphael.is(g,"array")?g[ab]:g)&&H.push(f[Raphael.is(g,"array")?g[ab]:g](l,k,(J.width||2)*3).attr({fill:S[ac],stroke:"none"}));if(J.smooth){if(ab&&ab!=w-1){var R=P+q+((A[ac]||A[0])[ab-1]-E)*Z,F=O+h-q-(z[ac][ab-1]-C)*V,Q=P+q+((A[ac]||A[0])[ab+1]-E)*Z,D=O+h-q-(z[ac][ab+1]-C)*V,af=d(R,F,l,k,Q,D);T=T.concat([af.x1,af.y1,l,k,af.x2,af.y2])}if(!ab){T=["M",l,k,"C",l,k]}}else{T=T.concat([ab?"L":"M",l,k])}}if(J.smooth){T=T.concat([l,k,l,k])}aa.push(H);if(J.shade){ae[ac].attr({path:T.concat(["L",l,O+h-q,"L",P+q+((A[ac]||A[0])[0]-E)*Z,O+h-q,"z"]).join(",")})}!J.nostroke&&r.attr({path:T.join(",")})}function K(an){var ak=[];for(var al=0,ap=A.length;al<ap;al++){ak=ak.concat(A[al])}ak.sort();var aq=[],ah=[];for(al=0,ap=ak.length;al<ap;al++){ak[al]!=ak[al-1]&&aq.push(ak[al])&&ah.push(P+q+(ak[al]-E)*Z)}ak=aq;ap=ak.length;var ag=an||f.set();for(al=0;al<ap;al++){var Y=ah[al]-(ah[al]-(ah[al-1]||P))/2,ao=((ah[al+1]||P+e)-ah[al])/2+(ah[al]-(ah[al-1]||P))/2,x;an?(x={}):ag.push(x=f.rect(Y-1,O,Math.max(ao+1,1),h).attr({stroke:"none",fill:"#000",opacity:0}));x.values=[];x.symbols=f.set();x.y=[];x.x=ah[al];x.axis=ak[al];for(var aj=0,am=z.length;aj<am;aj++){aq=A[aj]||A[0];for(var ai=0,y=aq.length;ai<y;ai++){if(aq[ai]==ak[al]){x.values.push(z[aj][ai]);x.y.push(O+h-q-(z[aj][ai]-C)*V);x.symbols.push(ad.symbols[aj][ai])}}}an&&an.call(x)}!an&&(v=ag)}function I(al){var ah=al||f.set(),x;for(var aj=0,an=z.length;aj<an;aj++){for(var ai=0,ak=z[aj].length;ai<ak;ai++){var ag=P+q+((A[aj]||A[0])[ai]-E)*Z,am=P+q+((A[aj]||A[0])[ai?ai-1:1]-E)*Z,y=O+h-q-(z[aj][ai]-C)*V;al?(x={}):ah.push(x=f.circle(ag,y,Math.abs(am-ag)/2).attr({stroke:"none",fill:"#000",opacity:0}));x.x=ag;x.y=y;x.value=z[aj][ai];x.line=ad.lines[aj];x.shade=ad.shades[aj];x.symbol=ad.symbols[aj][ai];x.symbols=ad.symbols[aj];x.axis=(A[aj]||A[0])[ai];al&&al.call(x)}}!al&&(p=ah)}ad.push(M,ae,aa,G,v,p);ad.lines=M;ad.shades=ae;ad.symbols=aa;ad.axis=G;ad.hoverColumn=function(j,i){!v&&K();v.mouseover(j).mouseout(i);return this};ad.clickColumn=function(i){!v&&K();v.click(i);return this};ad.hrefColumn=function(Y){var ag=f.raphael.is(arguments[0],"array")?arguments[0]:arguments;if(!(arguments.length-1)&&typeof Y=="object"){for(var j in Y){for(var y=0,X=v.length;y<X;y++){if(v[y].axis==j){v[y].attr("href",Y[j])}}}}!v&&K();for(y=0,X=ag.length;y<X;y++){v[y]&&v[y].attr("href",ag[y])}return this};ad.hover=function(j,i){!p&&I();p.mouseover(j).mouseout(i);return this};ad.click=function(i){!p&&I();p.click(i);return this};ad.each=function(i){I(i);return this};ad.eachColumn=function(i){K(i);return this};return ad}var c=function(){};c.prototype=Raphael.g;b.prototype=new c;Raphael.fn.linechart=function(f,k,g,e,j,i,h){return new b(this,f,k,g,e,j,i,h)}})(); \ No newline at end of file diff --git a/scp/js/g.raphael.js b/scp/js/g.raphael.js new file mode 100644 index 0000000000000000000000000000000000000000..acdf238b5b9a6ad809f94b4f12e187d35d17cc11 --- /dev/null +++ b/scp/js/g.raphael.js @@ -0,0 +1,870 @@ +/*! + * g.Raphael 0.5 - Charting library, based on Raphaël + * + * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com) + * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. + */ + +/* + * Tooltips on Element prototype + */ +/*\ + * Element.popup + [ method ] + ** + * Puts the context Element in a 'popup' tooltip. Can also be used on sets. + ** + > Parameters + ** + - dir (string) location of Element relative to the tail: `'down'`, `'left'`, `'up'` [default], or `'right'`. + - size (number) amount of bevel/padding around the Element, as well as half the width and height of the tail [default: `5`] + - x (number) x coordinate of the popup's tail [default: Element's `x` or `cx`] + - y (number) y coordinate of the popup's tail [default: Element's `y` or `cy`] + ** + = (object) path element of the popup + > Usage + | paper.circle(50, 50, 5).attr({ + | stroke: "#fff", + | fill: "0-#c9de96-#8ab66b:44-#398235" + | }).popup(); + \*/ +Raphael.el.popup = function (dir, size, x, y) { + var paper = this.paper || this[0].paper, + bb, xy, center, cw, ch; + + if (!paper) return; + + switch (this.type) { + case 'text': + case 'circle': + case 'ellipse': center = true; break; + default: center = false; + } + + dir = dir == null ? 'up' : dir; + size = size || 5; + bb = this.getBBox(); + + x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x); + y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y); + cw = Math.max(bb.width / 2 - size, 0); + ch = Math.max(bb.height / 2 - size, 0); + + this.translate(x - bb.x - (center ? bb.width / 2 : 0), y - bb.y - (center ? bb.height / 2 : 0)); + bb = this.getBBox(); + + var paths = { + up: [ + 'M', x, y, + 'l', -size, -size, -cw, 0, + 'a', size, size, 0, 0, 1, -size, -size, + 'l', 0, -bb.height, + 'a', size, size, 0, 0, 1, size, -size, + 'l', size * 2 + cw * 2, 0, + 'a', size, size, 0, 0, 1, size, size, + 'l', 0, bb.height, + 'a', size, size, 0, 0, 1, -size, size, + 'l', -cw, 0, + 'z' + ].join(','), + down: [ + 'M', x, y, + 'l', size, size, cw, 0, + 'a', size, size, 0, 0, 1, size, size, + 'l', 0, bb.height, + 'a', size, size, 0, 0, 1, -size, size, + 'l', -(size * 2 + cw * 2), 0, + 'a', size, size, 0, 0, 1, -size, -size, + 'l', 0, -bb.height, + 'a', size, size, 0, 0, 1, size, -size, + 'l', cw, 0, + 'z' + ].join(','), + left: [ + 'M', x, y, + 'l', -size, size, 0, ch, + 'a', size, size, 0, 0, 1, -size, size, + 'l', -bb.width, 0, + 'a', size, size, 0, 0, 1, -size, -size, + 'l', 0, -(size * 2 + ch * 2), + 'a', size, size, 0, 0, 1, size, -size, + 'l', bb.width, 0, + 'a', size, size, 0, 0, 1, size, size, + 'l', 0, ch, + 'z' + ].join(','), + right: [ + 'M', x, y, + 'l', size, -size, 0, -ch, + 'a', size, size, 0, 0, 1, size, -size, + 'l', bb.width, 0, + 'a', size, size, 0, 0, 1, size, size, + 'l', 0, size * 2 + ch * 2, + 'a', size, size, 0, 0, 1, -size, size, + 'l', -bb.width, 0, + 'a', size, size, 0, 0, 1, -size, -size, + 'l', 0, -ch, + 'z' + ].join(',') + }; + + xy = { + up: { x: -!center * (bb.width / 2), y: -size * 2 - (center ? bb.height / 2 : bb.height) }, + down: { x: -!center * (bb.width / 2), y: size * 2 + (center ? bb.height / 2 : bb.height) }, + left: { x: -size * 2 - (center ? bb.width / 2 : bb.width), y: -!center * (bb.height / 2) }, + right: { x: size * 2 + (center ? bb.width / 2 : bb.width), y: -!center * (bb.height / 2) } + }[dir]; + + this.translate(xy.x, xy.y); + return paper.path(paths[dir]).attr({ fill: "#000", stroke: "none" }).insertBefore(this.node ? this : this[0]); +}; + +/*\ + * Element.tag + [ method ] + ** + * Puts the context Element in a 'tag' tooltip. Can also be used on sets. + ** + > Parameters + ** + - angle (number) angle of orientation in degrees [default: `0`] + - r (number) radius of the loop [default: `5`] + - x (number) x coordinate of the center of the tag loop [default: Element's `x` or `cx`] + - y (number) y coordinate of the center of the tag loop [default: Element's `x` or `cx`] + ** + = (object) path element of the tag + > Usage + | paper.circle(50, 50, 15).attr({ + | stroke: "#fff", + | fill: "0-#c9de96-#8ab66b:44-#398235" + | }).tag(60); + \*/ +Raphael.el.tag = function (angle, r, x, y) { + var d = 3, + paper = this.paper || this[0].paper; + + if (!paper) return; + + var p = paper.path().attr({ fill: '#000', stroke: '#000' }), + bb = this.getBBox(), + dx, R, center, tmp; + + switch (this.type) { + case 'text': + case 'circle': + case 'ellipse': center = true; break; + default: center = false; + } + + angle = angle || 0; + x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x); + y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y); + r = r == null ? 5 : r; + R = .5522 * r; + + if (bb.height >= r * 2) { + p.attr({ + path: [ + "M", x, y + r, + "a", r, r, 0, 1, 1, 0, -r * 2, r, r, 0, 1, 1, 0, r * 2, + "m", 0, -r * 2 -d, + "a", r + d, r + d, 0, 1, 0, 0, (r + d) * 2, + "L", x + r + d, y + bb.height / 2 + d, + "l", bb.width + 2 * d, 0, 0, -bb.height - 2 * d, -bb.width - 2 * d, 0, + "L", x, y - r - d + ].join(",") + }); + } else { + dx = Math.sqrt(Math.pow(r + d, 2) - Math.pow(bb.height / 2 + d, 2)); + p.attr({ + path: [ + "M", x, y + r, + "c", -R, 0, -r, R - r, -r, -r, 0, -R, r - R, -r, r, -r, R, 0, r, r - R, r, r, 0, R, R - r, r, -r, r, + "M", x + dx, y - bb.height / 2 - d, + "a", r + d, r + d, 0, 1, 0, 0, bb.height + 2 * d, + "l", r + d - dx + bb.width + 2 * d, 0, 0, -bb.height - 2 * d, + "L", x + dx, y - bb.height / 2 - d + ].join(",") + }); + } + + angle = 360 - angle; + p.rotate(angle, x, y); + + if (this.attrs) { + //elements + this.attr(this.attrs.x ? 'x' : 'cx', x + r + d + (!center ? this.type == 'text' ? bb.width : 0 : bb.width / 2)).attr('y', center ? y : y - bb.height / 2); + this.rotate(angle, x, y); + angle > 90 && angle < 270 && this.attr(this.attrs.x ? 'x' : 'cx', x - r - d - (!center ? bb.width : bb.width / 2)).rotate(180, x, y); + } else { + //sets + if (angle > 90 && angle < 270) { + this.translate(x - bb.x - bb.width - r - d, y - bb.y - bb.height / 2); + this.rotate(angle - 180, bb.x + bb.width + r + d, bb.y + bb.height / 2); + } else { + this.translate(x - bb.x + r + d, y - bb.y - bb.height / 2); + this.rotate(angle, bb.x - r - d, bb.y + bb.height / 2); + } + } + + return p.insertBefore(this.node ? this : this[0]); +}; + +/*\ + * Element.drop + [ method ] + ** + * Puts the context Element in a 'drop' tooltip. Can also be used on sets. + ** + > Parameters + ** + - angle (number) angle of orientation in degrees [default: `0`] + - x (number) x coordinate of the drop's point [default: Element's `x` or `cx`] + - y (number) y coordinate of the drop's point [default: Element's `x` or `cx`] + ** + = (object) path element of the drop + > Usage + | paper.circle(50, 50, 8).attr({ + | stroke: "#fff", + | fill: "0-#c9de96-#8ab66b:44-#398235" + | }).drop(60); + \*/ +Raphael.el.drop = function (angle, x, y) { + var bb = this.getBBox(), + paper = this.paper || this[0].paper, + center, size, p, dx, dy; + + if (!paper) return; + + switch (this.type) { + case 'text': + case 'circle': + case 'ellipse': center = true; break; + default: center = false; + } + + angle = angle || 0; + + x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x); + y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y); + size = Math.max(bb.width, bb.height) + Math.min(bb.width, bb.height); + p = paper.path([ + "M", x, y, + "l", size, 0, + "A", size * .4, size * .4, 0, 1, 0, x + size * .7, y - size * .7, + "z" + ]).attr({fill: "#000", stroke: "none"}).rotate(22.5 - angle, x, y); + + angle = (angle + 90) * Math.PI / 180; + dx = (x + size * Math.sin(angle)) - (center ? 0 : bb.width / 2); + dy = (y + size * Math.cos(angle)) - (center ? 0 : bb.height / 2); + + this.attrs ? + this.attr(this.attrs.x ? 'x' : 'cx', dx).attr(this.attrs.y ? 'y' : 'cy', dy) : + this.translate(dx - bb.x, dy - bb.y); + + return p.insertBefore(this.node ? this : this[0]); +}; + +/*\ + * Element.flag + [ method ] + ** + * Puts the context Element in a 'flag' tooltip. Can also be used on sets. + ** + > Parameters + ** + - angle (number) angle of orientation in degrees [default: `0`] + - x (number) x coordinate of the flag's point [default: Element's `x` or `cx`] + - y (number) y coordinate of the flag's point [default: Element's `x` or `cx`] + ** + = (object) path element of the flag + > Usage + | paper.circle(50, 50, 10).attr({ + | stroke: "#fff", + | fill: "0-#c9de96-#8ab66b:44-#398235" + | }).flag(60); + \*/ +Raphael.el.flag = function (angle, x, y) { + var d = 3, + paper = this.paper || this[0].paper; + + if (!paper) return; + + var p = paper.path().attr({ fill: '#000', stroke: '#000' }), + bb = this.getBBox(), + h = bb.height / 2, + center; + + switch (this.type) { + case 'text': + case 'circle': + case 'ellipse': center = true; break; + default: center = false; + } + + angle = angle || 0; + x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x); + y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2: bb.y); + + p.attr({ + path: [ + "M", x, y, + "l", h + d, -h - d, bb.width + 2 * d, 0, 0, bb.height + 2 * d, -bb.width - 2 * d, 0, + "z" + ].join(",") + }); + + angle = 360 - angle; + p.rotate(angle, x, y); + + if (this.attrs) { + //elements + this.attr(this.attrs.x ? 'x' : 'cx', x + h + d + (!center ? this.type == 'text' ? bb.width : 0 : bb.width / 2)).attr('y', center ? y : y - bb.height / 2); + this.rotate(angle, x, y); + angle > 90 && angle < 270 && this.attr(this.attrs.x ? 'x' : 'cx', x - h - d - (!center ? bb.width : bb.width / 2)).rotate(180, x, y); + } else { + //sets + if (angle > 90 && angle < 270) { + this.translate(x - bb.x - bb.width - h - d, y - bb.y - bb.height / 2); + this.rotate(angle - 180, bb.x + bb.width + h + d, bb.y + bb.height / 2); + } else { + this.translate(x - bb.x + h + d, y - bb.y - bb.height / 2); + this.rotate(angle, bb.x - h - d, bb.y + bb.height / 2); + } + } + + return p.insertBefore(this.node ? this : this[0]); +}; + +/*\ + * Element.label + [ method ] + ** + * Puts the context Element in a 'label' tooltip. Can also be used on sets. + ** + = (object) path element of the label. + > Usage + | paper.circle(50, 50, 10).attr({ + | stroke: "#fff", + | fill: "0-#c9de96-#8ab66b:44-#398235" + | }).label(); + \*/ +Raphael.el.label = function () { + var bb = this.getBBox(), + paper = this.paper || this[0].paper, + r = Math.min(20, bb.width + 10, bb.height + 10) / 2; + + if (!paper) return; + + return paper.rect(bb.x - r / 2, bb.y - r / 2, bb.width + r, bb.height + r, r).attr({ stroke: 'none', fill: '#000' }).insertBefore(this.node ? this : this[0]); +}; + +/*\ + * Element.blob + [ method ] + ** + * Puts the context Element in a 'blob' tooltip. Can also be used on sets. + ** + > Parameters + ** + - angle (number) angle of orientation in degrees [default: `0`] + - x (number) x coordinate of the blob's tail [default: Element's `x` or `cx`] + - y (number) y coordinate of the blob's tail [default: Element's `x` or `cx`] + ** + = (object) path element of the blob + > Usage + | paper.circle(50, 50, 8).attr({ + | stroke: "#fff", + | fill: "0-#c9de96-#8ab66b:44-#398235" + | }).blob(60); + \*/ +Raphael.el.blob = function (angle, x, y) { + var bb = this.getBBox(), + rad = Math.PI / 180, + paper = this.paper || this[0].paper, + p, center, size; + + if (!paper) return; + + switch (this.type) { + case 'text': + case 'circle': + case 'ellipse': center = true; break; + default: center = false; + } + + p = paper.path().attr({ fill: "#000", stroke: "none" }); + angle = (+angle + 1 ? angle : 45) + 90; + size = Math.min(bb.height, bb.width); + x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x); + y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y); + + var w = Math.max(bb.width + size, size * 25 / 12), + h = Math.max(bb.height + size, size * 25 / 12), + x2 = x + size * Math.sin((angle - 22.5) * rad), + y2 = y + size * Math.cos((angle - 22.5) * rad), + x1 = x + size * Math.sin((angle + 22.5) * rad), + y1 = y + size * Math.cos((angle + 22.5) * rad), + dx = (x1 - x2) / 2, + dy = (y1 - y2) / 2, + rx = w / 2, + ry = h / 2, + k = -Math.sqrt(Math.abs(rx * rx * ry * ry - rx * rx * dy * dy - ry * ry * dx * dx) / (rx * rx * dy * dy + ry * ry * dx * dx)), + cx = k * rx * dy / ry + (x1 + x2) / 2, + cy = k * -ry * dx / rx + (y1 + y2) / 2; + + p.attr({ + x: cx, + y: cy, + path: [ + "M", x, y, + "L", x1, y1, + "A", rx, ry, 0, 1, 1, x2, y2, + "z" + ].join(",") + }); + + this.translate(cx - bb.x - bb.width / 2, cy - bb.y - bb.height / 2); + + return p.insertBefore(this.node ? this : this[0]); +}; + +/* + * Tooltips on Paper prototype + */ +/*\ + * Paper.label + [ method ] + ** + * Puts the given `text` into a 'label' tooltip. The text is given a default style according to @g.txtattr. See @Element.label + ** + > Parameters + ** + - x (number) x coordinate of the center of the label + - y (number) y coordinate of the center of the label + - text (string) text to place inside the label + ** + = (object) set containing the label path and the text element + > Usage + | paper.label(50, 50, "$9.99"); + \*/ +Raphael.fn.label = function (x, y, text) { + var set = this.set(); + + text = this.text(x, y, text).attr(Raphael.g.txtattr); + return set.push(text.label(), text); +}; + +/*\ + * Paper.popup + [ method ] + ** + * Puts the given `text` into a 'popup' tooltip. The text is given a default style according to @g.txtattr. See @Element.popup + * + * Note: The `dir` parameter has changed from g.Raphael 0.4.1 to 0.5. The options `0`, `1`, `2`, and `3` has been changed to `'down'`, `'left'`, `'up'`, and `'right'` respectively. + ** + > Parameters + ** + - x (number) x coordinate of the popup's tail + - y (number) y coordinate of the popup's tail + - text (string) text to place inside the popup + - dir (string) location of the text relative to the tail: `'down'`, `'left'`, `'up'` [default], or `'right'`. + - size (number) amount of padding around the Element [default: `5`] + ** + = (object) set containing the popup path and the text element + > Usage + | paper.popup(50, 50, "$9.99", 'down'); + \*/ +Raphael.fn.popup = function (x, y, text, dir, size) { + var set = this.set(); + + text = this.text(x, y, text).attr(Raphael.g.txtattr); + return set.push(text.popup(dir, size), text); +}; + +/*\ + * Paper.tag + [ method ] + ** + * Puts the given text into a 'tag' tooltip. The text is given a default style according to @g.txtattr. See @Element.tag + ** + > Parameters + ** + - x (number) x coordinate of the center of the tag loop + - y (number) y coordinate of the center of the tag loop + - text (string) text to place inside the tag + - angle (number) angle of orientation in degrees [default: `0`] + - r (number) radius of the loop [default: `5`] + ** + = (object) set containing the tag path and the text element + > Usage + | paper.tag(50, 50, "$9.99", 60); + \*/ +Raphael.fn.tag = function (x, y, text, angle, r) { + var set = this.set(); + + text = this.text(x, y, text).attr(Raphael.g.txtattr); + return set.push(text.tag(angle, r), text); +}; + +/*\ + * Paper.flag + [ method ] + ** + * Puts the given `text` into a 'flag' tooltip. The text is given a default style according to @g.txtattr. See @Element.flag + ** + > Parameters + ** + - x (number) x coordinate of the flag's point + - y (number) y coordinate of the flag's point + - text (string) text to place inside the flag + - angle (number) angle of orientation in degrees [default: `0`] + ** + = (object) set containing the flag path and the text element + > Usage + | paper.flag(50, 50, "$9.99", 60); + \*/ +Raphael.fn.flag = function (x, y, text, angle) { + var set = this.set(); + + text = this.text(x, y, text).attr(Raphael.g.txtattr); + return set.push(text.flag(angle), text); +}; + +/*\ + * Paper.drop + [ method ] + ** + * Puts the given text into a 'drop' tooltip. The text is given a default style according to @g.txtattr. See @Element.drop + ** + > Parameters + ** + - x (number) x coordinate of the drop's point + - y (number) y coordinate of the drop's point + - text (string) text to place inside the drop + - angle (number) angle of orientation in degrees [default: `0`] + ** + = (object) set containing the drop path and the text element + > Usage + | paper.drop(50, 50, "$9.99", 60); + \*/ +Raphael.fn.drop = function (x, y, text, angle) { + var set = this.set(); + + text = this.text(x, y, text).attr(Raphael.g.txtattr); + return set.push(text.drop(angle), text); +}; + +/*\ + * Paper.blob + [ method ] + ** + * Puts the given text into a 'blob' tooltip. The text is given a default style according to @g.txtattr. See @Element.blob + ** + > Parameters + ** + - x (number) x coordinate of the blob's tail + - y (number) y coordinate of the blob's tail + - text (string) text to place inside the blob + - angle (number) angle of orientation in degrees [default: `0`] + ** + = (object) set containing the blob path and the text element + > Usage + | paper.blob(50, 50, "$9.99", 60); + \*/ +Raphael.fn.blob = function (x, y, text, angle) { + var set = this.set(); + + text = this.text(x, y, text).attr(Raphael.g.txtattr); + return set.push(text.blob(angle), text); +}; + +/** + * Brightness functions on the Element prototype + */ +/*\ + * Element.lighter + [ method ] + ** + * Makes the context element lighter by increasing the brightness and reducing the saturation by a given factor. Can be called on Sets. + ** + > Parameters + ** + - times (number) adjustment factor [default: `2`] + ** + = (object) Element + > Usage + | paper.circle(50, 50, 20).attr({ + | fill: "#ff0000", + | stroke: "#fff", + | "stroke-width": 2 + | }).lighter(6); + \*/ +Raphael.el.lighter = function (times) { + times = times || 2; + + var fs = [this.attrs.fill, this.attrs.stroke]; + + this.fs = this.fs || [fs[0], fs[1]]; + + fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex); + fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex); + fs[0].b = Math.min(fs[0].b * times, 1); + fs[0].s = fs[0].s / times; + fs[1].b = Math.min(fs[1].b * times, 1); + fs[1].s = fs[1].s / times; + + this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"}); + return this; +}; + +/*\ + * Element.darker + [ method ] + ** + * Makes the context element darker by decreasing the brightness and increasing the saturation by a given factor. Can be called on Sets. + ** + > Parameters + ** + - times (number) adjustment factor [default: `2`] + ** + = (object) Element + > Usage + | paper.circle(50, 50, 20).attr({ + | fill: "#ff0000", + | stroke: "#fff", + | "stroke-width": 2 + | }).darker(6); + \*/ +Raphael.el.darker = function (times) { + times = times || 2; + + var fs = [this.attrs.fill, this.attrs.stroke]; + + this.fs = this.fs || [fs[0], fs[1]]; + + fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex); + fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex); + fs[0].s = Math.min(fs[0].s * times, 1); + fs[0].b = fs[0].b / times; + fs[1].s = Math.min(fs[1].s * times, 1); + fs[1].b = fs[1].b / times; + + this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"}); + return this; +}; + +/*\ + * Element.resetBrightness + [ method ] + ** + * Resets brightness and saturation levels to their original values. See @Element.lighter and @Element.darker. Can be called on Sets. + ** + = (object) Element + > Usage + | paper.circle(50, 50, 20).attr({ + | fill: "#ff0000", + | stroke: "#fff", + | "stroke-width": 2 + | }).lighter(6).resetBrightness(); + \*/ +Raphael.el.resetBrightness = function () { + if (this.fs) { + this.attr({ fill: this.fs[0], stroke: this.fs[1] }); + delete this.fs; + } + return this; +}; + +//alias to set prototype +(function () { + var brightness = ['lighter', 'darker', 'resetBrightness'], + tooltips = ['popup', 'tag', 'flag', 'label', 'drop', 'blob']; + + for (var f in tooltips) (function (name) { + Raphael.st[name] = function () { + return Raphael.el[name].apply(this, arguments); + }; + })(tooltips[f]); + + for (var f in brightness) (function (name) { + Raphael.st[name] = function () { + for (var i = 0; i < this.length; i++) { + this[i][name].apply(this[i], arguments); + } + + return this; + }; + })(brightness[f]); +})(); + +//chart prototype for storing common functions +Raphael.g = { + /*\ + * g.shim + [ object ] + ** + * An attribute object that charts will set on all generated shims (shims being the invisible objects that mouse events are bound to) + ** + > Default value + | { stroke: 'none', fill: '#000', 'fill-opacity': 0 } + \*/ + shim: { stroke: 'none', fill: '#000', 'fill-opacity': 0 }, + + /*\ + * g.txtattr + [ object ] + ** + * An attribute object that charts and tooltips will set on any generated text + ** + > Default value + | { font: '12px Arial, sans-serif', fill: '#fff' } + \*/ + txtattr: { font: '12px Arial, sans-serif', fill: '#fff' }, + + /*\ + * g.colors + [ array ] + ** + * An array of color values that charts will iterate through when drawing chart data values. + ** + \*/ + colors: (function () { + var hues = [.6, .2, .05, .1333, .75, 0], + colors = []; + + for (var i = 0; i < 10; i++) { + if (i < hues.length) { + colors.push('hsb(' + hues[i] + ',.75, .75)'); + } else { + colors.push('hsb(' + hues[i - hues.length] + ', 1, .5)'); + } + } + + return colors; + })(), + + snapEnds: function(from, to, steps) { + var f = from, + t = to; + + if (f == t) { + return {from: f, to: t, power: 0}; + } + + var d = (t - f) / steps, + mag = Math.floor(Math.log(d) / Math.log(10)), + magPow = Math.pow(10, mag), + magMsd = Math.floor(d / magPow + 0.5); + + // promote the MSD to either 1, 2, or 5 + if (magMsd > 5.0) + magMsd = 10.0; + else if (magMsd > 2.0) + magMsd = 5.0; + else if (magMsd > 1.0) + magMsd = 2.0; + + var step = magMsd * magPow; + + return { from: f - (f % step), to: t - (-t % step), i: mag } + + }, + + axis: function (x, y, length, from, to, steps, orientation, labels, type, dashsize, paper) { + dashsize = dashsize == null ? 2 : dashsize; + type = type || "t"; + steps = steps || 10; + paper = arguments[arguments.length-1] //paper is always last argument + + var path = type == "|" || type == " " ? ["M", x + .5, y, "l", 0, .001] : orientation == 1 || orientation == 3 ? ["M", x + .5, y, "l", 0, -length] : ["M", x, y + .5, "l", length, 0], + ends = this.snapEnds(from, to, steps), + f = ends.from, + t = ends.to, + i = ends.power, + j = 0, + txtattr = { font: "11px 'Fontin Sans', Fontin-Sans, sans-serif" }, + text = paper.set(), + d; + + d = (t - f) / steps; + + var label = f, + rnd = i > 0 ? i : 0; + dx = length / steps; + + if (+orientation == 1 || +orientation == 3) { + var Y = y, + addon = (orientation - 1 ? 1 : -1) * (dashsize + 3 + !!(orientation - 1)); + + while (Y >= y - length) { + type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), Y + .5, "l", dashsize * 2 + 1, 0])); + text.push(paper.text(x + addon, Y, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr).attr({ "text-anchor": orientation - 1 ? "start" : "end" })); + label += d; + Y -= dx; + } + + if (Math.round(Y + dx - (y - length))) { + type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), y - length + .5, "l", dashsize * 2 + 1, 0])); + text.push(paper.text(x + addon, y - length, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr).attr({ "text-anchor": orientation - 1 ? "start" : "end" })); + } + } else { + label = f; + rnd = (i > 0) * i; + addon = (orientation ? -1 : 1) * (dashsize + 9 + !orientation); + + var X = x, + dx = length / steps, + txt = 0, + prev = 0; + + while (X <= x + length) { + type != "-" && type != " " && (path = path.concat(["M", X + .5, y - (type == "+" ? dashsize : !!orientation * dashsize * 2), "l", 0, dashsize * 2 + 1])); + text.push(txt = paper.text(X, y + addon, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr)); + + var bb = txt.getBBox(); + + if (prev >= bb.x - 5) { + text.pop(text.length - 1).remove(); + } else { + prev = bb.x + bb.width; + } + + label += d; + X += dx; + } + + if (Math.round(X - dx - x - length)) { + type != "-" && type != " " && (path = path.concat(["M", x + length + .5, y - (type == "+" ? dashsize : !!orientation * dashsize * 2), "l", 0, dashsize * 2 + 1])); + text.push(paper.text(x + length, y + addon, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr)); + } + } + + var res = paper.path(path); + + res.text = text; + res.all = paper.set([res, text]); + res.remove = function () { + this.text.remove(); + this.constructor.prototype.remove.call(this); + }; + + return res; + }, + + labelise: function(label, val, total) { + if (label) { + return (label + "").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g, function (all, value, percent) { + if (value) { + return (+val).toFixed(value.replace(/^#+\.?/g, "").length); + } + if (percent) { + return (val * 100 / total).toFixed(percent.replace(/^%+\.?/g, "").length) + "%"; + } + }); + } else { + return (+val).toFixed(0); + } + } +} diff --git a/scp/js/raphael-min.js b/scp/js/raphael-min.js new file mode 100644 index 0000000000000000000000000000000000000000..d30dbad858fcbf9b06edb7bff74cb8feecaa8b71 --- /dev/null +++ b/scp/js/raphael-min.js @@ -0,0 +1,10 @@ +// ┌────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël 2.1.0 - JavaScript Vector Library │ \\ +// ├────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright © 2008-2012 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright © 2008-2012 Sencha Labs (http://sencha.com) │ \\ +// ├────────────────────────────────────────────────────────────────────┤ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license.│ \\ +// └────────────────────────────────────────────────────────────────────┘ \\ + +(function(a){var b="0.3.4",c="hasOwnProperty",d=/[\.\/]/,e="*",f=function(){},g=function(a,b){return a-b},h,i,j={n:{}},k=function(a,b){var c=j,d=i,e=Array.prototype.slice.call(arguments,2),f=k.listeners(a),l=0,m=!1,n,o=[],p={},q=[],r=h,s=[];h=a,i=0;for(var t=0,u=f.length;t<u;t++)"zIndex"in f[t]&&(o.push(f[t].zIndex),f[t].zIndex<0&&(p[f[t].zIndex]=f[t]));o.sort(g);while(o[l]<0){n=p[o[l++]],q.push(n.apply(b,e));if(i){i=d;return q}}for(t=0;t<u;t++){n=f[t];if("zIndex"in n)if(n.zIndex==o[l]){q.push(n.apply(b,e));if(i)break;do{l++,n=p[o[l]],n&&q.push(n.apply(b,e));if(i)break}while(n)}else p[n.zIndex]=n;else{q.push(n.apply(b,e));if(i)break}}i=d,h=r;return q.length?q:null};k.listeners=function(a){var b=a.split(d),c=j,f,g,h,i,k,l,m,n,o=[c],p=[];for(i=0,k=b.length;i<k;i++){n=[];for(l=0,m=o.length;l<m;l++){c=o[l].n,g=[c[b[i]],c[e]],h=2;while(h--)f=g[h],f&&(n.push(f),p=p.concat(f.f||[]))}o=n}return p},k.on=function(a,b){var c=a.split(d),e=j;for(var g=0,h=c.length;g<h;g++)e=e.n,!e[c[g]]&&(e[c[g]]={n:{}}),e=e[c[g]];e.f=e.f||[];for(g=0,h=e.f.length;g<h;g++)if(e.f[g]==b)return f;e.f.push(b);return function(a){+a==+a&&(b.zIndex=+a)}},k.stop=function(){i=1},k.nt=function(a){if(a)return(new RegExp("(?:\\.|\\/|^)"+a+"(?:\\.|\\/|$)")).test(h);return h},k.off=k.unbind=function(a,b){var f=a.split(d),g,h,i,k,l,m,n,o=[j];for(k=0,l=f.length;k<l;k++)for(m=0;m<o.length;m+=i.length-2){i=[m,1],g=o[m].n;if(f[k]!=e)g[f[k]]&&i.push(g[f[k]]);else for(h in g)g[c](h)&&i.push(g[h]);o.splice.apply(o,i)}for(k=0,l=o.length;k<l;k++){g=o[k];while(g.n){if(b){if(g.f){for(m=0,n=g.f.length;m<n;m++)if(g.f[m]==b){g.f.splice(m,1);break}!g.f.length&&delete g.f}for(h in g.n)if(g.n[c](h)&&g.n[h].f){var p=g.n[h].f;for(m=0,n=p.length;m<n;m++)if(p[m]==b){p.splice(m,1);break}!p.length&&delete g.n[h].f}}else{delete g.f;for(h in g.n)g.n[c](h)&&g.n[h].f&&delete g.n[h].f}g=g.n}}},k.once=function(a,b){var c=function(){var d=b.apply(this,arguments);k.unbind(a,c);return d};return k.on(a,c)},k.version=b,k.toString=function(){return"You are running Eve "+b},typeof module!="undefined"&&module.exports?module.exports=k:typeof define!="undefined"?define("eve",[],function(){return k}):a.eve=k})(this),function(){function cF(a){for(var b=0;b<cy.length;b++)cy[b].el.paper==a&&cy.splice(b--,1)}function cE(b,d,e,f,h,i){e=Q(e);var j,k,l,m=[],o,p,q,t=b.ms,u={},v={},w={};if(f)for(y=0,z=cy.length;y<z;y++){var x=cy[y];if(x.el.id==d.id&&x.anim==b){x.percent!=e?(cy.splice(y,1),l=1):k=x,d.attr(x.totalOrigin);break}}else f=+v;for(var y=0,z=b.percents.length;y<z;y++){if(b.percents[y]==e||b.percents[y]>f*b.top){e=b.percents[y],p=b.percents[y-1]||0,t=t/b.top*(e-p),o=b.percents[y+1],j=b.anim[e];break}f&&d.attr(b.anim[b.percents[y]])}if(!!j){if(!k){for(var A in j)if(j[g](A))if(U[g](A)||d.paper.customAttributes[g](A)){u[A]=d.attr(A),u[A]==null&&(u[A]=T[A]),v[A]=j[A];switch(U[A]){case C:w[A]=(v[A]-u[A])/t;break;case"colour":u[A]=a.getRGB(u[A]);var B=a.getRGB(v[A]);w[A]={r:(B.r-u[A].r)/t,g:(B.g-u[A].g)/t,b:(B.b-u[A].b)/t};break;case"path":var D=bR(u[A],v[A]),E=D[1];u[A]=D[0],w[A]=[];for(y=0,z=u[A].length;y<z;y++){w[A][y]=[0];for(var F=1,G=u[A][y].length;F<G;F++)w[A][y][F]=(E[y][F]-u[A][y][F])/t}break;case"transform":var H=d._,I=ca(H[A],v[A]);if(I){u[A]=I.from,v[A]=I.to,w[A]=[],w[A].real=!0;for(y=0,z=u[A].length;y<z;y++){w[A][y]=[u[A][y][0]];for(F=1,G=u[A][y].length;F<G;F++)w[A][y][F]=(v[A][y][F]-u[A][y][F])/t}}else{var J=d.matrix||new cb,K={_:{transform:H.transform},getBBox:function(){return d.getBBox(1)}};u[A]=[J.a,J.b,J.c,J.d,J.e,J.f],b$(K,v[A]),v[A]=K._.transform,w[A]=[(K.matrix.a-J.a)/t,(K.matrix.b-J.b)/t,(K.matrix.c-J.c)/t,(K.matrix.d-J.d)/t,(K.matrix.e-J.e)/t,(K.matrix.f-J.f)/t]}break;case"csv":var L=r(j[A])[s](c),M=r(u[A])[s](c);if(A=="clip-rect"){u[A]=M,w[A]=[],y=M.length;while(y--)w[A][y]=(L[y]-u[A][y])/t}v[A]=L;break;default:L=[][n](j[A]),M=[][n](u[A]),w[A]=[],y=d.paper.customAttributes[A].length;while(y--)w[A][y]=((L[y]||0)-(M[y]||0))/t}}var O=j.easing,P=a.easing_formulas[O];if(!P){P=r(O).match(N);if(P&&P.length==5){var R=P;P=function(a){return cC(a,+R[1],+R[2],+R[3],+R[4],t)}}else P=bf}q=j.start||b.start||+(new Date),x={anim:b,percent:e,timestamp:q,start:q+(b.del||0),status:0,initstatus:f||0,stop:!1,ms:t,easing:P,from:u,diff:w,to:v,el:d,callback:j.callback,prev:p,next:o,repeat:i||b.times,origin:d.attr(),totalOrigin:h},cy.push(x);if(f&&!k&&!l){x.stop=!0,x.start=new Date-t*f;if(cy.length==1)return cA()}l&&(x.start=new Date-x.ms*f),cy.length==1&&cz(cA)}else k.initstatus=f,k.start=new Date-k.ms*f;eve("raphael.anim.start."+d.id,d,b)}}function cD(a,b){var c=[],d={};this.ms=b,this.times=1;if(a){for(var e in a)a[g](e)&&(d[Q(e)]=a[e],c.push(Q(e)));c.sort(bd)}this.anim=d,this.top=c[c.length-1],this.percents=c}function cC(a,b,c,d,e,f){function o(a,b){var c,d,e,f,j,k;for(e=a,k=0;k<8;k++){f=m(e)-a;if(z(f)<b)return e;j=(3*i*e+2*h)*e+g;if(z(j)<1e-6)break;e=e-f/j}c=0,d=1,e=a;if(e<c)return c;if(e>d)return d;while(c<d){f=m(e);if(z(f-a)<b)return e;a>f?c=e:d=e,e=(d-c)/2+c}return e}function n(a,b){var c=o(a,b);return((l*c+k)*c+j)*c}function m(a){return((i*a+h)*a+g)*a}var g=3*b,h=3*(d-b)-g,i=1-g-h,j=3*c,k=3*(e-c)-j,l=1-j-k;return n(a,1/(200*f))}function cq(){return this.x+q+this.y+q+this.width+" × "+this.height}function cp(){return this.x+q+this.y}function cb(a,b,c,d,e,f){a!=null?(this.a=+a,this.b=+b,this.c=+c,this.d=+d,this.e=+e,this.f=+f):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0)}function bH(b,c,d){b=a._path2curve(b),c=a._path2curve(c);var e,f,g,h,i,j,k,l,m,n,o=d?0:[];for(var p=0,q=b.length;p<q;p++){var r=b[p];if(r[0]=="M")e=i=r[1],f=j=r[2];else{r[0]=="C"?(m=[e,f].concat(r.slice(1)),e=m[6],f=m[7]):(m=[e,f,e,f,i,j,i,j],e=i,f=j);for(var s=0,t=c.length;s<t;s++){var u=c[s];if(u[0]=="M")g=k=u[1],h=l=u[2];else{u[0]=="C"?(n=[g,h].concat(u.slice(1)),g=n[6],h=n[7]):(n=[g,h,g,h,k,l,k,l],g=k,h=l);var v=bG(m,n,d);if(d)o+=v;else{for(var w=0,x=v.length;w<x;w++)v[w].segment1=p,v[w].segment2=s,v[w].bez1=m,v[w].bez2=n;o=o.concat(v)}}}}}return o}function bG(b,c,d){var e=a.bezierBBox(b),f=a.bezierBBox(c);if(!a.isBBoxIntersect(e,f))return d?0:[];var g=bB.apply(0,b),h=bB.apply(0,c),i=~~(g/5),j=~~(h/5),k=[],l=[],m={},n=d?0:[];for(var o=0;o<i+1;o++){var p=a.findDotsAtSegment.apply(a,b.concat(o/i));k.push({x:p.x,y:p.y,t:o/i})}for(o=0;o<j+1;o++)p=a.findDotsAtSegment.apply(a,c.concat(o/j)),l.push({x:p.x,y:p.y,t:o/j});for(o=0;o<i;o++)for(var q=0;q<j;q++){var r=k[o],s=k[o+1],t=l[q],u=l[q+1],v=z(s.x-r.x)<.001?"y":"x",w=z(u.x-t.x)<.001?"y":"x",x=bD(r.x,r.y,s.x,s.y,t.x,t.y,u.x,u.y);if(x){if(m[x.x.toFixed(4)]==x.y.toFixed(4))continue;m[x.x.toFixed(4)]=x.y.toFixed(4);var y=r.t+z((x[v]-r[v])/(s[v]-r[v]))*(s.t-r.t),A=t.t+z((x[w]-t[w])/(u[w]-t[w]))*(u.t-t.t);y>=0&&y<=1&&A>=0&&A<=1&&(d?n++:n.push({x:x.x,y:x.y,t1:y,t2:A}))}}return n}function bF(a,b){return bG(a,b,1)}function bE(a,b){return bG(a,b)}function bD(a,b,c,d,e,f,g,h){if(!(x(a,c)<y(e,g)||y(a,c)>x(e,g)||x(b,d)<y(f,h)||y(b,d)>x(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(!k)return;var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(n<+y(a,c).toFixed(2)||n>+x(a,c).toFixed(2)||n<+y(e,g).toFixed(2)||n>+x(e,g).toFixed(2)||o<+y(b,d).toFixed(2)||o>+x(b,d).toFixed(2)||o<+y(f,h).toFixed(2)||o>+x(f,h).toFixed(2))return;return{x:l,y:m}}}function bC(a,b,c,d,e,f,g,h,i){if(!(i<0||bB(a,b,c,d,e,f,g,h)<i)){var j=1,k=j/2,l=j-k,m,n=.01;m=bB(a,b,c,d,e,f,g,h,l);while(z(m-i)>n)k/=2,l+=(m<i?1:-1)*k,m=bB(a,b,c,d,e,f,g,h,l);return l}}function bB(a,b,c,d,e,f,g,h,i){i==null&&(i=1),i=i>1?1:i<0?0:i;var j=i/2,k=12,l=[-0.1252,.1252,-0.3678,.3678,-0.5873,.5873,-0.7699,.7699,-0.9041,.9041,-0.9816,.9816],m=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],n=0;for(var o=0;o<k;o++){var p=j*l[o]+j,q=bA(p,a,c,e,g),r=bA(p,b,d,f,h),s=q*q+r*r;n+=m[o]*w.sqrt(s)}return j*n}function bA(a,b,c,d,e){var f=-3*b+9*c-9*d+3*e,g=a*f+6*b-12*c+6*d;return a*g-3*b+3*c}function by(a,b){var c=[];for(var d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push(["C",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}function bx(){return this.hex}function bv(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join("␀"),h=d.cache=d.cache||{},i=d.count=d.count||[];if(h[g](f)){bu(i,f);return c?c(h[f]):h[f]}i.length>=1e3&&delete h[i.shift()],i.push(f),h[f]=a[m](b,e);return c?c(h[f]):h[f]}return d}function bu(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return a.push(a.splice(c,1)[0])}function bm(a){if(Object(a)!==a)return a;var b=new a.constructor;for(var c in a)a[g](c)&&(b[c]=bm(a[c]));return b}function a(c){if(a.is(c,"function"))return b?c():eve.on("raphael.DOMload",c);if(a.is(c,E))return a._engine.create[m](a,c.splice(0,3+a.is(c[0],C))).add(c);var d=Array.prototype.slice.call(arguments,0);if(a.is(d[d.length-1],"function")){var e=d.pop();return b?e.call(a._engine.create[m](a,d)):eve.on("raphael.DOMload",function(){e.call(a._engine.create[m](a,d))})}return a._engine.create[m](a,arguments)}a.version="2.1.0",a.eve=eve;var b,c=/[, ]+/,d={circle:1,rect:1,path:1,ellipse:1,text:1,image:1},e=/\{(\d+)\}/g,f="prototype",g="hasOwnProperty",h={doc:document,win:window},i={was:Object.prototype[g].call(h.win,"Raphael"),is:h.win.Raphael},j=function(){this.ca=this.customAttributes={}},k,l="appendChild",m="apply",n="concat",o="createTouch"in h.doc,p="",q=" ",r=String,s="split",t="click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[s](q),u={mousedown:"touchstart",mousemove:"touchmove",mouseup:"touchend"},v=r.prototype.toLowerCase,w=Math,x=w.max,y=w.min,z=w.abs,A=w.pow,B=w.PI,C="number",D="string",E="array",F="toString",G="fill",H=Object.prototype.toString,I={},J="push",K=a._ISURL=/^url\(['"]?([^\)]+?)['"]?\)$/i,L=/^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i,M={NaN:1,Infinity:1,"-Infinity":1},N=/^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,O=w.round,P="setAttribute",Q=parseFloat,R=parseInt,S=r.prototype.toUpperCase,T=a._availableAttrs={"arrow-end":"none","arrow-start":"none",blur:0,"clip-rect":"0 0 1e9 1e9",cursor:"default",cx:0,cy:0,fill:"#fff","fill-opacity":1,font:'10px "Arial"',"font-family":'"Arial"',"font-size":"10","font-style":"normal","font-weight":400,gradient:0,height:0,href:"http://raphaeljs.com/","letter-spacing":0,opacity:1,path:"M0,0",r:0,rx:0,ry:0,src:"",stroke:"#000","stroke-dasharray":"","stroke-linecap":"butt","stroke-linejoin":"butt","stroke-miterlimit":0,"stroke-opacity":1,"stroke-width":1,target:"_blank","text-anchor":"middle",title:"Raphael",transform:"",width:0,x:0,y:0},U=a._availableAnimAttrs={blur:C,"clip-rect":"csv",cx:C,cy:C,fill:"colour","fill-opacity":C,"font-size":C,height:C,opacity:C,path:"path",r:C,rx:C,ry:C,stroke:"colour","stroke-opacity":C,"stroke-width":C,transform:"transform",width:C,x:C,y:C},V=/[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]/g,W=/[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/,X={hs:1,rg:1},Y=/,?([achlmqrstvxz]),?/gi,Z=/([achlmrqstvz])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig,$=/([rstm])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig,_=/(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/ig,ba=a._radial_gradient=/^r(?:\(([^,]+?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*([^\)]+?)\))?/,bb={},bc=function(a,b){return a.key-b.key},bd=function(a,b){return Q(a)-Q(b)},be=function(){},bf=function(a){return a},bg=a._rectPath=function(a,b,c,d,e){if(e)return[["M",a+e,b],["l",c-e*2,0],["a",e,e,0,0,1,e,e],["l",0,d-e*2],["a",e,e,0,0,1,-e,e],["l",e*2-c,0],["a",e,e,0,0,1,-e,-e],["l",0,e*2-d],["a",e,e,0,0,1,e,-e],["z"]];return[["M",a,b],["l",c,0],["l",0,d],["l",-c,0],["z"]]},bh=function(a,b,c,d){d==null&&(d=c);return[["M",a,b],["m",0,-d],["a",c,d,0,1,1,0,2*d],["a",c,d,0,1,1,0,-2*d],["z"]]},bi=a._getPath={path:function(a){return a.attr("path")},circle:function(a){var b=a.attrs;return bh(b.cx,b.cy,b.r)},ellipse:function(a){var b=a.attrs;return bh(b.cx,b.cy,b.rx,b.ry)},rect:function(a){var b=a.attrs;return bg(b.x,b.y,b.width,b.height,b.r)},image:function(a){var b=a.attrs;return bg(b.x,b.y,b.width,b.height)},text:function(a){var b=a._getBBox();return bg(b.x,b.y,b.width,b.height)}},bj=a.mapPath=function(a,b){if(!b)return a;var c,d,e,f,g,h,i;a=bR(a);for(e=0,g=a.length;e<g;e++){i=a[e];for(f=1,h=i.length;f<h;f+=2)c=b.x(i[f],i[f+1]),d=b.y(i[f],i[f+1]),i[f]=c,i[f+1]=d}return a};a._g=h,a.type=h.win.SVGAngle||h.doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1")?"SVG":"VML";if(a.type=="VML"){var bk=h.doc.createElement("div"),bl;bk.innerHTML='<v:shape adj="1"/>',bl=bk.firstChild,bl.style.behavior="url(#default#VML)";if(!bl||typeof bl.adj!="object")return a.type=p;bk=null}a.svg=!(a.vml=a.type=="VML"),a._Paper=j,a.fn=k=j.prototype=a.prototype,a._id=0,a._oid=0,a.is=function(a,b){b=v.call(b);if(b=="finite")return!M[g](+a);if(b=="array")return a instanceof Array;return b=="null"&&a===null||b==typeof a&&a!==null||b=="object"&&a===Object(a)||b=="array"&&Array.isArray&&Array.isArray(a)||H.call(a).slice(8,-1).toLowerCase()==b},a.angle=function(b,c,d,e,f,g){if(f==null){var h=b-d,i=c-e;if(!h&&!i)return 0;return(180+w.atan2(-i,-h)*180/B+360)%360}return a.angle(b,c,f,g)-a.angle(d,e,f,g)},a.rad=function(a){return a%360*B/180},a.deg=function(a){return a*180/B%360},a.snapTo=function(b,c,d){d=a.is(d,"finite")?d:10;if(a.is(b,E)){var e=b.length;while(e--)if(z(b[e]-c)<=d)return b[e]}else{b=+b;var f=c%b;if(f<d)return c-f;if(f>b-d)return c-f+b}return c};var bn=a.createUUID=function(a,b){return function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(a,b).toUpperCase()}}(/[xy]/g,function(a){var b=w.random()*16|0,c=a=="x"?b:b&3|8;return c.toString(16)});a.setWindow=function(b){eve("raphael.setWindow",a,h.win,b),h.win=b,h.doc=h.win.document,a._engine.initWin&&a._engine.initWin(h.win)};var bo=function(b){if(a.vml){var c=/^\s+|\s+$/g,d;try{var e=new ActiveXObject("htmlfile");e.write("<body>"),e.close(),d=e.body}catch(f){d=createPopup().document.body}var g=d.createTextRange();bo=bv(function(a){try{d.style.color=r(a).replace(c,p);var b=g.queryCommandValue("ForeColor");b=(b&255)<<16|b&65280|(b&16711680)>>>16;return"#"+("000000"+b.toString(16)).slice(-6)}catch(e){return"none"}})}else{var i=h.doc.createElement("i");i.title="Raphaël Colour Picker",i.style.display="none",h.doc.body.appendChild(i),bo=bv(function(a){i.style.color=a;return h.doc.defaultView.getComputedStyle(i,p).getPropertyValue("color")})}return bo(b)},bp=function(){return"hsb("+[this.h,this.s,this.b]+")"},bq=function(){return"hsl("+[this.h,this.s,this.l]+")"},br=function(){return this.hex},bs=function(b,c,d){c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b&&(d=b.b,c=b.g,b=b.r);if(c==null&&a.is(b,D)){var e=a.getRGB(b);b=e.r,c=e.g,d=e.b}if(b>1||c>1||d>1)b/=255,c/=255,d/=255;return[b,c,d]},bt=function(b,c,d,e){b*=255,c*=255,d*=255;var f={r:b,g:c,b:d,hex:a.rgb(b,c,d),toString:br};a.is(e,"finite")&&(f.opacity=e);return f};a.color=function(b){var c;a.is(b,"object")&&"h"in b&&"s"in b&&"b"in b?(c=a.hsb2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):a.is(b,"object")&&"h"in b&&"s"in b&&"l"in b?(c=a.hsl2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):(a.is(b,"string")&&(b=a.getRGB(b)),a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b?(c=a.rgb2hsl(b),b.h=c.h,b.s=c.s,b.l=c.l,c=a.rgb2hsb(b),b.v=c.b):(b={hex:"none"},b.r=b.g=b.b=b.h=b.s=b.v=b.l=-1)),b.toString=br;return b},a.hsb2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,a=a.h,d=a.o),a*=360;var e,f,g,h,i;a=a%360/60,i=c*b,h=i*(1-z(a%2-1)),e=f=g=c-i,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return bt(e,f,g,d)},a.hsl2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h);if(a>1||b>1||c>1)a/=360,b/=100,c/=100;a*=360;var e,f,g,h,i;a=a%360/60,i=2*b*(c<.5?c:1-c),h=i*(1-z(a%2-1)),e=f=g=c-i/2,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return bt(e,f,g,d)},a.rgb2hsb=function(a,b,c){c=bs(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;f=x(a,b,c),g=f-y(a,b,c),d=g==0?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=g==0?0:g/f;return{h:d,s:e,b:f,toString:bp}},a.rgb2hsl=function(a,b,c){c=bs(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;g=x(a,b,c),h=y(a,b,c),i=g-h,d=i==0?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=i==0?0:f<.5?i/(2*f):i/(2-2*f);return{h:d,s:e,l:f,toString:bq}},a._path2string=function(){return this.join(",").replace(Y,"$1")};var bw=a._preload=function(a,b){var c=h.doc.createElement("img");c.style.cssText="position:absolute;left:-9999em;top:-9999em",c.onload=function(){b.call(this),this.onload=null,h.doc.body.removeChild(this)},c.onerror=function(){h.doc.body.removeChild(this)},h.doc.body.appendChild(c),c.src=a};a.getRGB=bv(function(b){if(!b||!!((b=r(b)).indexOf("-")+1))return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:bx};if(b=="none")return{r:-1,g:-1,b:-1,hex:"none",toString:bx};!X[g](b.toLowerCase().substring(0,2))&&b.charAt()!="#"&&(b=bo(b));var c,d,e,f,h,i,j,k=b.match(L);if(k){k[2]&&(f=R(k[2].substring(5),16),e=R(k[2].substring(3,5),16),d=R(k[2].substring(1,3),16)),k[3]&&(f=R((i=k[3].charAt(3))+i,16),e=R((i=k[3].charAt(2))+i,16),d=R((i=k[3].charAt(1))+i,16)),k[4]&&(j=k[4][s](W),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),k[1].toLowerCase().slice(0,4)=="rgba"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100));if(k[5]){j=k[5][s](W),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsba"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsb2rgb(d,e,f,h)}if(k[6]){j=k[6][s](W),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsla"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsl2rgb(d,e,f,h)}k={r:d,g:e,b:f,toString:bx},k.hex="#"+(16777216|f|e<<8|d<<16).toString(16).slice(1),a.is(h,"finite")&&(k.opacity=h);return k}return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:bx}},a),a.hsb=bv(function(b,c,d){return a.hsb2rgb(b,c,d).hex}),a.hsl=bv(function(b,c,d){return a.hsl2rgb(b,c,d).hex}),a.rgb=bv(function(a,b,c){return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)}),a.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||.75},c=this.hsb2rgb(b.h,b.s,b.b);b.h+=.075,b.h>1&&(b.h=0,b.s-=.2,b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b}));return c.hex},a.getColor.reset=function(){delete this.start},a.parsePathString=function(b){if(!b)return null;var c=bz(b);if(c.arr)return bJ(c.arr);var d={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},e=[];a.is(b,E)&&a.is(b[0],E)&&(e=bJ(b)),e.length||r(b).replace(Z,function(a,b,c){var f=[],g=b.toLowerCase();c.replace(_,function(a,b){b&&f.push(+b)}),g=="m"&&f.length>2&&(e.push([b][n](f.splice(0,2))),g="l",b=b=="m"?"l":"L");if(g=="r")e.push([b][n](f));else while(f.length>=d[g]){e.push([b][n](f.splice(0,d[g])));if(!d[g])break}}),e.toString=a._path2string,c.arr=bJ(e);return e},a.parseTransformString=bv(function(b){if(!b)return null;var c={r:3,s:4,t:2,m:6},d=[];a.is(b,E)&&a.is(b[0],E)&&(d=bJ(b)),d.length||r(b).replace($,function(a,b,c){var e=[],f=v.call(b);c.replace(_,function(a,b){b&&e.push(+b)}),d.push([b][n](e))}),d.toString=a._path2string;return d});var bz=function(a){var b=bz.ps=bz.ps||{};b[a]?b[a].sleep=100:b[a]={sleep:100},setTimeout(function(){for(var c in b)b[g](c)&&c!=a&&(b[c].sleep--,!b[c].sleep&&delete b[c])});return b[a]};a.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=A(j,3),l=A(j,2),m=i*i,n=m*i,o=k*a+l*3*i*c+j*3*i*i*e+n*g,p=k*b+l*3*i*d+j*3*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,x=j*e+i*g,y=j*f+i*h,z=90-w.atan2(q-s,r-t)*180/B;(q>s||r<t)&&(z+=180);return{x:o,y:p,m:{x:q,y:r},n:{x:s,y:t},start:{x:u,y:v},end:{x:x,y:y},alpha:z}},a.bezierBBox=function(b,c,d,e,f,g,h,i){a.is(b,"array")||(b=[b,c,d,e,f,g,h,i]);var j=bQ.apply(null,b);return{x:j.min.x,y:j.min.y,x2:j.max.x,y2:j.max.y,width:j.max.x-j.min.x,height:j.max.y-j.min.y}},a.isPointInsideBBox=function(a,b,c){return b>=a.x&&b<=a.x2&&c>=a.y&&c<=a.y2},a.isBBoxIntersect=function(b,c){var d=a.isPointInsideBBox;return d(c,b.x,b.y)||d(c,b.x2,b.y)||d(c,b.x,b.y2)||d(c,b.x2,b.y2)||d(b,c.x,c.y)||d(b,c.x2,c.y)||d(b,c.x,c.y2)||d(b,c.x2,c.y2)||(b.x<c.x2&&b.x>c.x||c.x<b.x2&&c.x>b.x)&&(b.y<c.y2&&b.y>c.y||c.y<b.y2&&c.y>b.y)},a.pathIntersection=function(a,b){return bH(a,b)},a.pathIntersectionNumber=function(a,b){return bH(a,b,1)},a.isPointInsidePath=function(b,c,d){var e=a.pathBBox(b);return a.isPointInsideBBox(e,c,d)&&bH(b,[["M",c,d],["H",e.x2+10]],1)%2==1},a._removedFactory=function(a){return function(){eve("raphael.log",null,"Raphaël: you are calling to method “"+a+"” of removed object",a)}};var bI=a.pathBBox=function(a){var b=bz(a);if(b.bbox)return b.bbox;if(!a)return{x:0,y:0,width:0,height:0,x2:0,y2:0};a=bR(a);var c=0,d=0,e=[],f=[],g;for(var h=0,i=a.length;h<i;h++){g=a[h];if(g[0]=="M")c=g[1],d=g[2],e.push(c),f.push(d);else{var j=bQ(c,d,g[1],g[2],g[3],g[4],g[5],g[6]);e=e[n](j.min.x,j.max.x),f=f[n](j.min.y,j.max.y),c=g[5],d=g[6]}}var k=y[m](0,e),l=y[m](0,f),o=x[m](0,e),p=x[m](0,f),q={x:k,y:l,x2:o,y2:p,width:o-k,height:p-l};b.bbox=bm(q);return q},bJ=function(b){var c=bm(b);c.toString=a._path2string;return c},bK=a._pathToRelative=function(b){var c=bz(b);if(c.rel)return bJ(c.rel);if(!a.is(b,E)||!a.is(b&&b[0],E))b=a.parsePathString(b);var d=[],e=0,f=0,g=0,h=0,i=0;b[0][0]=="M"&&(e=b[0][1],f=b[0][2],g=e,h=f,i++,d.push(["M",e,f]));for(var j=i,k=b.length;j<k;j++){var l=d[j]=[],m=b[j];if(m[0]!=v.call(m[0])){l[0]=v.call(m[0]);switch(l[0]){case"a":l[1]=m[1],l[2]=m[2],l[3]=m[3],l[4]=m[4],l[5]=m[5],l[6]=+(m[6]-e).toFixed(3),l[7]=+(m[7]-f).toFixed(3);break;case"v":l[1]=+(m[1]-f).toFixed(3);break;case"m":g=m[1],h=m[2];default:for(var n=1,o=m.length;n<o;n++)l[n]=+(m[n]-(n%2?e:f)).toFixed(3)}}else{l=d[j]=[],m[0]=="m"&&(g=m[1]+e,h=m[2]+f);for(var p=0,q=m.length;p<q;p++)d[j][p]=m[p]}var r=d[j].length;switch(d[j][0]){case"z":e=g,f=h;break;case"h":e+=+d[j][r-1];break;case"v":f+=+d[j][r-1];break;default:e+=+d[j][r-2],f+=+d[j][r-1]}}d.toString=a._path2string,c.rel=bJ(d);return d},bL=a._pathToAbsolute=function(b){var c=bz(b);if(c.abs)return bJ(c.abs);if(!a.is(b,E)||!a.is(b&&b[0],E))b=a.parsePathString(b);if(!b||!b.length)return[["M",0,0]];var d=[],e=0,f=0,g=0,h=0,i=0;b[0][0]=="M"&&(e=+b[0][1],f=+b[0][2],g=e,h=f,i++,d[0]=["M",e,f]);var j=b.length==3&&b[0][0]=="M"&&b[1][0].toUpperCase()=="R"&&b[2][0].toUpperCase()=="Z";for(var k,l,m=i,o=b.length;m<o;m++){d.push(k=[]),l=b[m];if(l[0]!=S.call(l[0])){k[0]=S.call(l[0]);switch(k[0]){case"A":k[1]=l[1],k[2]=l[2],k[3]=l[3],k[4]=l[4],k[5]=l[5],k[6]=+(l[6]+e),k[7]=+(l[7]+f);break;case"V":k[1]=+l[1]+f;break;case"H":k[1]=+l[1]+e;break;case"R":var p=[e,f][n](l.slice(1));for(var q=2,r=p.length;q<r;q++)p[q]=+p[q]+e,p[++q]=+p[q]+f;d.pop(),d=d[n](by(p,j));break;case"M":g=+l[1]+e,h=+l[2]+f;default:for(q=1,r=l.length;q<r;q++)k[q]=+l[q]+(q%2?e:f)}}else if(l[0]=="R")p=[e,f][n](l.slice(1)),d.pop(),d=d[n](by(p,j)),k=["R"][n](l.slice(-2));else for(var s=0,t=l.length;s<t;s++)k[s]=l[s];switch(k[0]){case"Z":e=g,f=h;break;case"H":e=k[1];break;case"V":f=k[1];break;case"M":g=k[k.length-2],h=k[k.length-1];default:e=k[k.length-2],f=k[k.length-1]}}d.toString=a._path2string,c.abs=bJ(d);return d},bM=function(a,b,c,d){return[a,b,c,d,c,d]},bN=function(a,b,c,d,e,f){var g=1/3,h=2/3;return[g*a+h*c,g*b+h*d,g*e+h*c,g*f+h*d,e,f]},bO=function(a,b,c,d,e,f,g,h,i,j){var k=B*120/180,l=B/180*(+e||0),m=[],o,p=bv(function(a,b,c){var d=a*w.cos(c)-b*w.sin(c),e=a*w.sin(c)+b*w.cos(c);return{x:d,y:e}});if(!j){o=p(a,b,-l),a=o.x,b=o.y,o=p(h,i,-l),h=o.x,i=o.y;var q=w.cos(B/180*e),r=w.sin(B/180*e),t=(a-h)/2,u=(b-i)/2,v=t*t/(c*c)+u*u/(d*d);v>1&&(v=w.sqrt(v),c=v*c,d=v*d);var x=c*c,y=d*d,A=(f==g?-1:1)*w.sqrt(z((x*y-x*u*u-y*t*t)/(x*u*u+y*t*t))),C=A*c*u/d+(a+h)/2,D=A*-d*t/c+(b+i)/2,E=w.asin(((b-D)/d).toFixed(9)),F=w.asin(((i-D)/d).toFixed(9));E=a<C?B-E:E,F=h<C?B-F:F,E<0&&(E=B*2+E),F<0&&(F=B*2+F),g&&E>F&&(E=E-B*2),!g&&F>E&&(F=F-B*2)}else E=j[0],F=j[1],C=j[2],D=j[3];var G=F-E;if(z(G)>k){var H=F,I=h,J=i;F=E+k*(g&&F>E?1:-1),h=C+c*w.cos(F),i=D+d*w.sin(F),m=bO(h,i,c,d,e,0,g,I,J,[F,H,C,D])}G=F-E;var K=w.cos(E),L=w.sin(E),M=w.cos(F),N=w.sin(F),O=w.tan(G/4),P=4/3*c*O,Q=4/3*d*O,R=[a,b],S=[a+P*L,b-Q*K],T=[h+P*N,i-Q*M],U=[h,i];S[0]=2*R[0]-S[0],S[1]=2*R[1]-S[1];if(j)return[S,T,U][n](m);m=[S,T,U][n](m).join()[s](",");var V=[];for(var W=0,X=m.length;W<X;W++)V[W]=W%2?p(m[W-1],m[W],l).y:p(m[W],m[W+1],l).x;return V},bP=function(a,b,c,d,e,f,g,h,i){var j=1-i;return{x:A(j,3)*a+A(j,2)*3*i*c+j*3*i*i*e+A(i,3)*g,y:A(j,3)*b+A(j,2)*3*i*d+j*3*i*i*f+A(i,3)*h}},bQ=bv(function(a,b,c,d,e,f,g,h){var i=e-2*c+a-(g-2*e+c),j=2*(c-a)-2*(e-c),k=a-c,l=(-j+w.sqrt(j*j-4*i*k))/2/i,n=(-j-w.sqrt(j*j-4*i*k))/2/i,o=[b,h],p=[a,g],q;z(l)>"1e12"&&(l=.5),z(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bP(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bP(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y)),i=f-2*d+b-(h-2*f+d),j=2*(d-b)-2*(f-d),k=b-d,l=(-j+w.sqrt(j*j-4*i*k))/2/i,n=(-j-w.sqrt(j*j-4*i*k))/2/i,z(l)>"1e12"&&(l=.5),z(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bP(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bP(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y));return{min:{x:y[m](0,p),y:y[m](0,o)},max:{x:x[m](0,p),y:x[m](0,o)}}}),bR=a._path2curve=bv(function(a,b){var c=!b&&bz(a);if(!b&&c.curve)return bJ(c.curve);var d=bL(a),e=b&&bL(b),f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},h=function(a,b){var c,d;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null);switch(a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"][n](bO[m](0,[b.x,b.y][n](a.slice(1))));break;case"S":c=b.x+(b.x-(b.bx||b.x)),d=b.y+(b.y-(b.by||b.y)),a=["C",c,d][n](a.slice(1));break;case"T":b.qx=b.x+(b.x-(b.qx||b.x)),b.qy=b.y+(b.y-(b.qy||b.y)),a=["C"][n](bN(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"][n](bN(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"][n](bM(b.x,b.y,a[1],a[2]));break;case"H":a=["C"][n](bM(b.x,b.y,a[1],b.y));break;case"V":a=["C"][n](bM(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"][n](bM(b.x,b.y,b.X,b.Y))}return a},i=function(a,b){if(a[b].length>7){a[b].shift();var c=a[b];while(c.length)a.splice(b++,0,["C"][n](c.splice(0,6)));a.splice(b,1),l=x(d.length,e&&e.length||0)}},j=function(a,b,c,f,g){a&&b&&a[g][0]=="M"&&b[g][0]!="M"&&(b.splice(g,0,["M",f.x,f.y]),c.bx=0,c.by=0,c.x=a[g][1],c.y=a[g][2],l=x(d.length,e&&e.length||0))};for(var k=0,l=x(d.length,e&&e.length||0);k<l;k++){d[k]=h(d[k],f),i(d,k),e&&(e[k]=h(e[k],g)),e&&i(e,k),j(d,e,f,g,k),j(e,d,g,f,k);var o=d[k],p=e&&e[k],q=o.length,r=e&&p.length;f.x=o[q-2],f.y=o[q-1],f.bx=Q(o[q-4])||f.x,f.by=Q(o[q-3])||f.y,g.bx=e&&(Q(p[r-4])||g.x),g.by=e&&(Q(p[r-3])||g.y),g.x=e&&p[r-2],g.y=e&&p[r-1]}e||(c.curve=bJ(d));return e?[d,e]:d},null,bJ),bS=a._parseDots=bv(function(b){var c=[];for(var d=0,e=b.length;d<e;d++){var f={},g=b[d].match(/^([^:]*):?([\d\.]*)/);f.color=a.getRGB(g[1]);if(f.color.error)return null;f.color=f.color.hex,g[2]&&(f.offset=g[2]+"%"),c.push(f)}for(d=1,e=c.length-1;d<e;d++)if(!c[d].offset){var h=Q(c[d-1].offset||0),i=0;for(var j=d+1;j<e;j++)if(c[j].offset){i=c[j].offset;break}i||(i=100,j=e),i=Q(i);var k=(i-h)/(j-d+1);for(;d<j;d++)h+=k,c[d].offset=h+"%"}return c}),bT=a._tear=function(a,b){a==b.top&&(b.top=a.prev),a==b.bottom&&(b.bottom=a.next),a.next&&(a.next.prev=a.prev),a.prev&&(a.prev.next=a.next)},bU=a._tofront=function(a,b){b.top!==a&&(bT(a,b),a.next=null,a.prev=b.top,b.top.next=a,b.top=a)},bV=a._toback=function(a,b){b.bottom!==a&&(bT(a,b),a.next=b.bottom,a.prev=null,b.bottom.prev=a,b.bottom=a)},bW=a._insertafter=function(a,b,c){bT(a,c),b==c.top&&(c.top=a),b.next&&(b.next.prev=a),a.next=b.next,a.prev=b,b.next=a},bX=a._insertbefore=function(a,b,c){bT(a,c),b==c.bottom&&(c.bottom=a),b.prev&&(b.prev.next=a),a.prev=b.prev,b.prev=a,a.next=b},bY=a.toMatrix=function(a,b){var c=bI(a),d={_:{transform:p},getBBox:function(){return c}};b$(d,b);return d.matrix},bZ=a.transformPath=function(a,b){return bj(a,bY(a,b))},b$=a._extractTransform=function(b,c){if(c==null)return b._.transform;c=r(c).replace(/\.{3}|\u2026/g,b._.transform||p);var d=a.parseTransformString(c),e=0,f=0,g=0,h=1,i=1,j=b._,k=new cb;j.transform=d||[];if(d)for(var l=0,m=d.length;l<m;l++){var n=d[l],o=n.length,q=r(n[0]).toLowerCase(),s=n[0]!=q,t=s?k.invert():0,u,v,w,x,y;q=="t"&&o==3?s?(u=t.x(0,0),v=t.y(0,0),w=t.x(n[1],n[2]),x=t.y(n[1],n[2]),k.translate(w-u,x-v)):k.translate(n[1],n[2]):q=="r"?o==2?(y=y||b.getBBox(1),k.rotate(n[1],y.x+y.width/2,y.y+y.height/2),e+=n[1]):o==4&&(s?(w=t.x(n[2],n[3]),x=t.y(n[2],n[3]),k.rotate(n[1],w,x)):k.rotate(n[1],n[2],n[3]),e+=n[1]):q=="s"?o==2||o==3?(y=y||b.getBBox(1),k.scale(n[1],n[o-1],y.x+y.width/2,y.y+y.height/2),h*=n[1],i*=n[o-1]):o==5&&(s?(w=t.x(n[3],n[4]),x=t.y(n[3],n[4]),k.scale(n[1],n[2],w,x)):k.scale(n[1],n[2],n[3],n[4]),h*=n[1],i*=n[2]):q=="m"&&o==7&&k.add(n[1],n[2],n[3],n[4],n[5],n[6]),j.dirtyT=1,b.matrix=k}b.matrix=k,j.sx=h,j.sy=i,j.deg=e,j.dx=f=k.e,j.dy=g=k.f,h==1&&i==1&&!e&&j.bbox?(j.bbox.x+=+f,j.bbox.y+=+g):j.dirtyT=1},b_=function(a){var b=a[0];switch(b.toLowerCase()){case"t":return[b,0,0];case"m":return[b,1,0,0,1,0,0];case"r":return a.length==4?[b,0,a[2],a[3]]:[b,0];case"s":return a.length==5?[b,1,1,a[3],a[4]]:a.length==3?[b,1,1]:[b,1]}},ca=a._equaliseTransform=function(b,c){c=r(c).replace(/\.{3}|\u2026/g,b),b=a.parseTransformString(b)||[],c=a.parseTransformString(c)||[];var d=x(b.length,c.length),e=[],f=[],g=0,h,i,j,k;for(;g<d;g++){j=b[g]||b_(c[g]),k=c[g]||b_(j);if(j[0]!=k[0]||j[0].toLowerCase()=="r"&&(j[2]!=k[2]||j[3]!=k[3])||j[0].toLowerCase()=="s"&&(j[3]!=k[3]||j[4]!=k[4]))return;e[g]=[],f[g]=[];for(h=0,i=x(j.length,k.length);h<i;h++)h in j&&(e[g][h]=j[h]),h in k&&(f[g][h]=k[h])}return{from:e,to:f}};a._getContainer=function(b,c,d,e){var f;f=e==null&&!a.is(b,"object")?h.doc.getElementById(b):b;if(f!=null){if(f.tagName)return c==null?{container:f,width:f.style.pixelWidth||f.offsetWidth,height:f.style.pixelHeight||f.offsetHeight}:{container:f,width:c,height:d};return{container:1,x:b,y:c,width:d,height:e}}},a.pathToRelative=bK,a._engine={},a.path2curve=bR,a.matrix=function(a,b,c,d,e,f){return new cb(a,b,c,d,e,f)},function(b){function d(a){var b=w.sqrt(c(a));a[0]&&(a[0]/=b),a[1]&&(a[1]/=b)}function c(a){return a[0]*a[0]+a[1]*a[1]}b.add=function(a,b,c,d,e,f){var g=[[],[],[]],h=[[this.a,this.c,this.e],[this.b,this.d,this.f],[0,0,1]],i=[[a,c,e],[b,d,f],[0,0,1]],j,k,l,m;a&&a instanceof cb&&(i=[[a.a,a.c,a.e],[a.b,a.d,a.f],[0,0,1]]);for(j=0;j<3;j++)for(k=0;k<3;k++){m=0;for(l=0;l<3;l++)m+=h[j][l]*i[l][k];g[j][k]=m}this.a=g[0][0],this.b=g[1][0],this.c=g[0][1],this.d=g[1][1],this.e=g[0][2],this.f=g[1][2]},b.invert=function(){var a=this,b=a.a*a.d-a.b*a.c;return new cb(a.d/b,-a.b/b,-a.c/b,a.a/b,(a.c*a.f-a.d*a.e)/b,(a.b*a.e-a.a*a.f)/b)},b.clone=function(){return new cb(this.a,this.b,this.c,this.d,this.e,this.f)},b.translate=function(a,b){this.add(1,0,0,1,a,b)},b.scale=function(a,b,c,d){b==null&&(b=a),(c||d)&&this.add(1,0,0,1,c,d),this.add(a,0,0,b,0,0),(c||d)&&this.add(1,0,0,1,-c,-d)},b.rotate=function(b,c,d){b=a.rad(b),c=c||0,d=d||0;var e=+w.cos(b).toFixed(9),f=+w.sin(b).toFixed(9);this.add(e,f,-f,e,c,d),this.add(1,0,0,1,-c,-d)},b.x=function(a,b){return a*this.a+b*this.c+this.e},b.y=function(a,b){return a*this.b+b*this.d+this.f},b.get=function(a){return+this[r.fromCharCode(97+a)].toFixed(4)},b.toString=function(){return a.svg?"matrix("+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)].join()+")":[this.get(0),this.get(2),this.get(1),this.get(3),0,0].join()},b.toFilter=function(){return"progid:DXImageTransform.Microsoft.Matrix(M11="+this.get(0)+", M12="+this.get(2)+", M21="+this.get(1)+", M22="+this.get(3)+", Dx="+this.get(4)+", Dy="+this.get(5)+", sizingmethod='auto expand')"},b.offset=function(){return[this.e.toFixed(4),this.f.toFixed(4)]},b.split=function(){var b={};b.dx=this.e,b.dy=this.f;var e=[[this.a,this.c],[this.b,this.d]];b.scalex=w.sqrt(c(e[0])),d(e[0]),b.shear=e[0][0]*e[1][0]+e[0][1]*e[1][1],e[1]=[e[1][0]-e[0][0]*b.shear,e[1][1]-e[0][1]*b.shear],b.scaley=w.sqrt(c(e[1])),d(e[1]),b.shear/=b.scaley;var f=-e[0][1],g=e[1][1];g<0?(b.rotate=a.deg(w.acos(g)),f<0&&(b.rotate=360-b.rotate)):b.rotate=a.deg(w.asin(f)),b.isSimple=!+b.shear.toFixed(9)&&(b.scalex.toFixed(9)==b.scaley.toFixed(9)||!b.rotate),b.isSuperSimple=!+b.shear.toFixed(9)&&b.scalex.toFixed(9)==b.scaley.toFixed(9)&&!b.rotate,b.noRotation=!+b.shear.toFixed(9)&&!b.rotate;return b},b.toTransformString=function(a){var b=a||this[s]();if(b.isSimple){b.scalex=+b.scalex.toFixed(4),b.scaley=+b.scaley.toFixed(4),b.rotate=+b.rotate.toFixed(4);return(b.dx||b.dy?"t"+[b.dx,b.dy]:p)+(b.scalex!=1||b.scaley!=1?"s"+[b.scalex,b.scaley,0,0]:p)+(b.rotate?"r"+[b.rotate,0,0]:p)}return"m"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)]}}(cb.prototype);var cc=navigator.userAgent.match(/Version\/(.*?)\s/)||navigator.userAgent.match(/Chrome\/(\d+)/);navigator.vendor=="Apple Computer, Inc."&&(cc&&cc[1]<4||navigator.platform.slice(0,2)=="iP")||navigator.vendor=="Google Inc."&&cc&&cc[1]<8?k.safari=function(){var a=this.rect(-99,-99,this.width+99,this.height+99).attr({stroke:"none"});setTimeout(function(){a.remove()})}:k.safari=be;var cd=function(){this.returnValue=!1},ce=function(){return this.originalEvent.preventDefault()},cf=function(){this.cancelBubble=!0},cg=function(){return this.originalEvent.stopPropagation()},ch=function(){if(h.doc.addEventListener)return function(a,b,c,d){var e=o&&u[b]?u[b]:b,f=function(e){var f=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,i=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft,j=e.clientX+i,k=e.clientY+f;if(o&&u[g](b))for(var l=0,m=e.targetTouches&&e.targetTouches.length;l<m;l++)if(e.targetTouches[l].target==a){var n=e;e=e.targetTouches[l],e.originalEvent=n,e.preventDefault=ce,e.stopPropagation=cg;break}return c.call(d,e,j,k)};a.addEventListener(e,f,!1);return function(){a.removeEventListener(e,f,!1);return!0}};if(h.doc.attachEvent)return function(a,b,c,d){var e=function(a){a=a||h.win.event;var b=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,e=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft,f=a.clientX+e,g=a.clientY+b;a.preventDefault=a.preventDefault||cd,a.stopPropagation=a.stopPropagation||cf;return c.call(d,a,f,g)};a.attachEvent("on"+b,e);var f=function(){a.detachEvent("on"+b,e);return!0};return f}}(),ci=[],cj=function(a){var b=a.clientX,c=a.clientY,d=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,e=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft,f,g=ci.length;while(g--){f=ci[g];if(o){var i=a.touches.length,j;while(i--){j=a.touches[i];if(j.identifier==f.el._drag.id){b=j.clientX,c=j.clientY,(a.originalEvent?a.originalEvent:a).preventDefault();break}}}else a.preventDefault();var k=f.el.node,l,m=k.nextSibling,n=k.parentNode,p=k.style.display;h.win.opera&&n.removeChild(k),k.style.display="none",l=f.el.paper.getElementByPoint(b,c),k.style.display=p,h.win.opera&&(m?n.insertBefore(k,m):n.appendChild(k)),l&&eve("raphael.drag.over."+f.el.id,f.el,l),b+=e,c+=d,eve("raphael.drag.move."+f.el.id,f.move_scope||f.el,b-f.el._drag.x,c-f.el._drag.y,b,c,a)}},ck=function(b){a.unmousemove(cj).unmouseup(ck);var c=ci.length,d;while(c--)d=ci[c],d.el._drag={},eve("raphael.drag.end."+d.el.id,d.end_scope||d.start_scope||d.move_scope||d.el,b);ci=[]},cl=a.el={};for(var cm=t.length;cm--;)(function(b){a[b]=cl[b]=function(c,d){a.is(c,"function")&&(this.events=this.events||[],this.events.push({name:b,f:c,unbind:ch(this.shape||this.node||h.doc,b,c,d||this)}));return this},a["un"+b]=cl["un"+b]=function(a){var c=this.events||[],d=c.length;while(d--)if(c[d].name==b&&c[d].f==a){c[d].unbind(),c.splice(d,1),!c.length&&delete this.events;return this}return this}})(t[cm]);cl.data=function(b,c){var d=bb[this.id]=bb[this.id]||{};if(arguments.length==1){if(a.is(b,"object")){for(var e in b)b[g](e)&&this.data(e,b[e]);return this}eve("raphael.data.get."+this.id,this,d[b],b);return d[b]}d[b]=c,eve("raphael.data.set."+this.id,this,c,b);return this},cl.removeData=function(a){a==null?bb[this.id]={}:bb[this.id]&&delete bb[this.id][a];return this},cl.hover=function(a,b,c,d){return this.mouseover(a,c).mouseout(b,d||c)},cl.unhover=function(a,b){return this.unmouseover(a).unmouseout(b)};var cn=[];cl.drag=function(b,c,d,e,f,g){function i(i){(i.originalEvent||i).preventDefault();var j=h.doc.documentElement.scrollTop||h.doc.body.scrollTop,k=h.doc.documentElement.scrollLeft||h.doc.body.scrollLeft;this._drag.x=i.clientX+k,this._drag.y=i.clientY+j,this._drag.id=i.identifier,!ci.length&&a.mousemove(cj).mouseup(ck),ci.push({el:this,move_scope:e,start_scope:f,end_scope:g}),c&&eve.on("raphael.drag.start."+this.id,c),b&&eve.on("raphael.drag.move."+this.id,b),d&&eve.on("raphael.drag.end."+this.id,d),eve("raphael.drag.start."+this.id,f||e||this,i.clientX+k,i.clientY+j,i)}this._drag={},cn.push({el:this,start:i}),this.mousedown(i);return this},cl.onDragOver=function(a){a?eve.on("raphael.drag.over."+this.id,a):eve.unbind("raphael.drag.over."+this.id)},cl.undrag=function(){var b=cn.length;while(b--)cn[b].el==this&&(this.unmousedown(cn[b].start),cn.splice(b,1),eve.unbind("raphael.drag.*."+this.id));!cn.length&&a.unmousemove(cj).unmouseup(ck)},k.circle=function(b,c,d){var e=a._engine.circle(this,b||0,c||0,d||0);this.__set__&&this.__set__.push(e);return e},k.rect=function(b,c,d,e,f){var g=a._engine.rect(this,b||0,c||0,d||0,e||0,f||0);this.__set__&&this.__set__.push(g);return g},k.ellipse=function(b,c,d,e){var f=a._engine.ellipse(this,b||0,c||0,d||0,e||0);this.__set__&&this.__set__.push(f);return f},k.path=function(b){b&&!a.is(b,D)&&!a.is(b[0],E)&&(b+=p);var c=a._engine.path(a.format[m](a,arguments),this);this.__set__&&this.__set__.push(c);return c},k.image=function(b,c,d,e,f){var g=a._engine.image(this,b||"about:blank",c||0,d||0,e||0,f||0);this.__set__&&this.__set__.push(g);return g},k.text=function(b,c,d){var e=a._engine.text(this,b||0,c||0,r(d));this.__set__&&this.__set__.push(e);return e},k.set=function(b){!a.is(b,"array")&&(b=Array.prototype.splice.call(arguments,0,arguments.length));var c=new cG(b);this.__set__&&this.__set__.push(c);return c},k.setStart=function(a){this.__set__=a||this.set()},k.setFinish=function(a){var b=this.__set__;delete this.__set__;return b},k.setSize=function(b,c){return a._engine.setSize.call(this,b,c)},k.setViewBox=function(b,c,d,e,f){return a._engine.setViewBox.call(this,b,c,d,e,f)},k.top=k.bottom=null,k.raphael=a;var co=function(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.body,e=c.documentElement,f=e.clientTop||d.clientTop||0,g=e.clientLeft||d.clientLeft||0,i=b.top+(h.win.pageYOffset||e.scrollTop||d.scrollTop)-f,j=b.left+(h.win.pageXOffset||e.scrollLeft||d.scrollLeft)-g;return{y:i,x:j}};k.getElementByPoint=function(a,b){var c=this,d=c.canvas,e=h.doc.elementFromPoint(a,b);if(h.win.opera&&e.tagName=="svg"){var f=co(d),g=d.createSVGRect();g.x=a-f.x,g.y=b-f.y,g.width=g.height=1;var i=d.getIntersectionList(g,null);i.length&&(e=i[i.length-1])}if(!e)return null;while(e.parentNode&&e!=d.parentNode&&!e.raphael)e=e.parentNode;e==c.canvas.parentNode&&(e=d),e=e&&e.raphael?c.getById(e.raphaelid):null;return e},k.getById=function(a){var b=this.bottom;while(b){if(b.id==a)return b;b=b.next}return null},k.forEach=function(a,b){var c=this.bottom;while(c){if(a.call(b,c)===!1)return this;c=c.next}return this},k.getElementsByPoint=function(a,b){var c=this.set();this.forEach(function(d){d.isPointInside(a,b)&&c.push(d)});return c},cl.isPointInside=function(b,c){var d=this.realPath=this.realPath||bi[this.type](this);return a.isPointInsidePath(d,b,c)},cl.getBBox=function(a){if(this.removed)return{};var b=this._;if(a){if(b.dirty||!b.bboxwt)this.realPath=bi[this.type](this),b.bboxwt=bI(this.realPath),b.bboxwt.toString=cq,b.dirty=0;return b.bboxwt}if(b.dirty||b.dirtyT||!b.bbox){if(b.dirty||!this.realPath)b.bboxwt=0,this.realPath=bi[this.type](this);b.bbox=bI(bj(this.realPath,this.matrix)),b.bbox.toString=cq,b.dirty=b.dirtyT=0}return b.bbox},cl.clone=function(){if(this.removed)return null;var a=this.paper[this.type]().attr(this.attr());this.__set__&&this.__set__.push(a);return a},cl.glow=function(a){if(this.type=="text")return null;a=a||{};var b={width:(a.width||10)+(+this.attr("stroke-width")||1),fill:a.fill||!1,opacity:a.opacity||.5,offsetx:a.offsetx||0,offsety:a.offsety||0,color:a.color||"#000"},c=b.width/2,d=this.paper,e=d.set(),f=this.realPath||bi[this.type](this);f=this.matrix?bj(f,this.matrix):f;for(var g=1;g<c+1;g++)e.push(d.path(f).attr({stroke:b.color,fill:b.fill?b.color:"none","stroke-linejoin":"round","stroke-linecap":"round","stroke-width":+(b.width/c*g).toFixed(3),opacity:+(b.opacity/c).toFixed(3)}));return e.insertBefore(this).translate(b.offsetx,b.offsety)};var cr={},cs=function(b,c,d,e,f,g,h,i,j){return j==null?bB(b,c,d,e,f,g,h,i):a.findDotsAtSegment(b,c,d,e,f,g,h,i,bC(b,c,d,e,f,g,h,i,j))},ct=function(b,c){return function(d,e,f){d=bR(d);var g,h,i,j,k="",l={},m,n=0;for(var o=0,p=d.length;o<p;o++){i=d[o];if(i[0]=="M")g=+i[1],h=+i[2];else{j=cs(g,h,i[1],i[2],i[3],i[4],i[5],i[6]);if(n+j>e){if(c&&!l.start){m=cs(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),k+=["C"+m.start.x,m.start.y,m.m.x,m.m.y,m.x,m.y];if(f)return k;l.start=k,k=["M"+m.x,m.y+"C"+m.n.x,m.n.y,m.end.x,m.end.y,i[5],i[6]].join(),n+=j,g=+i[5],h=+i[6];continue}if(!b&&!c){m=cs(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);return{x:m.x,y:m.y,alpha:m.alpha}}}n+=j,g=+i[5],h=+i[6]}k+=i.shift()+i}l.end=k,m=b?n:c?l:a.findDotsAtSegment(g,h,i[0],i[1],i[2],i[3],i[4],i[5],1),m.alpha&&(m={x:m.x,y:m.y,alpha:m.alpha});return m}},cu=ct(1),cv=ct(),cw=ct(0,1);a.getTotalLength=cu,a.getPointAtLength=cv,a.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return cw(a,b).end;var d=cw(a,c,1);return b?cw(d,b).end:d},cl.getTotalLength=function(){if(this.type=="path"){if(this.node.getTotalLength)return this.node.getTotalLength();return cu(this.attrs.path)}},cl.getPointAtLength=function(a){if(this.type=="path")return cv(this.attrs.path,a)},cl.getSubpath=function(b,c){if(this.type=="path")return a.getSubpath(this.attrs.path,b,c)};var cx=a.easing_formulas={linear:function(a){return a},"<":function(a){return A(a,1.7)},">":function(a){return A(a,.48)},"<>":function(a){var b=.48-a/1.04,c=w.sqrt(.1734+b*b),d=c-b,e=A(z(d),1/3)*(d<0?-1:1),f=-c-b,g=A(z(f),1/3)*(f<0?-1:1),h=e+g+.5;return(1-h)*3*h*h+h*h*h},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a=a-1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){if(a==!!a)return a;return A(2,-10*a)*w.sin((a-.075)*2*B/.3)+1},bounce:function(a){var b=7.5625,c=2.75,d;a<1/c?d=b*a*a:a<2/c?(a-=1.5/c,d=b*a*a+.75):a<2.5/c?(a-=2.25/c,d=b*a*a+.9375):(a-=2.625/c,d=b*a*a+.984375);return d}};cx.easeIn=cx["ease-in"]=cx["<"],cx.easeOut=cx["ease-out"]=cx[">"],cx.easeInOut=cx["ease-in-out"]=cx["<>"],cx["back-in"]=cx.backIn,cx["back-out"]=cx.backOut;var cy=[],cz=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){setTimeout(a,16)},cA=function(){var b=+(new Date),c=0;for(;c<cy.length;c++){var d=cy[c];if(d.el.removed||d.paused)continue;var e=b-d.start,f=d.ms,h=d.easing,i=d.from,j=d.diff,k=d.to,l=d.t,m=d.el,o={},p,r={},s;d.initstatus?(e=(d.initstatus*d.anim.top-d.prev)/(d.percent-d.prev)*f,d.status=d.initstatus,delete d.initstatus,d.stop&&cy.splice(c--,1)):d.status=(d.prev+(d.percent-d.prev)*(e/f))/d.anim.top;if(e<0)continue;if(e<f){var t=h(e/f);for(var u in i)if(i[g](u)){switch(U[u]){case C:p=+i[u]+t*f*j[u];break;case"colour":p="rgb("+[cB(O(i[u].r+t*f*j[u].r)),cB(O(i[u].g+t*f*j[u].g)),cB(O(i[u].b+t*f*j[u].b))].join(",")+")";break;case"path":p=[];for(var v=0,w=i[u].length;v<w;v++){p[v]=[i[u][v][0]];for(var x=1,y=i[u][v].length;x<y;x++)p[v][x]=+i[u][v][x]+t*f*j[u][v][x];p[v]=p[v].join(q)}p=p.join(q);break;case"transform":if(j[u].real){p=[];for(v=0,w=i[u].length;v<w;v++){p[v]=[i[u][v][0]];for(x=1,y=i[u][v].length;x<y;x++)p[v][x]=i[u][v][x]+t*f*j[u][v][x]}}else{var z=function(a){return+i[u][a]+t*f*j[u][a]};p=[["m",z(0),z(1),z(2),z(3),z(4),z(5)]]}break;case"csv":if(u=="clip-rect"){p=[],v=4;while(v--)p[v]=+i[u][v]+t*f*j[u][v]}break;default:var A=[][n](i[u]);p=[],v=m.paper.customAttributes[u].length;while(v--)p[v]=+A[v]+t*f*j[u][v]}o[u]=p}m.attr(o),function(a,b,c){setTimeout(function(){eve("raphael.anim.frame."+a,b,c)})}(m.id,m,d.anim)}else{(function(b,c,d){setTimeout(function(){eve("raphael.anim.frame."+c.id,c,d),eve("raphael.anim.finish."+c.id,c,d),a.is(b,"function")&&b.call(c)})})(d.callback,m,d.anim),m.attr(k),cy.splice(c--,1);if(d.repeat>1&&!d.next){for(s in k)k[g](s)&&(r[s]=d.totalOrigin[s]);d.el.attr(r),cE(d.anim,d.el,d.anim.percents[0],null,d.totalOrigin,d.repeat-1)}d.next&&!d.stop&&cE(d.anim,d.el,d.next,null,d.totalOrigin,d.repeat)}}a.svg&&m&&m.paper&&m.paper.safari(),cy.length&&cz(cA)},cB=function(a){return a>255?255:a<0?0:a};cl.animateWith=function(b,c,d,e,f,g){var h=this;if(h.removed){g&&g.call(h);return h}var i=d instanceof cD?d:a.animation(d,e,f,g),j,k;cE(i,h,i.percents[0],null,h.attr());for(var l=0,m=cy.length;l<m;l++)if(cy[l].anim==c&&cy[l].el==b){cy[m-1].start=cy[l].start;break}return h},cl.onAnimation=function(a){a?eve.on("raphael.anim.frame."+this.id,a):eve.unbind("raphael.anim.frame."+this.id);return this},cD.prototype.delay=function(a){var b=new cD(this.anim,this.ms);b.times=this.times,b.del=+a||0;return b},cD.prototype.repeat=function(a){var b=new cD(this.anim,this.ms);b.del=this.del,b.times=w.floor(x(a,0))||1;return b},a.animation=function(b,c,d,e){if(b instanceof cD)return b;if(a.is(d,"function")||!d)e=e||d||null,d=null;b=Object(b),c=+c||0;var f={},h,i;for(i in b)b[g](i)&&Q(i)!=i&&Q(i)+"%"!=i&&(h=!0,f[i]=b[i]);if(!h)return new cD(b,c);d&&(f.easing=d),e&&(f.callback=e);return new cD({100:f},c)},cl.animate=function(b,c,d,e){var f=this;if(f.removed){e&&e.call(f);return f}var g=b instanceof cD?b:a.animation(b,c,d,e);cE(g,f,g.percents[0],null,f.attr());return f},cl.setTime=function(a,b){a&&b!=null&&this.status(a,y(b,a.ms)/a.ms);return this},cl.status=function(a,b){var c=[],d=0,e,f;if(b!=null){cE(a,this,-1,y(b,1));return this}e=cy.length;for(;d<e;d++){f=cy[d];if(f.el.id==this.id&&(!a||f.anim==a)){if(a)return f.status;c.push({anim:f.anim,status:f.status})}}if(a)return 0;return c},cl.pause=function(a){for(var b=0;b<cy.length;b++)cy[b].el.id==this.id&&(!a||cy[b].anim==a)&&eve("raphael.anim.pause."+this.id,this,cy[b].anim)!==!1&&(cy[b].paused=!0);return this},cl.resume=function(a){for(var b=0;b<cy.length;b++)if(cy[b].el.id==this.id&&(!a||cy[b].anim==a)){var c=cy[b];eve("raphael.anim.resume."+this.id,this,c.anim)!==!1&&(delete c.paused,this.status(c.anim,c.status))}return this},cl.stop=function(a){for(var b=0;b<cy.length;b++)cy[b].el.id==this.id&&(!a||cy[b].anim==a)&&eve("raphael.anim.stop."+this.id,this,cy[b].anim)!==!1&&cy.splice(b--,1);return this},eve.on("raphael.remove",cF),eve.on("raphael.clear",cF),cl.toString=function(){return"Raphaël’s object"};var cG=function(a){this.items=[],this.length=0,this.type="set";if(a)for(var b=0,c=a.length;b<c;b++)a[b]&&(a[b].constructor==cl.constructor||a[b].constructor==cG)&&(this[this.items.length]=this.items[this.items.length]=a[b],this.length++)},cH=cG.prototype;cH.push=function(){var a,b;for(var c=0,d=arguments.length;c<d;c++)a=arguments[c],a&&(a.constructor==cl.constructor||a.constructor==cG)&&(b=this.items.length,this[b]=this.items[b]=a,this.length++);return this},cH.pop=function(){this.length&&delete this[this.length--];return this.items.pop()},cH.forEach=function(a,b){for(var c=0,d=this.items.length;c<d;c++)if(a.call(b,this.items[c],c)===!1)return this;return this};for(var cI in cl)cl[g](cI)&&(cH[cI]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a][m](c,b)})}}(cI));cH.attr=function(b,c){if(b&&a.is(b,E)&&a.is(b[0],"object"))for(var d=0,e=b.length;d<e;d++)this.items[d].attr(b[d]);else for(var f=0,g=this.items.length;f<g;f++)this.items[f].attr(b,c);return this},cH.clear=function(){while(this.length)this.pop()},cH.splice=function(a,b,c){a=a<0?x(this.length+a,0):a,b=x(0,y(this.length-a,b));var d=[],e=[],f=[],g;for(g=2;g<arguments.length;g++)f.push(arguments[g]);for(g=0;g<b;g++)e.push(this[a+g]);for(;g<this.length-a;g++)d.push(this[a+g]);var h=f.length;for(g=0;g<h+d.length;g++)this.items[a+g]=this[a+g]=g<h?f[g]:d[g-h];g=this.items.length=this.length-=b-h;while(this[g])delete this[g++];return new cG(e)},cH.exclude=function(a){for(var b=0,c=this.length;b<c;b++)if(this[b]==a){this.splice(b,1);return!0}},cH.animate=function(b,c,d,e){(a.is(d,"function")||!d)&&(e=d||null);var f=this.items.length,g=f,h,i=this,j;if(!f)return this;e&&(j=function(){!--f&&e.call(i)}),d=a.is(d,D)?d:j;var k=a.animation(b,c,d,j);h=this.items[--g].animate(k);while(g--)this.items[g]&&!this.items[g].removed&&this.items[g].animateWith(h,k,k);return this},cH.insertAfter=function(a){var b=this.items.length;while(b--)this.items[b].insertAfter(a);return this},cH.getBBox=function(){var a=[],b=[],c=[],d=[];for(var e=this.items.length;e--;)if(!this.items[e].removed){var f=this.items[e].getBBox();a.push(f.x),b.push(f.y),c.push(f.x+f.width),d.push(f.y+f.height)}a=y[m](0,a),b=y[m](0,b),c=x[m](0,c),d=x[m](0,d);return{x:a,y:b,x2:c,y2:d,width:c-a,height:d-b}},cH.clone=function(a){a=new cG;for(var b=0,c=this.items.length;b<c;b++)a.push(this.items[b].clone());return a},cH.toString=function(){return"Raphaël‘s set"},a.registerFont=function(a){if(!a.face)return a;this.fonts=this.fonts||{};var b={w:a.w,face:{},glyphs:{}},c=a.face["font-family"];for(var d in a.face)a.face[g](d)&&(b.face[d]=a.face[d]);this.fonts[c]?this.fonts[c].push(b):this.fonts[c]=[b];if(!a.svg){b.face["units-per-em"]=R(a.face["units-per-em"],10);for(var e in a.glyphs)if(a.glyphs[g](e)){var f=a.glyphs[e];b.glyphs[e]={w:f.w,k:{},d:f.d&&"M"+f.d.replace(/[mlcxtrv]/g,function(a){return{l:"L",c:"C",x:"z",t:"m",r:"l",v:"c"}[a]||"M"})+"z"};if(f.k)for(var h in f.k)f[g](h)&&(b.glyphs[e].k[h]=f.k[h])}}return a},k.getFont=function(b,c,d,e){e=e||"normal",d=d||"normal",c=+c||{normal:400,bold:700,lighter:300,bolder:800}[c]||400;if(!!a.fonts){var f=a.fonts[b];if(!f){var h=new RegExp("(^|\\s)"+b.replace(/[^\w\d\s+!~.:_-]/g,p)+"(\\s|$)","i");for(var i in a.fonts)if(a.fonts[g](i)&&h.test(i)){f=a.fonts[i];break}}var j;if(f)for(var k=0,l=f.length;k<l;k++){j=f[k];if(j.face["font-weight"]==c&&(j.face["font-style"]==d||!j.face["font-style"])&&j.face["font-stretch"]==e)break}return j}},k.print=function(b,d,e,f,g,h,i){h=h||"middle",i=x(y(i||0,1),-1);var j=r(e)[s](p),k=0,l=0,m=p,n;a.is(f,e)&&(f=this.getFont(f));if(f){n=(g||16)/f.face["units-per-em"];var o=f.face.bbox[s](c),q=+o[0],t=o[3]-o[1],u=0,v=+o[1]+(h=="baseline"?t+ +f.face.descent:t/2);for(var w=0,z=j.length;w<z;w++){if(j[w]=="\n")k=0,B=0,l=0,u+=t;else{var A=l&&f.glyphs[j[w-1]]||{},B=f.glyphs[j[w]];k+=l?(A.w||f.w)+(A.k&&A.k[j[w]]||0)+f.w*i:0,l=1}B&&B.d&&(m+=a.transformPath(B.d,["t",k*n,u*n,"s",n,n,q,v,"t",(b-q)/n,(d-v)/n]))}}return this.path(m).attr({fill:"#000",stroke:"none"})},k.add=function(b){if(a.is(b,"array")){var c=this.set(),e=0,f=b.length,h;for(;e<f;e++)h=b[e]||{},d[g](h.type)&&c.push(this[h.type]().attr(h))}return c},a.format=function(b,c){var d=a.is(c,E)?[0][n](c):arguments;b&&a.is(b,D)&&d.length-1&&(b=b.replace(e,function(a,b){return d[++b]==null?p:d[b]}));return b||p},a.fullfill=function(){var a=/\{([^\}]+)\}/g,b=/(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g,c=function(a,c,d){var e=d;c.replace(b,function(a,b,c,d,f){b=b||d,e&&(b in e&&(e=e[b]),typeof e=="function"&&f&&(e=e()))}),e=(e==null||e==d?a:e)+"";return e};return function(b,d){return String(b).replace(a,function(a,b){return c(a,b,d)})}}(),a.ninja=function(){i.was?h.win.Raphael=i.is:delete Raphael;return a},a.st=cH,function(b,c,d){function e(){/in/.test(b.readyState)?setTimeout(e,9):a.eve("raphael.DOMload")}b.readyState==null&&b.addEventListener&&(b.addEventListener(c,d=function(){b.removeEventListener(c,d,!1),b.readyState="complete"},!1),b.readyState="loading"),e()}(document,"DOMContentLoaded"),i.was?h.win.Raphael=a:Raphael=a,eve.on("raphael.DOMload",function(){b=!0})}(),window.Raphael.svg&&function(a){var b="hasOwnProperty",c=String,d=parseFloat,e=parseInt,f=Math,g=f.max,h=f.abs,i=f.pow,j=/[, ]+/,k=a.eve,l="",m=" ",n="http://www.w3.org/1999/xlink",o={block:"M5,0 0,2.5 5,5z",classic:"M5,0 0,2.5 5,5 3.5,3 3.5,2z",diamond:"M2.5,0 5,2.5 2.5,5 0,2.5z",open:"M6,1 1,3.5 6,6",oval:"M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"},p={};a.toString=function(){return"Your browser supports SVG.\nYou are running Raphaël "+this.version};var q=function(d,e){if(e){typeof d=="string"&&(d=q(d));for(var f in e)e[b](f)&&(f.substring(0,6)=="xlink:"?d.setAttributeNS(n,f.substring(6),c(e[f])):d.setAttribute(f,c(e[f])))}else d=a._g.doc.createElementNS("http://www.w3.org/2000/svg",d),d.style&&(d.style.webkitTapHighlightColor="rgba(0,0,0,0)");return d},r=function(b,e){var j="linear",k=b.id+e,m=.5,n=.5,o=b.node,p=b.paper,r=o.style,s=a._g.doc.getElementById(k);if(!s){e=c(e).replace(a._radial_gradient,function(a,b,c){j="radial";if(b&&c){m=d(b),n=d(c);var e=(n>.5)*2-1;i(m-.5,2)+i(n-.5,2)>.25&&(n=f.sqrt(.25-i(m-.5,2))*e+.5)&&n!=.5&&(n=n.toFixed(5)-1e-5*e)}return l}),e=e.split(/\s*\-\s*/);if(j=="linear"){var t=e.shift();t=-d(t);if(isNaN(t))return null;var u=[0,0,f.cos(a.rad(t)),f.sin(a.rad(t))],v=1/(g(h(u[2]),h(u[3]))||1);u[2]*=v,u[3]*=v,u[2]<0&&(u[0]=-u[2],u[2]=0),u[3]<0&&(u[1]=-u[3],u[3]=0)}var w=a._parseDots(e);if(!w)return null;k=k.replace(/[\(\)\s,\xb0#]/g,"_"),b.gradient&&k!=b.gradient.id&&(p.defs.removeChild(b.gradient),delete b.gradient);if(!b.gradient){s=q(j+"Gradient",{id:k}),b.gradient=s,q(s,j=="radial"?{fx:m,fy:n}:{x1:u[0],y1:u[1],x2:u[2],y2:u[3],gradientTransform:b.matrix.invert()}),p.defs.appendChild(s);for(var x=0,y=w.length;x<y;x++)s.appendChild(q("stop",{offset:w[x].offset?w[x].offset:x?"100%":"0%","stop-color":w[x].color||"#fff"}))}}q(o,{fill:"url(#"+k+")",opacity:1,"fill-opacity":1}),r.fill=l,r.opacity=1,r.fillOpacity=1;return 1},s=function(a){var b=a.getBBox(1);q(a.pattern,{patternTransform:a.matrix.invert()+" translate("+b.x+","+b.y+")"})},t=function(d,e,f){if(d.type=="path"){var g=c(e).toLowerCase().split("-"),h=d.paper,i=f?"end":"start",j=d.node,k=d.attrs,m=k["stroke-width"],n=g.length,r="classic",s,t,u,v,w,x=3,y=3,z=5;while(n--)switch(g[n]){case"block":case"classic":case"oval":case"diamond":case"open":case"none":r=g[n];break;case"wide":y=5;break;case"narrow":y=2;break;case"long":x=5;break;case"short":x=2}r=="open"?(x+=2,y+=2,z+=2,u=1,v=f?4:1,w={fill:"none",stroke:k.stroke}):(v=u=x/2,w={fill:k.stroke,stroke:"none"}),d._.arrows?f?(d._.arrows.endPath&&p[d._.arrows.endPath]--,d._.arrows.endMarker&&p[d._.arrows.endMarker]--):(d._.arrows.startPath&&p[d._.arrows.startPath]--,d._.arrows.startMarker&&p[d._.arrows.startMarker]--):d._.arrows={};if(r!="none"){var A="raphael-marker-"+r,B="raphael-marker-"+i+r+x+y;a._g.doc.getElementById(A)?p[A]++:(h.defs.appendChild(q(q("path"),{"stroke-linecap":"round",d:o[r],id:A})),p[A]=1);var C=a._g.doc.getElementById(B),D;C?(p[B]++,D=C.getElementsByTagName("use")[0]):(C=q(q("marker"),{id:B,markerHeight:y,markerWidth:x,orient:"auto",refX:v,refY:y/2}),D=q(q("use"),{"xlink:href":"#"+A,transform:(f?"rotate(180 "+x/2+" "+y/2+") ":l)+"scale("+x/z+","+y/z+")","stroke-width":(1/((x/z+y/z)/2)).toFixed(4)}),C.appendChild(D),h.defs.appendChild(C),p[B]=1),q(D,w);var F=u*(r!="diamond"&&r!="oval");f?(s=d._.arrows.startdx*m||0,t=a.getTotalLength(k.path)-F*m):(s=F*m,t=a.getTotalLength(k.path)-(d._.arrows.enddx*m||0)),w={},w["marker-"+i]="url(#"+B+")";if(t||s)w.d=Raphael.getSubpath(k.path,s,t);q(j,w),d._.arrows[i+"Path"]=A,d._.arrows[i+"Marker"]=B,d._.arrows[i+"dx"]=F,d._.arrows[i+"Type"]=r,d._.arrows[i+"String"]=e}else f?(s=d._.arrows.startdx*m||0,t=a.getTotalLength(k.path)-s):(s=0,t=a.getTotalLength(k.path)-(d._.arrows.enddx*m||0)),d._.arrows[i+"Path"]&&q(j,{d:Raphael.getSubpath(k.path,s,t)}),delete d._.arrows[i+"Path"],delete d._.arrows[i+"Marker"],delete d._.arrows[i+"dx"],delete d._.arrows[i+"Type"],delete d._.arrows[i+"String"];for(w in p)if(p[b](w)&&!p[w]){var G=a._g.doc.getElementById(w);G&&G.parentNode.removeChild(G)}}},u={"":[0],none:[0],"-":[3,1],".":[1,1],"-.":[3,1,1,1],"-..":[3,1,1,1,1,1],". ":[1,3],"- ":[4,3],"--":[8,3],"- .":[4,3,1,3],"--.":[8,3,1,3],"--..":[8,3,1,3,1,3]},v=function(a,b,d){b=u[c(b).toLowerCase()];if(b){var e=a.attrs["stroke-width"]||"1",f={round:e,square:e,butt:0}[a.attrs["stroke-linecap"]||d["stroke-linecap"]]||0,g=[],h=b.length;while(h--)g[h]=b[h]*e+(h%2?1:-1)*f;q(a.node,{"stroke-dasharray":g.join(",")})}},w=function(d,f){var i=d.node,k=d.attrs,m=i.style.visibility;i.style.visibility="hidden";for(var o in f)if(f[b](o)){if(!a._availableAttrs[b](o))continue;var p=f[o];k[o]=p;switch(o){case"blur":d.blur(p);break;case"href":case"title":case"target":var u=i.parentNode;if(u.tagName.toLowerCase()!="a"){var w=q("a");u.insertBefore(w,i),w.appendChild(i),u=w}o=="target"?u.setAttributeNS(n,"show",p=="blank"?"new":p):u.setAttributeNS(n,o,p);break;case"cursor":i.style.cursor=p;break;case"transform":d.transform(p);break;case"arrow-start":t(d,p);break;case"arrow-end":t(d,p,1);break;case"clip-rect":var x=c(p).split(j);if(x.length==4){d.clip&&d.clip.parentNode.parentNode.removeChild(d.clip.parentNode);var z=q("clipPath"),A=q("rect");z.id=a.createUUID(),q(A,{x:x[0],y:x[1],width:x[2],height:x[3]}),z.appendChild(A),d.paper.defs.appendChild(z),q(i,{"clip-path":"url(#"+z.id+")"}),d.clip=A}if(!p){var B=i.getAttribute("clip-path");if(B){var C=a._g.doc.getElementById(B.replace(/(^url\(#|\)$)/g,l));C&&C.parentNode.removeChild(C),q(i,{"clip-path":l}),delete d.clip}}break;case"path":d.type=="path"&&(q(i,{d:p?k.path=a._pathToAbsolute(p):"M0,0"}),d._.dirty=1,d._.arrows&&("startString"in d._.arrows&&t(d,d._.arrows.startString),"endString"in d._.arrows&&t(d,d._.arrows.endString,1)));break;case"width":i.setAttribute(o,p),d._.dirty=1;if(k.fx)o="x",p=k.x;else break;case"x":k.fx&&(p=-k.x-(k.width||0));case"rx":if(o=="rx"&&d.type=="rect")break;case"cx":i.setAttribute(o,p),d.pattern&&s(d),d._.dirty=1;break;case"height":i.setAttribute(o,p),d._.dirty=1;if(k.fy)o="y",p=k.y;else break;case"y":k.fy&&(p=-k.y-(k.height||0));case"ry":if(o=="ry"&&d.type=="rect")break;case"cy":i.setAttribute(o,p),d.pattern&&s(d),d._.dirty=1;break;case"r":d.type=="rect"?q(i,{rx:p,ry:p}):i.setAttribute(o,p),d._.dirty=1;break;case"src":d.type=="image"&&i.setAttributeNS(n,"href",p);break;case"stroke-width":if(d._.sx!=1||d._.sy!=1)p/=g(h(d._.sx),h(d._.sy))||1;d.paper._vbSize&&(p*=d.paper._vbSize),i.setAttribute(o,p),k["stroke-dasharray"]&&v(d,k["stroke-dasharray"],f),d._.arrows&&("startString"in d._.arrows&&t(d,d._.arrows.startString),"endString"in d._.arrows&&t(d,d._.arrows.endString,1));break;case"stroke-dasharray":v(d,p,f);break;case"fill":var D=c(p).match(a._ISURL);if(D){z=q("pattern");var F=q("image");z.id=a.createUUID(),q(z,{x:0,y:0,patternUnits:"userSpaceOnUse",height:1,width:1}),q(F,{x:0,y:0,"xlink:href":D[1]}),z.appendChild(F),function(b){a._preload(D[1],function(){var a=this.offsetWidth,c=this.offsetHeight;q(b,{width:a,height:c}),q(F,{width:a,height:c}),d.paper.safari()})}(z),d.paper.defs.appendChild(z),q(i,{fill:"url(#"+z.id+")"}),d.pattern=z,d.pattern&&s(d);break}var G=a.getRGB(p);if(!G.error)delete f.gradient,delete k.gradient,!a.is(k.opacity,"undefined")&&a.is(f.opacity,"undefined")&&q(i,{opacity:k.opacity}),!a.is(k["fill-opacity"],"undefined")&&a.is(f["fill-opacity"],"undefined")&&q(i,{"fill-opacity":k["fill-opacity"]});else if((d.type=="circle"||d.type=="ellipse"||c(p).charAt()!="r")&&r(d,p)){if("opacity"in k||"fill-opacity"in k){var H=a._g.doc.getElementById(i.getAttribute("fill").replace(/^url\(#|\)$/g,l));if(H){var I=H.getElementsByTagName("stop");q(I[I.length-1],{"stop-opacity":("opacity"in k?k.opacity:1)*("fill-opacity"in k?k["fill-opacity"]:1)})}}k.gradient=p,k.fill="none";break}G[b]("opacity")&&q(i,{"fill-opacity":G.opacity>1?G.opacity/100:G.opacity});case"stroke":G=a.getRGB(p),i.setAttribute(o,G.hex),o=="stroke"&&G[b]("opacity")&&q(i,{"stroke-opacity":G.opacity>1?G.opacity/100:G.opacity}),o=="stroke"&&d._.arrows&&("startString"in d._.arrows&&t(d,d._.arrows.startString),"endString"in d._.arrows&&t(d,d._.arrows.endString,1));break;case"gradient":(d.type=="circle"||d.type=="ellipse"||c(p).charAt()!="r")&&r(d,p);break;case"opacity":k.gradient&&!k[b]("stroke-opacity")&&q(i,{"stroke-opacity":p>1?p/100:p});case"fill-opacity":if(k.gradient){H=a._g.doc.getElementById(i.getAttribute("fill").replace(/^url\(#|\)$/g,l)),H&&(I=H.getElementsByTagName("stop"),q(I[I.length-1],{"stop-opacity":p}));break};default:o=="font-size"&&(p=e(p,10)+"px");var J=o.replace(/(\-.)/g,function(a){return a.substring(1).toUpperCase()});i.style[J]=p,d._.dirty=1,i.setAttribute(o,p)}}y(d,f),i.style.visibility=m},x=1.2,y=function(d,f){if(d.type=="text"&&!!(f[b]("text")||f[b]("font")||f[b]("font-size")||f[b]("x")||f[b]("y"))){var g=d.attrs,h=d.node,i=h.firstChild?e(a._g.doc.defaultView.getComputedStyle(h.firstChild,l).getPropertyValue("font-size"),10):10;if(f[b]("text")){g.text=f.text;while(h.firstChild)h.removeChild(h.firstChild);var j=c(f.text).split("\n"),k=[],m;for(var n=0,o=j.length;n<o;n++)m=q("tspan"),n&&q(m,{dy:i*x,x:g.x}),m.appendChild(a._g.doc.createTextNode(j[n])),h.appendChild(m),k[n]=m}else{k=h.getElementsByTagName("tspan");for(n=0,o=k.length;n<o;n++)n?q(k[n],{dy:i*x,x:g.x}):q(k[0],{dy:0})}q(h,{x:g.x,y:g.y}),d._.dirty=1;var p=d._getBBox(),r=g.y-(p.y+p.height/2);r&&a.is(r,"finite")&&q(k[0],{dy:r})}},z=function(b,c){var d=0,e=0;this[0]=this.node=b,b.raphael=!0,this.id=a._oid++,b.raphaelid=this.id,this.matrix=a.matrix(),this.realPath=null,this.paper=c,this.attrs=this.attrs||{},this._={transform:[],sx:1,sy:1,deg:0,dx:0,dy:0,dirty:1},!c.bottom&&(c.bottom=this),this.prev=c.top,c.top&&(c.top.next=this),c.top=this,this.next=null},A=a.el;z.prototype=A,A.constructor=z,a._engine.path=function(a,b){var c=q("path");b.canvas&&b.canvas.appendChild(c);var d=new z(c,b);d.type="path",w(d,{fill:"none",stroke:"#000",path:a});return d},A.rotate=function(a,b,e){if(this.removed)return this;a=c(a).split(j),a.length-1&&(b=d(a[1]),e=d(a[2])),a=d(a[0]),e==null&&(b=e);if(b==null||e==null){var f=this.getBBox(1);b=f.x+f.width/2,e=f.y+f.height/2}this.transform(this._.transform.concat([["r",a,b,e]]));return this},A.scale=function(a,b,e,f){if(this.removed)return this;a=c(a).split(j),a.length-1&&(b=d(a[1]),e=d(a[2]),f=d(a[3])),a=d(a[0]),b==null&&(b=a),f==null&&(e=f);if(e==null||f==null)var g=this.getBBox(1);e=e==null?g.x+g.width/2:e,f=f==null?g.y+g.height/2:f,this.transform(this._.transform.concat([["s",a,b,e,f]]));return this},A.translate=function(a,b){if(this.removed)return this;a=c(a).split(j),a.length-1&&(b=d(a[1])),a=d(a[0])||0,b=+b||0,this.transform(this._.transform.concat([["t",a,b]]));return this},A.transform=function(c){var d=this._;if(c==null)return d.transform;a._extractTransform(this,c),this.clip&&q(this.clip,{transform:this.matrix.invert()}),this.pattern&&s(this),this.node&&q(this.node,{transform:this.matrix});if(d.sx!=1||d.sy!=1){var e=this.attrs[b]("stroke-width")?this.attrs["stroke-width"]:1;this.attr({"stroke-width":e})}return this},A.hide=function(){!this.removed&&this.paper.safari(this.node.style.display="none");return this},A.show=function(){!this.removed&&this.paper.safari(this.node.style.display="");return this},A.remove=function(){if(!this.removed&&!!this.node.parentNode){var b=this.paper;b.__set__&&b.__set__.exclude(this),k.unbind("raphael.*.*."+this.id),this.gradient&&b.defs.removeChild(this.gradient),a._tear(this,b),this.node.parentNode.tagName.toLowerCase()=="a"?this.node.parentNode.parentNode.removeChild(this.node.parentNode):this.node.parentNode.removeChild(this.node);for(var c in this)this[c]=typeof this[c]=="function"?a._removedFactory(c):null;this.removed=!0}},A._getBBox=function(){if(this.node.style.display=="none"){this.show();var a=!0}var b={};try{b=this.node.getBBox()}catch(c){}finally{b=b||{}}a&&this.hide();return b},A.attr=function(c,d){if(this.removed)return this;if(c==null){var e={};for(var f in this.attrs)this.attrs[b](f)&&(e[f]=this.attrs[f]);e.gradient&&e.fill=="none"&&(e.fill=e.gradient)&&delete e.gradient,e.transform=this._.transform;return e}if(d==null&&a.is(c,"string")){if(c=="fill"&&this.attrs.fill=="none"&&this.attrs.gradient)return this.attrs.gradient;if(c=="transform")return this._.transform;var g=c.split(j),h={};for(var i=0,l=g.length;i<l;i++)c=g[i],c in this.attrs?h[c]=this.attrs[c]:a.is(this.paper.customAttributes[c],"function")?h[c]=this.paper.customAttributes[c].def:h[c]=a._availableAttrs[c];return l-1?h:h[g[0]]}if(d==null&&a.is(c,"array")){h={};for(i=0,l=c.length;i<l;i++)h[c[i]]=this.attr(c[i]);return h}if(d!=null){var m={};m[c]=d}else c!=null&&a.is(c,"object")&&(m=c);for(var n in m)k("raphael.attr."+n+"."+this.id,this,m[n]);for(n in this.paper.customAttributes)if(this.paper.customAttributes[b](n)&&m[b](n)&&a.is(this.paper.customAttributes[n],"function")){var o=this.paper.customAttributes[n].apply(this,[].concat(m[n]));this.attrs[n]=m[n];for(var p in o)o[b](p)&&(m[p]=o[p])}w(this,m);return this},A.toFront=function(){if(this.removed)return this;this.node.parentNode.tagName.toLowerCase()=="a"?this.node.parentNode.parentNode.appendChild(this.node.parentNode):this.node.parentNode.appendChild(this.node);var b=this.paper;b.top!=this&&a._tofront(this,b);return this},A.toBack=function(){if(this.removed)return this;var b=this.node.parentNode;b.tagName.toLowerCase()=="a"?b.parentNode.insertBefore(this.node.parentNode,this.node.parentNode.parentNode.firstChild):b.firstChild!=this.node&&b.insertBefore(this.node,this.node.parentNode.firstChild),a._toback(this,this.paper);var c=this.paper;return this},A.insertAfter=function(b){if(this.removed)return this;var c=b.node||b[b.length-1].node;c.nextSibling?c.parentNode.insertBefore(this.node,c.nextSibling):c.parentNode.appendChild(this.node),a._insertafter(this,b,this.paper);return this},A.insertBefore=function(b){if(this.removed)return this;var c=b.node||b[0].node;c.parentNode.insertBefore(this.node,c),a._insertbefore(this,b,this.paper);return this},A.blur=function(b){var c=this;if(+b!==0){var d=q("filter"),e=q("feGaussianBlur");c.attrs.blur=b,d.id=a.createUUID(),q(e,{stdDeviation:+b||1.5}),d.appendChild(e),c.paper.defs.appendChild(d),c._blur=d,q(c.node,{filter:"url(#"+d.id+")"})}else c._blur&&(c._blur.parentNode.removeChild(c._blur),delete c._blur,delete c.attrs.blur),c.node.removeAttribute("filter")},a._engine.circle=function(a,b,c,d){var e=q("circle");a.canvas&&a.canvas.appendChild(e);var f=new z(e,a);f.attrs={cx:b,cy:c,r:d,fill:"none",stroke:"#000"},f.type="circle",q(e,f.attrs);return f},a._engine.rect=function(a,b,c,d,e,f){var g=q("rect");a.canvas&&a.canvas.appendChild(g);var h=new z(g,a);h.attrs={x:b,y:c,width:d,height:e,r:f||0,rx:f||0,ry:f||0,fill:"none",stroke:"#000"},h.type="rect",q(g,h.attrs);return h},a._engine.ellipse=function(a,b,c,d,e){var f=q("ellipse");a.canvas&&a.canvas.appendChild(f);var g=new z(f,a);g.attrs={cx:b,cy:c,rx:d,ry:e,fill:"none",stroke:"#000"},g.type="ellipse",q(f,g.attrs);return g},a._engine.image=function(a,b,c,d,e,f){var g=q("image");q(g,{x:c,y:d,width:e,height:f,preserveAspectRatio:"none"}),g.setAttributeNS(n,"href",b),a.canvas&&a.canvas.appendChild(g);var h=new z(g,a);h.attrs={x:c,y:d,width:e,height:f,src:b},h.type="image";return h},a._engine.text=function(b,c,d,e){var f=q("text");b.canvas&&b.canvas.appendChild(f);var g=new z(f,b);g.attrs={x:c,y:d,"text-anchor":"middle",text:e,font:a._availableAttrs.font,stroke:"none",fill:"#000"},g.type="text",w(g,g.attrs);return g},a._engine.setSize=function(a,b){this.width=a||this.width,this.height=b||this.height,this.canvas.setAttribute("width",this.width),this.canvas.setAttribute("height",this.height),this._viewBox&&this.setViewBox.apply(this,this._viewBox);return this},a._engine.create=function(){var b=a._getContainer.apply(0,arguments),c=b&&b.container,d=b.x,e=b.y,f=b.width,g=b.height;if(!c)throw new Error("SVG container not found.");var h=q("svg"),i="overflow:hidden;",j;d=d||0,e=e||0,f=f||512,g=g||342,q(h,{height:g,version:1.1,width:f,xmlns:"http://www.w3.org/2000/svg"}),c==1?(h.style.cssText=i+"position:absolute;left:"+d+"px;top:"+e+"px",a._g.doc.body.appendChild(h),j=1):(h.style.cssText=i+"position:relative",c.firstChild?c.insertBefore(h,c.firstChild):c.appendChild(h)),c=new a._Paper,c.width=f,c.height=g,c.canvas=h,c.clear(),c._left=c._top=0,j&&(c.renderfix=function(){}),c.renderfix();return c},a._engine.setViewBox=function(a,b,c,d,e){k("raphael.setViewBox",this,this._viewBox,[a,b,c,d,e]);var f=g(c/this.width,d/this.height),h=this.top,i=e?"meet":"xMinYMin",j,l;a==null?(this._vbSize&&(f=1),delete this._vbSize,j="0 0 "+this.width+m+this.height):(this._vbSize=f,j=a+m+b+m+c+m+d),q(this.canvas,{viewBox:j,preserveAspectRatio:i});while(f&&h)l="stroke-width"in h.attrs?h.attrs["stroke-width"]:1,h.attr({"stroke-width":l}),h._.dirty=1,h._.dirtyT=1,h=h.prev;this._viewBox=[a,b,c,d,!!e];return this},a.prototype.renderfix=function(){var a=this.canvas,b=a.style,c;try{c=a.getScreenCTM()||a.createSVGMatrix()}catch(d){c=a.createSVGMatrix()}var e=-c.e%1,f=-c.f%1;if(e||f)e&&(this._left=(this._left+e)%1,b.left=this._left+"px"),f&&(this._top=(this._top+f)%1,b.top=this._top+"px")},a.prototype.clear=function(){a.eve("raphael.clear",this);var b=this.canvas;while(b.firstChild)b.removeChild(b.firstChild);this.bottom=this.top=null,(this.desc=q("desc")).appendChild(a._g.doc.createTextNode("Created with Raphaël "+a.version)),b.appendChild(this.desc),b.appendChild(this.defs=q("defs"))},a.prototype.remove=function(){k("raphael.remove",this),this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas);for(var b in this)this[b]=typeof this[b]=="function"?a._removedFactory(b):null};var B=a.st;for(var C in A)A[b](C)&&!B[b](C)&&(B[C]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(C))}(window.Raphael),window.Raphael.vml&&function(a){var b="hasOwnProperty",c=String,d=parseFloat,e=Math,f=e.round,g=e.max,h=e.min,i=e.abs,j="fill",k=/[, ]+/,l=a.eve,m=" progid:DXImageTransform.Microsoft",n=" ",o="",p={M:"m",L:"l",C:"c",Z:"x",m:"t",l:"r",c:"v",z:"x"},q=/([clmz]),?([^clmz]*)/gi,r=/ progid:\S+Blur\([^\)]+\)/g,s=/-?[^,\s-]+/g,t="position:absolute;left:0;top:0;width:1px;height:1px",u=21600,v={path:1,rect:1,image:1},w={circle:1,ellipse:1},x=function(b){var d=/[ahqstv]/ig,e=a._pathToAbsolute;c(b).match(d)&&(e=a._path2curve),d=/[clmz]/g;if(e==a._pathToAbsolute&&!c(b).match(d)){var g=c(b).replace(q,function(a,b,c){var d=[],e=b.toLowerCase()=="m",g=p[b];c.replace(s,function(a){e&&d.length==2&&(g+=d+p[b=="m"?"l":"L"],d=[]),d.push(f(a*u))});return g+d});return g}var h=e(b),i,j;g=[];for(var k=0,l=h.length;k<l;k++){i=h[k],j=h[k][0].toLowerCase(),j=="z"&&(j="x");for(var m=1,r=i.length;m<r;m++)j+=f(i[m]*u)+(m!=r-1?",":o);g.push(j)}return g.join(n)},y=function(b,c,d){var e=a.matrix();e.rotate(-b,.5,.5);return{dx:e.x(c,d),dy:e.y(c,d)}},z=function(a,b,c,d,e,f){var g=a._,h=a.matrix,k=g.fillpos,l=a.node,m=l.style,o=1,p="",q,r=u/b,s=u/c;m.visibility="hidden";if(!!b&&!!c){l.coordsize=i(r)+n+i(s),m.rotation=f*(b*c<0?-1:1);if(f){var t=y(f,d,e);d=t.dx,e=t.dy}b<0&&(p+="x"),c<0&&(p+=" y")&&(o=-1),m.flip=p,l.coordorigin=d*-r+n+e*-s;if(k||g.fillsize){var v=l.getElementsByTagName(j);v=v&&v[0],l.removeChild(v),k&&(t=y(f,h.x(k[0],k[1]),h.y(k[0],k[1])),v.position=t.dx*o+n+t.dy*o),g.fillsize&&(v.size=g.fillsize[0]*i(b)+n+g.fillsize[1]*i(c)),l.appendChild(v)}m.visibility="visible"}};a.toString=function(){return"Your browser doesn’t support SVG. Falling down to VML.\nYou are running Raphaël "+this.version};var A=function(a,b,d){var e=c(b).toLowerCase().split("-"),f=d?"end":"start",g=e.length,h="classic",i="medium",j="medium";while(g--)switch(e[g]){case"block":case"classic":case"oval":case"diamond":case"open":case"none":h=e[g];break;case"wide":case"narrow":j=e[g];break;case"long":case"short":i=e[g]}var k=a.node.getElementsByTagName("stroke")[0];k[f+"arrow"]=h,k[f+"arrowlength"]=i,k[f+"arrowwidth"]=j},B=function(e,i){e.attrs=e.attrs||{};var l=e.node,m=e.attrs,p=l.style,q,r=v[e.type]&&(i.x!=m.x||i.y!=m.y||i.width!=m.width||i.height!=m.height||i.cx!=m.cx||i.cy!=m.cy||i.rx!=m.rx||i.ry!=m.ry||i.r!=m.r),s=w[e.type]&&(m.cx!=i.cx||m.cy!=i.cy||m.r!=i.r||m.rx!=i.rx||m.ry!=i.ry),t=e;for(var y in i)i[b](y)&&(m[y]=i[y]);r&&(m.path=a._getPath[e.type](e),e._.dirty=1),i.href&&(l.href=i.href),i.title&&(l.title=i.title),i.target&&(l.target=i.target),i.cursor&&(p.cursor=i.cursor),"blur"in i&&e.blur(i.blur);if(i.path&&e.type=="path"||r)l.path=x(~c(m.path).toLowerCase().indexOf("r")?a._pathToAbsolute(m.path):m.path),e.type=="image"&&(e._.fillpos=[m.x,m.y],e._.fillsize=[m.width,m.height],z(e,1,1,0,0,0));"transform"in i&&e.transform(i.transform);if(s){var B=+m.cx,D=+m.cy,E=+m.rx||+m.r||0,G=+m.ry||+m.r||0;l.path=a.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x",f((B-E)*u),f((D-G)*u),f((B+E)*u),f((D+G)*u),f(B*u))}if("clip-rect"in i){var H=c(i["clip-rect"]).split(k);if(H.length==4){H[2]=+H[2]+ +H[0],H[3]=+H[3]+ +H[1];var I=l.clipRect||a._g.doc.createElement("div"),J=I.style;J.clip=a.format("rect({1}px {2}px {3}px {0}px)",H),l.clipRect||(J.position="absolute",J.top=0,J.left=0,J.width=e.paper.width+"px",J.height=e.paper.height+"px",l.parentNode.insertBefore(I,l),I.appendChild(l),l.clipRect=I)}i["clip-rect"]||l.clipRect&&(l.clipRect.style.clip="auto")}if(e.textpath){var K=e.textpath.style;i.font&&(K.font=i.font),i["font-family"]&&(K.fontFamily='"'+i["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g,o)+'"'),i["font-size"]&&(K.fontSize=i["font-size"]),i["font-weight"]&&(K.fontWeight=i["font-weight"]),i["font-style"]&&(K.fontStyle=i["font-style"])}"arrow-start"in i&&A(t,i["arrow-start"]),"arrow-end"in i&&A(t,i["arrow-end"],1);if(i.opacity!=null||i["stroke-width"]!=null||i.fill!=null||i.src!=null||i.stroke!=null||i["stroke-width"]!=null||i["stroke-opacity"]!=null||i["fill-opacity"]!=null||i["stroke-dasharray"]!=null||i["stroke-miterlimit"]!=null||i["stroke-linejoin"]!=null||i["stroke-linecap"]!=null){var L=l.getElementsByTagName(j),M=!1;L=L&&L[0],!L&&(M=L=F(j)),e.type=="image"&&i.src&&(L.src=i.src),i.fill&&(L.on=!0);if(L.on==null||i.fill=="none"||i.fill===null)L.on=!1;if(L.on&&i.fill){var N=c(i.fill).match(a._ISURL);if(N){L.parentNode==l&&l.removeChild(L),L.rotate=!0,L.src=N[1],L.type="tile";var O=e.getBBox(1);L.position=O.x+n+O.y,e._.fillpos=[O.x,O.y],a._preload(N[1],function(){e._.fillsize=[this.offsetWidth,this.offsetHeight]})}else L.color=a.getRGB(i.fill).hex,L.src=o,L.type="solid",a.getRGB(i.fill).error&&(t.type in{circle:1,ellipse:1}||c(i.fill).charAt()!="r")&&C(t,i.fill,L)&&(m.fill="none",m.gradient=i.fill,L.rotate=!1)}if("fill-opacity"in i||"opacity"in i){var P=((+m["fill-opacity"]+1||2)-1)*((+m.opacity+1||2)-1)*((+a.getRGB(i.fill).o+1||2)-1);P=h(g(P,0),1),L.opacity=P,L.src&&(L.color="none")}l.appendChild(L);var Q=l.getElementsByTagName("stroke")&&l.getElementsByTagName("stroke")[0],T=!1;!Q&&(T=Q=F("stroke"));if(i.stroke&&i.stroke!="none"||i["stroke-width"]||i["stroke-opacity"]!=null||i["stroke-dasharray"]||i["stroke-miterlimit"]||i["stroke-linejoin"]||i["stroke-linecap"])Q.on=!0;(i.stroke=="none"||i.stroke===null||Q.on==null||i.stroke==0||i["stroke-width"]==0)&&(Q.on=!1);var U=a.getRGB(i.stroke);Q.on&&i.stroke&&(Q.color=U.hex),P=((+m["stroke-opacity"]+1||2)-1)*((+m.opacity+1||2)-1)*((+U.o+1||2)-1);var V=(d(i["stroke-width"])||1)*.75;P=h(g(P,0),1),i["stroke-width"]==null&&(V=m["stroke-width"]),i["stroke-width"]&&(Q.weight=V),V&&V<1&&(P*=V)&&(Q.weight=1),Q.opacity=P,i["stroke-linejoin"]&&(Q.joinstyle=i["stroke-linejoin"]||"miter"),Q.miterlimit=i["stroke-miterlimit"]||8,i["stroke-linecap"]&&(Q.endcap=i["stroke-linecap"]=="butt"?"flat":i["stroke-linecap"]=="square"?"square":"round");if(i["stroke-dasharray"]){var W={"-":"shortdash",".":"shortdot","-.":"shortdashdot","-..":"shortdashdotdot",". ":"dot","- ":"dash","--":"longdash","- .":"dashdot","--.":"longdashdot","--..":"longdashdotdot"};Q.dashstyle=W[b](i["stroke-dasharray"])?W[i["stroke-dasharray"]]:o}T&&l.appendChild(Q)}if(t.type=="text"){t.paper.canvas.style.display=o;var X=t.paper.span,Y=100,Z=m.font&&m.font.match(/\d+(?:\.\d*)?(?=px)/);p=X.style,m.font&&(p.font=m.font),m["font-family"]&&(p.fontFamily=m["font-family"]),m["font-weight"]&&(p.fontWeight=m["font-weight"]),m["font-style"]&&(p.fontStyle=m["font-style"]),Z=d(m["font-size"]||Z&&Z[0])||10,p.fontSize=Z*Y+"px",t.textpath.string&&(X.innerHTML=c(t.textpath.string).replace(/</g,"<").replace(/&/g,"&").replace(/\n/g,"<br>"));var $=X.getBoundingClientRect();t.W=m.w=($.right-$.left)/Y,t.H=m.h=($.bottom-$.top)/Y,t.X=m.x,t.Y=m.y+t.H/2,("x"in i||"y"in i)&&(t.path.v=a.format("m{0},{1}l{2},{1}",f(m.x*u),f(m.y*u),f(m.x*u)+1));var _=["x","y","text","font","font-family","font-weight","font-style","font-size"];for(var ba=0,bb=_.length;ba<bb;ba++)if(_[ba]in i){t._.dirty=1;break}switch(m["text-anchor"]){case"start":t.textpath.style["v-text-align"]="left",t.bbx=t.W/2;break;case"end":t.textpath.style["v-text-align"]="right",t.bbx=-t.W/2;break;default:t.textpath.style["v-text-align"]="center",t.bbx=0}t.textpath.style["v-text-kern"]=!0}},C=function(b,f,g){b.attrs=b.attrs||{};var h=b.attrs,i=Math.pow,j,k,l="linear",m=".5 .5";b.attrs.gradient=f,f=c(f).replace(a._radial_gradient,function(a,b,c){l="radial",b&&c&&(b=d(b),c=d(c),i(b-.5,2)+i(c-.5,2)>.25&&(c=e.sqrt(.25-i(b-.5,2))*((c>.5)*2-1)+.5),m=b+n+c);return o}),f=f.split(/\s*\-\s*/);if(l=="linear"){var p=f.shift();p=-d(p);if(isNaN(p))return null}var q=a._parseDots(f);if(!q)return null;b=b.shape||b.node;if(q.length){b.removeChild(g),g.on=!0,g.method="none",g.color=q[0].color,g.color2=q[q.length-1].color;var r=[];for(var s=0,t=q.length;s<t;s++)q[s].offset&&r.push(q[s].offset+n+q[s].color);g.colors=r.length?r.join():"0% "+g.color,l=="radial"?(g.type="gradientTitle",g.focus="100%",g.focussize="0 0",g.focusposition=m,g.angle=0):(g.type="gradient",g.angle=(270-p)%360),b.appendChild(g)}return 1},D=function(b,c){this[0]=this.node=b,b.raphael=!0,this.id=a._oid++,b.raphaelid=this.id,this.X=0,this.Y=0,this.attrs={},this.paper=c,this.matrix=a.matrix(),this._={transform:[],sx:1,sy:1,dx:0,dy:0,deg:0,dirty:1,dirtyT:1},!c.bottom&&(c.bottom=this),this.prev=c.top,c.top&&(c.top.next=this),c.top=this,this.next=null},E=a.el;D.prototype=E,E.constructor=D,E.transform=function(b){if(b==null)return this._.transform;var d=this.paper._viewBoxShift,e=d?"s"+[d.scale,d.scale]+"-1-1t"+[d.dx,d.dy]:o,f;d&&(f=b=c(b).replace(/\.{3}|\u2026/g,this._.transform||o)),a._extractTransform(this,e+b);var g=this.matrix.clone(),h=this.skew,i=this.node,j,k=~c(this.attrs.fill).indexOf("-"),l=!c(this.attrs.fill).indexOf("url(");g.translate(-0.5,-0.5);if(l||k||this.type=="image"){h.matrix="1 0 0 1",h.offset="0 0",j=g.split();if(k&&j.noRotation||!j.isSimple){i.style.filter=g.toFilter();var m=this.getBBox(),p=this.getBBox(1),q=m.x-p.x,r=m.y-p.y;i.coordorigin=q*-u+n+r*-u,z(this,1,1,q,r,0)}else i.style.filter=o,z(this,j.scalex,j.scaley,j.dx,j.dy,j.rotate)}else i.style.filter=o,h.matrix=c(g),h.offset=g.offset();f&&(this._.transform=f);return this},E.rotate=function(a,b,e){if(this.removed)return this;if(a!=null){a=c(a).split(k),a.length-1&&(b=d(a[1]),e=d(a[2])),a=d(a[0]),e==null&&(b=e);if(b==null||e==null){var f=this.getBBox(1);b=f.x+f.width/2,e=f.y+f.height/2}this._.dirtyT=1,this.transform(this._.transform.concat([["r",a,b,e]]));return this}},E.translate=function(a,b){if(this.removed)return this;a=c(a).split(k),a.length-1&&(b=d(a[1])),a=d(a[0])||0,b=+b||0,this._.bbox&&(this._.bbox.x+=a,this._.bbox.y+=b),this.transform(this._.transform.concat([["t",a,b]]));return this},E.scale=function(a,b,e,f){if(this.removed)return this;a=c(a).split(k),a.length-1&&(b=d(a[1]),e=d(a[2]),f=d(a[3]),isNaN(e)&&(e=null),isNaN(f)&&(f=null)),a=d(a[0]),b==null&&(b=a),f==null&&(e=f);if(e==null||f==null)var g=this.getBBox(1);e=e==null?g.x+g.width/2:e,f=f==null?g.y+g.height/2:f,this.transform(this._.transform.concat([["s",a,b,e,f]])),this._.dirtyT=1;return this},E.hide=function(){!this.removed&&(this.node.style.display="none");return this},E.show=function(){!this.removed&&(this.node.style.display=o);return this},E._getBBox=function(){if(this.removed)return{};return{x:this.X+(this.bbx||0)-this.W/2,y:this.Y-this.H,width:this.W,height:this.H}},E.remove=function(){if(!this.removed&&!!this.node.parentNode){this.paper.__set__&&this.paper.__set__.exclude(this),a.eve.unbind("raphael.*.*."+this.id),a._tear(this,this.paper),this.node.parentNode.removeChild(this.node),this.shape&&this.shape.parentNode.removeChild(this.shape);for(var b in this)this[b]=typeof this[b]=="function"?a._removedFactory(b):null;this.removed=!0}},E.attr=function(c,d){if(this.removed)return this;if(c==null){var e={};for(var f in this.attrs)this.attrs[b](f)&&(e[f]=this.attrs[f]);e.gradient&&e.fill=="none"&&(e.fill=e.gradient)&&delete e.gradient,e.transform=this._.transform;return e}if(d==null&&a.is(c,"string")){if(c==j&&this.attrs.fill=="none"&&this.attrs.gradient)return this.attrs.gradient;var g=c.split(k),h={};for(var i=0,m=g.length;i<m;i++)c=g[i],c in this.attrs?h[c]=this.attrs[c]:a.is(this.paper.customAttributes[c],"function")?h[c]=this.paper.customAttributes[c].def:h[c]=a._availableAttrs[c];return m-1?h:h[g[0]]}if(this.attrs&&d==null&&a.is(c,"array")){h={};for(i=0,m=c.length;i<m;i++)h[c[i]]=this.attr(c[i]);return h}var n;d!=null&&(n={},n[c]=d),d==null&&a.is(c,"object")&&(n=c);for(var o in n)l("raphael.attr."+o+"."+this.id,this,n[o]);if(n){for(o in this.paper.customAttributes)if(this.paper.customAttributes[b](o)&&n[b](o)&&a.is(this.paper.customAttributes[o],"function")){var p=this.paper.customAttributes[o].apply(this,[].concat(n[o]));this.attrs[o]=n[o];for(var q in p)p[b](q)&&(n[q]=p[q])}n.text&&this.type=="text"&&(this.textpath.string=n.text),B(this,n)}return this},E.toFront=function(){!this.removed&&this.node.parentNode.appendChild(this.node),this.paper&&this.paper.top!=this&&a._tofront(this,this.paper);return this},E.toBack=function(){if(this.removed)return this;this.node.parentNode.firstChild!=this.node&&(this.node.parentNode.insertBefore(this.node,this.node.parentNode.firstChild),a._toback(this,this.paper));return this},E.insertAfter=function(b){if(this.removed)return this;b.constructor==a.st.constructor&&(b=b[b.length-1]),b.node.nextSibling?b.node.parentNode.insertBefore(this.node,b.node.nextSibling):b.node.parentNode.appendChild(this.node),a._insertafter(this,b,this.paper);return this},E.insertBefore=function(b){if(this.removed)return this;b.constructor==a.st.constructor&&(b=b[0]),b.node.parentNode.insertBefore(this.node,b.node),a._insertbefore(this,b,this.paper);return this},E.blur=function(b){var c=this.node.runtimeStyle,d=c.filter;d=d.replace(r,o),+b!==0?(this.attrs.blur=b,c.filter=d+n+m+".Blur(pixelradius="+(+b||1.5)+")",c.margin=a.format("-{0}px 0 0 -{0}px",f(+b||1.5))):(c.filter=d,c.margin=0,delete this.attrs.blur)},a._engine.path=function(a,b){var c=F("shape");c.style.cssText=t,c.coordsize=u+n+u,c.coordorigin=b.coordorigin;var d=new D(c,b),e={fill:"none",stroke:"#000"};a&&(e.path=a),d.type="path",d.path=[],d.Path=o,B(d,e),b.canvas.appendChild(c);var f=F("skew");f.on=!0,c.appendChild(f),d.skew=f,d.transform(o);return d},a._engine.rect=function(b,c,d,e,f,g){var h=a._rectPath(c,d,e,f,g),i=b.path(h),j=i.attrs;i.X=j.x=c,i.Y=j.y=d,i.W=j.width=e,i.H=j.height=f,j.r=g,j.path=h,i.type="rect";return i},a._engine.ellipse=function(a,b,c,d,e){var f=a.path(),g=f.attrs;f.X=b-d,f.Y=c-e,f.W=d*2,f.H=e*2,f.type="ellipse",B(f,{cx:b,cy:c,rx:d,ry:e});return f},a._engine.circle=function(a,b,c,d){var e=a.path(),f=e.attrs;e.X=b-d,e.Y=c-d,e.W=e.H=d*2,e.type="circle",B(e,{cx:b,cy:c,r:d});return e},a._engine.image=function(b,c,d,e,f,g){var h=a._rectPath(d,e,f,g),i=b.path(h).attr({stroke:"none"}),k=i.attrs,l=i.node,m=l.getElementsByTagName(j)[0];k.src=c,i.X=k.x=d,i.Y=k.y=e,i.W=k.width=f,i.H=k.height=g,k.path=h,i.type="image",m.parentNode==l&&l.removeChild(m),m.rotate=!0,m.src=c,m.type="tile",i._.fillpos=[d,e],i._.fillsize=[f,g],l.appendChild(m),z(i,1,1,0,0,0);return i},a._engine.text=function(b,d,e,g){var h=F("shape"),i=F("path"),j=F("textpath");d=d||0,e=e||0,g=g||"",i.v=a.format("m{0},{1}l{2},{1}",f(d*u),f(e*u),f(d*u)+1),i.textpathok=!0,j.string=c(g),j.on=!0,h.style.cssText=t,h.coordsize=u+n+u,h.coordorigin="0 0";var k=new D(h,b),l={fill:"#000",stroke:"none",font:a._availableAttrs.font,text:g};k.shape=h,k.path=i,k.textpath=j,k.type="text",k.attrs.text=c(g),k.attrs.x=d,k.attrs.y=e,k.attrs.w=1,k.attrs.h=1,B(k,l),h.appendChild(j),h.appendChild(i),b.canvas.appendChild(h);var m=F("skew");m.on=!0,h.appendChild(m),k.skew=m,k.transform(o);return k},a._engine.setSize=function(b,c){var d=this.canvas.style;this.width=b,this.height=c,b==+b&&(b+="px"),c==+c&&(c+="px"),d.width=b,d.height=c,d.clip="rect(0 "+b+" "+c+" 0)",this._viewBox&&a._engine.setViewBox.apply(this,this._viewBox);return this},a._engine.setViewBox=function(b,c,d,e,f){a.eve("raphael.setViewBox",this,this._viewBox,[b,c,d,e,f]);var h=this.width,i=this.height,j=1/g(d/h,e/i),k,l;f&&(k=i/e,l=h/d,d*k<h&&(b-=(h-d*k)/2/k),e*l<i&&(c-=(i-e*l)/2/l)),this._viewBox=[b,c,d,e,!!f],this._viewBoxShift={dx:-b,dy:-c,scale:j},this.forEach(function(a){a.transform("...")});return this};var F;a._engine.initWin=function(a){var b=a.document;b.createStyleSheet().addRule(".rvml","behavior:url(#default#VML)");try{!b.namespaces.rvml&&b.namespaces.add("rvml","urn:schemas-microsoft-com:vml"),F=function(a){return b.createElement("<rvml:"+a+' class="rvml">')}}catch(c){F=function(a){return b.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}},a._engine.initWin(a._g.win),a._engine.create=function(){var b=a._getContainer.apply(0,arguments),c=b.container,d=b.height,e,f=b.width,g=b.x,h=b.y;if(!c)throw new Error("VML container not found.");var i=new a._Paper,j=i.canvas=a._g.doc.createElement("div"),k=j.style;g=g||0,h=h||0,f=f||512,d=d||342,i.width=f,i.height=d,f==+f&&(f+="px"),d==+d&&(d+="px"),i.coordsize=u*1e3+n+u*1e3,i.coordorigin="0 0",i.span=a._g.doc.createElement("span"),i.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;",j.appendChild(i.span),k.cssText=a.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",f,d),c==1?(a._g.doc.body.appendChild(j),k.left=g+"px",k.top=h+"px",k.position="absolute"):c.firstChild?c.insertBefore(j,c.firstChild):c.appendChild(j),i.renderfix=function(){};return i},a.prototype.clear=function(){a.eve("raphael.clear",this),this.canvas.innerHTML=o,this.span=a._g.doc.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas.appendChild(this.span),this.bottom=this.top=null},a.prototype.remove=function(){a.eve("raphael.remove",this),this.canvas.parentNode.removeChild(this.canvas);for(var b in this)this[b]=typeof this[b]=="function"?a._removedFactory(b):null;return!0};var G=a.st;for(var H in E)E[b](H)&&!G[b](H)&&(G[H]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(H))}(window.Raphael) \ No newline at end of file diff --git a/scp/js/scp.js b/scp/js/scp.js index 7a9e0e218d1da97b3ec4b2860f307dd1c1769d1f..b31f673f0d9f7119768846bae078d11770ed18fc 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -185,6 +185,14 @@ $(document).ready(function(){ }, 'json') .error( function() {}); + /* Datepicker */ + + $('.dp').datepicker({ + numberOfMonths: 2, + showButtonPanel: true, + buttonImage: './images/cal.png', + showOn:'both' + }); /* NicEdit richtext init */ var rtes = $('.richtext'); @@ -198,11 +206,11 @@ $(document).ready(function(){ } } - /* Typeahead init */ + /* Typeahead tickets lookup */ $('#basic-ticket-search').typeahead({ source: function (typeahead, query) { $.ajax({ - url: "ajax.php/tickets?q="+query, + url: "ajax.php/tickets/lookup?q="+query, dataType: 'json', success: function (data) { typeahead.process(data); @@ -215,6 +223,7 @@ $(document).ready(function(){ property: "value" }); + /* Typeahead user lookup */ $('#email.typeahead').typeahead({ source: function (typeahead, query) { if(query.length > 2) { @@ -235,5 +244,84 @@ $(document).ready(function(){ property: "email" }); + /* advanced search */ + $("#overlay").css({ + opacity : 0.3, + top : 0, + left : 0, + width : $(window).width(), + height : $(window).height() + }); + + $("#advanced-search").css({ + top : ($(window).height() / 6), + left : ($(window).width() / 2 - 300) + }); + + $('#go-advanced').click(function(e) { + e.preventDefault(); + $('#result-count').html(''); + $('#overlay').show(); + $('#advanced-search').show(); + }); + + $('#advanced-search').delegate('a.close, input.close', 'click', function(e) { + e.preventDefault(); + $('#advanced-search').hide() + $('#overlay').hide(); + }).delegate('#status', 'change', function() { + switch($(this).val()) { + case 'closed': + $('select#assignee').find('option:first').attr('selected', 'selected').parent('select'); + $('select#assignee').attr('disabled','disabled'); + $('select#staffId').removeAttr('disabled'); + break; + case 'open': + case 'overdue': + $('select#staffId').find('option:first').attr('selected', 'selected').parent('select'); + $('select#staffId').attr('disabled','disabled'); + $('select#assignee').removeAttr('disabled'); + break; + default: + $('select#staffId').removeAttr('disabled'); + $('select#assignee').removeAttr('disabled'); + } + }); + + $('#advanced-search form#search').submit(function(e) { + e.preventDefault(); + var fObj = $(this); + var elem = $('#advanced-search'); + $('#result-count').html(''); + $.ajax({ + url: "ajax.php/tickets/search", + data: fObj.serialize(), + dataType: 'json', + beforeSend: function ( xhr ) { + $('.buttons', elem).hide(); + $('.spinner', elem).show(); + return true; + }, + success: function (resp) { + + if(resp.success) { + $('#result-count').html('<div class="success">' + resp.success +'</div>'); + } else if (resp.fail) { + $('#result-count').html('<div class="fail">' + resp.fail +'</div>'); + } else { + $('#result-count').html('<div class="fail">Unknown error</div>'); + } + } + }) + .done( function () { + }) + .fail( function () { + $('#result-count').html('<div class="fail">Advanced search failed - try again!</div>'); + }) + .always( function () { + $('.spinner', elem).hide(); + $('.buttons', elem).show(); + }); + }); }); diff --git a/scp/js/ticket.js b/scp/js/ticket.js index 902298ce43f64240a819282967a45f984ce2a424..22a97d623bd34d0ef664b012c1cd040e9f55c15e 100644 --- a/scp/js/ticket.js +++ b/scp/js/ticket.js @@ -153,7 +153,7 @@ var autoLock = { } else { $.ajax({ type: "GET", - url: 'ajax.php/ticket/'+autoLock.tid+'/lock', + url: 'ajax.php/tickets/'+autoLock.tid+'/lock', dataType: 'json', cache: false, success: function(lock){ @@ -176,7 +176,7 @@ var autoLock = { if(!autoLock.lastcheckTime || (now-autoLock.lastcheckTime)>=(autoLock.renewFreq*1000)){ $.ajax({ type: 'POST', - url: 'ajax.php/ticket/'+autoLock.tid+'/lock/'+autoLock.lockId+'/renew', + url: 'ajax.php/tickets/'+autoLock.tid+'/lock/'+autoLock.lockId+'/renew', dataType: 'json', cache: false, success: function(lock){ @@ -193,7 +193,7 @@ var autoLock = { $.ajax({ type: 'POST', - url: 'ajax.php/ticket/'+autoLock.tid+'/lock/'+autoLock.lockId+'/release', + url: 'ajax.php/tickets/'+autoLock.tid+'/lock/'+autoLock.lockId+'/release', data: 'delete', cache: false, success: function(){ @@ -264,7 +264,7 @@ jQuery(function($) { if(location.hash != "" && $('#response_options '+location.hash).length) { $('#response_options '+location.hash+'_tab').addClass('active'); $('#response_options '+location.hash).show(); - } else if(location.hash == "#notes") { + } else if(location.hash == "#notes" && $('#ticket_notes').length) { $('#response_options #note_tab').addClass('active'); $('#response_options form').hide(); $('#response_options #note').show(); diff --git a/scp/js/tips.js b/scp/js/tips.js index ec0f1875d55f31e5b8e9afcf283d7700183ea6e8..c560b8d913e635047e98e7a8198262a9db2809fc 100644 --- a/scp/js/tips.js +++ b/scp/js/tips.js @@ -80,7 +80,7 @@ jQuery(function($) { var elem = $(this); var vars = elem.attr('href').split('='); - var url = 'ajax.php/ticket/'+vars[1]+'/preview'; + var url = 'ajax.php/tickets/'+vars[1]+'/preview'; var id='t'+vars[1]; var xoffset = 80; diff --git a/scp/staff.inc.php b/scp/staff.inc.php index b3ee30a4ec3a555c2fd8c3c86ed6e72b2c6517ca..7a4dfb9e3a596fcc480894c60ecf2bede2304181 100644 --- a/scp/staff.inc.php +++ b/scp/staff.inc.php @@ -63,19 +63,19 @@ if(!$thisstaff || !is_object($thisstaff) || !$thisstaff->getId() || !$thisstaff- exit; } //2) if not super admin..check system status and group status -if(!$thisstaff->isadmin()){ - //Staff are not allowed to login in offline mode!! - if($cfg->isHelpDeskOffline()){ - staffLoginPage('System Offline'); - exit; - } +if(!$thisstaff->isAdmin()) { //Check for disabled staff or group! if(!$thisstaff->isactive() || !$thisstaff->isGroupActive()) { staffLoginPage('Access Denied. Contact Admin'); exit; } -} + //Staff are not allowed to login in offline mode!! + if($cfg->isHelpDeskOffline() || $cfg->isUpgradePending()) { + staffLoginPage('System Offline'); + exit; + } +} //Keep the session activity alive $thisstaff->refreshSession(); @@ -93,10 +93,9 @@ $errors=array(); $msg=$warn=$sysnotice=''; $tabs=array(); $submenu=array(); - -if(defined('THIS_VERSION') && strcasecmp($cfg->getVersion(),THIS_VERSION)) { - $errors['err']=$sysnotice=sprintf('The script is version %s while the database is version %s',THIS_VERSION,$cfg->getVersion()); -}elseif($cfg->isHelpDeskOffline()){ +if($cfg->isUpgradePending()) { + $errors['err']=$sysnotice='System upgrade is pending <a href="../setup/upgrade.php">Upgrade Now</a>'; +} elseif($cfg->isHelpDeskOffline()) { $sysnotice='<strong>System is set to offline mode</strong> - Client interface is disabled and ONLY admins can access staff control panel.'; $sysnotice.=' <a href="settings.php">Enable</a>.'; } diff --git a/scp/tickets.php b/scp/tickets.php index c881381e0d9ff9613b1e26e1df6c410157df664b..567c3f69755525aca1146ce8433a44e2485c6fc3 100644 --- a/scp/tickets.php +++ b/scp/tickets.php @@ -55,7 +55,7 @@ if($_POST && !$errors): if(!$errors['err'] && EmailFilter::isBanned($ticket->getEmail())) $errors['err']='Email is in banlist. Must be removed to reply.'; - $wasOpen =($ticket->isopen()); + $wasOpen =($ticket->isOpen()); //If no error...do the do. if(!$errors && ($respId=$ticket->postReply($_POST,$_FILES['attachments'],$errors))) { $msg='Reply posted successfully'; @@ -189,7 +189,7 @@ if($_POST && !$errors): } break; case 'close': - if(!$thisstaff->isadmin() && !$thisstaff->canCloseTickets()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canCloseTickets()){ $errors['err']='Perm. Denied. You are not allowed to close tickets.'; }else{ if($ticket->close()){ @@ -204,7 +204,7 @@ if($_POST && !$errors): break; case 'reopen': //if they can close...then assume they can reopen. - if(!$thisstaff->isadmin() && !$thisstaff->canCloseTickets()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canCloseTickets()){ $errors['err']='Perm. Denied. You are not allowed to reopen tickets.'; }else{ if($ticket->reopen()){ @@ -233,7 +233,7 @@ if($_POST && !$errors): break; case 'overdue': //Mark the ticket as overdue - if(!$thisstaff->isadmin() && !$thisstaff->isManager()){ + if(!$thisstaff->isAdmin() && !$thisstaff->isManager()){ $errors['err']='Perm. Denied. You are not allowed to flag tickets overdue'; }else{ if($ticket->markOverdue()){ @@ -252,7 +252,7 @@ if($_POST && !$errors): } break; case 'banemail': - if(!$thisstaff->isadmin() && !$thisstaff->canManageBanList()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canBanEmails()){ $errors['err']='Perm. Denied. You are not allowed to ban emails'; }elseif(Banlist::add($ticket->getEmail(),$thisstaff->getName())){ $msg='Email ('.$ticket->getEmail().') added to banlist'; @@ -266,7 +266,7 @@ if($_POST && !$errors): } break; case 'unbanemail': - if(!$thisstaff->isadmin() && !$thisstaff->canManageBanList()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canBanEmails()){ $errors['err']='Perm. Denied. You are not allowed to remove emails from banlist.'; }elseif(Banlist::remove($ticket->getEmail())){ $msg='Email removed from banlist'; @@ -275,7 +275,7 @@ if($_POST && !$errors): } break; case 'delete': // Dude what are you trying to hide? bad customer support?? - if(!$thisstaff->isadmin() && !$thisstaff->canDeleteTickets()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canDeleteTickets()){ $errors['err']='Perm. Denied. You are not allowed to DELETE tickets!!'; }else{ if($ticket->delete()){ @@ -339,7 +339,7 @@ if($_POST && !$errors): $note='Ticket flagged as overdue by '.$thisstaff->getName(); foreach($_POST['tids'] as $k=>$v) { $t = new Ticket($v); - if($t && !$t->isoverdue()) + if($t && !$t->isOverdue()) if($t->markOverdue()) { $i++; $t->logActivity('Ticket Marked Overdue',$note,false,'System'); diff --git a/setup/cleanup.php b/setup/cleanup.php deleted file mode 100644 index 1309228eb6c64eaaee6f16926ec98b06d91d0221..0000000000000000000000000000000000000000 --- a/setup/cleanup.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php -/********************************************************************* - cleanup.php - - Cleanup script called via ajax to migrate attachments. - - Peter Rotich <peter@osticket.com> - Copyright (c) 2006-2012 osTicket - http://www.osticket.com - - Released under the GNU General Public License WITHOUT ANY WARRANTY. - See LICENSE.TXT for details. - - vim: expandtab sw=4 ts=4 sts=4: -**********************************************************************/ -session_start(); -if($_GET['c']>10) { //When Done send 304 - nothing else to do. - $_SESSION['s']='done'; - session_write_close(); - header("HTTP/1.1 304 Not Modified"); - exit; -} -echo "Cleaning up...".time(); -?> diff --git a/setup/css/wizard.css b/setup/css/wizard.css index 6fd18e17854f65a30a2947460a955ca4c403541c..c92b05447a6acb9992ea21be3ce13581840784a9 100644 --- a/setup/css/wizard.css +++ b/setup/css/wizard.css @@ -70,7 +70,7 @@ form .row span { width: 600px; color: #666666; } #overlay { display: none; position: fixed; background: #000; z-index: 2000; } -#loading { padding: 10px 10px 10px 60px; width: 300px; height: 100px; background: url('../images/ajax-loader.gif?1312925608') 10px 50% no-repeat white; position: fixed; display: none; z-index: 3000; } +#loading { padding: 10px 10px 10px 60px; width: 400px; height: 150px; background: url('../images/ajax-loader.gif?1312925608') 10px 50% no-repeat white; position: fixed; display: none; z-index: 3000; } #loading h4 { margin: 3px 0 0 0; padding: 0; color: #d80; } .tip { display: inline-block; width: 16px; height: 16px; outline: none; text-decoration: none; color: #d80; } diff --git a/setup/inc/class.installer.php b/setup/inc/class.installer.php new file mode 100644 index 0000000000000000000000000000000000000000..7b3dbe534eb0af30f13f27223f555849d30a6bb1 --- /dev/null +++ b/setup/inc/class.installer.php @@ -0,0 +1,204 @@ +<?php +/********************************************************************* + class.installer.php + + osTicket Intaller - installs the latest version. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +require_once INC_DIR.'class.setup.php'; + +class Installer extends SetupWizard { + + var $config; + + function Installer($configfile) { + $this->config =$configfile; + $this->errors=array(); + } + + function getConfigFile() { + return $this->config; + } + + function config_exists() { + return ($this->getConfigFile() && file_exists($this->getConfigFile())); + } + + function config_writable() { + return ($this->getConfigFile() && is_writable($this->getConfigFile())); + } + + function check_config() { + return ($this->config_exists() && $this->config_writable()); + } + + //XXX: Latest version insall logic...no carry over. + function install($vars) { + + $this->errors=$f=array(); + + $f['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required'); + $f['email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); + $f['fname'] = array('type'=>'string', 'required'=>1, 'error'=>'First name required'); + $f['lname'] = array('type'=>'string', 'required'=>1, 'error'=>'Last name required'); + $f['admin_email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); + $f['username'] = array('type'=>'username', 'required'=>1, 'error'=>'Username required'); + $f['passwd'] = array('type'=>'password', 'required'=>1, 'error'=>'Password required'); + $f['passwd2'] = array('type'=>'string', 'required'=>1, 'error'=>'Confirm password'); + $f['prefix'] = array('type'=>'string', 'required'=>1, 'error'=>'Table prefix required'); + $f['dbhost'] = array('type'=>'string', 'required'=>1, 'error'=>'Hostname required'); + $f['dbname'] = array('type'=>'string', 'required'=>1, 'error'=>'Database name required'); + $f['dbuser'] = array('type'=>'string', 'required'=>1, 'error'=>'Username required'); + $f['dbpass'] = array('type'=>'string', 'required'=>1, 'error'=>'password required'); + + + if(!Validator::process($f,$vars,$this->errors) && !$this->errors['err']) + $this->errors['err']='Missing or invalid data - correct the errors and try again.'; + + + //Staff's email can't be same as system emails. + if($vars['admin_email'] && $vars['email'] && !strcasecmp($vars['admin_email'],$vars['email'])) + $this->errors['admin_email']='Conflicts with system email above'; + //Admin's pass confirmation. + if(!$this->errors && strcasecmp($vars['passwd'],$vars['passwd2'])) + $this->errors['passwd2']='passwords to not match!'; + //Check table prefix underscore required at the end! + if($vars['prefix'] && substr($vars['prefix'], -1)!='_') + $this->errors['prefix']='Bad prefix. Must have underscore (_) at the end. e.g \'ost_\''; + + //Make sure admin username is not very predictable. XXX: feels dirty but necessary + if(!$this->errors['username'] && in_array(strtolower($vars['username']),array('admin','admins','username','osticket'))) + $this->errors['username']='Bad username'; + + //MYSQL: Connect to the DB and check the version & database (create database if it doesn't exist!) + if(!$this->errors) { + if(!db_connect($vars['dbhost'],$vars['dbuser'],$vars['dbpass'])) + $this->errors['db']='Unable to connect to MySQL server. Possibly invalid login info.'; + elseif(db_version()< $this->getMySQLVersion()) + $this->errors['db']=sprintf('osTicket requires MySQL %s or better!',$this->getMySQLVersion()); + elseif(!db_select_database($vars['dbname']) && !db_create_database($vars['dbname'])) { + $this->errors['dbname']='Database doesn\'t exist'; + $this->errors['db']='Unable to create the database.'; + } elseif(!db_select_database($vars['dbname'])) { + $this->errors['dbname']='Unable to select the database'; + } + } + + //bailout on errors. + if($this->errors) return false; + + /*************** We're ready to install ************************/ + define('ADMIN_EMAIL',$vars['admin_email']); //Needed to report SQL errors during install. + define('PREFIX',$vars['prefix']); //Table prefix + + $schemaFile =INC_DIR.'sql/osticket-v1.7-mysql.sql'; //DB dump. + $debug = true; //XXX:Change it to true to show SQL errors. + + //Last minute checks. + if(!file_exists($schemaFile)) + $this->errors['err']='Internal Error - please make sure your download is the latest (#1)'; + elseif(!($signature=trim(file_get_contents("$schemaFile.md5"))) || strcasecmp($signature, md5_file($schemaFile))) + $this->errors['err']='Unknown or invalid schema signature ('.$signature.' .. '.md5_file($schemaFile).')'; + elseif(!file_exists($this->getConfigFile()) || !($configFile=file_get_contents($this->getConfigFile()))) + $this->errors['err']='Unable to read config file. Permission denied! (#2)'; + elseif(!($fp = @fopen($this->getConfigFile(),'r+'))) + $this->errors['err']='Unable to open config file for writing. Permission denied! (#3)'; + elseif(!$this->load_sql_file($schemaFile,$vars['prefix'], true, $debug)) + $this->errors['err']='Error parsing SQL schema! Get help from developers (#4)'; + + if(!$this->errors) { + //Create admin user. + $sql='INSERT INTO '.PREFIX.'staff SET created=NOW() ' + .', isactive=1, isadmin=1, group_id=1, dept_id=1, timezone_id=8, max_page_size=25 ' + .', email='.db_input($_POST['admin_email']) + .', firstname='.db_input($vars['fname']) + .', lastname='.db_input($vars['lname']) + .', username='.db_input($vars['username']) + .', passwd='.db_input(Passwd::hash($vars['passwd'])); + if(!mysql_query($sql) || !($uid=mysql_insert_id())) + $this->errors['err']='Unable to create admin user (#6)'; + } + + if(!$this->errors) { + //Create config settings---default settings! + //XXX: rename ostversion helpdesk_* ?? + $sql='INSERT INTO '.PREFIX.'config SET updated=NOW(), isonline=0 ' + .', default_email_id=1, alert_email_id=2, default_dept_id=1 ' + .', default_sla_id=1, default_timezone_id=8, default_template_id=1 ' + .', admin_email='.db_input($vars['admin_email']) + .', schema_signature='.db_input($signature) + .', helpdesk_url='.db_input(URL) + .', helpdesk_title='.db_input($vars['name']); + if(!mysql_query($sql) || !($cid=mysql_insert_id())) + $this->errors['err']='Unable to create config settings (#7)'; + } + + if($this->errors) return false; //Abort on internal errors. + + + //Rewrite the config file - MUST be done last to allow for installer recovery. + $configFile= str_replace("define('OSTINSTALLED',FALSE);","define('OSTINSTALLED',TRUE);",$configFile); + $configFile= str_replace('%ADMIN-EMAIL',$vars['admin_email'],$configFile); + $configFile= str_replace('%CONFIG-DBHOST',$vars['dbhost'],$configFile); + $configFile= str_replace('%CONFIG-DBNAME',$vars['dbname'],$configFile); + $configFile= str_replace('%CONFIG-DBUSER',$vars['dbuser'],$configFile); + $configFile= str_replace('%CONFIG-DBPASS',$vars['dbpass'],$configFile); + $configFile= str_replace('%CONFIG-PREFIX',$vars['prefix'],$configFile); + $configFile= str_replace('%CONFIG-SIRI',Misc::randcode(32),$configFile); + if(!$fp || !ftruncate($fp,0) || !fwrite($fp,$configFile)) { + $this->errors['err']='Unable to write to config file. Permission denied! (#5)'; + return false; + } + @fclose($fp); + + /************* Make the system happy ***********************/ + //Create default emails! + $email = $vars['email']; + list(,$domain)=explode('@',$vars['email']); + $sql='INSERT INTO '.PREFIX.'email (`email_id`, `dept_id`, `name`,`email`,`created`,`updated`) VALUES ' + ." (1,1,'Support','$email',NOW(),NOW())" + .",(2,1,'osTicket Alerts','alerts@$domain',NOW(),NOW())" + .",(3,1,'','noreply@$domain',NOW(),NOW())"; + @mysql_query($sql); + + //Create a ticket to make the system warm and happy. + $sql='INSERT INTO '.PREFIX.'ticket SET created=NOW(), status="open", source="Web" ' + .' ,priority_id=2, dept_id=1, topic_id=1 ' + .' ,ticketID='.db_input(Misc::randNumber(6)) + .' ,email="support@osticket.com" ' + .' ,name="osTicket Support" ' + .' ,subject="osTicket Installed!"'; + if(mysql_query($sql) && ($tid=mysql_insert_id())) { + if(!($msg=file_get_contents(INC_DIR.'msg/installed.txt'))) + $msg='Congratulations and Thank you for choosing osTicket!'; + + $sql='INSERT INTO '.PREFIX.'ticket_thread SET created=NOW()' + .', source="Web" ' + .', thread_type="M" ' + .', ticket_id='.db_input($tid) + .', title='.db_input('osTicket Installed') + .', body='.db_input($msg); + @mysql_query($sql); + } + //TODO: create another personalized ticket and assign to admin?? + + //Log a message. + $msg="Congratulations osTicket basic installation completed!\n\nThank you for choosing osTicket!"; + $sql='INSERT INTO '.PREFIX.'syslog SET created=NOW(), updated=NOW(), log_type="Debug" ' + .', title="osTicket installed!"' + .', log='.db_input($msg) + .', ip_address='.db_input($_SERVER['REMOTE_ADDR']); + @mysql_query($sql); + + return true; + } +} +?> diff --git a/setup/inc/class.migrater.php b/setup/inc/class.migrater.php new file mode 100644 index 0000000000000000000000000000000000000000..de8a3d9590e97b9d78ecb905528bcbc1bc2c03a5 --- /dev/null +++ b/setup/inc/class.migrater.php @@ -0,0 +1,67 @@ +<?php +/********************************************************************* + class.migrater.php + + SQL database migrater. This provides the engine capable of rolling the + database for an osTicket installation forward (and perhaps even + backward) in time using a set of included migration scripts. Each script + will roll the database between two database checkpoints. Where possible, + the migrater will roll several checkpoint scripts into one to be applied + together. + + Jared Hancock <jared@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ + +class DatabaseMigrater { + + var $start; + var $end; + var $sqldir; + + function DatabaseMigrater($start, $end, $sqldir) { + + $this->start = $start; + $this->end = $end; + $this->sqldir = $sqldir; + + } + + function getPatches($stop=null) { + + $start= $this->start; + $stop = $stop?$stop:$this->end; + + $patches = array(); + while (true) { + $next = glob($this->sqldir . substr($start, 0, 8) + . '-*.patch.sql'); + if (count($next) == 1) { + $patches[] = $next[0]; + $start = substr(basename($next[0]), 9, 8); + } elseif (count($next) == 0) { + # There are no patches leaving the current signature. We + # have to assume that we've applied all the available + # patches. + break; + } else { + # Problem -- more than one patch exists from this snapshot. + # We probably need a graph approach to solve this. + break; + } + + # Break if we've reached our target stop. + if(!$start || !strncasecmp($start, $stop, 8)) + break; + } + + return $patches; + } +} +?> diff --git a/setup/inc/class.setup.php b/setup/inc/class.setup.php index c6bf7b6751c9e80236d3cbfe143a37c6d52cf6c5..438eca54505302a30d6da9575067c90b296369dc 100644 --- a/setup/inc/class.setup.php +++ b/setup/inc/class.setup.php @@ -21,8 +21,8 @@ Class SetupWizard { 'mysql' => '4.4'); //Version info - same as the latest version. - var $version ='1.7-rc1'; - var $version_verbose='1.7 RC 1'; + var $version ='1.7-dpr3'; + var $version_verbose='1.7 DPR 3'; //Errors var $errors=array(); @@ -31,34 +31,34 @@ Class SetupWizard { $this->errors=array(); } - function load_sql_file($file, $prefix, $debug=false) { + function load_sql_file($file, $prefix, $abort=true, $debug=false) { if(!file_exists($file) || !($schema=file_get_contents($file))) - return $this->abort('Error accessing SQL file'); + return $this->abort('Error accessing SQL file '.basename($file), $debug); - return $this->load_sql($schema, $prefix, $debug); + return $this->load_sql($schema, $prefix, $abort, $debug); } /* load SQL schema - assumes MySQL && existing connection */ - function load_sql($schema, $prefix, $debug=false) { + function load_sql($schema, $prefix, $abort=true, $debug=false) { # Strip comments and remarks - $schema=preg_replace('%^\s*(#|--).*$%m','',$schema); + $schema=preg_replace('%^\s*(#|--).*$%m', '', $schema); # Replace table prefis - $schema = str_replace('%TABLE_PREFIX%',$prefix, $schema); + $schema = str_replace('%TABLE_PREFIX%', $prefix, $schema); # Split by semicolons - and cleanup if(!($statements = array_filter(array_map('trim', @explode(';', $schema))))) - return $this->abort('Error parsing SQL schema'); + return $this->abort('Error parsing SQL schema', $debug); @mysql_query('SET SESSION SQL_MODE =""'); foreach($statements as $k=>$sql) { - if(!mysql_query($sql)) { - if($debug) echo "[$sql]=>".mysql_error(); - return $this->abort("[$sql] - ".mysql_error()); - } + if(mysql_query($sql)) continue; + $error = "[$sql] ".mysql_error(); + if($abort) + return $this->abort($error, $debug); } return true; @@ -81,7 +81,7 @@ Class SetupWizard { } function check_php() { - return (version_compare(PHP_VERSION,$this->getPHPVersion())>=0); + return (version_compare(PHP_VERSION, $this->getPHPVersion())>=0); } function check_mysql() { @@ -95,293 +95,28 @@ Class SetupWizard { /* @error is a mixed var. */ - function abort($error) { - + function abort($error, $debug=false) { + + if($debug) echo $error; + $this->onError($error); + return false; // Always false... It's an abort. + } + + function setError($error) { + if($error && is_array($error)) - $this->errors = array_merge($this->errors,$error); + $this->errors = array_merge($this->errors, $error); elseif($error) $this->errors[] = $error; - - //Always returns FALSE. - return false; } function getErrors(){ - return $this->errors; } - /* Access and user validation*/ - - function getThisUser() { - - - } -} - -class Upgrader extends SetupWizard { - - var $prefix; - - function Upgrader($prefix) { - $this->prefix = $prefix; - $this->errors = array(); - } - - function getTablePrefix() { - return $this->prefix; - } - - /* upgrade magic related to the given version */ - function upgradeTo($version) { - - $errors = array(); - switch($version) { - case '1.7-RC1': - //TODO: latest upgrade logic. - break; - case '1.6 ST': - //TODO: refactor code from 1.6 ST. - break; - case '1.6 RC5': - //TODO: refactor code from 1.6 ST. - break; - default: - //XXX: escape version - return $this->abort('Trying to upgrade unknown version '.$version); - } - - if($errors) - return $this->abort($errors); - - return true; - } - - /* - Do base upgrade - Does fall-through upgrade until we reach the current version. - We're assumming the user - is upgrading upgradable version of osTicket! - @version - version number to upgrade from! - */ - function upgradeFrom($version) { - - if(!$version || $this->getErrors()) - return false; - - if(!strcasecmp($version,$this->getVersion())) - return true; - - //XXX: Note FALLTHROUGH (we only break on error) and uppercase cases. - switch(strtoupper($version)) { - case 'OLD': //Upgrade old versions to 1.6 ST. - if(!$this->upgradeTo('1.6 RC5')) break; - /* FALLTHROUGH */ - case '1.6 RC5': //Upgrade 1.6 RC5 to 1.6 ST - if(!$this->upgradeTo('1.6 ST')) break; - /* FALLTHROUGH */ - case '1.6 ST': //Upgrade 1.6 ST to to 1.7 RC1 - if(!$this->upgradeTo('1.7-RC1')) break; - /* LAST CASE IS NOT FALLTHROUGH */ - break; - default: //Catch all - Upgrading older versions 1.3+ - return $this->upgradeFrom('OLD'); - } - //XXX: Set errors??? - - return (!$this->getErrors()); - } - - function cleanup() { - //FIXME: cleanup logic here. - sleep(2); - - return true; - } -} - -/* - Installer class - latest version. - */ -class Installer extends SetupWizard { - - var $config; - - function Installer($configfile) { - $this->config =$configfile; - $this->errors=array(); - } - - function getConfigFile() { - return $this->config; - } - - function config_exists() { - return ($this->getConfigFile() && file_exists($this->getConfigFile())); - } - - function config_writable() { - return ($this->getConfigFile() && is_writable($this->getConfigFile())); - } - - function check_config() { - return ($this->config_exists() && $this->config_writable()); - } - - //XXX: Latest version insall logic...no carry over. - function install($vars) { - - $this->errors=$f=array(); - - $f['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required'); - $f['email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); - $f['fname'] = array('type'=>'string', 'required'=>1, 'error'=>'First name required'); - $f['lname'] = array('type'=>'string', 'required'=>1, 'error'=>'Last name required'); - $f['admin_email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); - $f['username'] = array('type'=>'username', 'required'=>1, 'error'=>'Username required'); - $f['passwd'] = array('type'=>'password', 'required'=>1, 'error'=>'Password required'); - $f['passwd2'] = array('type'=>'string', 'required'=>1, 'error'=>'Confirm password'); - $f['prefix'] = array('type'=>'string', 'required'=>1, 'error'=>'Table prefix required'); - $f['dbhost'] = array('type'=>'string', 'required'=>1, 'error'=>'Hostname required'); - $f['dbname'] = array('type'=>'string', 'required'=>1, 'error'=>'Database name required'); - $f['dbuser'] = array('type'=>'string', 'required'=>1, 'error'=>'Username required'); - $f['dbpass'] = array('type'=>'string', 'required'=>1, 'error'=>'password required'); - - - if(!Validator::process($f,$vars,$this->errors) && !$this->errors['err']) - $this->errors['err']='Missing or invalid data - correct the errors and try again.'; - - - //Staff's email can't be same as system emails. - if($vars['admin_email'] && $vars['email'] && !strcasecmp($vars['admin_email'],$vars['email'])) - $this->errors['admin_email']='Conflicts with system email above'; - //Admin's pass confirmation. - if(!$this->errors && strcasecmp($vars['passwd'],$vars['passwd2'])) - $this->errors['passwd2']='passwords to not match!'; - //Check table prefix underscore required at the end! - if($vars['prefix'] && substr($vars['prefix'], -1)!='_') - $this->errors['prefix']='Bad prefix. Must have underscore (_) at the end. e.g \'ost_\''; - - //Make sure admin username is not very predictable. XXX: feels dirty but necessary - if(!$this->errors['username'] && in_array(strtolower($vars['username']),array('admin','admins','username','osticket'))) - $this->errors['username']='Bad username'; - - //MYSQL: Connect to the DB and check the version & database (create database if it doesn't exist!) - if(!$this->errors) { - if(!db_connect($vars['dbhost'],$vars['dbuser'],$vars['dbpass'])) - $this->errors['db']='Unable to connect to MySQL server. Possibly invalid login info.'; - elseif(db_version()< $this->getMySQLVersion()) - $this->errors['db']=sprintf('osTicket requires MySQL %s or better!',$this->getMySQLVersion()); - elseif(!db_select_database($vars['dbname']) && !db_create_database($vars['dbname'])) { - $this->errors['dbname']='Database doesn\'t exist'; - $this->errors['db']='Unable to create the database.'; - } elseif(!db_select_database($vars['dbname'])) { - $this->errors['dbname']='Unable to select the database'; - } - } - - //bailout on errors. - if($this->errors) return false; - - /*************** We're ready to install ************************/ - define('ADMIN_EMAIL',$vars['admin_email']); //Needed to report SQL errors during install. - define('PREFIX',$vars['prefix']); //Table prefix - - $schemaFile =INC_DIR.'sql/osticket-v1.7-mysql.sql'; //DB dump. - $debug = true; //XXX:Change it to true to show SQL errors. - - //Last minute checks. - if(!file_exists($schemaFile)) - $this->errors['err']='Internal Error - please make sure your download is the latest (#1)'; - elseif(!file_exists($this->getConfigFile()) || !($configFile=file_get_contents($this->getConfigFile()))) - $this->errors['err']='Unable to read config file. Permission denied! (#2)'; - elseif(!($fp = @fopen($this->getConfigFile(),'r+'))) - $this->errors['err']='Unable to open config file for writing. Permission denied! (#3)'; - elseif(!$this->load_sql_file($schemaFile,$vars['prefix'],$debug)) - $this->errors['err']='Error parsing SQL schema! Get help from developers (#4)'; - - if(!$this->errors) { - //Create admin user. - $sql='INSERT INTO '.PREFIX.'staff SET created=NOW() ' - .', isactive=1, isadmin=1, group_id=1, dept_id=1, timezone_id=8, max_page_size=25 ' - .', email='.db_input($_POST['admin_email']) - .', firstname='.db_input($vars['fname']) - .', lastname='.db_input($vars['lname']) - .', username='.db_input($vars['username']) - .', passwd='.db_input(Passwd::hash($vars['passwd'])); - if(!mysql_query($sql) || !($uid=mysql_insert_id())) - $this->errors['err']='Unable to create admin user (#6)'; - } - - if(!$this->errors) { - //Create config settings---default settings! - //XXX: rename ostversion helpdesk_* ?? - $sql='INSERT INTO '.PREFIX.'config SET updated=NOW(), isonline=0 ' - .', default_email_id=1, alert_email_id=2, default_dept_id=1 ' - .', default_sla_id=1, default_timezone_id=8, default_template_id=1 ' - .', admin_email='.db_input($vars['admin_email']) - .', schema_signature='.db_input(md5_file($schemaFile)) - .', helpdesk_url='.db_input(URL) - .', helpdesk_title='.db_input($vars['name']); - if(!mysql_query($sql) || !($cid=mysql_insert_id())) - $this->errors['err']='Unable to create config settings (#7)'; - } - - if($this->errors) return false; //Abort on internal errors. - - - //Rewrite the config file - MUST be done last to allow for installer recovery. - $configFile= str_replace("define('OSTINSTALLED',FALSE);","define('OSTINSTALLED',TRUE);",$configFile); - $configFile= str_replace('%ADMIN-EMAIL',$vars['admin_email'],$configFile); - $configFile= str_replace('%CONFIG-DBHOST',$vars['dbhost'],$configFile); - $configFile= str_replace('%CONFIG-DBNAME',$vars['dbname'],$configFile); - $configFile= str_replace('%CONFIG-DBUSER',$vars['dbuser'],$configFile); - $configFile= str_replace('%CONFIG-DBPASS',$vars['dbpass'],$configFile); - $configFile= str_replace('%CONFIG-PREFIX',$vars['prefix'],$configFile); - $configFile= str_replace('%CONFIG-SIRI',Misc::randcode(32),$configFile); - if(!$fp || !ftruncate($fp,0) || !fwrite($fp,$configFile)) { - $this->errors['err']='Unable to write to config file. Permission denied! (#5)'; - return false; - } - @fclose($fp); - - /************* Make the system happy ***********************/ - //Create default emails! - $email = $vars['email']; - list(,$domain)=explode('@',$vars['email']); - $sql='INSERT INTO '.PREFIX.'email (`email_id`, `dept_id`, `name`,`email`,`created`,`updated`) VALUES ' - ." (1,1,'Support','$email',NOW(),NOW())" - .",(2,1,'osTicket Alerts','alerts@$domain',NOW(),NOW())" - .",(3,1,'','noreply@$domain',NOW(),NOW())"; - @mysql_query($sql); - - //Create a ticket to make the system warm and happy. - $sql='INSERT INTO '.PREFIX.'ticket SET created=NOW(), status="open", source="Web" ' - .' ,priority_id=2, dept_id=1, topic_id=1 ' - .' ,ticketID='.db_input(Misc::randNumber(6)) - .' ,email="support@osticket.com" ' - .' ,name="osTicket Support" ' - .' ,subject="osTicket Installed!"'; - if(mysql_query($sql) && ($tid=mysql_insert_id())) { - if(!($msg=file_get_contents(INC_DIR.'msg/installed.txt'))) - $msg='Congratulations and Thank you for choosing osTicket!'; - - $sql='INSERT INTO '.PREFIX.'ticket_message SET created=NOW(),source="Web" ' - .', ticket_id='.db_input($tid) - .', message='.db_input($msg); - @mysql_query($sql); - } - //TODO: create another personalized ticket and assign to admin?? - - //Log a message. - $msg="Congratulations osTicket basic installation completed!\n\nThank you for choosing osTicket!"; - $sql='INSERT INTO '.PREFIX.'syslog SET created=NOW(),updated=NOW(),log_type="Debug" ' - .', title="osTicket installed!"' - .', log='.db_input($msg) - .', ip_address='.db_input($_SERVER['REMOTE_ADDR']); - @mysql_query($sql); - - return true; + function onError($error) { + return $this->setError($error); } } ?> diff --git a/setup/inc/class.upgrader.php b/setup/inc/class.upgrader.php new file mode 100644 index 0000000000000000000000000000000000000000..73af7e6066cddf41140d7bd6f2c2618431dfe83f --- /dev/null +++ b/setup/inc/class.upgrader.php @@ -0,0 +1,273 @@ +<?php +/********************************************************************* + class.upgrader.php + + osTicket Upgrader + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ + +require_once INC_DIR.'class.setup.php'; +require_once INC_DIR.'class.migrater.php'; + +class Upgrader extends SetupWizard { + + var $prefix; + var $sqldir; + var $signature; + + function Upgrader($signature, $prefix, $sqldir) { + + $this->signature = $signature; + $this->shash = substr($signature, 0, 8); + $this->prefix = $prefix; + $this->sqldir = $sqldir; + $this->errors = array(); + + //Init persistent state of upgrade. + $this->state = &$_SESSION['ost_upgrader'][$this->getShash()]['state']; + + //Init the task Manager. + if(!isset($_SESSION['ost_upgrader'][$this->getShash()])) + $_SESSION['ost_upgrader'][$this->getShash()]['tasks']=array(); + + //Tasks to perform - saved on the session. + $this->tasks = &$_SESSION['ost_upgrader'][$this->getShash()]['tasks']; + + //Database migrater + $this->migrater = new DatabaseMigrater($this->signature, SCHEMA_SIGNATURE, $this->sqldir); + } + + function getStops() { + return array('7be60a84' => 'migrateAttachments2DB'); + } + + function onError($error) { + + Sys::log(LOG_ERR, 'Upgrader Error', $error); + $this->setError($error); + $this->setState('aborted'); + } + + function isUpgradable() { + return (!$this->isAborted() && $this->getNextPatch()); + } + + function isAborted() { + return !strcasecmp($this->getState(), 'aborted'); + } + + function getSchemaSignature() { + return $this->signature; + } + + function getShash() { + return $this->shash; + } + + function getTablePrefix() { + return $this->prefix; + } + + function getSQLDir() { + return $this->sqldir; + } + + function getState() { + return $this->state; + } + + function setState($state) { + $this->state = $state; + } + + function getPatches() { + return $this->migrater->getPatches(); + } + + function getNextPatch() { + $p = $this->getPatches(); + return (count($p)) ? $p[0] : false; + } + + function getNextVersion() { + if(!$patch=$this->getNextPatch()) + return '(Latest)'; + + $info = $this->readPatchInfo($patch); + return $info['version']; + } + + function readPatchInfo($patch) { + $info = array(); + if (preg_match('/\*(.*)\*/', file_get_contents($patch), $matches)) { + if (preg_match('/@([\w\d_-]+)\s+(.*)$/', $matches[0], $matches2)) + foreach ($matches2 as $match) + $info[$match[0]] = $match[1]; + } + if (!isset($info['version'])) + $info['version'] = substr(basename($patch), 9, 8); + return $info; + } + + function getNextAction() { + + $action='Upgrade osTicket to '.$this->getVersion(); + if($this->getNumPendingTasks() && ($task=$this->getNextTask())) { + $action = $task['desc']; + if($task['status']) //Progress report... + $action.=' ('.$task['status'].')'; + } elseif($this->isUpgradable() && ($nextversion = $this->getNextVersion())) { + $action = "Upgrade to $nextversion"; + } + + return $action; + } + + function getNumPendingTasks() { + + return count($this->getPendingTasks()); + } + + function getPendingTasks() { + + $pending=array(); + if(($tasks=$this->getTasks())) { + foreach($tasks as $k => $task) { + if(!$task['done']) + $pending[$k] = $task; + } + } + + return $pending; + } + + function getTasks() { + return $this->tasks; + } + + function getNextTask() { + + if(!($tasks=$this->getPendingTasks())) + return null; + + return current($tasks); + } + + function removeTask($tId) { + + if(isset($this->tasks[$tId])) + unset($this->tasks[$tId]); + + return (!$this->tasks[$tId]); + } + + function setTaskStatus($tId, $status) { + if(isset($this->tasks[$tId])) + $this->tasks[$tId]['status'] = $status; + } + + function doTasks() { + + if(!($tasks=$this->getPendingTasks())) + return true; //Nothing to do. + + foreach($tasks as $k => $task) { + if(call_user_func(array($this, $task['func']), $k)===0) { + $this->tasks[$k]['done'] = true; + } else { //Task has pending items to process. + break; + } + } + + return (!$this->getPendingTasks()); + } + + function upgrade() { + + if($this->getPendingTasks() || !($patches=$this->getPatches())) + return false; + + foreach ($patches as $patch) { + if (!$this->load_sql_file($patch, $this->getTablePrefix())) + return false; + + //clear previous patch info - + unset($_SESSION['ost_upgrader'][$this->getShash()]); + + $phash = substr(basename($patch), 0, 17); + + //Log the patch info + $logMsg = "Patch $phash applied "; + if(($info = $this->readPatchInfo($patch)) && $info['version']) + $logMsg.= ' ('.$info['version'].') '; + + Sys::log(LOG_DEBUG, 'Upgrader - Patch applied', $logMsg); + + //Check if the said patch has scripted tasks + if(!($tasks=$this->getTasksForPatch($phash))) + continue; + + //We have work to do... set the tasks and break. + $shash = substr($phash, 9, 8); + $_SESSION['ost_upgrader'][$shash]['tasks'] = $tasks; + $_SESSION['ost_upgrader'][$shash]['state'] = 'upgrade'; + break; + } + + return true; + + } + + function getTasksForPatch($phash) { + + $tasks=array(); + switch($phash) { //Add patch specific scripted tasks. + case 'd4fe13b1-7be60a84': //V1.6 ST- 1.7 * + $tasks[] = array('func' => 'migrateAttachments2DB', + 'desc' => 'Migrating attachments to database, it might take a while depending on the number of files.'); + break; + } + + //Check if cleanup p + $file=$this->getSQLDir().$phash.'.cleanup.sql'; + if(file_exists($file)) + $tasks[] = array('func' => 'cleanup', 'desc' => 'Post-upgrade cleanup!'); + + + return $tasks; + } + + /************* TASKS **********************/ + function cleanup($tId=0) { + + $file=$this->getSQLDir().$this->getShash().'-cleanup.sql'; + if(!file_exists($file)) //No cleanup script. + return 0; + + //We have a cleanup script ::XXX: Don't abort on error? + if($this->load_sql_file($file, $this->getTablePrefix(), false, true)) + return 0; + + //XXX: ??? + return false; + } + + + function migrateAttachments2DB($tId=0) { + echo "Process attachments here - $tId"; + $att_migrater = new AttachmentMigrater(); + $att_migrater->start_migration(); + # XXX: Loop here (with help of task manager) + $att_migrater->do_batch(); + return 0; + } +} +?> diff --git a/setup/inc/sql/02decaa2-60fcbee1.patch.sql b/setup/inc/sql/02decaa2-60fcbee1.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..40dc644b3df64b0e103a3a7c16ed3c835a4bfae3 --- /dev/null +++ b/setup/inc/sql/02decaa2-60fcbee1.patch.sql @@ -0,0 +1,6 @@ +-- Update all temlates with the new wording. +UPDATE `%TABLE_PREFIX%email_template` + SET `ticket_overlimit_body` = '%name\r\n\r\nYou have reached the maximum number of open tickets allowed.\r\n\r\nTo be able to open another ticket, one of your pending tickets must be closed. To update or add comments to an open ticket simply login using the link below.\r\n\r\n%url/view.php?e=%email\r\n\r\nThank you.\r\n\r\nSupport Ticket System'; + +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='60fcbee1da3180d1b690187aa5006c88'; diff --git a/setup/inc/sql/49478749-c2d2fabf.patch.sql b/setup/inc/sql/49478749-c2d2fabf.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..506d85572be1438a2734627f447e04f8616d6285 --- /dev/null +++ b/setup/inc/sql/49478749-c2d2fabf.patch.sql @@ -0,0 +1,2 @@ +ALTER TABLE `%TABLE_PREFIX%config` CHANGE `show_answered_tickets` `show_answered_tickets` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0'; +ALTER TABLE `%TABLE_PREFIX%config` ADD `show_notes_inline` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `show_answered_tickets`; diff --git a/setup/inc/sql/522e5b78-02decaa2.patch.sql b/setup/inc/sql/522e5b78-02decaa2.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..78c951d69cc10f255ffb3e4ba85fcf93dae6db58 --- /dev/null +++ b/setup/inc/sql/522e5b78-02decaa2.patch.sql @@ -0,0 +1,10 @@ +/** + * @version v1.7-DPR2-P2 + */ +UPDATE `%TABLE_PREFIX%sla` + SET `created` = NOW(), + `updated` = NOW() + WHERE `created` IS NULL; + +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='02decaa20c10c9615558762018e25507'; diff --git a/setup/inc/sql/60fcbee1-f8856d56.patch.sql b/setup/inc/sql/60fcbee1-f8856d56.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..2b7e48599816e88702f709f50557189b160a727e --- /dev/null +++ b/setup/inc/sql/60fcbee1-f8856d56.patch.sql @@ -0,0 +1,19 @@ +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`; +CREATE TABLE `%TABLE_PREFIX%ticket_event` ( + `ticket_id` int(11) unsigned NOT NULL default '0', + `staff_id` int(11) unsigned NOT NULL, + `team_id` int(11) unsigned NOT NULL, + `dept_id` int(11) unsigned NOT NULL, + `topic_id` int(11) unsigned NOT NULL, + `state` enum('created','closed','reopened','assigned','transferred','overdue') NOT NULL, + `staff` varchar(255) NOT NULL default 'SYSTEM', + `timestamp` datetime NOT NULL, + KEY `ticket_state` (`ticket_id`, `state`, `timestamp`), + KEY `ticket_stats` (`timestamp`, `state`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_history`; +DROP TABLE IF EXISTS `%TABLE_PREFIX%history`; + +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='f8856d56e51c5cc3416389de78b54515'; diff --git a/setup/inc/sql/7be60a84-522e5b78.patch.sql b/setup/inc/sql/7be60a84-522e5b78.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..acdaf7d0d3c1f8baaedd40bd68e33b01b97e72c9 --- /dev/null +++ b/setup/inc/sql/7be60a84-522e5b78.patch.sql @@ -0,0 +1,9 @@ +/** + * @version v1.7-DPR1 (P1) + */ +UPDATE `%TABLE_PREFIX%email_template` + SET `ticket_overlimit_subj` = 'Open Tickets Limit Reached' + WHERE `tpl_id` = 1 AND `cfg_id` = 1; + +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='522e5b783c2824c67222260ee22baa93'; diff --git a/setup/inc/sql/abe9c0cb-bbb021fb.patch.sql b/setup/inc/sql/abe9c0cb-bbb021fb.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..0a3248db4569aebd2ce75eed39cfff3da68d559c --- /dev/null +++ b/setup/inc/sql/abe9c0cb-bbb021fb.patch.sql @@ -0,0 +1,14 @@ +/** + * Add an 'annulled' column to the %ticket_event table to assist in tracking + * real statistics for reopened and closed tickets -- the events should not + * count more than one time. + * + * @version 1.7-dpr3 ticket-event-annul + */ + +ALTER TABLE `%TABLE_PREFIX%ticket_event` + ADD `annulled` tinyint(1) NOT NULL DEFAULT '0' AFTER `staff`; + +-- Finished with patch +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='bbb021fbeb377ca66b6997b77e0167cc'; diff --git a/setup/inc/sql/bbb021fb-49478749.patch.sql b/setup/inc/sql/bbb021fb-49478749.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..8bd81f32016f936848f790ef325e1613317cc3fc --- /dev/null +++ b/setup/inc/sql/bbb021fb-49478749.patch.sql @@ -0,0 +1,9 @@ +/** + * Transitional patch - FIX on the INSTALLER schema + * + * @version 1.7-dpr3 installerfix + */ + +-- Finished with patch +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='49478749dc680eef08b7954bd568cfd1'; diff --git a/setup/inc/sql/f8856d56-abe9c0cb.patch.sql b/setup/inc/sql/f8856d56-abe9c0cb.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..a5f54aa8516aaaaf268e363b8ae58674725b61af --- /dev/null +++ b/setup/inc/sql/f8856d56-abe9c0cb.patch.sql @@ -0,0 +1,109 @@ +/** + * Merge ticket thread tables into one + * + * Replace the ticket_{message,response,note} tables with a single + * ticket_thread table that will contain data for all three current message + * types. This simplifies much of the ticket thread code and paves the way + * for other types of messages in the future. + * + * This patch automagically moves the data from the three federated tables + * into the one combined table. + */ +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_thread`; +CREATE TABLE `%TABLE_PREFIX%ticket_thread` ( + `id` int(11) unsigned NOT NULL auto_increment, + `pid` int(11) unsigned NOT NULL default '0', + `ticket_id` int(11) unsigned NOT NULL default '0', + `staff_id` int(11) unsigned NOT NULL default '0', + `thread_type` enum('M','R','N') NOT NULL, + `poster` varchar(128) NOT NULL default '', + `source` varchar(32) NOT NULL default '', + `title` varchar(255), + `body` text NOT NULL, + `ip_address` varchar(64) NOT NULL default '', + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + -- Temporary columns for conversion + `old_pk` int(11) unsigned NOT NULL, + `old_pid` int(11) unsigned, + PRIMARY KEY (`id`), + KEY `ticket_id` (`ticket_id`), + KEY `staff_id` (`staff_id`), + FULLTEXT KEY `body` (`body`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_email_info`; +CREATE TABLE `%TABLE_PREFIX%ticket_email_info` ( + `message_id` int(11) unsigned NOT NULL, + `email_mid` varchar(255) NOT NULL, + `headers` text, + KEY `message_id` (`email_mid`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- Transfer messages +INSERT INTO `%TABLE_PREFIX%ticket_thread` + (`ticket_id`, `thread_type`, `body`, `ip_address`, + `created`, `updated`, `old_pk`) + SELECT `ticket_id`, 'M', `message`, `ip_address`, + `created`, COALESCE(`updated`, NOW()), `msg_id` + FROM `%TABLE_PREFIX%ticket_message`; + +-- Transfer responses +INSERT INTO `%TABLE_PREFIX%ticket_thread` + (`ticket_id`, `staff_id`, `thread_type`, `poster`, `body`, `ip_address`, + `created`, `updated`, `old_pk`, `old_pid`) + SELECT `ticket_id`, `staff_id`, 'R', `staff_name`, `response`, `ip_address`, + `created`, COALESCE(`updated`, NOW()), `response_id`, `msg_id` + FROM `%TABLE_PREFIX%ticket_response`; + +-- Connect responses to (new) messages +CREATE TABLE `%TABLE_PREFIX%T_resp_links` + SELECT `id`, `old_pk`, `old_pid` FROM `%TABLE_PREFIX%ticket_thread`; + +UPDATE `%TABLE_PREFIX%ticket_thread` + SET `pid` = ( SELECT T2.`id` FROM `%TABLE_PREFIX%T_resp_links` T2 + WHERE `old_pid` = T2.`old_pk` ) + WHERE `thread_type` = 'R' + AND `old_pid` IS NOT NULL; + +DROP TABLE `%TABLE_PREFIX%T_resp_links`; + +-- Transfer notes +INSERT INTO `%TABLE_PREFIX%ticket_thread` + (`ticket_id`, `staff_id`, `thread_type`, `body`, `title`, + `source`, `poster`, `created`, `updated`, `old_pk`) + SELECT `ticket_id`, `staff_id`, 'N', `note`, `title`, + `source`, ( SELECT CONCAT_WS(' ', T2.`firstname`, T2.`lastname`) + FROM `%TABLE_PREFIX%staff` T2 + WHERE T2.`staff_id` = `staff_id` ), + `created`, NOW(), `note_id` + FROM `%TABLE_PREFIX%ticket_note`; + +-- Transfer email information from messages +INSERT INTO `%TABLE_PREFIX%ticket_email_info` + (`message_id`, `email_mid`, `headers`) + SELECT ( SELECT T2.`id` FROM `%TABLE_PREFIX%ticket_thread` T2 + WHERE `msg_id` = T2.`old_pk` + AND `thread_type` = 'M' ), + `messageId`, `headers` + FROM `%TABLE_PREFIX%ticket_message` + WHERE `messageId` IS NOT NULL; + +-- Update attachment table +UPDATE `%TABLE_PREFIX%ticket_attachment` + SET `ref_id` = ( SELECT T2.`id` FROM `%TABLE_PREFIX%ticket_thread` T2 + WHERE `ref_id` = T2.`old_pk` + AND `ref_type` = T2.`thread_type` ); + +-- Drop temporary columns +ALTER TABLE `%TABLE_PREFIX%ticket_thread` DROP COLUMN `old_pk`; +ALTER TABLE `%TABLE_PREFIX%ticket_thread` DROP COLUMN `old_pid`; + +-- Drop old tables +DROP TABLE `%TABLE_PREFIX%ticket_message`; +DROP TABLE `%TABLE_PREFIX%ticket_response`; +DROP TABLE `%TABLE_PREFIX%ticket_note`; + +-- Finished with patch +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='abe9c0cb845be52c10fcd7b3e626a589'; diff --git a/setup/inc/sql/osticket-v1.7-mysql.sql b/setup/inc/sql/osticket-v1.7-mysql.sql index df11daf8612702b46a2c9fda0be56a2fe16f2445..a3d03dd7218066d54ee3b900fba1fad9129add9a 100644 --- a/setup/inc/sql/osticket-v1.7-mysql.sql +++ b/setup/inc/sql/osticket-v1.7-mysql.sql @@ -134,7 +134,8 @@ CREATE TABLE `%TABLE_PREFIX%config` ( `auto_assign_reopened_tickets` tinyint(1) unsigned NOT NULL default '1', `show_related_tickets` tinyint(1) unsigned NOT NULL default '1', `show_assigned_tickets` tinyint(1) unsigned NOT NULL default '0', - `show_answered_tickets` tinyint(1) NOT NULL default '0', + `show_answered_tickets` tinyint(1) unsigned NOT NULL default '0', + `show_notes_inline` tinyint(1) unsigned NOT NULL default '1', `hide_staff_name` tinyint(1) unsigned NOT NULL default '0', `overlimit_notice_active` tinyint(1) unsigned NOT NULL default '0', `email_attachments` tinyint(1) unsigned NOT NULL default '1', @@ -598,48 +599,29 @@ CREATE TABLE `%TABLE_PREFIX%ticket_lock` ( KEY `staff_id` (`staff_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_history`; -CREATE TABLE `%TABLE_PREFIX%ticket_history` ( +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_email_info`; +CREATE TABLE `%TABLE_PREFIX%ticket_email_info` ( + `message_id` int(11) unsigned NOT NULL, + `email_mid` varchar(255) NOT NULL, + `headers` text, + KEY `message_id` (`email_mid`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`; +CREATE TABLE `%TABLE_PREFIX%ticket_event` ( `ticket_id` int(11) unsigned NOT NULL default '0', - `state` enum('opened','closed','assigned','transferred','overdue') NOT NULL, + `staff_id` int(11) unsigned NOT NULL, + `team_id` int(11) unsigned NOT NULL, + `dept_id` int(11) unsigned NOT NULL, + `topic_id` int(11) unsigned NOT NULL, + `state` enum('created','closed','reopened','assigned','transferred','overdue') NOT NULL, `staff` varchar(255) NOT NULL default 'SYSTEM', + `annulled` tinyint(1) unsigned NOT NULL default '0', `timestamp` datetime NOT NULL, KEY `ticket_state` (`ticket_id`, `state`, `timestamp`), KEY `ticket_stats` (`timestamp`, `state`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_message`; -CREATE TABLE `%TABLE_PREFIX%ticket_message` ( - `msg_id` int(11) unsigned NOT NULL auto_increment, - `ticket_id` int(11) unsigned NOT NULL default '0', - `messageId` varchar(255) default NULL, - `message` text NOT NULL, - `headers` text, - `source` varchar(16) default NULL, - `ip_address` varchar(16) default NULL, - `created` datetime NOT NULL, - `updated` datetime default NULL, - PRIMARY KEY (`msg_id`), - KEY `ticket_id` (`ticket_id`), - KEY `msgId` (`messageId`), - FULLTEXT KEY `message` (`message`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_note`; -CREATE TABLE `%TABLE_PREFIX%ticket_note` ( - `note_id` int(11) unsigned NOT NULL auto_increment, - `ticket_id` int(11) unsigned NOT NULL default '0', - `staff_id` int(10) unsigned NOT NULL default '0', - `source` varchar(32) NOT NULL default '', - `title` varchar(255) NOT NULL default 'Generic Intermal Notes', - `note` text NOT NULL, - `created` datetime NOT NULL, - PRIMARY KEY (`note_id`), - KEY `ticket_id` (`ticket_id`), - KEY `staff_id` (`staff_id`), - FULLTEXT KEY `note` (`note`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_priority`; CREATE TABLE `%TABLE_PREFIX%ticket_priority` ( `priority_id` tinyint(4) NOT NULL auto_increment, @@ -660,22 +642,24 @@ INSERT INTO `%TABLE_PREFIX%ticket_priority` (`priority_id`, `priority`, `priorit (3, 'high', 'High', '#FEE7E7', 2, 1), (4, 'emergency', 'Emergency', '#FEE7E7', 1, 0); -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_response`; -CREATE TABLE `%TABLE_PREFIX%ticket_response` ( - `response_id` int(11) unsigned NOT NULL auto_increment, - `msg_id` int(11) unsigned NOT NULL default '0', +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_thread`; +CREATE TABLE `%TABLE_PREFIX%ticket_thread` ( + `id` int(11) unsigned NOT NULL auto_increment, + `pid` int(11) unsigned NOT NULL default '0', `ticket_id` int(11) unsigned NOT NULL default '0', `staff_id` int(11) unsigned NOT NULL default '0', - `staff_name` varchar(32) NOT NULL default '', - `response` text NOT NULL, - `ip_address` varchar(16) NOT NULL default '', + `thread_type` enum('M','R','N') NOT NULL, + `poster` varchar(128) NOT NULL default '', + `source` varchar(32) NOT NULL default '', + `title` varchar(255), + `body` text NOT NULL, + `ip_address` varchar(64) NOT NULL default '', `created` datetime NOT NULL, `updated` datetime NOT NULL, - PRIMARY KEY (`response_id`), + PRIMARY KEY (`id`), KEY `ticket_id` (`ticket_id`), - KEY `msg_id` (`msg_id`), KEY `staff_id` (`staff_id`), - FULLTEXT KEY `response` (`response`) + FULLTEXT KEY `body` (`body`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `%TABLE_PREFIX%timezone`; diff --git a/setup/inc/sql/osticket-v1.7-mysql.sql.md5 b/setup/inc/sql/osticket-v1.7-mysql.sql.md5 new file mode 100644 index 0000000000000000000000000000000000000000..798a76acc57bcf65d56d7c11af8cda14317aefea --- /dev/null +++ b/setup/inc/sql/osticket-v1.7-mysql.sql.md5 @@ -0,0 +1 @@ +c2d2fabfdf15e1632f00850ffb361558 diff --git a/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql b/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql index efeb8de6f26eb4e4c4a5e10140147c5b1ebdd3c6..3a2acf2295170c9b6263b33f05d649c378ed5dbb 100644 --- a/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql +++ b/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql @@ -26,10 +26,14 @@ ALTER TABLE `%TABLE_PREFIX%ticket` 'Web', 'Email', 'Phone', 'API', 'Other') NOT NULL DEFAULT 'Other'; -- Add table for ticket history (statistics) tracking -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_history`; -CREATE TABLE `%TABLE_PREFIX%ticket_history` ( +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`; +CREATE TABLE `%TABLE_PREFIX%ticket_event` ( `ticket_id` int(11) unsigned NOT NULL default '0', - `state` enum('opened','closed','assigned','transferred','overdue') NOT NULL, + `staff_id` int(11) unsigned NOT NULL, + `team_id` int(11) unsigned NOT NULL, + `dept_id` int(11) unsigned NOT NULL, + `topic_id` int(11) unsigned NOT NULL, + `state` enum('created','closed','reopened','assigned','transferred','overdue') NOT NULL, `staff` varchar(255) NOT NULL default 'SYSTEM', `timestamp` datetime NOT NULL, KEY `ticket_state` (`ticket_id`, `state`, `timestamp`), diff --git a/setup/inc/upgrade-aborted.inc.php b/setup/inc/upgrade-aborted.inc.php index 8d8f64aa831841dd9431f017c7289760ba18448e..8624590d35710a42906952afab82b2688f028315 100644 --- a/setup/inc/upgrade-aborted.inc.php +++ b/setup/inc/upgrade-aborted.inc.php @@ -6,17 +6,18 @@ if(!defined('SETUPINC')) die('Kwaheri!'); <div id="intro"> <p>Upgrade aborted due to errors. Any errors at this stage are fatal. Please note the error(s), if any, when contacting us.<p> <?php - if($_SESSION['upgrader']['errors']) { - $errors=$_SESSION['upgrader']['errors']; + if($upgrader && ($errors=$upgrader->getErrors())) { if($errors['err']) echo sprintf('<b><font color="red">%s</font></b>',$errors['err']); - echo '<ul class="error">'; unset($errors['err']); - foreach($errors as $k=>$error) + foreach($errors as $k => $error) echo sprintf('<li>%s</li>',$error); echo '</ul>'; - } ?> + } else { + echo '<b><font color="red">Internal error occurred - get technical help.</font></b>'; + } + ?> <p>Please, refer to the <a target="_blank" href="http://osticket.com/wiki/Upgrade_and_Migration">Upgrade Guide</a> on the wiki for more information.</p> </div> <p><strong>Need Help?</strong> We provide <a target="_blank" href="http://osticket.com/support/professional_services.php"><u>professional upgrade services</u></a> and commercial support. <a target="_blank" href="http://osticket.com/support/">Contact us</a> today for expedited help.</p> diff --git a/setup/inc/upgrade-attachments.inc.php b/setup/inc/upgrade-attachments.inc.php deleted file mode 100644 index c8155d32c672e358cb068d79720a076327a88706..0000000000000000000000000000000000000000 --- a/setup/inc/upgrade-attachments.inc.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php -if(!defined('SETUPINC')) die('Kwaheri!'); -$msg = $_SESSION['ost_upgrader']['msg']; -?> -<div id="main"> - <h1>Attachments Migration</h1> - <p>We're almost done! We're now migrating attachments to the database, it might take a while dending on the number of files in your database.<p> - <p style="color:#FF7700;font-weight:bold;">We have to migrate files in batches for technical reasons.</p> - <p>Please don't cancel or close the browser.</p> - - <div id="bar"> - <form method="post" action="upgrade.php" id="attachments"> - <input type="hidden" name="s" value="cleanup"> - <input class="btn" type="submit" name="submit" value="Next Batch"> - </form> - - </div> -</div> -<div id="sidebar"> - <h3>Upgrade Tips</h3> - <p>1. Be patient the process will take a few minutes.</p> - <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> -</div> -<div id="overlay"></div> - <div id="loading"> - <h4>Moving attachments</h4> - <br> - Please wait... while we migrate attachments! - <br><br> - <div id="msg" style="font-weight: bold;"><?php echo Format::htmlchars($msg); ?></div> - </div> diff --git a/setup/inc/upgrade-cleanup.inc.php b/setup/inc/upgrade-cleanup.inc.php deleted file mode 100644 index f8406ae533a9efbce73e864239d749b586e8f66e..0000000000000000000000000000000000000000 --- a/setup/inc/upgrade-cleanup.inc.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php -if(!defined('SETUPINC')) die('Kwaheri!'); - -?> - <div id="main"> - <h1>osTicket Upgrade</h1> - <div id="intro"> - <p>We're almost done! Please don't cancel or close the browser, any errors at this stage will be fatal.</p> - </div> - <h2>Cleanup: Step 2 of 2</h2> - <p>The upgrade wizard will now attempt to do post upgrade cleanup. It might take a while dending on the size of your database. </p> - <ul> - <li>Setting Changes</li> - <li>Attachment Migration</li> - <li>Database Optimization</li> - </ul> - <div id="bar"> - <form method="post" action="upgrade.php" id="cleanup"> - <input type="hidden" name="s" value="cleanup"> - <input class="btn" type="submit" name="submit" value="Do It Now!"> - </form> - </div> - </div> - <div id="sidebar"> - <h3>Upgrade Tips</h3> - <p>1. Be patient the process will take a couple of seconds.</p> - <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> - </div> - - <div id="overlay"></div> - <div id="loading"> - <h4>Doing serious stuff!</h4> - <br> - Please wait... while we do post-upgrade cleanup! - <br><br> - <div id="msg" style="font-weight: bold;"></div> - </div> diff --git a/setup/inc/upgrade-core.inc.php b/setup/inc/upgrade-core.inc.php deleted file mode 100644 index ec42e50437537ea01931484a18e86c902ba909b1..0000000000000000000000000000000000000000 --- a/setup/inc/upgrade-core.inc.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php -if(!defined('SETUPINC')) die('Kwaheri!'); - -?> - <div id="main"> - <h1>osTicket Upgrade</h1> - <div id="intro"> - <p>Thank you for taking the time to upgrade your osTicket intallation!</p> - <p>Please don't cancel or close the browser, any errors at this - stage will be fatal.</p> - </div> - <h2>Base upgrade: Step 1 of 2</h2> - <p>The upgrade wizard will now attempt to upgrade your database and core settings!</p> - <ul> - <li>Database enhancements</li> - <li>New and updated features</li> - <li>Enhance settings and security</li> - </ul> - <div id="bar"> - <form method="post" action="upgrade.php" id="upgrade"> - <input type="hidden" name="s" value="upgrade"> - <input class="btn" type="submit" name="submit" value="Do It Now!"> - </form> - </div> - </div> - <div id="sidebar"> - <h3>Upgrade Tips</h3> - <p>1. Be patient the process will take a couple of seconds.</p> - <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> - </div> - - <div id="overlay"></div> - <div id="loading"> - <h4>Doing serious stuff!</h4> - Please wait... while we upgrade your osTicket installation! - <div id="udb"><br><b>Smile!</b></div> - </div> diff --git a/setup/inc/upgrade-prereq.inc.php b/setup/inc/upgrade-prereq.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..5f60cece25500679de83b01981ea05ac634949e9 --- /dev/null +++ b/setup/inc/upgrade-prereq.inc.php @@ -0,0 +1,50 @@ +<?php +if(!defined('SETUPINC')) die('Kwaheri!'); + +?> + <div id="main"> + <h1>osTicket Upgrade!</h1> + <font color="red"><b><?php echo $errors['err']; ?></b></font> + <div id="intro"> + <p>Thank you for being a loyal osTicket user!</p> + <p>The upgrade wizard will guide you every step of the way in the upgrade process. While we try to ensure that the upgrade process is straightforward and painless, we can't guarantee it will be the case for every user.</p> + </div> + <h2>Getting ready!</h2> + <p>Before we begin, we'll check your server configuration to make sure you meet the minimum requirements to run the latest version of osTicket.</p> + <h3>Prerequisites: <font color="red"><?php echo $errors['prereq']; ?></font></h3> + These items are necessary in order to use osTicket the latest version of osTicket. + <ul class="progress"> + <li class="<? echo $upgrader->check_php()?'yes':'no'; ?>"> + PHP v4.3 or greater - (<small><b><?php echo PHP_VERSION; ?></b></small>)</li> + <li class="<? echo $upgrader->check_mysql()?'yes':'no'; ?>"> + MySQL v4.4 or greater - (<small><b><?php echo extension_loaded('mysql')?'module loaded':'missing!'; ?></b></small>)</li> + </ul> + <h3>Higly Recommended:</h3> + We hightly recommend that you follow the steps below. + <ul> + <li>Take osTicket offline momentarily during upgrade.</li> + <li>Backup the current database, if you haven't done so already.</li> + <li>Be patient the upgrade process will take a couple of seconds.</li> + </ul> + <div id="bar"> + <form method="post" action="upgrade.php" id="prereq"> + <input type="hidden" name="s" value="prereq"> + <input class="btn" type="submit" name="submit" value="Start Upgrade Now »"> + </form> + </div> + </div> + <div id="sidebar"> + <h3>Upgrade Tips</h3> + <p>1. Remember to backup your osTicket database</p> + <p>2. Take osTicket offline momentarily</p> + <p>3. If you experience any problems, you can always restore your files/dabase backup.</p> + <p>4. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> + + </div> + + <div id="overlay"></div> + <div id="loading"> + <h4>Doing stuff!</h4> + Please wait... while we upgrade your osTicket installation! + <div id="udb"></div> + </div> diff --git a/setup/inc/upgrade.inc.php b/setup/inc/upgrade.inc.php index e5b8ba77bef7da18c547820031d1ca294b2b4dea..6f05cd169c66d49163908d8a6c6bef9d5b9a1a18 100644 --- a/setup/inc/upgrade.inc.php +++ b/setup/inc/upgrade.inc.php @@ -1,50 +1,40 @@ <?php -if(!defined('SETUPINC')) die('Kwaheri!'); +if(!defined('SETUPINC') || !$upgrader) die('Kwaheri!'); +$action=$upgrader->getNextAction(); ?> <div id="main"> - <h1>osTicket Upgrade!</h1> - <font color="red"><b><?php echo $errors['err']; ?></b></font> + <h1>osTicket Upgrade</h1> <div id="intro"> - <p>Thank you for being a loyal osTicket user!</p> - <p>The upgrade wizard will guide you every step of the way in the upgrade process. While we try to ensure that the upgrade process is straightforward and painless, we can't guarantee it will be the case for every user.</p> + <p>Thank you for taking the time to upgrade your osTicket intallation!</p> + <p>Please don't cancel or close the browser, any errors at this + stage will be fatal.</p> </div> - <h2>Getting ready!</h2> - <p>Before we begin, we'll check your server configuration to make sure you meet the minimum requirements to run the latest version of osTicket.</p> - <h3>Prerequisites: <font color="red"><?php echo $errors['prereq']; ?></font></h3> - These items are necessary in order to use osTicket the latest version of osTicket. - <ul class="progress"> - <li class="<? echo $upgrader->check_php()?'yes':'no'; ?>"> - PHP v4.3 or greater - (<small><b><?php echo PHP_VERSION; ?></b></small>)</li> - <li class="<? echo $upgrader->check_mysql()?'yes':'no'; ?>"> - MySQL v4.4 or greater - (<small><b><?php echo extension_loaded('mysql')?'module loaded':'missing!'; ?></b></small>)</li> - </ul> - <h3>Higly Recommended:</h3> - We hightly recommend that you follow the steps below. + <h2><?php echo $action ?></h2> + <p>The upgrade wizard will now attempt to upgrade your database and core settings!</p> <ul> - <li>Take osTicket offline momentarily during upgrade.</li> - <li>Backup the current database, if you haven't done so already.</li> - <li>Be patient the upgrade process will take a couple of seconds.</li> + <li>Database enhancements</li> + <li>New and updated features</li> + <li>Enhance settings and security</li> </ul> <div id="bar"> <form method="post" action="upgrade.php" id="upgrade"> - <input type="hidden" name="s" value="prereq"> - <input class="btn" type="submit" name="submit" value="Start Upgrade Now »"> + <input type="hidden" name="s" value="upgrade"> + <input type="hidden" name="sh" value="<?php echo $upgrader->getSchemaSignature(); ?>"> + <input class="btn" type="submit" name="submit" value="Do It Now!"> </form> </div> </div> <div id="sidebar"> <h3>Upgrade Tips</h3> - <p>1. Remember to backup your osTicket database</p> - <p>2. Take osTicket offline momentarily</p> - <p>3. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>4. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> - + <p>1. Be patient the process will take a couple of seconds.</p> + <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> + <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> </div> <div id="overlay"></div> <div id="loading"> - <h4>Doing stuff!</h4> + <h4><?php echo $action; ?></h4> Please wait... while we upgrade your osTicket installation! - <div id="udb"></div> + <div id="msg" style="font-weight: bold;padding-top:10px;">Smile!</div> </div> diff --git a/setup/install.php b/setup/install.php index 27b1388933d03ef9c0db5690dd147213848d750f..d019598e55de7099c9dbb517b4a9aa1663886ad0 100644 --- a/setup/install.php +++ b/setup/install.php @@ -15,6 +15,9 @@ **********************************************************************/ require('setup.inc.php'); +require_once INC_DIR.'class.installer.php'; + + //define('OSTICKET_CONFIGFILE','../include/ost-config.php'); //osTicket config file full path. define('OSTICKET_CONFIGFILE','../include/ost-config.php'); //XXX: Make sure the path is corrent b4 releasing. diff --git a/setup/js/setup.js b/setup/js/setup.js index 5d274ea3198bbec310c20abef16ac68df51ee270..b1f8e08c3aa48397206c43ad854fc3bf4815473c 100644 --- a/setup/js/setup.js +++ b/setup/js/setup.js @@ -13,30 +13,30 @@ jQuery(function($) { left : ($(window).width() / 2 - 160) }); - $('form#install, form#upgrade, form#attachments').submit(function(e) { + $('form#install').submit(function(e) { $('input[type=submit]', this).attr('disabled', 'disabled'); $('#overlay, #loading').show(); return true; }); - $('form#cleanup').submit(function(e) { + $('form#upgrade').submit(function(e) { e.preventDefault(); var form = $(this); $('input[type=submit]', this).attr('disabled', 'disabled'); $('#overlay, #loading').show(); - doCleanup('upgrade',form.attr('action')); + doTasks('upgrade.php',form.serialize()); + return false; }); - - function doCleanup(type,url) { + function doTasks(url, data) { function _lp(count) { $.ajax({ type: 'GET', - url: 'cleanup.php', + url: 'p.php', async: true, cache: false, - data: {c:count,type:type}, + data: data, dataType: 'text', success: function(res) { if (res) { @@ -45,16 +45,17 @@ jQuery(function($) { }, statusCode: { 200: function() { - setTimeout(function() { _lp(count+1); },2); + setTimeout(function() { _lp(count+1); }, 2); }, 304: function() { - $('#loading #msg').html("We're done... "); - setTimeout(function() { location.href =url;},1000); + $('#loading #msg').html("We're done... cleaning up!"); + setTimeout(function() { location.href =url;}, 3000); } }, - error: function(){ - alert("Something went wrong"); + error: function() { + $('#loading #msg').html("Something went wrong"); + setTimeout(function() { location.href =url;}, 1000); } }); }; diff --git a/setup/p.php b/setup/p.php new file mode 100644 index 0000000000000000000000000000000000000000..babeebb866f198e7fc78516a34133164d72a9b47 --- /dev/null +++ b/setup/p.php @@ -0,0 +1,69 @@ +<?php +/********************************************************************* + upgrader.php + + osTicket Upgrader Helper - called via ajax. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +function staffLoginPage($msg) { + Http::response(403, $msg?$msg:'Access Denied'); + exit; +} + +require '../scp/staff.inc.php'; +if(!$thisstaff or !$thisstaff->isAdmin()) { + staffLoginPage('Admin Access Required!'); + exit; +} + +define('SETUPINC', true); +define('INC_DIR', './inc/'); +define('SQL_DIR', INC_DIR.'sql/'); + +require_once INC_DIR.'class.upgrader.php'; + + +$upgrader = new Upgrader($cfg->getSchemaSignature(), TABLE_PREFIX, SQL_DIR); + +//Just report the next action on the first call. +if(!$_SESSION['ost_upgrader'][$upgrader->getShash()]['progress']) { + $_SESSION['ost_upgrader'][$upgrader->getShash()]['progress'] = $upgrader->getNextAction(); + Http::response(200, $upgrader->getNextAction()); + exit; +} + +if($upgrader->getNumPendingTasks()) { + if($upgrader->doTasks() && !$upgrader->getNumPendingTasks() && $cfg->isUpgradePending()) { + //Just reporting done...with tasks - break in between patches! + header("HTTP/1.1 304 Not Modified"); + exit; + } +} elseif($cfg->isUpgradePending() && $upgrader->isUpgradable()) { + $version = $upgrader->getNextVersion(); + if($upgrader->upgrade()) { + //We're simply reporting progress here - call back will report next action' + Http::response(200, "Upgraded to $version ... post-upgrade checks!"); + exit; + } +} elseif(!$cfg->isUpgradePending()) { + $upgrader->setState('done'); + session_write_close(); + header("HTTP/1.1 304 Not Modified"); + exit; +} + +if($upgrader->isAborted() || $upgrader->getErrors()) { + Http::response(416, "We have a problem ... wait a sec."); + exit; +} + +Http::response(200, $upgrader->getNextAction()); +?> diff --git a/setup/setup.inc.php b/setup/setup.inc.php index f2af40af61e1b7e94b9ae915eb1e81e103560594..44b2ad4d593f5521b66ad170c9e801a817cf74f1 100644 --- a/setup/setup.inc.php +++ b/setup/setup.inc.php @@ -52,10 +52,8 @@ ini_set('include_path', './'.PATH_SEPARATOR.INC_DIR.PATH_SEPARATOR.INCLUDE_DIR.P endif; #required files -require_once(INC_DIR.'class.setup.php'); require_once(INCLUDE_DIR.'class.validator.php'); require_once(INCLUDE_DIR.'class.format.php'); require_once(INCLUDE_DIR.'class.misc.php'); require_once(INCLUDE_DIR.'mysql.php'); - ?> diff --git a/setup/test/lint.php b/setup/test/lint.php index c25f7acec092a0a17e0dcf295173cc742b480329..4566c495a247874f538fc043cd777185e17d509c 100644 --- a/setup/test/lint.php +++ b/setup/test/lint.php @@ -9,7 +9,7 @@ function get_osticket_root_path() { if (file_exists($start . '/main.inc.php')) break; $start .= '/..'; } - return $start; + return realpath($start); } $root = get_osticket_root_path(); @@ -17,8 +17,7 @@ $root = get_osticket_root_path(); # Check PHP syntax across all php files function glob_recursive($pattern, $flags = 0) { $files = glob($pattern, $flags); - foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) - as $dir) { + foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) { $files = array_merge($files, glob_recursive($dir.'/'.basename($pattern), $flags)); } @@ -26,7 +25,7 @@ function glob_recursive($pattern, $flags = 0) { } echo "PHP Syntax Errors: "; ob_start(); -$scripts=glob_recursive("$root/*/*.php"); +$scripts=glob_recursive("$root/*.php"); $exit=0; $syntax_errors=""; foreach ($scripts as $s) { @@ -63,4 +62,46 @@ if (strlen($lint_errors)) { } else { echo "\n"; } + +function find_function_calls($scripts) { + $calls=array(); + foreach ($scripts as $s) { + $lines = explode("\n", file_get_contents($s)); + $lineno=0; + foreach (explode("\n", file_get_contents($s)) as $line) { + $lineno++; $matches=array(); + preg_match_all('/-[>]([a-zA-Z0-9]*)\(/', $line, $matches, + PREG_SET_ORDER); + foreach ($matches as $m) { + $calls[] = array($s, $lineno, $line, $m[1]); + } + } + } + return $calls; +} + +$php_script_content=''; +foreach ($scripts as $s) { + $php_script_content .= file_get_contents($s); +} +echo "Access to undefined object methods: "; +ob_start(); +foreach (find_function_calls($scripts) as $call) { + list($file, $no, $line, $func) = $call; + if (!preg_match('/^\s*(\/\*[^*]*\*\/)?'."\s*function\s+&?\s*$func\\(/m", + $php_script_content)) { + print "$func: Definitely undefined, from $file:$no\n"; + } +} +$undef_func_errors = ob_get_clean(); + +if (strlen($undef_func_errors)) { + $undef_func_errors=str_replace("$root/", '', $undef_func_errors); + echo "FAIL\n"; + echo "-------------------------------------------------------\n"; + echo "$undef_func_errors"; + exit(); +} else { + echo "\n"; +} ?> diff --git a/setup/upgrade.php b/setup/upgrade.php index 6fc34cfd307cfcc9df319deb25101ec159f52d75..0406383707cfe245fd11aae9323ee1422d6d679e 100644 --- a/setup/upgrade.php +++ b/setup/upgrade.php @@ -13,5 +13,89 @@ vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ -die('Upgrade NOT supported for v1.7 DPR.'); +function staffLoginPage($msg) { + + $_SESSION['_staff']['auth']['dest']=THISPAGE; + $_SESSION['_staff']['auth']['msg']=$msg; + header('Location: ../scp/login.php'); + exit; +} + +require '../scp/staff.inc.php'; +if(!$thisstaff or !$thisstaff->isAdmin()) { + staffLoginPage('Admin Access Required!'); + exit; +} + +define('SETUPINC', true); +define('INC_DIR', './inc/'); +define('SQL_DIR', INC_DIR.'sql/'); + +require_once INC_DIR.'class.upgrader.php'; + +//$_SESSION['ost_upgrader']=null; +$upgrader = new Upgrader($cfg->getSchemaSignature(), TABLE_PREFIX, SQL_DIR); + + +$wizard=array(); +$wizard['title']='osTicket Upgrade Wizard'; +$wizard['tagline']='Upgrading osTicket to v'.$upgrader->getVersionVerbose(); +$wizard['logo']='logo-upgrade.png'; +$wizard['menu']=array('Upgrade Guide'=>'http://osticket.com/wiki/Upgrade_and_Migration', + 'Get Professional Help'=>'http://osticket.com/support'); +$errors=array(); +if($_POST && $_POST['s'] && !$upgrader->isAborted()) { + switch(strtolower($_POST['s'])) { + case 'prereq': + //XXX: check if it's upgradable version?? + if(!$cfg->isUpgradePending()) + $errors['err']=' Nothing to do! System already upgraded to the current version'; + elseif(!$upgrader->isUpgradable()) + $errors['err']='The upgrader does NOT support upgrading from the current vesion!'; + elseif($upgrader->check_prereq()) + $upgrader->setState('upgrade'); + else + $errors['prereq']='Minimum requirements not met!'; + break; + case 'upgrade': //Manual upgrade.... when JS (ajax) is not supported. + if($upgrader->getNumPendingTasks()) { + $upgrader->doTasks(); + } elseif($cfg->isUpgradePending() && $upgrader->isUpgradable()) { + $upgrader->upgrade(); + } elseif(!$cfg->isUpgradePending()) { + $upgrader->setState('done'); + } + + if(($errors=$upgrader->getErrors())) { + $upgrader->setState('aborted'); + } + break; + default: + $errors['err']='Unknown action!'; + } +} + +switch(strtolower($upgrader->getState())) { + case 'aborted': + $inc='upgrade-aborted.inc.php'; + break; + case 'upgrade': + $inc='upgrade.inc.php'; + break; + case 'done': + $inc='upgrade-done.inc.php'; + break; + default: + $inc='upgrade-prereq.inc.php'; + if($upgrader->isAborted()) + $inc='upgrade-aborted.inc.php'; + elseif(!$cfg->isUpgradePending()) + $errors['err']='Nothing to do! System already upgraded to the latest version'; + elseif(!$upgrader->isUpgradable()) + $errors['err']='The upgrader does NOT support upgrading from the current vesion!'; +} + +require(INC_DIR.'header.inc.php'); +require(INC_DIR.$inc); +require(INC_DIR.'footer.inc.php'); ?> diff --git a/tickets.php b/tickets.php index d4759ba522e328911d2e9a494254ce338ea7f905..81b8ed68f153b551c4b063d2fa6860ea84070ac1 100644 --- a/tickets.php +++ b/tickets.php @@ -52,7 +52,7 @@ if($_POST && is_object($ticket) && $ticket->getId()): } } - if(!$errors){ + if(!$errors) { //Everything checked out...do the magic. if(($msgid=$ticket->postMessage($_POST['message'],'Web'))) { if($files && $cfg->allowOnlineAttachments()) @@ -64,9 +64,7 @@ if($_POST && is_object($ticket) && $ticket->getId()): } } elseif(!$errors['err']) { - print_r($errors); $errors['err']='Error(s) occurred. Please try again'; - } break; default: