commit f73e139d8f3ae93ef44c44fa9a21a4217821afac Author: Brian C. Lane <bcl@brianlane.com> Date: Sat, 27 Feb 2010 09:00:08 -0800 Initial import from mercurial Renamed the project to Home Media Server (hms) Moved some files around to make the directory structure make more sense Diffstat:
95 files changed, 6559 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +*.pyc +*.pyo +root/ +pyvirt/ +.*.swp + diff --git a/COPYING b/COPYING diff --git a/LICENSE b/LICENSE diff --git a/README b/README diff --git a/roku_player/Makefile b/roku_player/Makefile @@ -0,0 +1,113 @@ +######################################################################### +# Simple makefile for packaging Roku Video Player example +# +# Makefile Usage: +# > make +# > make install +# > make remove +# +# Important Notes: +# To use the "install" and "remove" targets to install your +# application directly from the shell, you must do the following: +# +# 1) Make sure that you have the curl command line executable in your path +# 2) Set the variable ROKU_DEV_TARGET in your environment to the IP +# address of your Roku box. (e.g. export ROKU_DEV_TARGET=192.168.1.1. +# Set in your this variable in your shell startup (e.g. .bashrc) +########################################################################## +PKGREL = ../packages +ZIPREL = ../zips +SOURCEREL = .. +APPNAME = homevideo +VERSION = 1.0 + +.PHONY: all homevideo + +homevideo: + @echo "*** Creating $(APPNAME).zip ***" + + @echo " >> removing old application zip $(ZIPREL)/$(APPNAME).zip" + @if [ -e "$(ZIPREL)/$(APPNAME).zip" ]; \ + then \ + rm $(ZIPREL)/$(APPNAME).zip; \ + fi + + @echo " >> creating destination directory $(ZIPREL)" + @if [ ! -d $(ZIPREL) ]; \ + then \ + mkdir -p $(ZIPREL); \ + fi + + @echo " >> setting directory permissions for $(ZIPREL)" + @if [ ! -w $(ZIPREL) ]; \ + then \ + chmod 755 $(ZIPREL); \ + fi + + @echo " >> creating application zip $(ZIPREL)/$(APPNAME).zip" + @if [ -d $(SOURCEREL)/$(APPNAME) ]; \ + then \ + (zip -9 -r "$(ZIPREL)/$(APPNAME).zip" . -x Makefile xml/\* artwork/\*.jpg ); \ + else \ + echo "Source for $(APPNAME) not found at $(SOURCEREL)/$(APPNAME)"; \ + fi + + @echo "*** developer zip $(APPNAME) complete ***" + +archive: + @echo "*** archiving $(APPNAME).zip ***" + + @echo " >> removing old archive package $(ZIPREL)/$(APPNAME)_archive.zip" + @if [ -e "$(ZIPREL)/$(APPNAME)_archive.zip" ]; \ + then \ + rm $(ZIPREL)/$(APPNAME)_archive.zip; \ + fi + + @echo " >> creating destination directory $(ZIPREL)" + @if [ ! -d $(ZIPREL) ]; \ + then \ + mkdir -p $(ZIPREL); \ + fi + + @echo " >> setting directory permissions for $(ZIPREL)" + @if [ ! -w $(ZIPREL) ]; \ + then \ + chmod 755 $(ZIPREL); \ + fi + + @echo " >> creating complete application archive $(ZIPREL)/$(APPNAME)_archive.zip" + @if [ -d $(SOURCEREL)/$(APPNAME) ]; \ + then \ + (zip -9 -r "$(ZIPREL)/$(APPNAME)_archive.zip" .); \ + else \ + echo "Source for $(APPNAME) not found at $(SOURCEREL)/$(APPNAME)"; \ + fi + + @echo "*** packaging $(APPNAME) archive file complete ***" + +install: homevideo + @echo "Installing $(APPNAME) to host $(ROKU_DEV_TARGET)" + @curl -s -S -F "mysubmit=Install" -F "archive=@$(ZIPREL)/$(APPNAME).zip" -F "passwd=" http://$(ROKU_DEV_TARGET)/plugin_install | grep "<font color" | sed "s/<font color=\"red\">//" + +pkg: install + @echo "*** Creating Package ***" + + @echo " >> creating destination directory $(PKGREL)" + @if [ ! -d $(PKGREL) ]; \ + then \ + mkdir -p $(PKGREL); \ + fi + + @echo " >> setting directory permissions for $(PKGREL)" + @if [ ! -w $(PKGREL) ]; \ + then \ + chmod 755 $(PKGREL); \ + fi + + @echo "Packaging $(APPNAME) on host $(ROKU_DEV_TARGET)" + @read -p "Password: " REPLY ; echo $$REPLY | xargs -i curl -s -S -Fmysubmit=Package -Fapp_name=$(APPNAME)/$(VERSION) -Fpasswd={} -Fpkg_time=`expr \`date +%s\` \* 1000` "http://$(ROKU_DEV_TARGET)/plugin_package" | grep '^<font face=' | sed 's/.*href=\"\([^\"]*\)\".*/\1/' | sed 's#pkgs/##' | xargs -i curl -s -S -o $(PKGREL)/$(APPNAME)_{} http://$(ROKU_DEV_TARGET)/pkgs/{} + + @echo "*** Package $(APPNAME) complete ***" +remove: + @echo "Removing $(APPNAME) from host $(ROKU_DEV_TARGET)" + @curl -s -S -F "mysubmit=Delete" -F "archive=" -F "passwd=" http://$(ROKU_DEV_TARGET)/plugin_install | grep "<font color" | sed "s/<font color=\"red\">//" diff --git a/roku_player/README.txt b/roku_player/README.txt @@ -0,0 +1,67 @@ +The videoplayer example demonstrates a hierarchical, +category based video playback application. The +application allows the playback of a selection +of TED Talks videos which are organized by category. + +The application uses a category based XML feed +to drive the application. The XML describes all +of the categories used, artwork required and +videos to be played. The hierarchy of categories +is described in the file categories.xml. +The actual XML request/response uses our servers, +but the XML is all included for reference. + +Each category branch node, ultimately terminates at a +leaf node that lists details for all of the videos +included in that category. The XML for the leaf +nodes is also included and named in the format +<category>.xml. + +It is possible to easily use this as a template +for a production application by implementing the +appropriate web service API's to provide the +category and content XML feeds. You must also +provide the artwork and brand specific assets +appropriate for your application. + +Contents of the application directories are: + +images - Artwork that is embedded as part of + the application. In general, this + should be kept to a minimum to conserve + space on flash, and is usually just the + main menu icons, plus the logo and + overhang used for branding. +source - The complete BrightScript source code + for the application +xml - Examples of the XML returned by the + server for reference +artwork - Examples of the artwork returned by the + server for reference. +manifest - This file describes the application + package and is used on the main menu + prior to the start of execution for the + application. +Makefile - Optional method of building the application + using "make". This has been provided for + convenience and tested on OSX and linux. + + +Note: The xml and artwork directories are NOT part of the application + package, but can be saved as an archive using the "make archive" + target. The makefile also can push the development app directly + to the device if "make" and "curl" are available. See the comments + in the Makefile for more information. + + ************************************************** + +This example uses videos streamed directly from the TED Talks +website (www.ted.com). Please visit the TED website to see the +full lineup of talks made available by TED. + +Please see the following for license details: +http://creativecommons.org/licenses/by-nc-nd/3.0/ + + + + diff --git a/roku_player/artwork/AlGore.jpg b/roku_player/artwork/AlGore.jpg Binary files differ. diff --git a/roku_player/artwork/BenjaminZander.jpg b/roku_player/artwork/BenjaminZander.jpg Binary files differ. diff --git a/roku_player/artwork/CameronCarpenter.jpg b/roku_player/artwork/CameronCarpenter.jpg Binary files differ. diff --git a/roku_player/artwork/CynthiaSchneider.jpg b/roku_player/artwork/CynthiaSchneider.jpg Binary files differ. diff --git a/roku_player/artwork/DanGilbert.jpg b/roku_player/artwork/DanGilbert.jpg Binary files differ. diff --git a/roku_player/artwork/DavidKelley.jpg b/roku_player/artwork/DavidKelley.jpg Binary files differ. diff --git a/roku_player/artwork/ElizabethGilbert.jpg b/roku_player/artwork/ElizabethGilbert.jpg Binary files differ. diff --git a/roku_player/artwork/ImogenHeap.jpg b/roku_player/artwork/ImogenHeap.jpg Binary files differ. diff --git a/roku_player/artwork/JeffHan.jpg b/roku_player/artwork/JeffHan.jpg Binary files differ. diff --git a/roku_player/artwork/JimFallon.jpg b/roku_player/artwork/JimFallon.jpg Binary files differ. diff --git a/roku_player/artwork/JuanEnriquez.jpg b/roku_player/artwork/JuanEnriquez.jpg Binary files differ. diff --git a/roku_player/artwork/JulianTreasure.jpg b/roku_player/artwork/JulianTreasure.jpg Binary files differ. diff --git a/roku_player/artwork/Naturally7.jpg b/roku_player/artwork/Naturally7.jpg Binary files differ. diff --git a/roku_player/artwork/RachelPike.jpg b/roku_player/artwork/RachelPike.jpg Binary files differ. diff --git a/roku_player/artwork/RaulMidon.jpg b/roku_player/artwork/RaulMidon.jpg Binary files differ. diff --git a/roku_player/artwork/RobHopkins.jpg b/roku_player/artwork/RobHopkins.jpg Binary files differ. diff --git a/roku_player/artwork/SamMartin.jpg b/roku_player/artwork/SamMartin.jpg Binary files differ. diff --git a/roku_player/artwork/SethGodin.jpg b/roku_player/artwork/SethGodin.jpg Binary files differ. diff --git a/roku_player/artwork/TED_Design.png b/roku_player/artwork/TED_Design.png Binary files differ. diff --git a/roku_player/artwork/TED_Entertainment.png b/roku_player/artwork/TED_Entertainment.png Binary files differ. diff --git a/roku_player/artwork/TED_Technology.png b/roku_player/artwork/TED_Technology.png Binary files differ. diff --git a/roku_player/artwork/TimBrown.jpg b/roku_player/artwork/TimBrown.jpg Binary files differ. diff --git a/roku_player/artwork/VSRamachandran.jpg b/roku_player/artwork/VSRamachandran.jpg Binary files differ. diff --git a/roku_player/artwork/YvesBehar.jpg b/roku_player/artwork/YvesBehar.jpg Binary files differ. diff --git a/roku_player/images/MainMenu_Icon_CenterFocus_HD.png b/roku_player/images/MainMenu_Icon_CenterFocus_HD.png Binary files differ. diff --git a/roku_player/images/MainMenu_Icon_CenterFocus_SD.png b/roku_player/images/MainMenu_Icon_CenterFocus_SD.png Binary files differ. diff --git a/roku_player/images/MainMenu_Icon_Side_HD.png b/roku_player/images/MainMenu_Icon_Side_HD.png Binary files differ. diff --git a/roku_player/images/MainMenu_Icon_Side_SD.png b/roku_player/images/MainMenu_Icon_Side_SD.png Binary files differ. diff --git a/roku_player/images/Overhang_Background_HD.png b/roku_player/images/Overhang_Background_HD.png Binary files differ. diff --git a/roku_player/images/Overhang_Background_SD.png b/roku_player/images/Overhang_Background_SD.png Binary files differ. diff --git a/roku_player/images/Overhang_Logo_HD.png b/roku_player/images/Overhang_Logo_HD.png Binary files differ. diff --git a/roku_player/images/Overhang_Logo_SD.png b/roku_player/images/Overhang_Logo_SD.png Binary files differ. diff --git a/roku_player/manifest b/roku_player/manifest @@ -0,0 +1,9 @@ +title=Home Media Server +subtitle=Local Streaming Media Player +mm_icon_focus_hd=pkg:/images/MainMenu_Icon_CenterFocus_HD.png +mm_icon_side_hd=pkg:/images/MainMenu_Icon_Side_HD.png +mm_icon_focus_sd=pkg:/images/MainMenu_Icon_CenterFocus_SD.png +mm_icon_side_sd=pkg:/images/MainMenu_Icon_Side_SD.png +major_version=1 +minor_version=0 +build_version=00001 diff --git a/roku_player/source/appDetailScreen.brs b/roku_player/source/appDetailScreen.brs @@ -0,0 +1,145 @@ +'********************************************************** +'** Video Player Example Application - Detail Screen +'** November 2009 +'** Copyright (c) 2009 Roku Inc. All Rights Reserved. +'********************************************************** + +Function preShowDetailScreen(breadA=invalid, breadB=invalid) As Object + port=CreateObject("roMessagePort") + screen = CreateObject("roSpringboardScreen") + screen.SetMessagePort(port) + if breadA<>invalid and breadB<>invalid then + screen.SetBreadcrumbText(breadA, breadB) + end if + + return screen +End Function + +'*************************************************************** +'** The show detail screen (springboard) is where the user sees +'** the details for a show and is allowed to select a show to +'** begin playback. This is the main event loop for that screen +'** and where we spend our time waiting until the user presses a +'** button and then we decide how best to handle the event. +'*************************************************************** +Function showDetailScreen(screen As Object, showList As Object, showIndex as Integer) As Integer + + if validateParam(screen, "roSpringboardScreen", "showDetailScreen") = false return -1 + if validateParam(showList, "roArray", "showDetailScreen") = false return -1 + + refreshShowDetail(screen, showList, showIndex) + + 'remote key id's for left/right navigation + remoteKeyLeft = 4 + remoteKeyRight = 5 + + while true + msg = wait(0, screen.GetMessagePort()) + + if type(msg) = "roSpringboardScreenEvent" then + if msg.isScreenClosed() + print "Screen closed" + exit while + else if msg.isRemoteKeyPressed() + print "Remote key pressed" + if msg.GetIndex() = remoteKeyLeft then + showIndex = getPrevShow(showList, showIndex) + if showIndex <> -1 + refreshShowDetail(screen, showList, showIndex) + end if + else if msg.GetIndex() = remoteKeyRight + showIndex = getNextShow(showList, showIndex) + if showIndex <> -1 + refreshShowDetail(screen, showList, showIndex) + end if + endif + else if msg.isButtonPressed() + print "ButtonPressed" + if msg.GetIndex() = 1 + showVideoScreen(showList[showIndex]) + endif + if msg.GetIndex() = 2 + endif + if msg.GetIndex() = 3 + endif + print "Button pressed: "; msg.GetIndex(); " " msg.GetData() + end if + else + print "Unexpected message class: "; type(msg) + end if + end while + + return showIndex + +End Function + +'************************************************************** +'** Refresh the contents of the show detail screen. This may be +'** required on initial entry to the screen or as the user moves +'** left/right on the springboard. When the user is on the +'** springboard, we generally let them press left/right arrow keys +'** to navigate to the previous/next show in a circular manner. +'** When leaving the screen, the should be positioned on the +'** corresponding item in the poster screen matching the current show +'************************************************************** +Function refreshShowDetail(screen As Object, showList As Object, showIndex as Integer) As Integer + + if validateParam(screen, "roSpringboardScreen", "refreshShowDetail") = false return -1 + if validateParam(showList, "roArray", "refreshShowDetail") = false return -1 + + show = showList[showIndex] + + 'Uncomment this statement to dump the details for each show + PrintAA(show) + + screen.SetDescriptionStyle(show.ContentType) + + screen.ClearButtons() + screen.AddButton(1, "play") + screen.SetContent(show) + screen.Show() + +End Function + +'******************************************************** +'** Get the next item in the list and handle the wrap +'** around case to implement a circular list for left/right +'** navigation on the springboard screen +'******************************************************** +Function getNextShow(showList As Object, showIndex As Integer) As Integer + if validateParam(showList, "roArray", "getNextShow") = false return -1 + + nextIndex = showIndex + 1 + if nextIndex >= showList.Count() or nextIndex < 0 then + nextIndex = 0 + end if + + show = showList[nextIndex] + if validateParam(show, "roAssociativeArray", "getNextShow") = false return -1 + + return nextIndex +End Function + + +'******************************************************** +'** Get the previous item in the list and handle the wrap +'** around case to implement a circular list for left/right +'** navigation on the springboard screen +'******************************************************** +Function getPrevShow(showList As Object, showIndex As Integer) As Integer + if validateParam(showList, "roArray", "getPrevShow") = false return -1 + + prevIndex = showIndex - 1 + if prevIndex < 0 or prevIndex >= showList.Count() then + if showList.Count() > 0 then + prevIndex = showList.Count() - 1 + else + return -1 + end if + end if + + show = showList[prevIndex] + if validateParam(show, "roAssociativeArray", "getPrevShow") = false return -1 + + return prevIndex +End Function diff --git a/roku_player/source/appHomeScreen.brs b/roku_player/source/appHomeScreen.brs @@ -0,0 +1,160 @@ +'***************************************************************** +'** Video Player Example Application -- Home Screen +'** November 2009 +'** Copyright (c) 2009 Roku Inc. All Rights Reserved. +'***************************************************************** + +'****************************************************** +'** Perform any startup/initialization stuff prior to +'** initially showing the screen. +'****************************************************** +Function preShowHomeScreen(breadA=invalid, breadB=invalid) As Object + + if validateParam(breadA, "roString", "preShowHomeScreen", true) = false return -1 + if validateParam(breadA, "roString", "preShowHomeScreen", true) = false return -1 + + port=CreateObject("roMessagePort") + screen = CreateObject("roPosterScreen") + screen.SetMessagePort(port) + if breadA<>invalid and breadB<>invalid then + screen.SetBreadcrumbText(breadA, breadB) + end if + + screen.SetListStyle("flat-category") + screen.setAdDisplayMode("scale-to-fit") + return screen + +End Function + + +'****************************************************** +'** Display the home screen and wait for events from +'** the screen. The screen will show retreiving while +'** we fetch and parse the feeds for the game posters +'****************************************************** +Function showHomeScreen(screen) As Integer + + if validateParam(screen, "roPosterScreen", "showHomeScreen") = false return -1 + + checkServerUrl() ' Check Registry for server URL + + ' @TODO This needs to show something while it is loading the category list + + initCategoryList() + screen.SetContentList(m.Categories.Kids) + screen.SetFocusedListItem(0) + screen.Show() + + while true + msg = wait(0, screen.GetMessagePort()) + if type(msg) = "roPosterScreenEvent" then + print "showHomeScreen | msg = "; msg.GetMessage() " | index = "; msg.GetIndex() + if msg.isListFocused() then + print "list focused | index = "; msg.GetIndex(); " | category = "; m.curCategory + else if msg.isListItemSelected() then + print "list item selected | index = "; msg.GetIndex() + kid = m.Categories.Kids[msg.GetIndex()] + if kid.type = "special_category" then + displaySpecialCategoryScreen() + else + displayCategoryPosterScreen(kid) + end if + else if msg.isScreenClosed() then + return -1 + end if + end If + end while + + return 0 + +End Function + + +'********************************************************** +'** When a poster on the home screen is selected, we call +'** this function passing an associative array with the +'** data for the selected show. This data should be +'** sufficient for the show detail (springboard) to display +'********************************************************** +Function displayCategoryPosterScreen(category As Object) As Dynamic + + if validateParam(category, "roAssociativeArray", "displayCategoryPosterScreen") = false return -1 + screen = preShowPosterScreen(category.Title, "") + showPosterScreen(screen, category) + + return 0 +End Function + +'********************************************************** +'** Special categories can be used to have categories that +'** don't correspond to the content hierarchy, but are +'** managed from the server by data from the feed. In these +'** cases we might show a different type of screen other +'** than a poster screen of content. For example, a special +'** category could be search, music, options or similar. +'********************************************************** +Function displaySpecialCategoryScreen() As Dynamic + + ' do nothing, this is intended to just show how + ' you might add a special category ionto the feed + print "Special Category" + + return 0 +End Function + +'************************************************************ +'** initialize the category tree. We fetch a category list +'** from the server, parse it into a hierarchy of nodes and +'** then use this to build the home screen and pass to child +'** screen in the heirarchy. Each node terminates at a list +'** of content for the sub-category describing individual videos +'************************************************************ +Function initCategoryList() As Void + + conn = InitCategoryFeedConnection() + + m.Categories = conn.LoadCategoryFeed(conn) + m.CategoryNames = conn.GetCategoryNames(m.Categories) + +End Function + +'************************************************************ +' ** Check the registry for the server URL +' ** Prompt the user to enter the URL or IP if it is not +' ** found and write it to the registry. +'************************************************************ +Function checkServerUrl() as Void + serverURL = RegRead("ServerURL") + if (serverURL = invalid) then + print "ServerURL not found in the registry" + serverURL = "video.local" + endif + + screen = CreateObject("roKeyboardScreen") + port = CreateObject("roMessagePort") + screen.SetMessagePort(port) + screen.SetTitle("Video Server URL") + screen.SetText(serverURL) + screen.SetDisplayText("Enter Host Name or IP Address") + screen.SetMaxLength(25) + screen.AddButton(1, "finished") + screen.Show() + + while true + msg = wait(0, screen.GetMessagePort()) + print "message received" + if type(msg) = "roKeyboardScreenEvent" + if msg.isScreenClosed() + return + else if msg.isButtonPressed() then + print "Evt: ";msg.GetMessage();" idx:"; msg.GetIndex() + if msg.GetIndex() = 1 + searchText = screen.GetText() + print "search text: "; searchText + RegWrite("ServerURL", searchText) + return + endif + endif + endif + end while +End Function diff --git a/roku_player/source/appMain.brs b/roku_player/source/appMain.brs @@ -0,0 +1,50 @@ +'******************************************************************** +'** Video Player Example Application - Main +'** November 2009 +'** Copyright (c) 2009 Roku Inc. All Rights Reserved. +'******************************************************************** + +Sub Main() + + 'initialize theme attributes like titles, logos and overhang color + initTheme() + + 'prepare the screen for display and get ready to begin + screen=preShowHomeScreen("", "") + if screen=invalid then + print "unexpected error in preShowHomeScreen" + return + end if + + 'set to go, time to get started + showHomeScreen(screen) + +End Sub + + +'************************************************************* +'** Set the configurable theme attributes for the application +'** +'** Configure the custom overhang and Logo attributes +'** Theme attributes affect the branding of the application +'** and are artwork, colors and offsets specific to the app +'************************************************************* + +Sub initTheme() + + app = CreateObject("roAppManager") + theme = CreateObject("roAssociativeArray") + + theme.OverhangOffsetSD_X = "72" + theme.OverhangOffsetSD_Y = "31" + theme.OverhangSliceSD = "pkg:/images/Overhang_Background_SD.png" + theme.OverhangLogoSD = "pkg:/images/Overhang_Logo_SD.png" + + theme.OverhangOffsetHD_X = "125" + theme.OverhangOffsetHD_Y = "35" + theme.OverhangSliceHD = "pkg:/images/Overhang_Background_HD.png" + theme.OverhangLogoHD = "pkg:/images/Overhang_Logo_HD.png" + + app.SetTheme(theme) + +End Sub diff --git a/roku_player/source/appPosterScreen.brs b/roku_player/source/appPosterScreen.brs @@ -0,0 +1,126 @@ +'****************************************************** +'** Video Player Example Application -- Poster Screen +'** November 2009 +'** Copyright (c) 2009 Roku Inc. All Rights Reserved. +'****************************************************** + +'****************************************************** +'** Perform any startup/initialization stuff prior to +'** initially showing the screen. +'****************************************************** +Function preShowPosterScreen(breadA=invalid, breadB=invalid) As Object + + if validateParam(breadA, "roString", "preShowPosterScreen", true) = false return -1 + if validateParam(breadB, "roString", "preShowPosterScreen", true) = false return -1 + + port=CreateObject("roMessagePort") + screen = CreateObject("roPosterScreen") + screen.SetMessagePort(port) + if breadA<>invalid and breadB<>invalid then + screen.SetBreadcrumbText(breadA, breadB) + end if + + screen.SetListStyle("arced-portrait") + return screen + +End Function + + +'****************************************************** +'** Display the home screen and wait for events from +'** the screen. The screen will show retreiving while +'** we fetch and parse the feeds for the game posters +'****************************************************** +Function showPosterScreen(screen As Object, category As Object) As Integer + + if validateParam(screen, "roPosterScreen", "showPosterScreen") = false return -1 + if validateParam(category, "roAssociativeArray", "showPosterScreen") = false return -1 + + m.curCategory = 0 + m.curShow = 0 + + screen.SetListNames(getCategoryList(category)) + screen.SetContentList(getShowsForCategoryItem(category, m.curCategory)) + screen.Show() + + while true + msg = wait(0, screen.GetMessagePort()) + if type(msg) = "roPosterScreenEvent" then + print "showPosterScreen | msg = "; msg.GetMessage() " | index = "; msg.GetIndex() + if msg.isListFocused() then + m.curCategory = msg.GetIndex() + m.curShow = 0 + screen.SetFocusedListItem(m.curShow) + screen.SetContentList(getShowsForCategoryItem(category, m.curCategory)) + print "list focused | current category = "; m.curCategory + else if msg.isListItemSelected() then + m.curShow = msg.GetIndex() + print "list item selected | current show = "; m.curShow + m.curShow = displayShowDetailScreen(category, m.curShow) + screen.SetFocusedListItem(m.curShow) + print "list item updated | new show = "; m.curShow + else if msg.isScreenClosed() then + return -1 + end if + end If + end while + + +End Function + +'********************************************************** +'** When a poster on the home screen is selected, we call +'** this function passing an associative array with the +'** data for the selected show. This data should be +'** sufficient for the show detail (springboard) to display +'********************************************************** +Function displayShowDetailScreen(category as Object, showIndex as Integer) As Integer + + if validateParam(category, "roAssociativeArray", "displayShowDetailScreen") = false return -1 + + shows = getShowsForCategoryItem(category, m.curCategory) + screen = preShowDetailScreen(category.Title, category.kids[m.curCategory].Title) + showIndex = showDetailScreen(screen, shows, showIndex) + + return showIndex +End Function + + +'************************************************************** +'** Given an roAssociativeArray representing a category node +'** from the category feed tree, return an roArray containing +'** the names of all of the sub categories in the list. +'*************************************************************** +Function getCategoryList(topCategory As Object) As Object + + if validateParam(topCategory, "roAssociativeArray", "getCategoryList") = false return -1 + + if type(topCategory) <> "roAssociativeArray" then + print "incorrect type passed to getCategoryList" + return -1 + endif + + categoryList = CreateObject("roArray", 100, true) + for each subCategory in topCategory.Kids + categoryList.Push(subcategory.Title) + next + return categoryList + +End Function + +'******************************************************************** +'** Return the list of shows corresponding the currently selected +'** category in the filter banner. As the user highlights a +'** category on the top of the poster screen, the list of posters +'** displayed should be refreshed to corrrespond to the highlighted +'** item. This function returns the list of shows for that category +'******************************************************************** +Function getShowsForCategoryItem(category As Object, item As Integer) As Object + + if validateParam(category, "roAssociativeArray", "getCategoryList") = false return invalid + + conn = InitShowFeedConnection(category.kids[item]) + showList = conn.LoadShowFeed(conn) + return showList + +End Function diff --git a/roku_player/source/appVideoScreen.brs b/roku_player/source/appVideoScreen.brs @@ -0,0 +1,57 @@ +'********************************************************** +'** Video Player Example Application - Video Playback +'** November 2009 +'** Copyright (c) 2009 Roku Inc. All Rights Reserved. +'********************************************************** + +'*********************************************************** +'** Create and show the video screen. The video screen is +'** a special full screen video playback component. It +'** handles most of the keypresses automatically and our +'** job is primarily to make sure it has the correct data +'** at startup. We will receive event back on progress and +'** error conditions so it's important to monitor these to +'** understand what's going on, especially in the case of errors +'*********************************************************** +Function showVideoScreen(episode As Object) + + if type(episode) <> "roAssociativeArray" then + print "invalid data passed to showVideoScreen" + return -1 + endif + + port = CreateObject("roMessagePort") + screen = CreateObject("roVideoScreen") + screen.SetMessagePort(port) + + screen.Show() + screen.SetContent(episode) + screen.Show() + + 'Uncomment his line to dump the contents of the episode to be played + PrintAA(episode) + + while true + msg = wait(0, port) + + if type(msg) = "roVideoScreenEvent" then + print "showHomeScreen | msg = "; msg.getMessage() " | index = "; msg.GetIndex() + if msg.isScreenClosed() + print "Screen closed" + exit while + elseif msg.isRequestFailed() + print "Video request failure: "; msg.GetIndex(); " " msg.GetData() + elseif msg.isStatusMessage() + print "Video status: "; msg.GetIndex(); " " msg.GetData() + elseif msg.isButtonPressed() + print "Button pressed: "; msg.GetIndex(); " " msg.GetData() + else + print "Unexpected event type: "; msg.GetType() + end if + else + print "Unexpected message class: "; type(msg) + end if + end while + +End Function + diff --git a/roku_player/source/categoryFeed.brs b/roku_player/source/categoryFeed.brs @@ -0,0 +1,249 @@ +'****************************************************** +'** Video Player Example Application -- Category Feed +'** November 2009 +'** Copyright (c) 2009 Roku Inc. All Rights Reserved. +'****************************************************** + +'****************************************************** +' Set up the category feed connection object +' This feed provides details about top level categories +'****************************************************** +Function InitCategoryFeedConnection() As Object + + conn = CreateObject("roAssociativeArray") + + conn.UrlPrefix = "http://" + RegRead("ServerURL") + conn.UrlCategoryFeed = conn.UrlPrefix + "/xml/users" + print "Retrieving categories from: "; conn.UrlCategoryFeed + + conn.Timer = CreateObject("roTimespan") + + conn.LoadCategoryFeed = load_category_feed + conn.GetCategoryNames = get_category_names + + print "created feed connection for " + conn.UrlCategoryFeed + return conn + +End Function + +'********************************************************* +'** Create an array of names representing the children +'** for the current list of categories. This is useful +'** for filling in the filter banner with the names of +'** all the categories at the next level in the hierarchy +'********************************************************* +Function get_category_names(categories As Object) As Dynamic + + categoryNames = CreateObject("roArray", 100, true) + + for each category in categories.kids + 'print category.Title + categoryNames.Push(category.Title) + next + + return categoryNames + +End Function + + +'****************************************************************** +'** Given a connection object for a category feed, fetch, +'** parse and build the tree for the feed. the results are +'** stored hierarchically with parent/child relationships +'** with a single default node named Root at the root of the tree +'****************************************************************** +Function load_category_feed(conn As Object) As Dynamic + + http = NewHttp(conn.UrlCategoryFeed) + + Dbg("url: ", http.Http.GetUrl()) + + m.Timer.Mark() + rsp = http.GetToStringWithRetry() + Dbg("Took: ", m.Timer) + + m.Timer.Mark() + xml=CreateObject("roXMLElement") + if not xml.Parse(rsp) then + print "Can't parse feed" + return invalid + endif + Dbg("Parse Took: ", m.Timer) + + m.Timer.Mark() + if xml.category = invalid then + print "no categories tag" + return invalid + endif + + if islist(xml.category) = false then + print "invalid feed body" + return invalid + endif + + if xml.category[0].GetName() <> "category" then + print "no initial category tag" + return invalid + endif + + topNode = MakeEmptyCatNode() + topNode.Title = "root" + topNode.isapphome = true + + print "begin category node parsing" + + categories = xml.GetChildElements() + print "number of categories: " + itostr(categories.Count()) + for each e in categories + o = ParseCategoryNode(e) + if o <> invalid then + topNode.AddKid(o) + print "added new child node" + else + print "parse returned no child node" + endif + next + Dbg("Traversing: ", m.Timer) + + return topNode + +End Function + +'****************************************************** +'MakeEmptyCatNode - use to create top node in the tree +'****************************************************** +Function MakeEmptyCatNode() As Object + return init_category_item() +End Function + + +'*********************************************************** +'Given the xml element to an <Category> tag in the category +'feed, walk it and return the top level node to its tree +'*********************************************************** +Function ParseCategoryNode(xml As Object) As dynamic + o = init_category_item() + + print "ParseCategoryNode: " + xml.GetName() + 'PrintXML(xml, 5) + + 'parse the curent node to determine the type. everything except + 'special categories are considered normal, others have unique types + if xml.GetName() = "category" then + print "category: " + xml@title + " | " + xml@description + o.Type = "normal" + o.Title = xml@title + o.Description = xml@Description + o.ShortDescriptionLine1 = xml@Title + o.ShortDescriptionLine2 = xml@Description + o.SDPosterURL = xml@sd_img + o.HDPosterURL = xml@hd_img + elseif xml.GetName() = "categoryLeaf" then + o.Type = "normal" + elseif xml.GetName() = "specialCategory" then + if invalid <> xml.GetAttributes() then + for each a in xml.GetAttributes() + if a = "type" then + o.Type = xml.GetAttributes()[a] + print "specialCategory: " + xml@type + "|" + xml@title + " | " + xml@description + o.Title = xml@title + o.Description = xml@Description + o.ShortDescriptionLine1 = xml@Title + o.ShortDescriptionLine2 = xml@Description + o.SDPosterURL = xml@sd_img + o.HDPosterURL = xml@hd_img + endif + next + endif + else + print "ParseCategoryNode skip: " + xml.GetName() + return invalid + endif + + 'only continue processing if we are dealing with a known type + 'if new types are supported, make sure to add them to the list + 'and parse them correctly further downstream in the parser + while true + if o.Type = "normal" exit while + if o.Type = "special_category" exit while + print "ParseCategoryNode unrecognized feed type" + return invalid + end while + + 'get the list of child nodes and recursed + 'through everything under the current node + for each e in xml.GetBody() + name = e.GetName() + if name = "category" then + print "category: " + e@title + " [" + e@description + "]" + kid = ParseCategoryNode(e) + kid.Title = e@title + kid.Description = e@Description + kid.ShortDescriptionLine1 = xml@Description + kid.SDPosterURL = xml@sd_img + kid.HDPosterURL = xml@hd_img + o.AddKid(kid) + elseif name = "categoryLeaf" then + print "categoryLeaf: " + e@title + " [" + e@description + "]" + kid = ParseCategoryNode(e) + kid.Title = e@title + kid.Description = e@Description + kid.Feed = e@feed + o.AddKid(kid) + elseif name = "specialCategory" then + print "specialCategory: " + e@title + " [" + e@description + "]" + kid = ParseCategoryNode(e) + kid.Title = e@title + kid.Description = e@Description + kid.sd_img = e@sd_img + kid.hd_img = e@hd_img + kid.Feed = e@feed + o.AddKid(kid) + endif + next + + return o +End Function + + +'****************************************************** +'Initialize a Category Item +'****************************************************** +Function init_category_item() As Object + o = CreateObject("roAssociativeArray") + o.Title = "" + o.Type = "normal" + o.Description = "" + o.Kids = CreateObject("roArray", 100, true) + o.Parent = invalid + o.Feed = "" + o.IsLeaf = cn_is_leaf + o.AddKid = cn_add_kid + return o +End Function + + +'******************************************************** +'** Helper function for each node, returns true/false +'** indicating that this node is a leaf node in the tree +'******************************************************** +Function cn_is_leaf() As Boolean + if m.Kids.Count() > 0 return true + if m.Feed <> "" return false + return true +End Function + + +'********************************************************* +'** Helper function for each node in the tree to add a +'** new node as a child to this node. +'********************************************************* +Sub cn_add_kid(kid As Object) + if kid = invalid then + print "skipping: attempt to add invalid kid failed" + return + endif + + kid.Parent = m + m.Kids.Push(kid) +End Sub diff --git a/roku_player/source/deviceInfo.brs b/roku_player/source/deviceInfo.brs @@ -0,0 +1,21 @@ +'********************************************************** +'** Video Player Example Application - DeviceInfo +'** November 2009 +'** Copyright (c) 2009 Roku Inc. All Rights Reserved. +'********************************************************** + +'****************************************************** +'Get our device version +'****************************************************** + +Function GetDeviceVersion() + return CreateObject("roDeviceInfo").GetVersion() +End Function + +'****************************************************** +'Get our serial number +'****************************************************** + +Function GetDeviceESN() + return CreateObject("roDeviceInfo").GetDeviceUniqueId() +End Function diff --git a/roku_player/source/generalDlgs.brs b/roku_player/source/generalDlgs.brs @@ -0,0 +1,150 @@ +'********************************************************** +'** Video Player Example Application - General Dialogs +'** November 2009 +'** Copyright (c) 2009 Roku Inc. All Rights Reserved. +'********************************************************** + +'****************************************************** +'Show basic message dialog without buttons +'Dialog remains up until caller releases the returned object +'****************************************************** + +Function ShowPleaseWait(title As dynamic, text As dynamic) As Object + if not isstr(title) title = "" + if not isstr(text) text = "" + + port = CreateObject("roMessagePort") + dialog = invalid + + 'the OneLineDialog renders a single line of text better + 'than the MessageDialog. + if text = "" + dialog = CreateObject("roOneLineDialog") + else + dialog = CreateObject("roMessageDialog") + dialog.SetText(text) + endif + + dialog.SetMessagePort(port) + + dialog.SetTitle(title) + dialog.ShowBusyAnimation() + dialog.Show() + return dialog +End Function + +'****************************************************** +'Retrieve text for connection failed +'****************************************************** + +Function GetConnectionFailedText() as String + return "We were unable to connect to the service. Please try again in a few minutes." +End Function + +'****************************************************** +'Show connection error dialog +' +'Parameter: retry t/f - offer retry option +'Return 0 = retry, 1 = back +'****************************************************** + +Function ShowConnectionFailedRetry() as dynamic + Dbg("Connection Failed Retry") + title = "Can't connect to video service" + text = GetConnectionFailedText() + return ShowDialog2Buttons(title, text, "try again", "back") +End Function + +'****************************************************** +'Show Amzon connection error dialog with only an OK button +'****************************************************** + +Sub ShowConnectionFailed() + Dbg("Connection Failed") + title = "Can't connect to video service" + text = GetConnectionFailedText() + ShowErrorDialog(text, title) +End Sub + +'****************************************************** +'Show error dialog with OK button +'****************************************************** + +Sub ShowErrorDialog(text As dynamic, title=invalid as dynamic) + if not isstr(text) text = "Unspecified error" + if not isstr(title) title = "" + ShowDialog1Button(title, text, "Done") +End Sub + +'****************************************************** +'Show 1 button dialog +'Return: nothing +'****************************************************** + +Sub ShowDialog1Button(title As dynamic, text As dynamic, but1 As String) + if not isstr(title) title = "" + if not isstr(text) text = "" + + Dbg("DIALOG1: ", title + " - " + text) + + port = CreateObject("roMessagePort") + dialog = CreateObject("roMessageDialog") + dialog.SetMessagePort(port) + + dialog.SetTitle(title) + dialog.SetText(text) + dialog.AddButton(0, but1) + dialog.Show() + + while true + dlgMsg = wait(0, dialog.GetMessagePort()) + + if type(dlgMsg) = "roMessageDialogEvent" + if dlgMsg.isScreenClosed() + print "Screen closed" + return + else if dlgMsg.isButtonPressed() + print "Button pressed: "; dlgMsg.GetIndex(); " " dlgMsg.GetData() + return + endif + endif + end while +End Sub + +'****************************************************** +'Show 2 button dialog +'Return: 0=first button or screen closed, 1=second button +'****************************************************** + +Function ShowDialog2Buttons(title As dynamic, text As dynamic, but1 As String, but2 As String) As Integer + if not isstr(title) title = "" + if not isstr(text) text = "" + + Dbg("DIALOG2: ", title + " - " + text) + + port = CreateObject("roMessagePort") + dialog = CreateObject("roMessageDialog") + dialog.SetMessagePort(port) + + dialog.SetTitle(title) + dialog.SetText(text) + dialog.AddButton(0, but1) + dialog.AddButton(1, but2) + dialog.Show() + + while true + dlgMsg = wait(0, dialog.GetMessagePort()) + + if type(dlgMsg) = "roMessageDialogEvent" + if dlgMsg.isScreenClosed() + print "Screen closed" + dialog = invalid + return 0 + else if dlgMsg.isButtonPressed() + print "Button pressed: "; dlgMsg.GetIndex(); " " dlgMsg.GetData() + dialog = invalid + return dlgMsg.GetIndex() + endif + endif + end while +End Function diff --git a/roku_player/source/generalUtils.brs b/roku_player/source/generalUtils.brs @@ -0,0 +1,658 @@ +'********************************************************** +'** Video Player Example Application - General Utilities +'** November 2009 +'** Copyright (c) 2009 Roku Inc. All Rights Reserved. +'********************************************************** + +'****************************************************** +'Registry Helper Functions +'****************************************************** +Function RegRead(key, section=invalid) + if section = invalid then section = "Default" + sec = CreateObject("roRegistrySection", section) + if sec.Exists(key) then return sec.Read(key) + return invalid +End Function + +Function RegWrite(key, val, section=invalid) + if section = invalid then section = "Default" + sec = CreateObject("roRegistrySection", section) + sec.Write(key, val) + sec.Flush() 'commit it +End Function + +Function RegDelete(key, section=invalid) + if section = invalid then section = "Default" + sec = CreateObject("roRegistrySection", section) + sec.Delete(key) + sec.Flush() +End Function + + +'****************************************************** +'Insertion Sort +'Will sort an array directly, or use a key function +'****************************************************** +Sub Sort(A as Object, key=invalid as dynamic) + + if type(A)<>"roArray" then return + + if (key=invalid) then + for i = 1 to A.Count()-1 + value = A[i] + j = i-1 + while j>= 0 and A[j] > value + A[j + 1] = A[j] + j = j-1 + end while + A[j+1] = value + next + + else + if type(key)<>"Function" then return + for i = 1 to A.Count()-1 + valuekey = key(A[i]) + value = A[i] + j = i-1 + while j>= 0 and key(A[j]) > valuekey + A[j + 1] = A[j] + j = j-1 + end while + A[j+1] = value + next + + end if + +End Sub + + +'****************************************************** +'Convert anything to a string +' +'Always returns a string +'****************************************************** +Function tostr(any) + ret = AnyToString(any) + if ret = invalid ret = type(any) + if ret = invalid ret = "unknown" 'failsafe + return ret +End Function + + +'****************************************************** +'Get a " char as a string +'****************************************************** +Function Quote() + q$ = Chr(34) + return q$ +End Function + + +'****************************************************** +'isxmlelement +' +'Determine if the given object supports the ifXMLElement interface +'****************************************************** +Function isxmlelement(obj as dynamic) As Boolean + if obj = invalid return false + if GetInterface(obj, "ifXMLElement") = invalid return false + return true +End Function + + +'****************************************************** +'islist +' +'Determine if the given object supports the ifList interface +'****************************************************** +Function islist(obj as dynamic) As Boolean + if obj = invalid return false + if GetInterface(obj, "ifArray") = invalid return false + return true +End Function + + +'****************************************************** +'isint +' +'Determine if the given object supports the ifInt interface +'****************************************************** +Function isint(obj as dynamic) As Boolean + if obj = invalid return false + if GetInterface(obj, "ifInt") = invalid return false + return true +End Function + +'****************************************************** +' validstr +' +' always return a valid string. if the argument is +' invalid or not a string, return an empty string +'****************************************************** +Function validstr(obj As Dynamic) As String + if isnonemptystr(obj) return obj + return "" +End Function + + +'****************************************************** +'isstr +' +'Determine if the given object supports the ifString interface +'****************************************************** +Function isstr(obj as dynamic) As Boolean + if obj = invalid return false + if GetInterface(obj, "ifString") = invalid return false + return true +End Function + + +'****************************************************** +'isnonemptystr +' +'Determine if the given object supports the ifString interface +'and returns a string of non zero length +'****************************************************** +Function isnonemptystr(obj) + if isnullorempty(obj) return false + return true +End Function + + +'****************************************************** +'isnullorempty +' +'Determine if the given object is invalid or supports +'the ifString interface and returns a string of non zero length +'****************************************************** +Function isnullorempty(obj) + if obj = invalid return true + if not isstr(obj) return true + if Len(obj) = 0 return true + return false +End Function + + +'****************************************************** +'isbool +' +'Determine if the given object supports the ifBoolean interface +'****************************************************** +Function isbool(obj as dynamic) As Boolean + if obj = invalid return false + if GetInterface(obj, "ifBoolean") = invalid return false + return true +End Function + + +'****************************************************** +'isfloat +' +'Determine if the given object supports the ifFloat interface +'****************************************************** +Function isfloat(obj as dynamic) As Boolean + if obj = invalid return false + if GetInterface(obj, "ifFloat") = invalid return false + return true +End Function + + +'****************************************************** +'strtobool +' +'Convert string to boolean safely. Don't crash +'Looks for certain string values +'****************************************************** +Function strtobool(obj As dynamic) As Boolean + if obj = invalid return false + if type(obj) <> "roString" return false + o = strTrim(obj) + o = Lcase(o) + if o = "true" return true + if o = "t" return true + if o = "y" return true + if o = "1" return true + return false +End Function + + +'****************************************************** +'itostr +' +'Convert int to string. This is necessary because +'the builtin Stri(x) prepends whitespace +'****************************************************** +Function itostr(i As Integer) As String + str = Stri(i) + return strTrim(str) +End Function + + +'****************************************************** +'Get remaining hours from a total seconds +'****************************************************** +Function hoursLeft(seconds As Integer) As Integer + hours% = seconds / 3600 + return hours% +End Function + + +'****************************************************** +'Get remaining minutes from a total seconds +'****************************************************** +Function minutesLeft(seconds As Integer) As Integer + hours% = seconds / 3600 + mins% = seconds - (hours% * 3600) + mins% = mins% / 60 + return mins% +End Function + + +'****************************************************** +'Pluralize simple strings like "1 minute" or "2 minutes" +'****************************************************** +Function Pluralize(val As Integer, str As String) As String + ret = itostr(val) + " " + str + if val <> 1 ret = ret + "s" + return ret +End Function + + +'****************************************************** +'Trim a string +'****************************************************** +Function strTrim(str As String) As String + st=CreateObject("roString") + st.SetString(str) + return st.Trim() +End Function + + +'****************************************************** +'Tokenize a string. Return roList of strings +'****************************************************** +Function strTokenize(str As String, delim As String) As Object + st=CreateObject("roString") + st.SetString(str) + return st.Tokenize(delim) +End Function + + +'****************************************************** +'Replace substrings in a string. Return new string +'****************************************************** +Function strReplace(basestr As String, oldsub As String, newsub As String) As String + newstr = "" + + i = 1 + while i <= Len(basestr) + x = Instr(i, basestr, oldsub) + if x = 0 then + newstr = newstr + Mid(basestr, i) + exit while + endif + + if x > i then + newstr = newstr + Mid(basestr, i, x-i) + i = x + endif + + newstr = newstr + newsub + i = i + Len(oldsub) + end while + + return newstr +End Function + + +'****************************************************** +'Get all XML subelements by name +' +'return list of 0 or more elements +'****************************************************** +Function GetXMLElementsByName(xml As Object, name As String) As Object + list = CreateObject("roArray", 100, true) + if islist(xml.GetBody()) = false return list + + for each e in xml.GetBody() + if e.GetName() = name then + list.Push(e) + endif + next + + return list +End Function + + +'****************************************************** +'Get all XML subelement's string bodies by name +' +'return list of 0 or more strings +'****************************************************** +Function GetXMLElementBodiesByName(xml As Object, name As String) As Object + list = CreateObject("roArray", 100, true) + if islist(xml.GetBody()) = false return list + + for each e in xml.GetBody() + if e.GetName() = name then + b = e.GetBody() + if type(b) = "roString" list.Push(b) + endif + next + + return list +End Function + + +'****************************************************** +'Get first XML subelement by name +' +'return invalid if not found, else the element +'****************************************************** +Function GetFirstXMLElementByName(xml As Object, name As String) As dynamic + if islist(xml.GetBody()) = false return invalid + + for each e in xml.GetBody() + if e.GetName() = name return e + next + + return invalid +End Function + + +'****************************************************** +'Get first XML subelement's string body by name +' +'return invalid if not found, else the subelement's body string +'****************************************************** +Function GetFirstXMLElementBodyStringByName(xml As Object, name As String) As dynamic + e = GetFirstXMLElementByName(xml, name) + if e = invalid return invalid + if type(e.GetBody()) <> "roString" return invalid + return e.GetBody() +End Function + + +'****************************************************** +'Get the xml element as an integer +' +'return invalid if body not a string, else the integer as converted by strtoi +'****************************************************** +Function GetXMLBodyAsInteger(xml As Object) As dynamic + if type(xml.GetBody()) <> "roString" return invalid + return strtoi(xml.GetBody()) +End Function + + +'****************************************************** +'Parse a string into a roXMLElement +' +'return invalid on error, else the xml object +'****************************************************** +Function ParseXML(str As String) As dynamic + if str = invalid return invalid + xml=CreateObject("roXMLElement") + if not xml.Parse(str) return invalid + return xml +End Function + + +'****************************************************** +'Get XML sub elements whose bodies are strings into an associative array. +'subelements that are themselves parents are skipped +'namespace :'s are replaced with _'s +' +'So an XML element like... +' +'<blah> +' <This>abcdefg</This> +' <Sucks>xyz</Sucks> +' <sub> +' <sub2> +' .... +' </sub2> +' </sub> +' <ns:doh>homer</ns:doh> +'</blah> +' +'returns an AA with: +' +'aa.This = "abcdefg" +'aa.Sucks = "xyz" +'aa.ns_doh = "homer" +' +'return an empty AA if nothing found +'****************************************************** +Sub GetXMLintoAA(xml As Object, aa As Object) + for each e in xml.GetBody() + body = e.GetBody() + if type(body) = "roString" then + name = e.GetName() + name = strReplace(name, ":", "_") + aa.AddReplace(name, body) + endif + next +End Sub + + +'****************************************************** +'Walk an AA and print it +'****************************************************** +Sub PrintAA(aa as Object) + print "---- AA ----" + if aa = invalid + print "invalid" + return + else + cnt = 0 + for each e in aa + x = aa[e] + PrintAny(0, e + ": ", aa[e]) + cnt = cnt + 1 + next + if cnt = 0 + PrintAny(0, "Nothing from for each. Looks like :", aa) + endif + endif + print "------------" +End Sub + + +'****************************************************** +'Walk a list and print it +'****************************************************** +Sub PrintList(list as Object) + print "---- list ----" + PrintAnyList(0, list) + print "--------------" +End Sub + + +'****************************************************** +'Print an associativearray +'****************************************************** +Sub PrintAnyAA(depth As Integer, aa as Object) + for each e in aa + x = aa[e] + PrintAny(depth, e + ": ", aa[e]) + next +End Sub + + +'****************************************************** +'Print a list with indent depth +'****************************************************** +Sub PrintAnyList(depth As Integer, list as Object) + i = 0 + for each e in list + PrintAny(depth, "List(" + itostr(i) + ")= ", e) + i = i + 1 + next +End Sub + + +'****************************************************** +'Print anything +'****************************************************** +Sub PrintAny(depth As Integer, prefix As String, any As Dynamic) + if depth >= 10 + print "**** TOO DEEP " + itostr(5) + return + endif + prefix = string(depth*2," ") + prefix + depth = depth + 1 + str = AnyToString(any) + if str <> invalid + print prefix + str + return + endif + if type(any) = "roAssociativeArray" + print prefix + "(assocarr)..." + PrintAnyAA(depth, any) + return + endif + if islist(any) = true + print prefix + "(list of " + itostr(any.Count()) + ")..." + PrintAnyList(depth, any) + return + endif + + print prefix + "?" + type(any) + "?" +End Sub + + +'****************************************************** +'Print an object as a string for debugging. If it is +'very long print the first 500 chars. +'****************************************************** +Sub Dbg(pre As Dynamic, o=invalid As Dynamic) + p = AnyToString(pre) + if p = invalid p = "" + if o = invalid o = "" + s = AnyToString(o) + if s = invalid s = "???: " + type(o) + if Len(s) > 4000 + s = Left(s, 4000) + endif + print p + s +End Sub + + +'****************************************************** +'Try to convert anything to a string. Only works on simple items. +' +'Test with this script... +' +' s$ = "yo1" +' ss = "yo2" +' i% = 111 +' ii = 222 +' f! = 333.333 +' ff = 444.444 +' d# = 555.555 +' dd = 555.555 +' bb = true +' +' so = CreateObject("roString") +' so.SetString("strobj") +' io = CreateObject("roInt") +' io.SetInt(666) +' tm = CreateObject("roTimespan") +' +' Dbg("", s$ ) 'call the Dbg() function which calls AnyToString() +' Dbg("", ss ) +' Dbg("", "yo3") +' Dbg("", i% ) +' Dbg("", ii ) +' Dbg("", 2222 ) +' Dbg("", f! ) +' Dbg("", ff ) +' Dbg("", 3333.3333 ) +' Dbg("", d# ) +' Dbg("", dd ) +' Dbg("", so ) +' Dbg("", io ) +' Dbg("", bb ) +' Dbg("", true ) +' Dbg("", tm ) +' +'try to convert an object to a string. return invalid if can't +'****************************************************** +Function AnyToString(any As Dynamic) As dynamic + if any = invalid return "invalid" + if isstr(any) return any + if isint(any) return itostr(any) + if isbool(any) + if any = true return "true" + return "false" + endif + if isfloat(any) return Str(any) + if type(any) = "roTimespan" return itostr(any.TotalMilliseconds()) + "ms" + return invalid +End Function + + +'****************************************************** +'Walk an XML tree and print it +'****************************************************** +Sub PrintXML(element As Object, depth As Integer) + print tab(depth*3);"Name: [" + element.GetName() + "]" + if invalid <> element.GetAttributes() then + print tab(depth*3);"Attributes: "; + for each a in element.GetAttributes() + print a;"=";left(element.GetAttributes()[a], 4000); + if element.GetAttributes().IsNext() then print ", "; + next + print + endif + + if element.GetBody()=invalid then + ' print tab(depth*3);"No Body" + else if type(element.GetBody())="roString" then + print tab(depth*3);"Contains string: [" + left(element.GetBody(), 4000) + "]" + else + print tab(depth*3);"Contains list:" + for each e in element.GetBody() + PrintXML(e, depth+1) + next + endif + print +end sub + + +'****************************************************** +'Dump the bytes of a string +'****************************************************** +Sub DumpString(str As String) + print "DUMP STRING" + print "---------------------------" + print str + print "---------------------------" + l = Len(str)-1 + i = 0 + for i = 0 to l + c = Mid(str, i) + val = Asc(c) + print itostr(val) + next + print "---------------------------" +End Sub + + +'****************************************************** +'Validate parameter is the correct type +'****************************************************** +Function validateParam(param As Object, paramType As String,functionName As String, allowInvalid = false) As Boolean + if type(param) = paramType then + return true + endif + + if allowInvalid = true then + if type(param) = invalid then + return true + endif + endif + + print "invalid parameter of type "; type(param); " for "; paramType; " in function "; functionName + return false +End Function diff --git a/roku_player/source/showFeed.brs b/roku_player/source/showFeed.brs @@ -0,0 +1,201 @@ +'********************************************************** +'** Video Player Example Application - Show Feed +'** November 2009 +'** Copyright (c) 2009 Roku Inc. All Rights Reserved. +'********************************************************** + +'****************************************************** +'** Set up the show feed connection object +'** This feed provides the detailed list of shows for +'** each subcategory (categoryLeaf) in the category +'** category feed. Given a category leaf node for the +'** desired show list, we'll hit the url and get the +'** results. +'****************************************************** + +Function InitShowFeedConnection(category As Object) As Object + + if validateParam(category, "roAssociativeArray", "initShowFeedConnection") = false return invalid + + conn = CreateObject("roAssociativeArray") + conn.UrlShowFeed = category.feed + + conn.Timer = CreateObject("roTimespan") + + conn.LoadShowFeed = load_show_feed + conn.ParseShowFeed = parse_show_feed + conn.InitFeedItem = init_show_feed_item + + print "created feed connection for " + conn.UrlShowFeed + return conn + +End Function + + +'****************************************************** +'Initialize a new feed object +'****************************************************** +Function newShowFeed() As Object + + o = CreateObject("roArray", 100, true) + return o + +End Function + + +'*********************************************************** +' Initialize a ShowFeedItem. This sets the default values +' for everything. The data in the actual feed is sometimes +' sparse, so these will be the default values unless they +' are overridden while parsing the actual game data +'*********************************************************** +Function init_show_feed_item() As Object + o = CreateObject("roAssociativeArray") + + o.ContentId = "" + o.Title = "" + o.ContentType = "" + o.Description = "" + o.Length = "" + o.Actors = CreateObject("roArray", 3, true) + o.Director = CreateObject("roArray", 1, true) + o.Categories = CreateObject("roArray", 3, true) + o.StreamFormats = CreateObject("roArray", 5, true) + o.StreamQualities = CreateObject("roArray", 5, true) + o.StreamBitrates = CreateObject("roArray", 5, true) + o.StreamUrls = CreateObject("roArray", 5, true) + + return o +End Function + + +'************************************************************* +'** Grab and load a show detail feed. The url we are fetching +'** is specified as part of the category provided during +'** initialization. This feed provides a list of all shows +'** with details for the given category feed. +'********************************************************* +Function load_show_feed(conn As Object) As Dynamic + + if validateParam(conn, "roAssociativeArray", "load_show_feed") = false return invalid + + print "url: " + conn.UrlShowFeed + http = NewHttp(conn.UrlShowFeed) + + m.Timer.Mark() + rsp = http.GetToStringWithRetry() + print "Request Time: " + itostr(m.Timer.TotalMilliseconds()) + + feed = newShowFeed() + xml=CreateObject("roXMLElement") + if not xml.Parse(rsp) then + print "Can't parse feed" + print rsp + return feed + endif + + if xml.GetName() <> "feed" then + print "no feed tag found" + return feed + endif + + if islist(xml.GetBody()) = false then + print "no feed body found" + return feed + endif + + m.Timer.Mark() + m.ParseShowFeed(xml, feed) + print "Show Feed Parse Took : " + itostr(m.Timer.TotalMilliseconds()) + + return feed + +End Function + + +'************************************************************************** +'************************************************************************** +Function parse_show_feed(xml As Object, feed As Object) As Void + + showCount = 0 + showList = xml.GetChildElements() + + for each curShow in showList + + 'for now, don't process meta info about the feed size + if curShow.GetName() = "resultLength" or curShow.GetName() = "endIndex" then + goto skipitem + endif + + item = init_show_feed_item() + + 'fetch all values from the xml for the current show + item.HDPosterUrl = validstr(curShow@hdPosterUrl) + item.SDPosterUrl = validstr(curShow@sdPosterUrl) + item.ContentId = validstr(curShow.contentId.GetText()) + item.Title = validstr(curShow.title.GetText()) + item.Description = validstr(curShow.description.GetText()) + item.ContentType = validstr(curShow.contentType.GetText()) + item.ContentQuality = validstr(curShow.contentQuality.GetText()) + item.Length = strtoi(validstr(curShow.length.GetText())) + item.HDBifUrl = validstr(curShow.hdBifUrl.GetText()) + item.SDBifUrl = validstr(curShow.sdBifUrl.GetText()) + item.StreamFormat = validstr(curShow.streamFormat.GetText()) + item.ReleaseDate = validstr(curshow.releaseDate.GetText()) + item.Rating = validstr(curshow.rating.GetText()) + item.StarRating = validstr(curshow.starRating.GetText()) + item.UserStarRating = validstr(curshow.userStarRating.GetText()) + item.ShortDescriptionLine1 = validstr(curshow.ShortDescriptionLine1.GetText()) + item.ShortDescriptionLine2 = validstr(curshow.ShortDescriptionLine2.GetText()) + item.EpisodeNumber = validstr(curshow.episodeNumber.GetText()) + item.HDBranded = strtobool(validstr(curshow.hdBranded.GetText())) + item.isHD = strtobool(validstr(curshow.isHD.GetText())) + item.TextOverlayUL = validstr(curshow.textOverlayUL.GetText()) + item.TextOverlayUR = validstr(curshow.textOverlayUR.GetText()) + item.TextOverlayBody = validstr(curshow.textOverlayBody.GetText()) + item.Album = validstr(curshow.album.GetText()) + item.Artist = validstr(curshow.artist.GetText()) + + 'media may be at multiple bitrates, so parse an build arrays + for idx = 0 to 4 + e = curShow.media[idx] + if e <> invalid then + item.StreamFormats.Push(validstr(e.streamFormat.GetText())) + item.StreamBitrates.Push(strtoi(validstr(e.streamBitrate.GetText()))) + item.StreamQualities.Push(validstr(e.streamQuality.GetText())) + item.StreamUrls.Push(validstr(e.streamUrl.GetText())) + endif + next idx + + ' May be multiple actors + for idx = 0 to 2 + e = curShow.actor[idx] + if e <> invalid then + item.Actors.Push(validstr(e.GetText())) + endif + next idx + + ' May be multiple directors + for idx = 0 to 2 + e = curShow.director[idx] + if e <> invalid then + item.Director.Push(validstr(e.GetText())) + endif + next idx + + ' May be multiple categories + for idx = 0 to 2 + e = curShow.category[idx] + if e <> invalid then + item.Categories.Push(validstr(e.GetText())) + endif + next idx + + showCount = showCount + 1 + feed.Push(item) + + skipitem: + + next + +End Function diff --git a/roku_player/source/urlUtils.brs b/roku_player/source/urlUtils.brs @@ -0,0 +1,215 @@ +'********************************************************** +'** Video Player Example Application - URL Utilities +'** November 2009 +'** Copyright (c) 2009 Roku Inc. All Rights Reserved. +'********************************************************** + +REM ****************************************************** +REM Constucts a URL Transfer object +REM ****************************************************** + +Function CreateURLTransferObject(url As String) as Object + obj = CreateObject("roUrlTransfer") + obj.SetPort(CreateObject("roMessagePort")) + obj.SetUrl(url) + obj.AddHeader("Content-Type", "application/x-www-form-urlencoded") + obj.EnableEncodings(true) + return obj +End Function + +REM ****************************************************** +REM Url Query builder +REM so this is a quick and dirty name/value encoder/accumulator +REM ****************************************************** + +Function NewHttp(url As String) as Object + obj = CreateObject("roAssociativeArray") + obj.Http = CreateURLTransferObject(url) + obj.FirstParam = true + obj.AddParam = http_add_param + obj.AddRawQuery = http_add_raw_query + obj.GetToStringWithRetry = http_get_to_string_with_retry + obj.PrepareUrlForQuery = http_prepare_url_for_query + obj.GetToStringWithTimeout = http_get_to_string_with_timeout + obj.PostFromStringWithTimeout = http_post_from_string_with_timeout + + if Instr(1, url, "?") > 0 then obj.FirstParam = false + + return obj +End Function + + +REM ****************************************************** +REM Constucts a URL Transfer object 2 +REM ****************************************************** + +Function CreateURLTransferObject2(url As String, contentHeader As String) as Object + obj = CreateObject("roUrlTransfer") + obj.SetPort(CreateObject("roMessagePort")) + obj.SetUrl(url) + obj.AddHeader("Content-Type", contentHeader) + obj.EnableEncodings(true) + return obj +End Function + +REM ****************************************************** +REM Url Query builder 2 +REM so this is a quick and dirty name/value encoder/accumulator +REM ****************************************************** + +Function NewHttp2(url As String, contentHeader As String) as Object + obj = CreateObject("roAssociativeArray") + obj.Http = CreateURLTransferObject2(url, contentHeader) + obj.FirstParam = true + obj.AddParam = http_add_param + obj.AddRawQuery = http_add_raw_query + obj.GetToStringWithRetry = http_get_to_string_with_retry + obj.PrepareUrlForQuery = http_prepare_url_for_query + obj.GetToStringWithTimeout = http_get_to_string_with_timeout + obj.PostFromStringWithTimeout = http_post_from_string_with_timeout + + if Instr(1, url, "?") > 0 then obj.FirstParam = false + + return obj +End Function + + +REM ****************************************************** +REM HttpEncode - just encode a string +REM ****************************************************** + +Function HttpEncode(str As String) As String + o = CreateObject("roUrlTransfer") + return o.Escape(str) +End Function + +REM ****************************************************** +REM Prepare the current url for adding query parameters +REM Automatically add a '?' or '&' as necessary +REM ****************************************************** + +Function http_prepare_url_for_query() As String + url = m.Http.GetUrl() + if m.FirstParam then + url = url + "?" + m.FirstParam = false + else + url = url + "&" + endif + m.Http.SetUrl(url) + return url +End Function + +REM ****************************************************** +REM Percent encode a name/value parameter pair and add the +REM the query portion of the current url +REM Automatically add a '?' or '&' as necessary +REM Prevent duplicate parameters +REM ****************************************************** + +Function http_add_param(name As String, val As String) as Void + q = m.Http.Escape(name) + q = q + "=" + url = m.Http.GetUrl() + if Instr(1, url, q) > 0 return 'Parameter already present + q = q + m.Http.Escape(val) + m.AddRawQuery(q) +End Function + +REM ****************************************************** +REM Tack a raw query string onto the end of the current url +REM Automatically add a '?' or '&' as necessary +REM ****************************************************** + +Function http_add_raw_query(query As String) as Void + url = m.PrepareUrlForQuery() + url = url + query + m.Http.SetUrl(url) +End Function + +REM ****************************************************** +REM Performs Http.AsyncGetToString() in a retry loop +REM with exponential backoff. To the outside +REM world this appears as a synchronous API. +REM ****************************************************** + +Function http_get_to_string_with_retry() as String + timeout% = 1500 + num_retries% = 5 + + str = "" + while num_retries% > 0 +' print "httpget try " + itostr(num_retries%) + if (m.Http.AsyncGetToString()) + event = wait(timeout%, m.Http.GetPort()) + if type(event) = "roUrlEvent" + str = event.GetString() + exit while + elseif event = invalid + m.Http.AsyncCancel() + REM reset the connection on timeouts + m.Http = CreateURLTransferObject(m.Http.GetUrl()) + timeout% = 2 * timeout% + else + print "roUrlTransfer::AsyncGetToString(): unknown event" + endif + endif + + num_retries% = num_retries% - 1 + end while + + return str +End Function + +REM ****************************************************** +REM Performs Http.AsyncGetToString() with a single timeout in seconds +REM To the outside world this appears as a synchronous API. +REM ****************************************************** + +Function http_get_to_string_with_timeout(seconds as Integer) as String + timeout% = 1000 * seconds + + str = "" + m.Http.EnableFreshConnection(true) 'Don't reuse existing connections + if (m.Http.AsyncGetToString()) + event = wait(timeout%, m.Http.GetPort()) + if type(event) = "roUrlEvent" + str = event.GetString() + elseif event = invalid + Dbg("AsyncGetToString timeout") + m.Http.AsyncCancel() + else + Dbg("AsyncGetToString unknown event", event) + endif + endif + + return str +End Function + +REM ****************************************************** +REM Performs Http.AsyncPostFromString() with a single timeout in seconds +REM To the outside world this appears as a synchronous API. +REM ****************************************************** + +Function http_post_from_string_with_timeout(val As String, seconds as Integer) as String + timeout% = 1000 * seconds + + str = "" +' m.Http.EnableFreshConnection(true) 'Don't reuse existing connections + if (m.Http.AsyncPostFromString(val)) + event = wait(timeout%, m.Http.GetPort()) + if type(event) = "roUrlEvent" + print "1" + str = event.GetString() + elseif event = invalid + print "2" + Dbg("AsyncPostFromString timeout") + m.Http.AsyncCancel() + else + print "3" + Dbg("AsyncPostFromString unknown event", event) + endif + endif + + return str +End Function diff --git a/roku_player/xml/categories.xml b/roku_player/xml/categories.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<categories> + + <!-- banner_ad: optional element which displays an at the top level category screen --> + <banner_ad sd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/missing.png" hd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/missing.png"/> + + <category title="Technology" description="TED Talks on Technology" sd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/TED_Technology.png" hd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/TED_Technology.png"> + <categoryLeaf title="The Mind" description="" feed="http://rokudev.roku.com/rokudev/examples/videoplayer/xml/themind.xml"/> + <categoryLeaf title="Global Issues" description="" feed="http://rokudev.roku.com/rokudev/examples/videoplayer/xml/globalissues.xml" /> + </category> + + <category title="Entertainment" description="TED Talks on Entertainment" sd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/TED_Entertainment.png" hd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/TED_Entertainment.png"> + <categoryLeaf title="Music" description="" feed="http://rokudev.roku.com/rokudev/examples/videoplayer/xml/music.xml" /> + <categoryLeaf title="Inspiration" description="" feed="http://rokudev.roku.com/rokudev/examples/videoplayer/xml/inspiration.xml" /> + </category> + + <category title="Design" description="TED Talks on Design" sd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/TED_Design.png" hd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/TED_Design.png"> + <categoryLeaf title="Creativity" description="" feed="http://rokudev.roku.com/rokudev/examples/videoplayer/xml/creativity.xml"/> + <categoryLeaf title="Design" description="" feed="http://rokudev.roku.com/rokudev/examples/videoplayer/xml/design.xml" /> + </category> + + </categories> diff --git a/roku_player/xml/creativity.xml b/roku_player/xml/creativity.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<feed> + <!-- resultLength indicates the total number of results for this feed --> + <resultLength>3</resultLength> + <!-- endIndix indicates the number of results for this *paged* section of the feed --> + <endIndex>3</endIndex> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/ElizabethGilbert.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/ElizabethGilbert.jpg"> + <title>Elizabeth Gilbert on nurturing creativity</title> + <contentId>10051</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/ElizabethGilbert_2009_480.mp4</streamUrl> + </media> + <synopsis>Elizabeth Gilbert muses on the impossible things we expect from artists and geniuses -- and shares the radical idea that, instead of the rare person 'being' a genius, all of us 'have' a genius. It's a funny, personal and surprisingly moving talk.</synopsis> + <genres>Creativity</genres> + <runtime>1172</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/SethGodin.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/SethGodin.jpg"> + <title>Seth Godin on standing out</title> + <contentId>10052</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/SethGodin_2003_480.mp4</streamUrl> + </media> + <synopsis>In a world of too many options and too little time, our obvious choice is to just ignore the ordinary stuff. Marketing guru Seth Godin spells out why, when it comes to getting our attention, bad or bizarre ideas are more successful than boring ones.</synopsis> + <genres>Creativity</genres> + <runtime>1024</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/TimBrown.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/TimBrown.jpg"> + <title>Tim Brown urges designers to think big</title> + <contentId>10053</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/TimBrown_2009G_480.mp4</streamUrl> + </media> + <synopsis>Tim Brown says the design profession is preoccupied with creating nifty, fashionable objects -- even as pressing questions like clean water access show it has a bigger role to play. He calls for a shift to local, collaborative, participatory 'design thinking.'</synopsis> + <genres>Creativity</genres> + <runtime>1010</runtime> + </item> +</feed> diff --git a/roku_player/xml/design.xml b/roku_player/xml/design.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<feed> + <!-- resultLength indicates the total number of results for this feed --> + <resultLength>4</resultLength> + <!-- endIndix indicates the number of results for this *paged* section of the feed --> + <endIndex>4</endIndex> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/JeffHan.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/JeffHan.jpg"> + <title>Jeff Han demos his breakthrough touchscreen</title> + <contentId>10061</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/JeffHan_2006_480.mp4</streamUrl> + </media> + <synopsis>After years of research on touch-driven computer displays, Jeff Han has created a simple, multi-touch, multi-user screen interface that just might herald the end of the point-and-click era.</synopsis> + <genres>Design</genres> + <runtime>531</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/DavidKelley.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/DavidKelley.jpg"> + <title>David Kelley on human-centered design</title> + <contentId>10062</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/DavidKelley_2002_480.mp4</streamUrl> + </media> + <synopsis>IDEO’s David Kelley says that product design has become much less about the hardware and more about the user experience. He shows video of this new, broader approach, including footage from the Prada store in New York.</synopsis> + <genres>Design</genres> + <runtime>1024</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/YvesBehar.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/YvesBehar.jpg"> + <title>Yves Behar on designing objects that tell stories</title> + <contentId>10063</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/YvesBehar_2008_480.mp4</streamUrl> + </media> + <synopsis>Designer Yves Behar digs up his creative roots to discuss some of the iconic objects he's created (the Leaf lamp, the Jawbone headset). Then he turns to the witty, surprising, elegant objects he's working on now -- including the '$100 laptop.'</synopsis> + <genres>Design</genres> + <runtime>1066</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/SamMartin.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/SamMartin.jpg"> + <title>Sam Martin: The quirky world of 'manspaces'</title> + <contentId>10064</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/SamMartin_2009G_480.mp4</streamUrl> + </media> + <synopsis>Author Sam Martin shares photos of a quirky world hobby that's trending with the XY set: the 'manspace.' (They're custom-built hangouts where a man can claim a bit of his own territory to work, relax, be himself.) Grab a cold one and enjoy.</synopsis> + <genres>Design</genres> + <runtime>267</runtime> + </item> +</feed> diff --git a/roku_player/xml/generic.xml b/roku_player/xml/generic.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<feed> + <!-- resultLength indicates the total number of results for this feed --> + <resultLength>3</resultLength> + <!-- endIndix indicates the number of results for this *paged* section of the feed --> + <endIndex>3</endIndex> + <item sdImg="http://www.rokudev.com/rokudev/examples/videoplayer/images/" hdImg="http://www.rokudev.com/rokudev/examples/videoplayer/images/"> + <title></title> + <contentId>10001</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl></streamUrl> + </media> + <synopsis></synopsis> + <genres>Clip</genres> + <runtime>1260</runtime> + </item> + <item sdImg="http://www.rokudev.com/rokudev/examples/videoplayer/images/" hdImg="http://www.rokudev.com/rokudev/examples/videoplayer/images/"> + <title></title> + <contentId>10002</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl></streamUrl> + </media> + <synopsis></synopsis> + <genres>Clip</genres> + <runtime>1280</runtime> + </item> + <item sdImg="http://www.rokudev.com/rokudev/examples/videoplayer/images/" hdImg="http://www.rokudev.com/rokudev/examples/videoplayer/images/"> + <title></title> + <contentId>10002</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl></streamUrl> + </media> + <synopsis></synopsis> + <genres>Clip</genres> + <runtime>1280</runtime> + </item> +</feed> diff --git a/roku_player/xml/globalissues.xml b/roku_player/xml/globalissues.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<feed> + <!-- resultLength indicates the total number of results for this feed --> + <resultLength>4</resultLength> + <!-- endIndix indicates the number of results for this *paged* section of the feed --> + <endIndex>4</endIndex> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/AlGore.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/AlGore.jpg"> + <title>Al Gore warns on latest climate trends</title> + <contentId>10011</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/AlGore_2009_480.mp4</streamUrl> + </media> + <synopsis>At TED2009, Al Gore presents updated slides from around the globe to make the case that worrying climate trends are even worse than scientists predicted, and to make clear his stance on "clean coal."</synopsis> + <genres>Global Issues</genres> + <runtime>468</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/RobHopkins.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/RobHopkins.jpg"> + <title>Rob Hopkins: Transition to a world without oil</title> + <contentId>10012</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/RobHopkins_2009G_480.mp4</streamUrl> + </media> + <synopsis>Rob Hopkins reminds us that the oil our world depends on is steadily running out. He proposes a unique solution to this problem -- the Transition response, where we prepare ourselves for life without oil and sacrifice our luxuries to build systems and communities that are completely independent of fossil fuels.</synopsis> + <genres>Global Issues</genres> + <runtime>1000</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/JuanEnriquez.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/JuanEnriquez.jpg"> + <title>Juan Enriquez wants to grow energy</title> + <contentId>10013</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/JuanEnriquez_2007S_480.mp4</streamUrl> + </media> + <synopsis>Juan Enriquez challenges our definition of bioenergy. Oil, coal, gas and other hydrocarbons are not chemical but biological products, based on plant matter -- and thus, growable. Our whole approach to fuel, he argues, needs to change.</synopsis> + <genres>Global Issues</genres> + <runtime>1088</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/RachelPike.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/RachelPike.jpg"> + <title>Rachel Pike: The science behind a climate headline</title> + <contentId>10014</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/RachelPike_2009G_480.mp4</streamUrl> + </media> + <synopsis>In 4 minutes, atmospheric chemist Rachel Pike provides a glimpse of the massive scientific effort behind the bold headlines on climate change, with her team -- one of thousands who contributed -- taking a risky flight over the rainforest in pursuit of data on a key molecule.</synopsis> + <genres>Global Issues</genres> + <runtime>254</runtime> + </item> +</feed> diff --git a/roku_player/xml/inspiration.xml b/roku_player/xml/inspiration.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<feed> + <!-- resultLength indicates the total number of results for this feed --> + <resultLength>3</resultLength> + <!-- endIndex indicates the number of results for this *paged* section of the feed --> + <endIndex>3</endIndex> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/BenjaminZander.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/BenjaminZander.jpg"> + <title>Benjamin Zander on music and passion</title> + <contentId>10041</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/BenjaminZander_2008_480.mp4</streamUrl> + </media> + <synopsis>Benjamin Zander has two infectious passions: classical music, and helping us all realize our untapped love for it -- and by extension, our untapped love for all new possibilities, new experiences, new connections.</synopsis> + <genres>Inspiration</genres> + <runtime>1246</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/CynthiaSchneider.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/CynthiaSchneider.jpg"> + <title>Cynthia Schneider: The surprising spread of "Idol" TV</title> + <contentId>10042</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/CynthiaSchneider_2009G_480.mp4</streamUrl> + </media> + <synopsis>Cynthia Schneider looks at two international 'American Idol'-style shows -- one in Afghanistan, and one in the United Arab Emirates -- and shows the surprising effect that these reality-TV competitions are creating in their societies.</synopsis> + <genres>Inspiration</genres> + <runtime>338</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/JulianTreasure.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/JulianTreasure.jpg"> + <title>Julian Treasure: The 4 ways sound affects us</title> + <contentId>10043</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/JulianTreasure_2009G_480.mp4</streamUrl> + </media> + <synopsis>Playing sound effects both pleasant and awful, Julian Treasure shows how sound affects us in four significant ways. Listen carefully for a shocking fact about noisy open-plan offices.</synopsis> + <genres>Inspiration</genres> + <runtime>347</runtime> + </item> +</feed> diff --git a/roku_player/xml/music.xml b/roku_player/xml/music.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<feed> + <!-- resultLength indicates the total number of results for this feed --> + <resultLength>4</resultLength> + <!-- endIndix indicates the number of results for this *paged* section of the feed --> + <endIndex>4</endIndex> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/CameronCarpenter.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/CameronCarpenter.jpg"> + <title>Cameron Carpenter's dizzying improv on the organ</title> + <contentId>10031</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/CameronCarpenter_2008P_480.mp4</streamUrl> + </media> + <synopsis>At the 2008 EG conference, revolutionary organist Cameron Carpenter performs a classic piece of organ repertory -- and then cuts loose in an incendiary improv. Young organist Eric Fricke closes the set.</synopsis> + <genres>Music</genres> + <runtime>1790</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/Naturally7.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/Naturally7.jpg"> + <title>Naturally 7 beatboxes a whole band</title> + <contentId>10032</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/Naturally7FLYBABY_2009_480.mp4</streamUrl> + </media> + <synopsis>One-of-a-kind R and B group Naturally 7 beatboxes an orchestra's worth of instruments to groove through their smooth single, 'Fly Baby.'</synopsis> + <genres>Music</genres> + <runtime>239</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/ImogenHeap.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/ImogenHeap.jpg"> + <title>Imogen Heap plays 'Wait It Out'</title> + <contentId>10033</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/ImogenHeap_WaitItOut_2009G_480.mp4</streamUrl> + </media> + <synopsis>Imogen Heap's aching voice and spectral electronics infuse countless films and iPods with bone-chilling atmospherics.</synopsis> + <genres>Music</genres> + <runtime>238</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/RaulMidon.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/RaulMidon.jpg"> + <title>Raul Midon plays 'Tembererana'</title> + <contentId>10034</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/RaulMidonANSWERS_2007_480.mp4</streamUrl> + </media> + <synopsis>Singer/guitarist Raul Midon performs 'All the Answers' in a world premiere at TED2007, followed by the sprightly 'Tembererana.'</synopsis> + <genres>Music</genres> + <runtime>643</runtime> + </item> +</feed> diff --git a/roku_player/xml/themind.xml b/roku_player/xml/themind.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<feed> + <!-- resultLength indicates the total number of results for this feed --> + <resultLength>4</resultLength> + <!-- endIndix indicates the number of results for this *paged* section of the feed --> + <endIndex>4</endIndex> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/JimFallon.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/JimFallon.jpg"> + <title>Jim Fallon: Exploring the mind of a killer</title> + <contentId>10001</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/JimFallon_2009_480.mp4</streamUrl> + </media> + <synopsis>Psychopathic killers are the basis for some must-watch TV, but what really makes them tick? Neuroscientist Jim Fallon talks about brain scans and genetic analysis that may uncover the rotten wiring in the nature (and nurture) of murderers. In a too-strange-for-fiction twist, he shares a fascinating family history that makes his work chillingly personal.</synopsis> + <genres>Clip</genres> + <runtime>1260</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/DanGilbert.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/DanGilbert.jpg"> + <title>Dan Gilbert asks, Why are we happy?</title> + <contentId>10002</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/DanGilbert_2004_480.mp4</streamUrl> + </media> + <synopsis>Harvard psychologist Dan Gilbert says our beliefs about what will make us happy are often wrong -- a premise he supports with intriguing research, and explains in his accessible and unexpectedly funny book, Stumbling on Happiness.</synopsis> + <genres>Technology</genres> + <runtime>1280</runtime> + </item> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/VSRamachandran.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/VSRamachandran.jpg"> + <title>VS Ramachandran on your mind</title> + <contentId>10003</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/VilayanurRamachandran_2007_480.mp4</streamUrl> + </media> + <synopsis>Vilayanur Ramachandran tells us what brain damage can reveal about the connection between celebral tissue and the mind, using three startling delusions as examples.</synopsis> + <genres>Technology</genres> + <runtime>1418</runtime> + </item> +</feed> diff --git a/server/hms/hms.py b/server/hms/hms.py @@ -0,0 +1,1344 @@ +#!/usr/bin/env python +""" +Home Media Streaming Server +Copyright 2009-2010 by Brian C. Lane <bcl@brianlane.com> +All Rights Reserved + +""" + +""" +Implement handling of byte range header +http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1 + + +Here's what Apache sends on the initial request: +HTTP/1.1 200 OK +Date: Sun, 20 Dec 2009 23:14:56 GMT +Server: Apache/2.2.13 (Fedora) +Last-Modified: Fri, 26 Sep 2008 07:51:20 GMT +ETag: "4a4001-2bc97329-457c7c8740e00" +Accept-Ranges: bytes +Content-Length: 734622505 +Connection: close +Content-Type: video/mp4 + +Here is a range request and the response: +GET /movies/CitySlickers.mp4 HTTP/1.1 +Connection: close +Host: wyatt.home +User-Agent: Roku/DVP-2.4 (012.04E00350A) +Range: bytes=517334659- + +HTTP/1.1 206 Partial Content +Date: Sun, 20 Dec 2009 23:14:57 GMT +Server: Apache/2.2.13 (Fedora) +Last-Modified: Fri, 26 Sep 2008 07:51:20 GMT +ETag: "4a4001-2bc97329-457c7c8740e00" +Accept-Ranges: bytes +Content-Length: 217287846 +Content-Range: bytes 517334659-734622504/734622505 +Connection: close +Content-Type: video/mp4 + +""" + +import os +import sys +import logging +import mimetypes +import datetime +import sqlite3 +import traceback +from subprocess import Popen, PIPE +import operator +import cPickle + +# Tornado modules +import tornado.httpserver +import tornado.ioloop +import tornado.options +import tornado.web +import tornado.httpclient +from tornado.web import StaticFileHandler + +from tornado.options import define, options + +define("port", default=8888, help="run on the given port", type=int) +define("database", default=os.path.join(os.getcwd(), 'library.db'), type=str) + +# API Key for tmdb searches (please request your own if you alter this code +# in a substantial way). http://api.themoviedb.org +TMDB_KEY="f025da9c9066f7016a3ccdce4a9ccf3f" + +# Recognized ratings strings +RATINGS = [ "G", "NC-17", "PG", "PG-13", "R", "UR", "UNRATED", "NR", + "TV-Y", "TV-Y7", "TV-Y7-FV", "TV-G", "TV-PG", "TV-14", "TV-MA"] + +class DbSchema(object): + """ + Database schema creation and modification + """ + + # Schema revisions, rev[0], etc. is a list of SQL operations to run to + # bring the database up to date. + sql = [""" create table user(id INTEGER PRIMARY KEY, username TEXT UNIQUE, password TEXT, email TEXT); + create table source(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT UNIQUE); + + create table schema(version INTEGER); + insert into schema(version) values(1); + """, + # Add default values + """ insert into user(username, password) values("admin","badpassword"); + + update schema set version=2; + """, + # Add media table + """ create table media( + id INTEGER PRIMARY KEY, + path TEXT, + bitrate REAL, + length REAL, + media_description TEXT, + description TEXT + ); + + update schema set version=3; + """, + """ create table list( + id INTEGER PRIMARY KEY, + user_id INTEGER REFERENCES user(id), + name TEXT + ); + + create table list_media( + id INTEGER PRIMARY KEY, + media_id INTEGER REFERENCES media(id), + user_id INTEGER REFERENCES user(id), + list_id INTEGER REFERENCES list(id) + ); + + update schema set version=4; + """, + """ alter table user add avatar_image BLOB; + alter table user add content_type TEXT; + alter table user add filename TEXT; + + update schema set version=5; + """, + """ alter table media add contentType TEXT; + alter table media add title TEXT; + alter table media add titleSeason TEXT; + alter table media add live INTEGER; + alter table media add sdBifUrl TEXT; + alter table media add hdBifUrl TEXT; + alter table media add sdPosterUrl TEXT; + alter table media add sdPosterImage BLOB; + alter table media add hdPosterUrl TEXT; + alter table media add hdPosterImage BLOB; + alter table media add streamQuality TEXT; + alter table media add streamFormat TEXT; + alter table media add releaseDate TEXT; + alter table media add rating TEXT; + alter table media add starRating INTEGER; + alter table media add userStarRating INTEGER; + alter table media add shortDescriptionLine1 TEXT; + alter table media add shortDescriptionLine2 TEXT; + alter table media add episodeNumber INTEGER; + alter table media add actors TEXT; + alter table media add director TEXT; + alter table media add categories TEXT; + alter table media add hdBranded INTEGER; + alter table media add isHD INTEGER; + alter table media add textOverlayUL TEXT; + alter table media add textOverlayUR TEXT; + alter table media add textOverlayBody TEXT; + alter table media add album TEXT; + alter table media add artist TEXT; + + update schema set version=6; + """, + """ + alter table media add sdPosterImageType; + alter table media add sdPosterImageFilename; + alter table media add hdPosterImageType; + alter table media add hdPosterImageFilename; + + update schema set version=7; + """, + ] + + def __init__(self, database): + self.database = database + + def upgrade(self): + """ + Upgrade the database to the current schema version + """ + # Get the current schema version number + conn = sqlite3.connect(self.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + try: + cur.execute("select version from schema") + version = cur.fetchone()['version'] + except: + version = 0 + + if len(self.sql) > version: + for update in self.sql[version:]: + cur.executescript(update) + cur.close() + conn.close() + + +class MissingSourceError(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + + +# From http://www.djangosnippets.org/snippets/224/ +def rescale(data, width, height, force=True): + """Rescale the given image, optionally cropping it to make sure the result image has the specified width and height.""" + import Image as pil + from cStringIO import StringIO + + max_width = width + max_height = height + + input_file = StringIO(data) + img = pil.open(input_file) + if not force: + img.thumbnail((max_width, max_height), pil.ANTIALIAS) + else: + src_width, src_height = img.size + src_ratio = float(src_width) / float(src_height) + dst_width, dst_height = max_width, max_height + dst_ratio = float(dst_width) / float(dst_height) + + if dst_ratio < src_ratio: + crop_height = src_height + crop_width = crop_height * dst_ratio + x_offset = float(src_width - crop_width) / 2 + y_offset = 0 + else: + crop_width = src_width + crop_height = crop_width / dst_ratio + x_offset = 0 + y_offset = float(src_height - crop_height) / 3 + img = img.crop((x_offset, y_offset, x_offset+int(crop_width), y_offset+int(crop_height))) + img = img.resize((dst_width, dst_height), pil.ANTIALIAS) + + tmp = StringIO() + img.save(tmp, 'JPEG') + tmp.seek(0) + output_data = tmp.getvalue() + input_file.close() + tmp.close() + + return output_data + + + + +def getMP4Info(filename): + """ + Get mp4 info about the video + """ + details = { 'type':"", 'length':0, 'bitrate':1500, 'format':""} + cmd = "mp4info %s" % (filename) + p = Popen( cmd, shell=True, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=os.environ ) + (stdout, stderr) = p.communicate() + + # Parse the results + for line in stdout.split('\n'): + fields = line.split(None, 2) + if not fields or len(fields) < 2: + continue + try: + if fields[1] == 'video': + # parse the video info + # MPEG-4 Simple @ L3, 5706.117 secs, 897 kbps, 712x480 @ 23.976024 fps + videoFields = fields[2].split(',') + details['type'] = videoFields[0] + details['length'] = float(videoFields[1].split()[0]) + details['bitrate'] = float(videoFields[2].split()[0]) + details['format'] = videoFields[3] + except: + print stdout + print stderr + print traceback.format_exc() + + return details + + +def import_local_media(conn, cur, path): + """ + Read a local directory and add missing files to the media database + + @param cur sqlite3 database cursor + @param path absolute path to directory of media files + + """ + streamFormat = { 'mp4':'mp4', 'm4v':'mp4', 'mov':'mp4', + 'wmv':'wmv', + 'mp3':'mp3', + 'wma':'wma' + } + new_files = [] + files = os.listdir(path) + files.sort() + for f in files: + if f[-3:] not in ['mp4', 'm4v', 'mov', 'wmv', 'mp3', 'wma']: + continue + + # Is it in the table already? + try: + cur.execute("select * from media where path=?", (os.path.join(path,f),)) + media = cur.fetchone() + except: + print traceback.format_exc() + media = None + + if not media: + if f[-3:] in ['mp4', 'm4v', 'mov']: + mp4info = getMP4Info(os.path.join(path,f)) + else: + mp4info = None + + # Insert it into the media table + if mp4info: + + sql = "insert into media(title, path, bitrate, length, media_description, streamFormat)" + sql += " values (?,?,?,?,?,?)" + cur.execute(sql, (os.path.basename(f)[:-4], + os.path.join(path,f), mp4info['bitrate'], + mp4info['length'], + mp4info['type'] + " " + mp4info['format'], + streamFormat[f[-3:]]) + ) + else: + cur.execute("insert into media(title, path, streamFormat) values(?,?,?)", + (os.path.basename(f)[:-4], + os.path.join(path,f), + streamFormat[f[-3:]]) + ) + conn.commit() + new_files.append((os.path.join(path,f),)) + + return new_files + + +def import_media(sourceId): + """ + Import new media files from a local server dircetory or from a remote + URL. Methods supported are http, https and ftp + + """ + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + try: + cur.execute("select * from source where id=?", (sourceId,)) + source = cur.fetchone() + except: + print traceback.format_exc() + + if not source: + raise MissingSourceError("No source id %s" % (sourceId)) + + if source['type'] == "local": + # Read a local directory + try: + import_local_media(conn, cur, source['path']) + except: + # @TODO Return some kind of error report to the user + print traceback.format_exc() + elif source['type'] == "remote": + # Read a remote directly listing + try: + import_remote_media(conn, cur, source['path']) + except: + # @TODO Return some kind of error report to the user + print traceback.format_exc() + + cur.close() + conn.close() + + +class BaseHandler(tornado.web.RequestHandler): + def get_current_user(self): + user_id = self.get_secure_cookie("user") + if not user_id: return None + + # Check it against the database? + + # return self.backend.get_user_by_id(user_id) + return user_id + + # def get_user_locale(self): + # if "locale" not in self.current_user.prefs: + # # Use the Accept-Language header + # return None + # return self.current_user.prefs["locale"] + + +class SearchTMDBHandler(BaseHandler): + """ + Search themoviedb.org for matching movies + """ + def get(self, media_id): + pass + + @tornado.web.asynchronous + def post(self, media_id): + print self.request.arguments["searchTitle"] + + # Need to replace '/' with '-' in the string + search = self.request.arguments["searchTitle"][0].replace('/','-') + search = tornado.escape.url_escape(search) + url = "http://api.themoviedb.org/2.1/Movie.search/en/json/%s/%s" % (TMDB_KEY, search) + http = tornado.httpclient.AsyncHTTPClient() + http.fetch(url, callback=self.async_callback(self.on_response, media_id)) + + def on_response(self, media_id, response): + if response.error: + raise tornado.web.HTTPError(500) + json = tornado.escape.json_decode(response.body) + if len(json) > 0 and type(json[0]) != type(dict()): + if json[0].startswith("Nothing found"): + json = [] + else: + print "Unknown response: " + json + raise tornado.web.HTTPError(500) + + # Reorganize the posters so the template can get to them + for m in json: + # Parse the posters + posters = {} + for p in m["posters"]: + size = p["image"]["size"] + posters[size] = p["image"] + m['posters'] = posters + # Some don't have a cover image + if 'cover' not in posters: + if 'original' in posters: + posters['cover'] = posters['original'] + else: + posters['cover'] = {"url" : None} + + name = tornado.escape.xhtml_escape(self.current_user) + self.render(os.path.join("templates","tmdbsearch.html"), + movies=json, + media_id=media_id, + name=name) + +class UpdateTMDBHandler(BaseHandler): + def get(self, media_id, tmdb_id): + pass + + @tornado.web.asynchronous + def post(self, media_id, tmdb_id): + """ + Lookup the details of this movie + """ + if self.current_user != 'admin': + self.redirect("/media/") + return + + url = "http://api.themoviedb.org/2.1/Movie.getInfo/en/json/%s/%s" % (TMDB_KEY, tmdb_id) + http = tornado.httpclient.AsyncHTTPClient() + http.fetch(url, callback=self.async_callback(self.on_response, media_id, tmdb_id)) + + def on_response(self, media_id, tmdb_id, response): + """ + Process the details from tbdb and replace associated info for this + movie. + """ + if response.error: + raise tornado.web.HTTPError(500) + json = tornado.escape.json_decode(response.body) + if len(json) > 0 and type(json[0]) != type(dict()): + if json[0].startswith("Nothing found"): + json = [] + else: + print "Unknown response: " + json + raise tornado.web.HTTPError(500) + + # Get the current details for this movie + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + cur.execute("select * from media where id=?", (media_id,)) + row = cur.fetchone() + + cur.close() + conn.close() + + # Make a copy of the row into a dict so it can be modified + metadata = {} + for field in row.keys(): + metadata[field] = row[field] + + movie = json[0] + # Parse the posters + posters = {} + for p in movie["posters"]: + size = p["image"]["size"] + if size in posters: + posters[size].append(p["image"]) + else: + posters[size] = [p["image"]] + # Some don't have a cover image + if 'cover' not in posters: + if 'original' in posters: + posters['cover'] = posters['original'] + else: + posters['cover'] = {"url" : None} + movie['posters'] = posters + metadata["posters"] = posters + if "cover" in posters: + metadata["sdPosterUrl"] = posters["cover"][0]["url"] + metadata["hdPosterUrl"] = posters["cover"][0]["url"] + + print posters + + # @TODO + # pull out the following: + # name + # rating + # Cast "job" : "Actor" + # Director (member of the cast with "job" : "Director" + # overview + # released + # poster for cover + # categories + + metadata["title"] = movie.get("name", metadata["title"]) + metadata["description"] = movie.get("overview", metadata["description"]) + metadata["releaseDate"] = movie.get("released", metadata["releaseDate"]) + if "rating" in movie: + starRating = int(float(movie["rating"]) * 10) + metadata["starRating"] = starRating; + + # Find the director and first 2 actors + actors = [] + for person in movie["cast"]: + if person["job"] == "Director": + metadata["director"] = person.get("name", metadata["director"]) + if person["job"] == "Actor": + actors.append(person["name"]) + if actors: + metadata["actors"] = ",".join(actors) + + # Genres + genres = [] + for genre in movie["genres"]: + genres.append(genre["name"]) + if genre: + metadata["categories"] = ",".join(genres) + + name = tornado.escape.xhtml_escape(self.current_user) + self.render(os.path.join("templates","mediaedit.html"), + metadata=metadata, + name=name, + movie=movie, + ratings=RATINGS) + + + +class MediaPlayHandler(BaseHandler): + def get(self, media_id): + print self.request.headers + + # Find the source to this file + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + cur.execute("select path from media where id=?", (media_id,)) + row = cur.fetchone() + cur.close() + conn.close() + + # We only handle local sources right now + filePath = row["path"] + fileName = os.path.basename(filePath) + if not os.path.isfile(filePath): + raise tornado.web.HTTPError(404) + + self.set_header("Accept-Ranges", "bytes") + + # Get info about the file + statinfo = os.stat(filePath) + modified = datetime.datetime.fromtimestamp(statinfo.st_mtime) + self.set_header("Last-Modified", modified) + contentType, encodingType = mimetypes.guess_type(filePath) + if contentType: + self.set_header('Content-Type',contentType) + else: + pass + + + # Is the Range header set? + if 'Range' in self.request.headers: + if not self.request.headers['Range'].startswith('bytes='): + # What is the right error? + raise tornado.web.HTTPError(500) + + (start, end) = self.request.headers['Range'][6:].split('-') + start = int(start) + if end: + self.end = int(end)+1 + else: + self.end = statinfo.st_size + self.set_status(206) + # Content-Range: bytes 517334659-734622504/734622505 + range = "bytes %d-%d/%d" % (start, self.end-1, statinfo.st_size) + self.set_header("Content-Range", range) + print "Content-Range: %s" % (range) + else: + # Serve up the whole file + start = 0 + self.end = statinfo.st_size + + self.set_header("Content-Length", self.end-start) + self.flush() + + print "Serving up %d to %d / %d" % (start, self.end-1, self.end-start) + + # Return the part of the file requested + self.fp = open(filePath, 'rb') + self.fp.seek(start) + + if self.end - start > 8192: + blk_size = 8192 + else: + blk_size = self.end - start + self.request.connection.stream.write(self.fp.read(blk_size), self.finishWrite) + self.sent = start + blk_size + + + def finishWrite(self): + """ + Keep writing the file until it is finished + """ + if self.sent >= self.end: + print "Finished sending %d bytes" % (self.sent) + # Should something be done here to finish up? + return + + if self.end - self.sent < 8192: + blk_size = self.end - self.sent + else: + blk_size = 8192 + self.sent += blk_size + + self.request.connection.stream.write(self.fp.read(blk_size), self.finishWrite) + + +class LoginHandler(BaseHandler): + def get(self): + self.render(os.path.join("templates","login.html"), name="") + + def post(self): + # Look up the username and password in the database + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + params = (self.get_argument("username"), self.get_argument("password")) + cur.execute("select * from user where username=? and password=?", params) + r = cur.fetchone() + print r + if r and r['username'] == self.get_argument("username"): + self.set_secure_cookie("user", self.get_argument("username")) + cur.close() + conn.close() + + # This will redirect back to login if it failed + self.redirect("/") + return + + +class LogoutHandler(BaseHandler): + def get(self): + self.set_secure_cookie("user", "") + self.redirect("/login") + + +class SourceHandler(BaseHandler): + """ + Handle the Media source page and methods + """ + @tornado.web.authenticated + def get(self, method=None): + if self.current_user != 'admin': + self.redirect("/") + + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + cur.execute("select * from source") + sources = [] + for row in cur: + sources.append([row['id'], row['name'], row['type'], row['path']]) + cur.close() + conn.close() + + print sources + name = tornado.escape.xhtml_escape(self.current_user) + self.render(os.path.join("templates","sources.html"), + sources=sources, + name=name) + + @tornado.web.authenticated + def post(self, method=None): + if self.current_user != 'admin': + self.redirect("/") + return + + if method == "add": + params = (self.get_argument("name"), self.get_argument("type"), self.get_argument("path")) + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + try: + cur.execute("insert into source(name, type, path) values(?,?,?)", params) + + # @TODO check for errors and report to user + conn.commit() + except: + print traceback.format_exc() + finally: + cur.close() + conn.close() + self.redirect("/source/") + + +class MediaEditHandler(BaseHandler): + @tornado.web.authenticated + def get(self, media_id): + if self.current_user != 'admin': + self.redirect("/media/") + return + + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + cur.execute("select * from media where id=?", (media_id,)) + metadata = cur.fetchone() + + cur.close() + conn.close() + + name = tornado.escape.xhtml_escape(self.current_user) + self.render(os.path.join("templates","mediaedit.html"), + metadata=metadata, + name=name, + ratings=RATINGS) + + + @tornado.web.asynchronous + @tornado.web.authenticated + def post(self, media_id): + if self.current_user != 'admin': + self.redirect("/media/") + return + + # These are fields that could be blank, and not returned by the POST + blank_fields = [ "title", "episodeNumber", "titleSeason", "shortDescriptionLine1", + "shortDescriptionLine2", "description", "actors", "director", + "categories", "starRating", "userStarRating", "sdBifUrl", + "hdBifUrl", "hdPosterUrl", "sdPosterUrl", "album", "artist" + ] + + sql_set = [] + sql_args = [] + for field in self.request.arguments: + if field[0] == "_" or field in ["sdPosterImage", "hdPosterImage", "sdPosterUrl", "hdPosterUrl"]: + continue + sql_set.append("%s=?" % (field)) + sql_args.append(self.get_argument(field)) + if field in blank_fields: + blank_fields.remove(field) + for field in blank_fields: + sql_set.append("%s=?" % (field)) + sql_args.append("") + + sql_args.append(int(media_id)) + sql = "update media set %s where id=?" % ",".join(sql_set) + + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + cur.execute(sql, sql_args) + conn.commit() + + # Update the images if they were included + files = self.request.files + if files.get("sdPosterImage", None) and files["sdPosterImage"][0]: + sdPosterImage = files["sdPosterImage"][0] + params = ( buffer(sdPosterImage["body"]), + sdPosterImage["content_type"], + sdPosterImage["filename"], + int(media_id)) + cur.execute("update media set sdPosterImage=?,sdPosterImageType=?,sdPosterImageFilename=? where id=?", params) + conn.commit() + + if files.get("hdPosterImage", None) and files["hdPosterImage"][0]: + hdPosterImage = files["hdPosterImage"][0] + params = ( buffer(hdPosterImage["body"]), + hdPosterImage["content_type"], + hdPosterImage["filename"], + int(media_id)) + cur.execute("update media set hdPosterImage=?,hdPosterImageType=?,hdPosterImageFilename=? where id=?", params) + conn.commit() + + cur.close() + conn.close() + + if self.request.arguments.get("sdPosterUrl", None): + url = self.request.arguments["sdPosterUrl"][0] + print "Found sdPosterUrl - %s" % (url) + http = tornado.httpclient.AsyncHTTPClient() + http.fetch( url, + callback=self.async_callback(self.on_response, media_id, url)) + else: + self.redirect("/media/") + + def on_response(self, media_id, url, response): + if response.error: + raise tornado.web.HTTPError(500) + + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + params = ( buffer(response.body), + response.headers["Content-Type"], + os.path.basename(url), + int(media_id)) + cur.execute("update media set sdPosterImage=?,sdPosterImageType=?,sdPosterImageFilename=? where id=?", params) + cur.execute("update media set hdPosterImage=?,hdPosterImageType=?,hdPosterImageFilename=? where id=?", params) + conn.commit() + + self.redirect("/media/") + + + +class MediaHandler(BaseHandler): + @tornado.web.authenticated + def get(self, method=None, *args): + if not method: + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + cur.execute("select * from user where username=?", (self.current_user,)) + row = cur.fetchone() + print row + if row: + user_id = row['id'] + else: + print "failed to find user id, DO SOMETHING HERE" + return + + cur.execute("select media.*,list.name as listname from media LEFT JOIN list_media on list_media.media_id = media.id AND list_media.user_id=? LEFT JOIN list ON list.id = list_media.list_id", (user_id,)) + media = cur.fetchall() + + cur.execute("select * from list where user_id=?", (user_id,)) + lists = cur.fetchall() + + cur.close() + conn.close() + + media = sorted(media, key=operator.itemgetter("title")) + lists = [l["name"] for l in lists] + name = tornado.escape.xhtml_escape(self.current_user) + self.render(os.path.join("templates","media.html"), media=media, + basename=os.path.basename, lists=lists, user_id=user_id, + name=name) + elif method == 'import': + import_media(args[0]) + self.redirect("/source/") + return + + @tornado.web.authenticated + def post(self, method, *args): + pass + + +class UserHandler(BaseHandler): + @tornado.web.authenticated + def get(self, method=None): + if not method: + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + cur.execute("select * from user where username=?", (self.current_user,)) + row = cur.fetchone() + print row + if row: + user_id = int(row['id']) + else: + print "failed to find user id, DO SOMETHING HERE" + return + + if self.current_user == 'admin': + cur.execute("select * from user") + else: + cur.execute("select * from user where id=?", (user_id,)) + users = [] + for row in cur: + users.append([row['id'], row['username'], row['email']]) + cur.close() + conn.close() + + print users + name = tornado.escape.xhtml_escape(self.current_user) + self.render(os.path.join("templates","users.html"), users=users, name=name) + + @tornado.web.authenticated + def post(self, method=None): + """ + @TODO Add update user, allowing users to change their own data or admin to + update everyones. + """ + if method == "add": + if self.current_user != 'admin': + self.redirect("/") + return + + params = (self.get_argument("username"), self.get_argument("password"), + self.get_argument("email", None)) + if self.get_argument("password") != self.get_argument("password2"): + # @TODO return a warning to the user + self.redirect("/user/") + return + + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + try: + sql = "insert into user(username, password, email) " + sql += "values(?,?,?)" + cur.execute(sql, params) + + # @TODO check for errors and report to user + conn.commit() + finally: + cur.close() + conn.close() + self.redirect("/user/") + return + + +class UserImageHandler(BaseHandler): + def get(self, user_id): + # Get the user's image + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + try: + cur.execute("select * from user where id=?", (int(user_id),)) + row = cur.fetchone() + except: + print traceback.format_exc() + finally: + conn.commit() + cur.close() + conn.close() + + if not row or not row["avatar_image"]: + raise tornado.web.HTTPError(404) + + image = row["avatar_image"] + from hashlib import sha1 + cksum = sha1() + cksum.update(image) + print cksum.hexdigest() + + image = rescale( image, 224, 158, True) + self.set_header('Content-Type',"image/jpeg") + self.set_header("Content-Length", len(image)) + self.write(str(image)) + + @tornado.web.authenticated + def post(self, user_id): + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + try: + imagefile = self.request.files["imagefile"][0] + from hashlib import sha1 + cksum = sha1() + cksum.update(imagefile["body"]) + print cksum.hexdigest() + + params = ( sqlite3.Binary(imagefile["body"]), + imagefile["content_type"], + imagefile["filename"], + int(user_id)) + cur.execute("update user set avatar_image=?,content_type=?,filename=? where id=?", params) + except: + print traceback.format_exc() + finally: + conn.commit() + cur.close() + conn.close() + + self.redirect("/user/") + return + + +class PosterImageHandler(BaseHandler): + """ + Handle serving up the movie's cover art + """ + def get(self, cover_type, media_id): + # Get the cover's image + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + try: + cur.execute("select * from media where id=?", (int(media_id),)) + row = cur.fetchone() + except: + print traceback.format_exc() + finally: + conn.commit() + cur.close() + conn.close() + + if not row: + raise tornado.web.HTTPError(404) + + if cover_type == 'sd': + if not row["sdPosterImage"]: + raise tornado.web.HTTPError(404) + image = row["sdPosterImage"] + content_type = "image/jpeg" + image = rescale( image, 158, 204, True ) + elif cover_type == 'hd': + if not row["hdPosterImage"]: + raise tornado.web.HTTPError(404) + image = row["hdPosterImage"] + content_type = "image/jpeg" + image = rescale( image, 214, 306, True) + elif cover_type == 'thumb': + if not row["sdPosterImage"]: + raise tornado.web.HTTPError(404) + image = row["sdPosterImage"] + content_type = "image/jpeg" + image = rescale( image, 79, 102, True ) + else: + if not row["sdPosterImage"]: + raise tornado.web.HTTPError(404) + + (width, height) = cover_type.split("x") + image = row["sdPosterImage"] + content_type = "image/jpeg" + image = rescale( image, int(width), int(height), True ) + + self.set_header('Content-Type',content_type) + self.set_header("Content-Length", len(image)) + self.write(str(image)) + + +class ListHandler(BaseHandler): + @tornado.web.authenticated + def get(self, method=None, *args): + pass + + @tornado.web.authenticated + def post(self, method=None, *args): + if method == 'update': + user_id = int(args[0]) + print self.request.arguments + + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + list_names = {} + for key in self.request.arguments: + if not key.startswith("list-"): + continue + + list_name = self.request.arguments[key][0] + if list_name == 'None': + continue + + media_id = int(key[5:]) + if list_name not in list_names: + # Check for this list name, pull its id if it exists + params = (list_name, user_id) + cur.execute("select * from list where name=? and user_id=?", params) + row = cur.fetchone() + if not row: + # Create it if it doesn't + cur.execute("insert into list(name,user_id) values(?,?)", params) + conn.commit() + list_id = cur.lastrowid + else: + list_id = row['id'] + + # Add it to list_names + list_names[list_name] = list_id + else: + list_id = list_names[list_name] + + # Check the movie to see if it has this list + cur.execute("select * from list_media where media_id=? and user_id=?", (media_id, user_id)) + row = cur.fetchone() + if not row: + cur.execute("insert into list_media(list_id,media_id,user_id) values(?,?,?)", (list_id, media_id, user_id)) + conn.commit() + else: + # Otherwise update the entry + if row['list_id'] != list_id: + cur.execute("update list_media set list_id=? where id=?", (list_id, row['id'])) + conn.commit() + cur.close() + conn.close() + self.redirect("/media/") + return + + +class XMLUsersHandler(BaseHandler): + def get(self): + """ + Return the list of the users and their lists + """ + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + cur.execute("select * from user") + users = [] + for row in cur: + if row['username'] == 'admin': + continue + + cur2 = conn.cursor() + cur2.execute("select * from list where user_id=?", (row['id'],)) + lists = [] + for row2 in cur2: + lists.append([row2['id'], row2['name']]) + cur2.close() + lists = sorted(lists, key=operator.itemgetter(1)) + lists.append([-1, 'All Movies']) + + users.append([row['id'], row['username'], lists]) + + users = sorted(users, key=operator.itemgetter(1)) + cur.close() + conn.close() + + host = "%s://%s" % (self.request.protocol, self.request.host) + self.render(os.path.join("templates","xmlusers.html"), users=users, host=host) + + +class XMLListHandler(BaseHandler): + def get(self, user_id, list_id): + """ + Return the User's List of media + """ + host = "%s://%s" % (self.request.protocol, self.request.host) + + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + if int(list_id) > -1: + cur.execute("select * from media JOIN list_media on list_media.media_id = media.id AND list_media.user_id=? AND list_media.list_id=?", (int(user_id), int(list_id))) + else: + cur.execute("select * from media") + + media = [] + for row in cur: + print row + coverImage = "%s/images/default.jpg" % (host) + + sdBifUrl = None + hdBifUrl = None + bifname = "%s-SD.bif" % (os.path.basename(row["path"]).rsplit('.', 1)[0]) +# if (os.path.isfile(bifname)): + sdBifUrl = "%s/movies/%s" % (host,bifname) + bifname = "%s-HD.bif" % (os.path.basename(row["path"]).rsplit('.', 1)[0]) +# if (os.path.isfile(bifname)): + hdBifUrl = "%s/movies/%s" % (host,bifname) + + + description = "%s %d kbps" % (row['media_description'], row['bitrate']) + description += row["description"] or "" + + if row["actors"]: + actors = row["actors"].split(",") + else: + actors = [] + + if row["director"]: + directors = row["director"].split(",") + else: + directors = [] + + if row["categories"]: + categories = row["categories"].split(",") + else: + categories = [] + + + metadata = { + 'contentType' : row["contentType"] or "movie", + 'title' : row["title"] or os.path.basename(row["path"])[:-4], + 'titleSeason' : row["titleSeason"], + 'description' : description, + 'sdbifurl' : sdBifUrl, + 'hdbifurl' : hdBifUrl, + 'sdPosterUrl' : '%s/media/image/sd/%s' % (host, row["id"]), + 'hdPosterUrl' : '%s/media/image/hd/%s' % (host, row["id"]), + 'streams' : [{ + 'format' : row["streamFormat"], + 'quality' : row["streamQuality"] or "SD", + 'bitrate' : row['bitrate'], + 'url' : "%s/media/play/%s" % (host, row["id"]), + }], + 'length' : int(row['length']), + 'id' : "user_%s-list_%s-movie_%s" % (user_id, list_id, row["id"]), + 'streamFormat' : row["streamFormat"], + 'releaseDate' : row["releaseDate"], + 'rating' : row["rating"], + 'starRating' : row["starRating"], + 'userStarRating' : row["userStarRating"], + 'shortDescriptionLine1' : row["shortDescriptionLine1"], + 'shortDescriptionLine2' : row["shortDescriptionLine2"], + 'episodeNumber' : row["episodeNumber"], + 'actors' : actors, + 'directors' : directors, + 'categories' : categories, + 'hdBranded' : row["hdBranded"] and "True" or "False", + 'isHD' : row["isHD"] and "True" or "False", + 'textOverlayUL' : row["textOverlayUL"], + 'textOverlayUR' : row["textOverlayUL"], + 'textOverlayBody':row["textOverlayBody"], + 'album' : row["album"], + 'artist' : row["artist"] + } + media.append(metadata) + media = sorted(media, key=operator.itemgetter('title')) + print media + self.render(os.path.join("templates","xmllist.html"), media=media, host=host) + + +class MediaListHandler(BaseHandler): + def get(self, user_id, list_id): + """ + Return the User's List of media + """ + host = "%s://%s" % (self.request.protocol, self.request.host) + + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + if int(list_id) > -1: + cur.execute("select * from media JOIN list_media on list_media.media_id = media.id AND list_media.user_id=? AND list_media.list_id=?", (int(user_id), int(list_id))) + else: + cur.execute("select * from media") + + media = [] + for row in cur: + metadata = { + 'title' : row["title"] or os.path.basename(row["path"])[:-4], + 'url' : "%s/media/play/%s" % (host, row["id"]), + } + media.append(metadata) + media = sorted(media, key=operator.itemgetter('title')) + + cur.close() + conn.close() + + name = tornado.escape.xhtml_escape(self.current_user) + self.render(os.path.join("templates","medialist.html"), media=media, name=name) + + + +class MainHandler(BaseHandler): + @tornado.web.authenticated + def get(self): + conn = sqlite3.connect(options.database) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + cur.execute("select * from user where username=?", (self.current_user,)) + row = cur.fetchone() + print row + if row: + user_id = row['id'] + else: + print "failed to find user id, DO SOMETHING HERE" + return + + cur.execute("select * from list where user_id=?", (user_id,)) + lists = cur.fetchall() + lists = sorted(lists, key=operator.itemgetter("name")) + lists.append({"id":-1, "user_id":user_id, "name":"All Movies"}) + + cur.close() + conn.close() + + name = tornado.escape.xhtml_escape(self.current_user) + self.render(os.path.join("templates","index.html"), name=name, user_id=user_id, lists=lists) + + +def main(): + tornado.options.parse_command_line() + + # Setup the database + if not os.path.exists(options.database): + sqlite3.connect(options.database) + schema = DbSchema(options.database) + schema.upgrade() + + # Application setup + settings = { + "static_path": os.path.join(os.path.dirname(__file__), "static"), + "cookie_secret": "480BE2C7-E684-4CFB-9BE7-E7BA55952ECB", + "login_url": "/login", + "xsrf_cookies": True, + } + + application = tornado.web.Application([ + (r"/", MainHandler), + (r"/login", LoginHandler), + (r"/logout", LogoutHandler), + (r"/source/(.*)", SourceHandler), + (r"/media/list/(.*)/(.*)", MediaListHandler), + (r"/media/edit/(.*)", MediaEditHandler), + (r"/media/play/(.*)", MediaPlayHandler), + (r"/media/image/(.*)/(.*)", PosterImageHandler), + (r"/media/(.*)/(.*)", MediaHandler), + (r"/media/(.*)", MediaHandler), + (r"/tmdb/search/(.*)", SearchTMDBHandler), + (r"/tmdb/update/(.*)/(.*)", UpdateTMDBHandler), + (r"/list/(.*)/(.*)", ListHandler), + (r"/user/image/(.*)", UserImageHandler), + (r"/user/(.*)", UserHandler), + (r"/xml/users", XMLUsersHandler), + (r"/xml/list/(.*)/(.*)", XMLListHandler), + (r"/css/(.*)", StaticFileHandler, dict(path=os.path.join(os.path.dirname(__file__), "static","css"))), + (r"/js/(.*)", StaticFileHandler, dict(path=os.path.join(os.path.dirname(__file__), "static","js"))), + ], **settings) + http_server = tornado.httpserver.HTTPServer(application) + http_server.listen(options.port) + tornado.ioloop.IOLoop.instance().start() + + +if __name__ == "__main__": + main() + diff --git a/server/hms/static/css/cupertino/images/ui-bg_diagonals-thick_90_eeeeee_40x40.png b/server/hms/static/css/cupertino/images/ui-bg_diagonals-thick_90_eeeeee_40x40.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-bg_flat_15_cd0a0a_40x100.png b/server/hms/static/css/cupertino/images/ui-bg_flat_15_cd0a0a_40x100.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-bg_glass_100_e4f1fb_1x400.png b/server/hms/static/css/cupertino/images/ui-bg_glass_100_e4f1fb_1x400.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-bg_glass_50_3baae3_1x400.png b/server/hms/static/css/cupertino/images/ui-bg_glass_50_3baae3_1x400.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-bg_glass_80_d7ebf9_1x400.png b/server/hms/static/css/cupertino/images/ui-bg_glass_80_d7ebf9_1x400.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-bg_highlight-hard_100_f2f5f7_1x100.png b/server/hms/static/css/cupertino/images/ui-bg_highlight-hard_100_f2f5f7_1x100.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-bg_highlight-hard_70_000000_1x100.png b/server/hms/static/css/cupertino/images/ui-bg_highlight-hard_70_000000_1x100.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-bg_highlight-soft_100_deedf7_1x100.png b/server/hms/static/css/cupertino/images/ui-bg_highlight-soft_100_deedf7_1x100.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-bg_highlight-soft_25_ffef8f_1x100.png b/server/hms/static/css/cupertino/images/ui-bg_highlight-soft_25_ffef8f_1x100.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-icons_2694e8_256x240.png b/server/hms/static/css/cupertino/images/ui-icons_2694e8_256x240.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-icons_2e83ff_256x240.png b/server/hms/static/css/cupertino/images/ui-icons_2e83ff_256x240.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-icons_3d80b3_256x240.png b/server/hms/static/css/cupertino/images/ui-icons_3d80b3_256x240.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-icons_72a7cf_256x240.png b/server/hms/static/css/cupertino/images/ui-icons_72a7cf_256x240.png Binary files differ. diff --git a/server/hms/static/css/cupertino/images/ui-icons_ffffff_256x240.png b/server/hms/static/css/cupertino/images/ui-icons_ffffff_256x240.png Binary files differ. diff --git a/server/hms/static/css/cupertino/jquery-ui-1.7.2.custom.css b/server/hms/static/css/cupertino/jquery-ui-1.7.2.custom.css @@ -0,0 +1,406 @@ +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +*/ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute; left: -99999999px; } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + + + +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=6px&bgColorHeader=deedf7&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=100&borderColorHeader=aed0ea&fcHeader=222222&iconColorHeader=72a7cf&bgColorContent=f2f5f7&bgTextureContent=04_highlight_hard.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=362b36&iconColorContent=72a7cf&bgColorDefault=d7ebf9&bgTextureDefault=02_glass.png&bgImgOpacityDefault=80&borderColorDefault=aed0ea&fcDefault=2779aa&iconColorDefault=3d80b3&bgColorHover=e4f1fb&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=74b2e2&fcHover=0070a3&iconColorHover=2694e8&bgColorActive=3baae3&bgTextureActive=02_glass.png&bgImgOpacityActive=50&borderColorActive=2694e8&fcActive=ffffff&iconColorActive=ffffff&bgColorHighlight=ffef8f&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=25&borderColorHighlight=f9dd34&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=cd0a0a&bgTextureError=01_flat.png&bgImgOpacityError=15&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffffff&bgColorOverlay=eeeeee&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=90&opacityOverlay=80&bgColorShadow=000000&bgTextureShadow=04_highlight_hard.png&bgImgOpacityShadow=70&opacityShadow=30&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px +*/ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #dddddd; background: #f2f5f7 url(images/ui-bg_highlight-hard_100_f2f5f7_1x100.png) 50% top repeat-x; color: #362b36; } +.ui-widget-content a { color: #362b36; } +.ui-widget-header { border: 1px solid #aed0ea; background: #deedf7 url(images/ui-bg_highlight-soft_100_deedf7_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; } +.ui-widget-header a { color: #222222; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #aed0ea; background: #d7ebf9 url(images/ui-bg_glass_80_d7ebf9_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2779aa; outline: none; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2779aa; text-decoration: none; outline: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #74b2e2; background: #e4f1fb url(images/ui-bg_glass_100_e4f1fb_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #0070a3; outline: none; } +.ui-state-hover a, .ui-state-hover a:hover { color: #0070a3; text-decoration: none; outline: none; } +.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #2694e8; background: #3baae3 url(images/ui-bg_glass_50_3baae3_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #ffffff; outline: none; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #ffffff; outline: none; text-decoration: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #f9dd34; background: #ffef8f url(images/ui-bg_highlight-soft_25_ffef8f_1x100.png) 50% top repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #cd0a0a url(images/ui-bg_flat_15_cd0a0a_40x100.png) 50% 50% repeat-x; color: #ffffff; } +.ui-state-error a, .ui-widget-content .ui-state-error a { color: #ffffff; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #ffffff; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_72a7cf_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_72a7cf_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_72a7cf_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_3d80b3_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_2694e8_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffffff_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-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-tl { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; } +.ui-corner-tr { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; } +.ui-corner-bl { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; } +.ui-corner-br { -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; } +.ui-corner-top { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; } +.ui-corner-right { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; } +.ui-corner-left { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; } +.ui-corner-all { -moz-border-radius: 6px; -webkit-border-radius: 6px; } + +/* Overlays */ +.ui-widget-overlay { background: #eeeeee url(images/ui-bg_diagonals-thick_90_eeeeee_40x40.png) 50% 50% repeat; opacity: .80;filter:Alpha(Opacity=80); } +.ui-widget-shadow { margin: -7px 0 0 -7px; padding: 7px; background: #000000 url(images/ui-bg_highlight-hard_70_000000_1x100.png) 50% top repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; }/* Accordion +----------------------------------*/ +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; } +.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker +----------------------------------*/ +.ui-datepicker { width: 17em; padding: .2em .2em 0; } +.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 { float:left; 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 .ui-datepicker-title select.ui-datepicker-year { float: right; } +.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%; } + +/* 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*/ +}/* Dialog +----------------------------------*/ +.ui-dialog { position: relative; padding: .2em; width: 300px; } +.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } +/* Progressbar +----------------------------------*/ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable +----------------------------------*/ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider +----------------------------------*/ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs +----------------------------------*/ +.ui-tabs { padding: .2em; zoom: 1; } +.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; } +.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } diff --git a/server/hms/static/css/jquery.autocomplete.css b/server/hms/static/css/jquery.autocomplete.css @@ -0,0 +1,48 @@ +.ac_results { + padding: 0px; + border: 1px solid black; + background-color: white; + overflow: hidden; + z-index: 99999; +} + +.ac_results ul { + width: 100%; + list-style-position: outside; + list-style: none; + padding: 0; + margin: 0; +} + +.ac_results li { + margin: 0px; + padding: 2px 5px; + cursor: default; + display: block; + /* + if width will be 100% horizontal scrollbar will apear + when scroll mode will be used + */ + /*width: 100%;*/ + font: menu; + font-size: 12px; + /* + it is very important, if line-height not setted or setted + in relative units scroll will be broken in firefox + */ + line-height: 16px; + overflow: hidden; +} + +.ac_loading { + background: white url('indicator.gif') right center no-repeat; +} + +.ac_odd { + background-color: #eee; +} + +.ac_over { + background-color: #0A246A; + color: white; +} diff --git a/server/hms/static/css/mediaedit.css b/server/hms/static/css/mediaedit.css @@ -0,0 +1,13 @@ +#movie_details { + float: left; +} + +#file_details { +} + +#stream_quality { +} + +#audio { + float: left; +} +\ No newline at end of file diff --git a/server/hms/static/css/site.css b/server/hms/static/css/site.css @@ -0,0 +1,54 @@ +html, body { +} + +body { + font-family: Tahoma, "Lucida Grande", Arial, sans-serif; + font-size: 100%; +} + +#sourceForm label { + width: 6em; + float: left; + text-align: right; + margin-right: 0.5em; + display: block; +} + +#sourceForm .submit input { + margin-left: 7.5em; +} + +#userForm label { + width: 4em; + float: left; + text-align: right; + margin-right: 0.5em; + display: block; +} + +#userForm .submit input { + margin-left: 5.5em; +} + +#loginForm label { + width: 6em; + float: left; + text-align: right; + margin-right: 0.5em; + display: block; +} + +#loginForm .submit input { + margin-left: 7.5em; +} + +.covers { + width: 780px; +} + + +.cover-selection { + float: left; + width: 155px; +} + diff --git a/server/hms/static/js/jquery-1.3.2.min.js b/server/hms/static/js/jquery-1.3.2.min.js @@ -0,0 +1,19 @@ +/* + * jQuery JavaScript Library v1.3.2 + * http://jquery.com/ + * + * Copyright (c) 2009 John Resig + * Dual licensed under the MIT and GPL licenses. + * http://docs.jquery.com/License + * + * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) + * Revision: 6246 + */ +(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); +/* + * Sizzle CSS Selector Engine - v0.9.3 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML=' <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); +\ No newline at end of file diff --git a/server/hms/static/js/jquery-ui-1.7.2.custom.min.js b/server/hms/static/js/jquery-ui-1.7.2.custom.min.js @@ -0,0 +1,298 @@ +/* + * jQuery UI 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI + */ +jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.2",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m<n.length;m++){if(j.options[n[m][0]]){n[m][1].apply(j.element,k)}}}},contains:function(k,j){return document.compareDocumentPosition?k.compareDocumentPosition(j)&16:k!==j&&k.contains(j)},hasScroll:function(m,k){if(c(m).css("overflow")=="hidden"){return false}var j=(k&&k=="left")?"scrollLeft":"scrollTop",l=false;if(m[j]>0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,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}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function(k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);;/* + * jQuery UI Draggable 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Draggables + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.draggable",a.extend({},a.ui.mouse,{_init:function(){if(this.options.helper=="original"&&!(/^(?:r|a|f)/).test(this.element.css("position"))){this.element[0].style.position="relative"}(this.options.addClasses&&this.element.addClass("ui-draggable"));(this.options.disabled&&this.element.addClass("ui-draggable-disabled"));this._mouseInit()},destroy:function(){if(!this.element.data("draggable")){return}this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy()},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")){return false}this.handle=this._getHandle(b);if(!this.handle){return false}return true},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b);this._cacheHelperProportions();if(a.ui.ddmanager){a.ui.ddmanager.current=this}this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(b);this.originalPageX=b.pageX;this.originalPageY=b.pageY;if(c.cursorAt){this._adjustOffsetFromHelper(c.cursorAt)}if(c.containment){this._setContainment()}this._trigger("start",b);this._cacheHelperProportions();if(a.ui.ddmanager&&!c.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,b)}this.helper.addClass("ui-draggable-dragging");this._mouseDrag(b,true);return true},_mouseDrag:function(b,d){this.position=this._generatePosition(b);this.positionAbs=this._convertPositionTo("absolute");if(!d){var c=this._uiHash();this._trigger("drag",b,c);this.position=c.position}if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}if(a.ui.ddmanager){a.ui.ddmanager.drag(this,b)}return false},_mouseStop:function(c){var d=false;if(a.ui.ddmanager&&!this.options.dropBehaviour){d=a.ui.ddmanager.drop(this,c)}if(this.dropped){d=this.dropped;this.dropped=false}if((this.options.revert=="invalid"&&!d)||(this.options.revert=="valid"&&d)||this.options.revert===true||(a.isFunction(this.options.revert)&&this.options.revert.call(this.element,d))){var b=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){b._trigger("stop",c);b._clear()})}else{this._trigger("stop",c);this._clear()}return false},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==b.target){c=true}});return c},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c])):(d.helper=="clone"?this.element.clone():this.element);if(!b.parents("body").length){b.appendTo((d.appendTo=="parent"?this.element[0].parentNode:d.appendTo))}if(b[0]!=this.element[0]&&!(/(fixed|absolute)/).test(b.css("position"))){b.css("position","absolute")}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.element.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css("marginLeft"),10)||0),top:(parseInt(this.element.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)&&e.containment.constructor!=Array){var c=a(e.containment)[0];if(!c){return}var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}else{if(e.containment.constructor==Array){this.containment=e.containment}}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.left<this.containment[0]){d=this.containment[0]+this.offset.click.left}if(e.pageY-this.offset.click.top<this.containment[1]){c=this.containment[1]+this.offset.click.top}if(e.pageX-this.offset.click.left>this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:(!(g-this.offset.click.top<this.containment[1])?g-h.grid[1]:g+h.grid[1])):g;var f=this.originalPageX+Math.round((d-this.originalPageX)/h.grid[0])*h.grid[0];d=this.containment?(!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:(!(f-this.offset.click.left<this.containment[0])?f-h.grid[0]:f+h.grid[0])):f}}return{top:(c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(i?0:b.scrollTop())))),left:(d-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():i?0:b.scrollLeft())))}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");if(this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval){this.helper.remove()}this.helper=null;this.cancelHelperRemoval=false},_trigger:function(b,c,d){d=d||this._uiHash();a.ui.plugin.call(this,b,[c,d]);if(b=="drag"){this.positionAbs=this._convertPositionTo("absolute")}return a.widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(b){return{helper:this.helper,position:this.position,absolutePosition:this.positionAbs,offset:this.positionAbs}}}));a.extend(a.ui.draggable,{version:"1.7.2",eventPrefix:"drag",defaults:{addClasses:true,appendTo:"parent",axis:false,cancel:":input,option",connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,delay:0,distance:1,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false}});a.ui.plugin.add("draggable","connectToSortable",{start:function(c,e){var d=a(this).data("draggable"),f=d.options,b=a.extend({},e,{item:d.element});d.sortables=[];a(f.connectToSortable).each(function(){var g=a.data(this,"sortable");if(g&&!g.options.disabled){d.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",c,b)}})},stop:function(c,e){var d=a(this).data("draggable"),b=a.extend({},e,{item:d.element});a.each(d.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;d.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert){this.instance.options.revert=true}this.instance._mouseStop(c);this.instance.options.helper=this.instance.options._helper;if(d.options.helper=="original"){this.instance.currentItem.css({top:"auto",left:"auto"})}}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",c,b)}})},drag:function(c,f){var e=a(this).data("draggable"),b=this;var d=function(i){var n=this.offset.click.top,m=this.offset.click.left;var g=this.positionAbs.top,k=this.positionAbs.left;var j=i.height,l=i.width;var p=i.top,h=i.left;return a.ui.isOver(g+n,k+m,p,h,j,l)};a.each(e.sortables,function(g){this.instance.positionAbs=e.positionAbs;this.instance.helperProportions=e.helperProportions;this.instance.offset.click=e.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=a(b).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return f.helper[0]};c.target=this.instance.currentItem[0];this.instance._mouseCapture(c,true);this.instance._mouseStart(c,true,true);this.instance.offset.click.top=e.offset.click.top;this.instance.offset.click.left=e.offset.click.left;this.instance.offset.parent.left-=e.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=e.offset.parent.top-this.instance.offset.parent.top;e._trigger("toSortable",c);e.dropped=this.instance.element;e.currentItem=e.element;this.instance.fromOutside=e}if(this.instance.currentItem){this.instance._mouseDrag(c)}}else{if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",c,this.instance._uiHash(this.instance));this.instance._mouseStop(c,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();if(this.instance.placeholder){this.instance.placeholder.remove()}e._trigger("fromSortable",c);e.dropped=false}}})}});a.ui.plugin.add("draggable","cursor",{start:function(c,d){var b=a("body"),e=a(this).data("draggable").options;if(b.css("cursor")){e._cursor=b.css("cursor")}b.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._cursor){a("body").css("cursor",d._cursor)}}});a.ui.plugin.add("draggable","iframeFix",{start:function(b,c){var d=a(this).data("draggable").options;a(d.iframeFix===true?"iframe":d.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css(a(this).offset()).appendTo("body")})},stop:function(b,c){a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});a.ui.plugin.add("draggable","opacity",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("opacity")){e._opacity=b.css("opacity")}b.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._opacity){a(c.helper).css("opacity",d._opacity)}}});a.ui.plugin.add("draggable","scroll",{start:function(c,d){var b=a(this).data("draggable");if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){b.overflowOffset=b.scrollParent.offset()}},drag:function(d,e){var c=a(this).data("draggable"),f=c.options,b=false;if(c.scrollParent[0]!=document&&c.scrollParent[0].tagName!="HTML"){if(!f.axis||f.axis!="x"){if((c.overflowOffset.top+c.scrollParent[0].offsetHeight)-d.pageY<f.scrollSensitivity){c.scrollParent[0].scrollTop=b=c.scrollParent[0].scrollTop+f.scrollSpeed}else{if(d.pageY-c.overflowOffset.top<f.scrollSensitivity){c.scrollParent[0].scrollTop=b=c.scrollParent[0].scrollTop-f.scrollSpeed}}}if(!f.axis||f.axis!="y"){if((c.overflowOffset.left+c.scrollParent[0].offsetWidth)-d.pageX<f.scrollSensitivity){c.scrollParent[0].scrollLeft=b=c.scrollParent[0].scrollLeft+f.scrollSpeed}else{if(d.pageX-c.overflowOffset.left<f.scrollSensitivity){c.scrollParent[0].scrollLeft=b=c.scrollParent[0].scrollLeft-f.scrollSpeed}}}}else{if(!f.axis||f.axis!="x"){if(d.pageY-a(document).scrollTop()<f.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()-f.scrollSpeed)}else{if(a(window).height()-(d.pageY-a(document).scrollTop())<f.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()+f.scrollSpeed)}}}if(!f.axis||f.axis!="y"){if(d.pageX-a(document).scrollLeft()<f.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()-f.scrollSpeed)}else{if(a(window).width()-(d.pageX-a(document).scrollLeft())<f.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()+f.scrollSpeed)}}}}if(b!==false&&a.ui.ddmanager&&!f.dropBehaviour){a.ui.ddmanager.prepareOffsets(c,d)}}});a.ui.plugin.add("draggable","snap",{start:function(c,d){var b=a(this).data("draggable"),e=b.options;b.snapElements=[];a(e.snap.constructor!=String?(e.snap.items||":data(draggable)"):e.snap).each(function(){var g=a(this);var f=g.offset();if(this!=b.element[0]){b.snapElements.push({item:this,width:g.outerWidth(),height:g.outerHeight(),top:f.top,left:f.left})}})},drag:function(u,p){var g=a(this).data("draggable"),q=g.options;var y=q.snapTolerance;var x=p.offset.left,w=x+g.helperProportions.width,f=p.offset.top,e=f+g.helperProportions.height;for(var v=g.snapElements.length-1;v>=0;v--){var s=g.snapElements[v].left,n=s+g.snapElements[v].width,m=g.snapElements[v].top,A=m+g.snapElements[v].height;if(!((s-y<x&&x<n+y&&m-y<f&&f<A+y)||(s-y<x&&x<n+y&&m-y<e&&e<A+y)||(s-y<w&&w<n+y&&m-y<f&&f<A+y)||(s-y<w&&w<n+y&&m-y<e&&e<A+y))){if(g.snapElements[v].snapping){(g.options.snap.release&&g.options.snap.release.call(g.element,u,a.extend(g._uiHash(),{snapItem:g.snapElements[v].item})))}g.snapElements[v].snapping=false;continue}if(q.snapMode!="inner"){var c=Math.abs(m-e)<=y;var z=Math.abs(A-f)<=y;var j=Math.abs(s-w)<=y;var k=Math.abs(n-x)<=y;if(c){p.position.top=g._convertPositionTo("relative",{top:m-g.helperProportions.height,left:0}).top-g.margins.top}if(z){p.position.top=g._convertPositionTo("relative",{top:A,left:0}).top-g.margins.top}if(j){p.position.left=g._convertPositionTo("relative",{top:0,left:s-g.helperProportions.width}).left-g.margins.left}if(k){p.position.left=g._convertPositionTo("relative",{top:0,left:n}).left-g.margins.left}}var h=(c||z||j||k);if(q.snapMode!="outer"){var c=Math.abs(m-f)<=y;var z=Math.abs(A-e)<=y;var j=Math.abs(s-x)<=y;var k=Math.abs(n-w)<=y;if(c){p.position.top=g._convertPositionTo("relative",{top:m,left:0}).top-g.margins.top}if(z){p.position.top=g._convertPositionTo("relative",{top:A-g.helperProportions.height,left:0}).top-g.margins.top}if(j){p.position.left=g._convertPositionTo("relative",{top:0,left:s}).left-g.margins.left}if(k){p.position.left=g._convertPositionTo("relative",{top:0,left:n-g.helperProportions.width}).left-g.margins.left}}if(!g.snapElements[v].snapping&&(c||z||j||k||h)){(g.options.snap.snap&&g.options.snap.snap.call(g.element,u,a.extend(g._uiHash(),{snapItem:g.snapElements[v].item})))}g.snapElements[v].snapping=(c||z||j||k||h)}}});a.ui.plugin.add("draggable","stack",{start:function(b,c){var e=a(this).data("draggable").options;var d=a.makeArray(a(e.stack.group)).sort(function(g,f){return(parseInt(a(g).css("zIndex"),10)||e.stack.min)-(parseInt(a(f).css("zIndex"),10)||e.stack.min)});a(d).each(function(f){this.style.zIndex=e.stack.min+f});this[0].style.zIndex=e.stack.min+d.length}});a.ui.plugin.add("draggable","zIndex",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("zIndex")){e._zIndex=b.css("zIndex")}b.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._zIndex){a(c.helper).css("zIndex",d._zIndex)}}})})(jQuery);;/* + * jQuery UI Droppable 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Droppables + * + * Depends: + * ui.core.js + * ui.draggable.js + */ +(function(a){a.widget("ui.droppable",{_init:function(){var c=this.options,b=c.accept;this.isover=0;this.isout=1;this.options.accept=this.options.accept&&a.isFunction(this.options.accept)?this.options.accept:function(e){return e.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};a.ui.ddmanager.droppables[this.options.scope]=a.ui.ddmanager.droppables[this.options.scope]||[];a.ui.ddmanager.droppables[this.options.scope].push(this);(this.options.addClasses&&this.element.addClass("ui-droppable"))},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++){if(b[c]==this){b.splice(c,1)}}this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable")},_setData:function(b,c){if(b=="accept"){this.options.accept=c&&a.isFunction(c)?c:function(e){return e.is(c)}}else{a.widget.prototype._setData.apply(this,arguments)}},_activate:function(c){var b=a.ui.ddmanager.current;if(this.options.activeClass){this.element.addClass(this.options.activeClass)}(b&&this._trigger("activate",c,this.ui(b)))},_deactivate:function(c){var b=a.ui.ddmanager.current;if(this.options.activeClass){this.element.removeClass(this.options.activeClass)}(b&&this._trigger("deactivate",c,this.ui(b)))},_over:function(c){var b=a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.hoverClass){this.element.addClass(this.options.hoverClass)}this._trigger("over",c,this.ui(b))}},_out:function(c){var b=a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass)}this._trigger("out",c,this.ui(b))}},_drop:function(c,d){var b=d||a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return false}var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var f=a.data(this,"droppable");if(f.options.greedy&&a.ui.intersect(b,a.extend(f,{offset:f.element.offset()}),f.options.tolerance)){e=true;return false}});if(e){return false}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.activeClass){this.element.removeClass(this.options.activeClass)}if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass)}this._trigger("drop",c,this.ui(b));return this.element}return false},ui:function(b){return{draggable:(b.currentItem||b.element),helper:b.helper,position:b.position,absolutePosition:b.positionAbs,offset:b.positionAbs}}});a.extend(a.ui.droppable,{version:"1.7.2",eventPrefix:"drop",defaults:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"}});a.ui.intersect=function(q,j,o){if(!j.offset){return false}var e=(q.positionAbs||q.position.absolute).left,d=e+q.helperProportions.width,n=(q.positionAbs||q.position.absolute).top,m=n+q.helperProportions.height;var g=j.offset.left,c=g+j.proportions.width,p=j.offset.top,k=p+j.proportions.height;switch(o){case"fit":return(g<e&&d<c&&p<n&&m<k);break;case"intersect":return(g<e+(q.helperProportions.width/2)&&d-(q.helperProportions.width/2)<c&&p<n+(q.helperProportions.height/2)&&m-(q.helperProportions.height/2)<k);break;case"pointer":var h=((q.positionAbs||q.position.absolute).left+(q.clickOffset||q.offset.click).left),i=((q.positionAbs||q.position.absolute).top+(q.clickOffset||q.offset.click).top),f=a.ui.isOver(i,h,p,g,j.proportions.height,j.proportions.width);return f;break;case"touch":return((n>=p&&n<=k)||(m>=p&&m<=k)||(n<p&&m>k))&&((e>=g&&e<=c)||(d>=g&&d<=c)||(e<g&&d>c));break;default:return false;break}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,g){var b=a.ui.ddmanager.droppables[e.options.scope];var f=g?g.type:null;var h=(e.currentItem||e.element).find(":data(droppable)").andSelf();droppablesLoop:for(var d=0;d<b.length;d++){if(b[d].options.disabled||(e&&!b[d].options.accept.call(b[d].element[0],(e.currentItem||e.element)))){continue}for(var c=0;c<h.length;c++){if(h[c]==b[d].element[0]){b[d].proportions.height=0;continue droppablesLoop}}b[d].visible=b[d].element.css("display")!="none";if(!b[d].visible){continue}b[d].offset=b[d].element.offset();b[d].proportions={width:b[d].element[0].offsetWidth,height:b[d].element[0].offsetHeight};if(f=="mousedown"){b[d]._activate.call(b[d],g)}}},drop:function(b,c){var d=false;a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(!this.options){return}if(!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)){d=this._drop.call(this,c)}if(!this.options.disabled&&this.visible&&this.options.accept.call(this.element[0],(b.currentItem||b.element))){this.isout=1;this.isover=0;this._deactivate.call(this,c)}});return d},drag:function(b,c){if(b.options.refreshPositions){a.ui.ddmanager.prepareOffsets(b,c)}a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(this.options.disabled||this.greedyChild||!this.visible){return}var e=a.ui.intersect(b,this,this.options.tolerance);var g=!e&&this.isover==1?"isout":(e&&this.isover==0?"isover":null);if(!g){return}var f;if(this.options.greedy){var d=this.element.parents(":data(droppable):eq(0)");if(d.length){f=a.data(d[0],"droppable");f.greedyChild=(g=="isover"?1:0)}}if(f&&g=="isover"){f.isover=0;f.isout=1;f._out.call(f,c)}this[g]=1;this[g=="isout"?"isover":"isout"]=0;this[g=="isover"?"_over":"_out"].call(this,c);if(f&&g=="isout"){f.isout=0;f.isover=1;f._over.call(f,c)}})}}})(jQuery);;/* + * jQuery UI Resizable 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Resizables + * + * Depends: + * ui.core.js + */ +(function(c){c.widget("ui.resizable",c.extend({},c.ui.mouse,{_init:function(){var e=this,j=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(j.aspectRatio),aspectRatio:j.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:j.helper||j.ghost||j.animate?j.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){if(/relative/.test(this.element.css("position"))&&c.browser.opera){this.element.css({position:"relative",top:"auto",left:"auto"})}this.element.wrap(c('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f<k.length;f++){var h=c.trim(k[f]),d="ui-resizable-"+h;var g=c('<div class="ui-resizable-handle '+d+'"></div>');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).end().remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidth<k.width),l=a(k.height)&&h.maxHeight&&(h.maxHeight<k.height),g=a(k.width)&&h.minWidth&&(h.minWidth>k.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e<this._proportionallyResizeElements.length;e++){var g=this._proportionallyResizeElements[e];if(!this.borderDif){var d=[g.css("borderTopWidth"),g.css("borderRightWidth"),g.css("borderBottomWidth"),g.css("borderLeftWidth")],h=[g.css("paddingTop"),g.css("paddingRight"),g.css("paddingBottom"),g.css("paddingLeft")];this.borderDif=c.map(d,function(k,m){var l=parseInt(k,10)||0,n=parseInt(h[m],10)||0;return l+n})}if(c.browser.msie&&!(!(c(f).is(":hidden")||c(f).parents(":hidden").length))){continue}g.css({height:(f.height()-this.borderDif[0]-this.borderDif[2])||0,width:(f.width()-this.borderDif[1]-this.borderDif[3])||0})}},_renderProxy:function(){var e=this.element,h=this.options;this.elementOffset=e.offset();if(this._helper){this.helper=this.helper||c('<div style="overflow:hidden;"></div>');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:"1.7.2",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),g=d.options;_store=function(h){c(h).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(g.alsoResize)=="object"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)){s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);;/* + * jQuery UI Selectable 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Selectables + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.selectable",a.extend({},a.ui.mouse,{_init:function(){var b=this;this.element.addClass("ui-selectable");this.dragged=false;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]);c.each(function(){var d=a(this);var e=d.offset();a.data(this,"selectable-item",{element:this,$element:d,left:e.left,top:e.top,right:e.left+d.outerWidth(),bottom:e.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=c.addClass("ui-selectee");this._mouseInit();this.helper=a(document.createElement("div")).css({border:"1px dotted black"}).addClass("ui-selectable-helper")},destroy:function(){this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy()},_mouseStart:function(d){var b=this;this.opos=[d.pageX,d.pageY];if(this.options.disabled){return}var c=this.options;this.selectees=a(c.filter,this.element[0]);this._trigger("start",d);a(c.appendTo).append(this.helper);this.helper.css({"z-index":100,position:"absolute",left:d.clientX,top:d.clientY,width:0,height:0});if(c.autoRefresh){this.refresh()}this.selectees.filter(".ui-selected").each(function(){var e=a.data(this,"selectable-item");e.startselected=true;if(!d.metaKey){e.$element.removeClass("ui-selected");e.selected=false;e.$element.addClass("ui-unselecting");e.unselecting=true;b._trigger("unselecting",d,{unselecting:e.element})}});a(d.target).parents().andSelf().each(function(){var e=a.data(this,"selectable-item");if(e){e.$element.removeClass("ui-unselecting").addClass("ui-selecting");e.unselecting=false;e.selecting=true;e.selected=true;b._trigger("selecting",d,{selecting:e.element});return false}})},_mouseDrag:function(i){var c=this;this.dragged=true;if(this.options.disabled){return}var e=this.options;var d=this.opos[0],h=this.opos[1],b=i.pageX,g=i.pageY;if(d>b){var f=b;b=d;d=f}if(h>g){var f=g;g=h;h=f}this.helper.css({left:d,top:h,width:b-d,height:g-h});this.selectees.each(function(){var j=a.data(this,"selectable-item");if(!j||j.element==c.element[0]){return}var k=false;if(e.tolerance=="touch"){k=(!(j.left>b||j.right<d||j.top>g||j.bottom<h))}else{if(e.tolerance=="fit"){k=(j.left>d&&j.right<b&&j.top>h&&j.bottom<g)}}if(k){if(j.selected){j.$element.removeClass("ui-selected");j.selected=false}if(j.unselecting){j.$element.removeClass("ui-unselecting");j.unselecting=false}if(!j.selecting){j.$element.addClass("ui-selecting");j.selecting=true;c._trigger("selecting",i,{selecting:j.element})}}else{if(j.selecting){if(i.metaKey&&j.startselected){j.$element.removeClass("ui-selecting");j.selecting=false;j.$element.addClass("ui-selected");j.selected=true}else{j.$element.removeClass("ui-selecting");j.selecting=false;if(j.startselected){j.$element.addClass("ui-unselecting");j.unselecting=true}c._trigger("unselecting",i,{unselecting:j.element})}}if(j.selected){if(!i.metaKey&&!j.startselected){j.$element.removeClass("ui-selected");j.selected=false;j.$element.addClass("ui-unselecting");j.unselecting=true;c._trigger("unselecting",i,{unselecting:j.element})}}}});return false},_mouseStop:function(d){var b=this;this.dragged=false;var c=this.options;a(".ui-unselecting",this.element[0]).each(function(){var e=a.data(this,"selectable-item");e.$element.removeClass("ui-unselecting");e.unselecting=false;e.startselected=false;b._trigger("unselected",d,{unselected:e.element})});a(".ui-selecting",this.element[0]).each(function(){var e=a.data(this,"selectable-item");e.$element.removeClass("ui-selecting").addClass("ui-selected");e.selecting=false;e.selected=true;e.startselected=true;b._trigger("selected",d,{selected:e.element})});this._trigger("stop",d);this.helper.remove();return false}}));a.extend(a.ui.selectable,{version:"1.7.2",defaults:{appendTo:"body",autoRefresh:true,cancel:":input,option",delay:0,distance:0,filter:"*",tolerance:"touch"}})})(jQuery);;/* + * jQuery UI Sortable 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Sortables + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.sortable",a.extend({},a.ui.mouse,{_init:function(){var b=this.options;this.containerCache={};this.element.addClass("ui-sortable");this.refresh();this.floating=this.items.length?(/left|right/).test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--){this.items[b].item.removeData("sortable-item")}},_mouseCapture:function(e,f){if(this.reverting){return false}if(this.options.disabled||this.options.type=="static"){return false}this._refreshItems(e);var d=null,c=this,b=a(e.target).parents().each(function(){if(a.data(this,"sortable-item")==c){d=a(this);return false}});if(a.data(e.target,"sortable-item")==c){d=a(e.target)}if(!d){return false}if(this.options.handle&&!f){var g=false;a(this.options.handle,d).find("*").andSelf().each(function(){if(this==e.target){g=true}});if(!g){return false}}this.currentItem=d;this._removeCurrentsFromItems();return true},_mouseStart:function(e,f,b){var g=this.options,c=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(e);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");a.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(e);this.originalPageX=e.pageX;this.originalPageY=e.pageY;if(g.cursorAt){this._adjustOffsetFromHelper(g.cursorAt)}this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!=this.currentItem[0]){this.currentItem.hide()}this._createPlaceholder();if(g.containment){this._setContainment()}if(g.cursor){if(a("body").css("cursor")){this._storedCursor=a("body").css("cursor")}a("body").css("cursor",g.cursor)}if(g.opacity){if(this.helper.css("opacity")){this._storedOpacity=this.helper.css("opacity")}this.helper.css("opacity",g.opacity)}if(g.zIndex){if(this.helper.css("zIndex")){this._storedZIndex=this.helper.css("zIndex")}this.helper.css("zIndex",g.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){this.overflowOffset=this.scrollParent.offset()}this._trigger("start",e,this._uiHash());if(!this._preserveHelperProportions){this._cacheHelperProportions()}if(!b){for(var d=this.containers.length-1;d>=0;d--){this.containers[d]._trigger("activate",e,c._uiHash(this))}}if(a.ui.ddmanager){a.ui.ddmanager.current=this}if(a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,e)}this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(e);return true},_mouseDrag:function(f){this.position=this._generatePosition(f);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs}if(this.options.scroll){var g=this.options,b=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-f.pageY<g.scrollSensitivity){this.scrollParent[0].scrollTop=b=this.scrollParent[0].scrollTop+g.scrollSpeed}else{if(f.pageY-this.overflowOffset.top<g.scrollSensitivity){this.scrollParent[0].scrollTop=b=this.scrollParent[0].scrollTop-g.scrollSpeed}}if((this.overflowOffset.left+this.scrollParent[0].offsetWidth)-f.pageX<g.scrollSensitivity){this.scrollParent[0].scrollLeft=b=this.scrollParent[0].scrollLeft+g.scrollSpeed}else{if(f.pageX-this.overflowOffset.left<g.scrollSensitivity){this.scrollParent[0].scrollLeft=b=this.scrollParent[0].scrollLeft-g.scrollSpeed}}}else{if(f.pageY-a(document).scrollTop()<g.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()-g.scrollSpeed)}else{if(a(window).height()-(f.pageY-a(document).scrollTop())<g.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()+g.scrollSpeed)}}if(f.pageX-a(document).scrollLeft()<g.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()-g.scrollSpeed)}else{if(a(window).width()-(f.pageX-a(document).scrollLeft())<g.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()+g.scrollSpeed)}}}if(b!==false&&a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,f)}}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}for(var d=this.items.length-1;d>=0;d--){var e=this.items[d],c=e.item[0],h=this._intersectsWithPointer(e);if(!h){continue}if(c!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=c&&!a.ui.contains(this.placeholder[0],c)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],c):true)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(e)){this._rearrange(f,e)}else{break}this._trigger("change",f,this._uiHash());break}}this._contactContainers(f);if(a.ui.ddmanager){a.ui.ddmanager.drag(this,f)}this._trigger("sort",f,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(c,d){if(!c){return}if(a.ui.ddmanager&&!this.options.dropBehaviour){a.ui.ddmanager.drop(this,c)}if(this.options.revert){var b=this;var e=b.placeholder.offset();b.reverting=true;a(this.helper).animate({left:e.left-this.offset.parent.left-b.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-b.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){b._clear(c)})}else{this._clear(c,d)}return false},cancel:function(){var b=this;if(this.dragging){this._mouseUp();if(this.options.helper=="original"){this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger("deactivate",null,b._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",null,b._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder[0].parentNode){this.placeholder[0].parentNode.removeChild(this.placeholder[0])}if(this.options.helper!="original"&&this.helper&&this.helper[0].parentNode){this.helper.remove()}a.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){a(this.domPosition.prev).after(this.currentItem)}else{a(this.domPosition.parent).prepend(this.currentItem)}return true},serialize:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};a(b).each(function(){var e=(a(d.item||this).attr(d.attribute||"id")||"").match(d.expression||(/(.+)[-=_](.+)/));if(e){c.push((d.key||e[1]+"[]")+"="+(d.key&&d.expression?e[1]:e[2]))}});return c.join("&")},toArray:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};b.each(function(){c.push(a(d.item||this).attr(d.attribute||"id")||"")});return c},_intersectsWith:function(m){var e=this.positionAbs.left,d=e+this.helperProportions.width,k=this.positionAbs.top,j=k+this.helperProportions.height;var f=m.left,c=f+m.width,n=m.top,i=n+m.height;var o=this.offset.click.top,h=this.offset.click.left;var g=(k+o)>n&&(k+o)<i&&(e+h)>f&&(e+h)<c;if(this.options.tolerance=="pointer"||this.options.forcePointerForContainers||(this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>m[this.floating?"width":"height"])){return g}else{return(f<e+(this.helperProportions.width/2)&&d-(this.helperProportions.width/2)<c&&n<k+(this.helperProportions.height/2)&&j-(this.helperProportions.height/2)<i)}},_intersectsWithPointer:function(d){var e=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,d.top,d.height),c=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,d.left,d.width),g=e&&c,b=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();if(!g){return false}return this.floating?(((f&&f=="right")||b=="down")?2:1):(b&&(b=="down"?2:1))},_intersectsWithSides:function(e){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+(e.height/2),e.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+(e.width/2),e.width),b=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();if(this.floating&&f){return((f=="right"&&d)||(f=="left"&&!d))}else{return b&&((b=="down"&&c)||(b=="up"&&!c))}},_getDragVerticalDirection:function(){var b=this.positionAbs.top-this.lastPositionAbs.top;return b!=0&&(b>0?"down":"up")},_getDragHorizontalDirection:function(){var b=this.positionAbs.left-this.lastPositionAbs.left;return b!=0&&(b>0?"right":"left")},refresh:function(b){this._refreshItems(b);this.refreshPositions()},_connectWith:function(){var b=this.options;return b.connectWith.constructor==String?[b.connectWith]:b.connectWith},_getItemsAsjQuery:function(b){var l=this;var g=[];var e=[];var h=this._connectWith();if(h&&b){for(var d=h.length-1;d>=0;d--){var k=a(h[d]);for(var c=k.length-1;c>=0;c--){var f=a.data(k[c],"sortable");if(f&&f!=this&&!f.options.disabled){e.push([a.isFunction(f.options.items)?f.options.items.call(f.element):a(f.options.items,f.element).not(".ui-sortable-helper"),f])}}}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper"),this]);for(var d=e.length-1;d>=0;d--){e[d][0].each(function(){g.push(this)})}return a(g)},_removeCurrentsFromItems:function(){var d=this.currentItem.find(":data(sortable-item)");for(var c=0;c<this.items.length;c++){for(var b=0;b<d.length;b++){if(d[b]==this.items[c].item[0]){this.items.splice(c,1)}}}},_refreshItems:function(b){this.items=[];this.containers=[this];var h=this.items;var p=this;var f=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]];var l=this._connectWith();if(l){for(var e=l.length-1;e>=0;e--){var m=a(l[e]);for(var d=m.length-1;d>=0;d--){var g=a.data(m[d],"sortable");if(g&&g!=this&&!g.options.disabled){f.push([a.isFunction(g.options.items)?g.options.items.call(g.element[0],b,{item:this.currentItem}):a(g.options.items,g.element),g]);this.containers.push(g)}}}}for(var e=f.length-1;e>=0;e--){var k=f[e][1];var c=f[e][0];for(var d=0,n=c.length;d<n;d++){var o=a(c[d]);o.data("sortable-item",k);h.push({item:o,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){if(this.offsetParent&&this.helper){this.offset.parent=this._getParentOffset()}for(var d=this.items.length-1;d>=0;d--){var e=this.items[d];if(e.instance!=this.currentContainer&&this.currentContainer&&e.item[0]!=this.currentItem[0]){continue}var c=this.options.toleranceElement?a(this.options.toleranceElement,e.item):e.item;if(!b){e.width=c.outerWidth();e.height=c.outerHeight()}var f=c.offset();e.left=f.left;e.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this)}else{for(var d=this.containers.length-1;d>=0;d--){var f=this.containers[d].element.offset();this.containers[d].containerCache.left=f.left;this.containers[d].containerCache.top=f.top;this.containers[d].containerCache.width=this.containers[d].element.outerWidth();this.containers[d].containerCache.height=this.containers[d].element.outerHeight()}}},_createPlaceholder:function(d){var b=d||this,e=b.options;if(!e.placeholder||e.placeholder.constructor==String){var c=e.placeholder;e.placeholder={element:function(){var f=a(document.createElement(b.currentItem[0].nodeName)).addClass(c||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!c){f.style.visibility="hidden"}return f},update:function(f,g){if(c&&!e.forcePlaceholderSize){return}if(!g.height()){g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10))}if(!g.width()){g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=a(e.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);e.placeholder.update(b,b.placeholder)},_contactContainers:function(d){for(var c=this.containers.length-1;c>=0;c--){if(this._intersectsWith(this.containers[c].containerCache)){if(!this.containers[c].containerCache.over){if(this.currentContainer!=this.containers[c]){var h=10000;var g=null;var e=this.positionAbs[this.containers[c].floating?"left":"top"];for(var b=this.items.length-1;b>=0;b--){if(!a.ui.contains(this.containers[c].element[0],this.items[b].item[0])){continue}var f=this.items[b][this.containers[c].floating?"left":"top"];if(Math.abs(f-e)<h){h=Math.abs(f-e);g=this.items[b]}}if(!g&&!this.options.dropOnEmpty){continue}this.currentContainer=this.containers[c];g?this._rearrange(d,g,null,true):this._rearrange(d,null,this.containers[c].element,true);this._trigger("change",d,this._uiHash());this.containers[c]._trigger("change",d,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder)}this.containers[c]._trigger("over",d,this._uiHash(this));this.containers[c].containerCache.over=1}}else{if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",d,this._uiHash(this));this.containers[c].containerCache.over=0}}}},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c,this.currentItem])):(d.helper=="clone"?this.currentItem.clone():this.currentItem);if(!b.parents("body").length){a(d.appendTo!="parent"?d.appendTo:this.currentItem[0].parentNode)[0].appendChild(b[0])}if(b[0]==this.currentItem[0]){this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}}if(b[0].style.width==""||d.forceHelperSize){b.width(this.currentItem.width())}if(b[0].style.height==""||d.forceHelperSize){b.height(this.currentItem.height())}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.currentItem.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.currentItem.css("marginLeft"),10)||0),top:(parseInt(this.currentItem.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)){var c=a(e.containment)[0];var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.left<this.containment[0]){d=this.containment[0]+this.offset.click.left}if(e.pageY-this.offset.click.top<this.containment[1]){c=this.containment[1]+this.offset.click.top}if(e.pageX-this.offset.click.left>this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:(!(g-this.offset.click.top<this.containment[1])?g-h.grid[1]:g+h.grid[1])):g;var f=this.originalPageX+Math.round((d-this.originalPageX)/h.grid[0])*h.grid[0];d=this.containment?(!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:(!(f-this.offset.click.left<this.containment[0])?f-h.grid[0]:f+h.grid[0])):f}}return{top:(c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(i?0:b.scrollTop())))),left:(d-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():i?0:b.scrollLeft())))}},_rearrange:function(g,f,c,e){c?c[0].appendChild(this.placeholder[0]):f.item[0].parentNode.insertBefore(this.placeholder[0],(this.direction=="down"?f.item[0]:f.item[0].nextSibling));this.counter=this.counter?++this.counter:1;var d=this,b=this.counter;window.setTimeout(function(){if(b==d.counter){d.refreshPositions(!e)}},0)},_clear:function(d,e){this.reverting=false;var f=[],b=this;if(!this._noFinalSort&&this.currentItem[0].parentNode){this.placeholder.before(this.currentItem)}this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var c in this._storedCSS){if(this._storedCSS[c]=="auto"||this._storedCSS[c]=="static"){this._storedCSS[c]=""}}this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}if(this.fromOutside&&!e){f.push(function(g){this._trigger("receive",g,this._uiHash(this.fromOutside))})}if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!e){f.push(function(g){this._trigger("update",g,this._uiHash())})}if(!a.ui.contains(this.element[0],this.currentItem[0])){if(!e){f.push(function(g){this._trigger("remove",g,this._uiHash())})}for(var c=this.containers.length-1;c>=0;c--){if(a.ui.contains(this.containers[c].element[0],this.currentItem[0])&&!e){f.push((function(g){return function(h){g._trigger("receive",h,this._uiHash(this))}}).call(this,this.containers[c]));f.push((function(g){return function(h){g._trigger("update",h,this._uiHash(this))}}).call(this,this.containers[c]))}}}for(var c=this.containers.length-1;c>=0;c--){if(!e){f.push((function(g){return function(h){g._trigger("deactivate",h,this._uiHash(this))}}).call(this,this.containers[c]))}if(this.containers[c].containerCache.over){f.push((function(g){return function(h){g._trigger("out",h,this._uiHash(this))}}).call(this,this.containers[c]));this.containers[c].containerCache.over=0}}if(this._storedCursor){a("body").css("cursor",this._storedCursor)}if(this._storedOpacity){this.helper.css("opacity",this._storedOpacity)}if(this._storedZIndex){this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex)}this.dragging=false;if(this.cancelHelperRemoval){if(!e){this._trigger("beforeStop",d,this._uiHash());for(var c=0;c<f.length;c++){f[c].call(this,d)}this._trigger("stop",d,this._uiHash())}return false}if(!e){this._trigger("beforeStop",d,this._uiHash())}this.placeholder[0].parentNode.removeChild(this.placeholder[0]);if(this.helper[0]!=this.currentItem[0]){this.helper.remove()}this.helper=null;if(!e){for(var c=0;c<f.length;c++){f[c].call(this,d)}this._trigger("stop",d,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){if(a.widget.prototype._trigger.apply(this,arguments)===false){this.cancel()}},_uiHash:function(c){var b=c||this;return{helper:b.helper,placeholder:b.placeholder||a([]),position:b.position,absolutePosition:b.positionAbs,offset:b.positionAbs,item:b.currentItem,sender:c?c.element:null}}}));a.extend(a.ui.sortable,{getter:"serialize toArray",version:"1.7.2",eventPrefix:"sort",defaults:{appendTo:"parent",axis:false,cancel:":input,option",connectWith:false,containment:false,cursor:"auto",cursorAt:false,delay:0,distance:1,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1000}})})(jQuery);;/* + * jQuery UI Accordion 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Accordion + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.accordion",{_init:function(){var d=this.options,b=this;this.running=0;if(d.collapsible==a.ui.accordion.defaults.collapsible&&d.alwaysOpen!=a.ui.accordion.defaults.alwaysOpen){d.collapsible=!d.alwaysOpen}if(d.navigation){var c=this.element.find("a").filter(d.navigationFilter);if(c.length){if(c.filter(d.header).length){this.active=c}else{this.active=c.parent().parent().prev();c.addClass("ui-accordion-content-active")}}}this.element.addClass("ui-accordion ui-widget ui-helper-reset");if(this.element[0].nodeName=="UL"){this.element.children("li").addClass("ui-accordion-li-fix")}this.headers=this.element.find(d.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){a(this).removeClass("ui-state-focus")});this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");this.active=this._findActive(this.active||d.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");this.active.next().addClass("ui-accordion-content-active");a("<span/>").addClass("ui-icon "+d.icons.header).prependTo(this.headers);this.active.find(".ui-icon").toggleClass(d.icons.header).toggleClass(d.icons.headerSelected);if(a.browser.msie){this.element.find("a").css("zoom","1")}this.resize();this.element.attr("role","tablist");this.headers.attr("role","tab").bind("keydown",function(e){return b._keydown(e)}).next().attr("role","tabpanel");this.headers.not(this.active||"").attr("aria-expanded","false").attr("tabIndex","-1").next().hide();if(!this.active.length){this.headers.eq(0).attr("tabIndex","0")}else{this.active.attr("aria-expanded","true").attr("tabIndex","0")}if(!a.browser.safari){this.headers.find("a").attr("tabIndex","-1")}if(d.event){this.headers.bind((d.event)+".accordion",function(e){return b._clickHandler.call(b,e,this)})}},destroy:function(){var c=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role").unbind(".accordion").removeData("accordion");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex");this.headers.find("a").removeAttr("tabindex");this.headers.children(".ui-icon").remove();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active");if(c.autoHeight||c.fillHeight){b.css("height","")}},_setData:function(b,c){if(b=="alwaysOpen"){b="collapsible";c=!c}a.widget.prototype._setData.apply(this,arguments)},_keydown:function(e){var g=this.options,f=a.ui.keyCode;if(g.disabled||e.altKey||e.ctrlKey){return}var d=this.headers.length;var b=this.headers.index(e.target);var c=false;switch(e.keyCode){case f.RIGHT:case f.DOWN:c=this.headers[(b+1)%d];break;case f.LEFT:case f.UP:c=this.headers[(b-1+d)%d];break;case f.SPACE:case f.ENTER:return this._clickHandler({target:e.target},e.target)}if(c){a(e.target).attr("tabIndex","-1");a(c).attr("tabIndex","0");c.focus();return false}return true},resize:function(){var e=this.options,d;if(e.fillSpace){if(a.browser.msie){var b=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}d=this.element.parent().height();if(a.browser.msie){this.element.parent().css("overflow",b)}this.headers.each(function(){d-=a(this).outerHeight()});var c=0;this.headers.next().each(function(){c=Math.max(c,a(this).innerHeight()-a(this).height())}).height(Math.max(0,d-c)).css("overflow","auto")}else{if(e.autoHeight){d=0;this.headers.next().each(function(){d=Math.max(d,a(this).outerHeight())}).height(d)}}},activate:function(b){var c=this._findActive(b)[0];this._clickHandler({target:c},c)},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===false?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,f){var d=this.options;if(d.disabled){return false}if(!b.target&&d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var h=this.active.next(),e={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:h},c=(this.active=a([]));this._toggle(c,h,e);return false}var g=a(b.currentTarget||f);var i=g[0]==this.active[0];if(this.running||(!d.collapsible&&i)){return false}this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");if(!i){g.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").find(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);g.next().addClass("ui-accordion-content-active")}var c=g.next(),h=this.active.next(),e={options:d,newHeader:i&&d.collapsible?a([]):g,oldHeader:this.active,newContent:i&&d.collapsible?a([]):c.find("> *"),oldContent:h.find("> *")},j=this.headers.index(this.active[0])>this.headers.index(g[0]);this.active=i?a([]):g;this._toggle(c,h,e,i,j);return false},_toggle:function(b,i,g,j,k){var d=this.options,m=this;this.toShow=b;this.toHide=i;this.data=g;var c=function(){if(!m){return}return m._completed.apply(m,arguments)};this._trigger("changestart",null,this.data);this.running=i.size()===0?b.size():i.size();if(d.animated){var f={};if(d.collapsible&&j){f={toShow:a([]),toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}else{f={toShow:b,toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}if(!d.proxied){d.proxied=d.animated}if(!d.proxiedDuration){d.proxiedDuration=d.duration}d.animated=a.isFunction(d.proxied)?d.proxied(f):d.proxied;d.duration=a.isFunction(d.proxiedDuration)?d.proxiedDuration(f):d.proxiedDuration;var l=a.ui.accordion.animations,e=d.duration,h=d.animated;if(!l[h]){l[h]=function(n){this.slide(n,{easing:h,duration:e||700})}}l[h](f)}else{if(d.collapsible&&j){b.toggle()}else{i.hide();b.show()}c(true)}i.prev().attr("aria-expanded","false").attr("tabIndex","-1").blur();b.prev().attr("aria-expanded","true").attr("tabIndex","0").focus()},_completed:function(b){var c=this.options;this.running=b?0:--this.running;if(this.running){return}if(c.clearStyle){this.toShow.add(this.toHide).css({height:"",overflow:""})}this._trigger("change",null,this.data)}});a.extend(a.ui.accordion,{version:"1.7.2",defaults:{active:null,alwaysOpen:true,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()==location.href.toLowerCase()}},animations:{slide:function(j,h){j=a.extend({easing:"swing",duration:300},j,h);if(!j.toHide.size()){j.toShow.animate({height:"show"},j);return}if(!j.toShow.size()){j.toHide.animate({height:"hide"},j);return}var c=j.toShow.css("overflow"),g,d={},f={},e=["height","paddingTop","paddingBottom"],b;var i=j.toShow;b=i[0].style.width;i.width(parseInt(i.parent().width(),10)-parseInt(i.css("paddingLeft"),10)-parseInt(i.css("paddingRight"),10)-(parseInt(i.css("borderLeftWidth"),10)||0)-(parseInt(i.css("borderRightWidth"),10)||0));a.each(e,function(k,m){f[m]="hide";var l=(""+a.css(j.toShow[0],m)).match(/^([\d+-.]+)(.*)$/);d[m]={value:l[1],unit:l[2]||"px"}});j.toShow.css({height:0,overflow:"hidden"}).show();j.toHide.filter(":hidden").each(j.complete).end().filter(":visible").animate(f,{step:function(k,l){if(l.prop=="height"){g=(l.now-l.start)/(l.end-l.start)}j.toShow[0].style[l.prop]=(g*d[l.prop].value)+d[l.prop].unit},duration:j.duration,easing:j.easing,complete:function(){if(!j.autoHeight){j.toShow.css("height","")}j.toShow.css("width",b);j.toShow.css({overflow:c});j.complete()}})},bounceslide:function(b){this.slide(b,{easing:b.down?"easeOutBounce":"swing",duration:b.down?1000:200})},easeslide:function(b){this.slide(b,{easing:"easeinout",duration:700})}}})})(jQuery);;/* + * jQuery UI Dialog 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Dialog + * + * Depends: + * ui.core.js + * ui.draggable.js + * ui.resizable.js + */ +(function(c){var b={dragStart:"start.draggable",drag:"drag.draggable",dragStop:"stop.draggable",maxHeight:"maxHeight.resizable",minHeight:"minHeight.resizable",maxWidth:"maxWidth.resizable",minWidth:"minWidth.resizable",resizeStart:"start.resizable",resize:"drag.resizable",resizeStop:"stop.resizable"},a="ui-dialog ui-widget ui-widget-content ui-corner-all ";c.widget("ui.dialog",{_init:function(){this.originalTitle=this.element.attr("title");var l=this,m=this.options,j=m.title||this.originalTitle||" ",e=c.ui.dialog.getTitleId(this.element),k=(this.uiDialog=c("<div/>")).appendTo(document.body).hide().addClass(a+m.dialogClass).css({position:"absolute",overflow:"hidden",zIndex:m.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(n){(m.closeOnEscape&&n.keyCode&&n.keyCode==c.ui.keyCode.ESCAPE&&l.close(n))}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(n){l.moveToTop(false,n)}),g=this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(k),f=(this.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(k),i=c('<a href="#"/>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){i.addClass("ui-state-hover")},function(){i.removeClass("ui-state-hover")}).focus(function(){i.addClass("ui-state-focus")}).blur(function(){i.removeClass("ui-state-focus")}).mousedown(function(n){n.stopPropagation()}).click(function(n){l.close(n);return false}).appendTo(f),h=(this.uiDialogTitlebarCloseText=c("<span/>")).addClass("ui-icon ui-icon-closethick").text(m.closeText).appendTo(i),d=c("<span/>").addClass("ui-dialog-title").attr("id",e).html(j).prependTo(f);f.find("*").add(f).disableSelection();(m.draggable&&c.fn.draggable&&this._makeDraggable());(m.resizable&&c.fn.resizable&&this._makeResizable());this._createButtons(m.buttons);this._isOpen=false;(m.bgiframe&&c.fn.bgiframe&&k.bgiframe());(m.autoOpen&&this.open())},destroy:function(){(this.overlay&&this.overlay.destroy());this.uiDialog.hide();this.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");this.uiDialog.remove();(this.originalTitle&&this.element.attr("title",this.originalTitle))},close:function(f){var d=this;if(false===d._trigger("beforeclose",f)){return}(d.overlay&&d.overlay.destroy());d.uiDialog.unbind("keypress.ui-dialog");(d.options.hide?d.uiDialog.hide(d.options.hide,function(){d._trigger("close",f)}):d.uiDialog.hide()&&d._trigger("close",f));c.ui.dialog.overlay.resize();d._isOpen=false;if(d.options.modal){var e=0;c(".ui-dialog").each(function(){if(this!=d.uiDialog[0]){e=Math.max(e,c(this).css("z-index"))}});c.ui.dialog.maxZ=e}},isOpen:function(){return this._isOpen},moveToTop:function(f,e){if((this.options.modal&&!f)||(!this.options.stack&&!this.options.modal)){return this._trigger("focus",e)}if(this.options.zIndex>c.ui.dialog.maxZ){c.ui.dialog.maxZ=this.options.zIndex}(this.overlay&&this.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=++c.ui.dialog.maxZ));var d={scrollTop:this.element.attr("scrollTop"),scrollLeft:this.element.attr("scrollLeft")};this.uiDialog.css("z-index",++c.ui.dialog.maxZ);this.element.attr(d);this._trigger("focus",e)},open:function(){if(this._isOpen){return}var e=this.options,d=this.uiDialog;this.overlay=e.modal?new c.ui.dialog.overlay(this):null;(d.next().length&&d.appendTo("body"));this._size();this._position(e.position);d.show(e.show);this.moveToTop(true);(e.modal&&d.bind("keypress.ui-dialog",function(h){if(h.keyCode!=c.ui.keyCode.TAB){return}var g=c(":tabbable",this),i=g.filter(":first")[0],f=g.filter(":last")[0];if(h.target==f&&!h.shiftKey){setTimeout(function(){i.focus()},1)}else{if(h.target==i&&h.shiftKey){setTimeout(function(){f.focus()},1)}}}));c([]).add(d.find(".ui-dialog-content :tabbable:first")).add(d.find(".ui-dialog-buttonpane :tabbable:first")).add(d).filter(":first").focus();this._trigger("open");this._isOpen=true},_createButtons:function(g){var f=this,d=false,e=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");this.uiDialog.find(".ui-dialog-buttonpane").remove();(typeof g=="object"&&g!==null&&c.each(g,function(){return !(d=true)}));if(d){c.each(g,function(h,i){c('<button type="button"></button>').addClass("ui-state-default ui-corner-all").text(h).click(function(){i.apply(f.element[0],arguments)}).hover(function(){c(this).addClass("ui-state-hover")},function(){c(this).removeClass("ui-state-hover")}).focus(function(){c(this).addClass("ui-state-focus")}).blur(function(){c(this).removeClass("ui-state-focus")}).appendTo(e)});e.appendTo(this.uiDialog)}},_makeDraggable:function(){var d=this,f=this.options,e;this.uiDialog.draggable({cancel:".ui-dialog-content",handle:".ui-dialog-titlebar",containment:"document",start:function(){e=f.height;c(this).height(c(this).height()).addClass("ui-dialog-dragging");(f.dragStart&&f.dragStart.apply(d.element[0],arguments))},drag:function(){(f.drag&&f.drag.apply(d.element[0],arguments))},stop:function(){c(this).removeClass("ui-dialog-dragging").height(e);(f.dragStop&&f.dragStop.apply(d.element[0],arguments));c.ui.dialog.overlay.resize()}})},_makeResizable:function(g){g=(g===undefined?this.options.resizable:g);var d=this,f=this.options,e=typeof g=="string"?g:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",alsoResize:this.element,maxWidth:f.maxWidth,maxHeight:f.maxHeight,minWidth:f.minWidth,minHeight:f.minHeight,start:function(){c(this).addClass("ui-dialog-resizing");(f.resizeStart&&f.resizeStart.apply(d.element[0],arguments))},resize:function(){(f.resize&&f.resize.apply(d.element[0],arguments))},handles:e,stop:function(){c(this).removeClass("ui-dialog-resizing");f.height=c(this).height();f.width=c(this).width();(f.resizeStop&&f.resizeStop.apply(d.element[0],arguments));c.ui.dialog.overlay.resize()}}).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_position:function(i){var e=c(window),f=c(document),g=f.scrollTop(),d=f.scrollLeft(),h=g;if(c.inArray(i,["center","top","right","bottom","left"])>=0){i=[i=="right"||i=="left"?i:"center",i=="top"||i=="bottom"?i:"middle"]}if(i.constructor!=Array){i=["center","middle"]}if(i[0].constructor==Number){d+=i[0]}else{switch(i[0]){case"left":d+=0;break;case"right":d+=e.width()-this.uiDialog.outerWidth();break;default:case"center":d+=(e.width()-this.uiDialog.outerWidth())/2}}if(i[1].constructor==Number){g+=i[1]}else{switch(i[1]){case"top":g+=0;break;case"bottom":g+=e.height()-this.uiDialog.outerHeight();break;default:case"middle":g+=(e.height()-this.uiDialog.outerHeight())/2}}g=Math.max(g,h);this.uiDialog.css({top:g,left:d})},_setData:function(e,f){(b[e]&&this.uiDialog.data(b[e],f));switch(e){case"buttons":this._createButtons(f);break;case"closeText":this.uiDialogTitlebarCloseText.text(f);break;case"dialogClass":this.uiDialog.removeClass(this.options.dialogClass).addClass(a+f);break;case"draggable":(f?this._makeDraggable():this.uiDialog.draggable("destroy"));break;case"height":this.uiDialog.height(f);break;case"position":this._position(f);break;case"resizable":var d=this.uiDialog,g=this.uiDialog.is(":data(resizable)");(g&&!f&&d.resizable("destroy"));(g&&typeof f=="string"&&d.resizable("option","handles",f));(g||this._makeResizable(f));break;case"title":c(".ui-dialog-title",this.uiDialogTitlebar).html(f||" ");break;case"width":this.uiDialog.width(f);break}c.widget.prototype._setData.apply(this,arguments)},_size:function(){var e=this.options;this.element.css({height:0,minHeight:0,width:"auto"});var d=this.uiDialog.css({height:"auto",width:e.width}).height();this.element.css({minHeight:Math.max(e.minHeight-d,0),height:e.height=="auto"?"auto":Math.max(e.height-d,0)})}});c.extend(c.ui.dialog,{version:"1.7.2",defaults:{autoOpen:true,bgiframe:false,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:"center",resizable:true,show:null,stack:true,title:"",width:300,zIndex:1000},getter:"isOpen",uuid:0,maxZ:0,getTitleId:function(d){return"ui-dialog-title-"+(d.attr("id")||++this.uuid)},overlay:function(d){this.$el=c.ui.dialog.overlay.create(d)}});c.extend(c.ui.dialog.overlay,{instances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(d){return d+".dialog-overlay"}).join(" "),create:function(e){if(this.instances.length===0){setTimeout(function(){if(c.ui.dialog.overlay.instances.length){c(document).bind(c.ui.dialog.overlay.events,function(f){var g=c(f.target).parents(".ui-dialog").css("zIndex")||0;return(g>c.ui.dialog.overlay.maxZ)})}},1);c(document).bind("keydown.dialog-overlay",function(f){(e.options.closeOnEscape&&f.keyCode&&f.keyCode==c.ui.keyCode.ESCAPE&&e.close(f))});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var d=c("<div></div>").appendTo(document.body).addClass("ui-widget-overlay").css({width:this.width(),height:this.height()});(e.options.bgiframe&&c.fn.bgiframe&&d.bgiframe());this.instances.push(d);return d},destroy:function(d){this.instances.splice(c.inArray(this.instances,d),1);if(this.instances.length===0){c([document,window]).unbind(".dialog-overlay")}d.remove();var e=0;c.each(this.instances,function(){e=Math.max(e,this.css("z-index"))});this.maxZ=e},height:function(){if(c.browser.msie&&c.browser.version<7){var e=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);var d=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);if(e<d){return c(window).height()+"px"}else{return e+"px"}}else{return c(document).height()+"px"}},width:function(){if(c.browser.msie&&c.browser.version<7){var d=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);var e=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);if(d<e){return c(window).width()+"px"}else{return d+"px"}}else{return c(document).width()+"px"}},resize:function(){var d=c([]);c.each(c.ui.dialog.overlay.instances,function(){d=d.add(this)});d.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);;/* + * jQuery UI Slider 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Slider + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.slider",a.extend({},a.ui.mouse,{_init:function(){var b=this,c=this.options;this._keySliding=false;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");this.range=a([]);if(c.range){if(c.range===true){this.range=a("<div></div>");if(!c.values){c.values=[this._valueMin(),this._valueMin()]}if(c.values.length&&c.values.length!=2){c.values=[c.values[0],c.values[0]]}}else{this.range=a("<div></div>")}this.range.appendTo(this.element).addClass("ui-slider-range");if(c.range=="min"||c.range=="max"){this.range.addClass("ui-slider-range-"+c.range)}this.range.addClass("ui-widget-header")}if(a(".ui-slider-handle",this.element).length==0){a('<a href="#"></a>').appendTo(this.element).addClass("ui-slider-handle")}if(c.values&&c.values.length){while(a(".ui-slider-handle",this.element).length<c.values.length){a('<a href="#"></a>').appendTo(this.element).addClass("ui-slider-handle")}}this.handles=a(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(d){d.preventDefault()}).hover(function(){if(!c.disabled){a(this).addClass("ui-state-hover")}},function(){a(this).removeClass("ui-state-hover")}).focus(function(){if(!c.disabled){a(".ui-slider .ui-state-focus").removeClass("ui-state-focus");a(this).addClass("ui-state-focus")}else{a(this).blur()}}).blur(function(){a(this).removeClass("ui-state-focus")});this.handles.each(function(d){a(this).data("index.ui-slider-handle",d)});this.handles.keydown(function(i){var f=true;var e=a(this).data("index.ui-slider-handle");if(b.options.disabled){return}switch(i.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:f=false;if(!b._keySliding){b._keySliding=true;a(this).addClass("ui-state-active");b._start(i,e)}break}var g,d,h=b._step();if(b.options.values&&b.options.values.length){g=d=b.values(e)}else{g=d=b.value()}switch(i.keyCode){case a.ui.keyCode.HOME:d=b._valueMin();break;case a.ui.keyCode.END:d=b._valueMax();break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g==b._valueMax()){return}d=g+h;break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g==b._valueMin()){return}d=g-h;break}b._slide(i,e,d);return f}).keyup(function(e){var d=a(this).data("index.ui-slider-handle");if(b._keySliding){b._stop(e,d);b._change(e,d);b._keySliding=false;a(this).removeClass("ui-state-active")}});this._refreshValue()},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy()},_mouseCapture:function(d){var e=this.options;if(e.disabled){return false}this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();var h={x:d.pageX,y:d.pageY};var j=this._normValueFromMouse(h);var c=this._valueMax()-this._valueMin()+1,f;var k=this,i;this.handles.each(function(l){var m=Math.abs(j-k.values(l));if(c>m){c=m;f=a(this);i=l}});if(e.range==true&&this.values(1)==e.min){f=a(this.handles[++i])}this._start(d,i);k._handleIndex=i;f.addClass("ui-state-active").focus();var g=f.offset();var b=!a(d.target).parents().andSelf().is(".ui-slider-handle");this._clickOffset=b?{left:0,top:0}:{left:d.pageX-g.left-(f.width()/2),top:d.pageY-g.top-(f.height()/2)-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};j=this._normValueFromMouse(h);this._slide(d,i,j);return true},_mouseStart:function(b){return true},_mouseDrag:function(d){var b={x:d.pageX,y:d.pageY};var c=this._normValueFromMouse(b);this._slide(d,this._handleIndex,c);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._handleIndex=null;this._clickOffset=null;return false},_detectOrientation:function(){this.orientation=this.options.orientation=="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(d){var c,h;if("horizontal"==this.orientation){c=this.elementSize.width;h=d.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{c=this.elementSize.height;h=d.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}var f=(h/c);if(f>1){f=1}if(f<0){f=0}if("vertical"==this.orientation){f=1-f}var e=this._valueMax()-this._valueMin(),i=f*e,b=i%this.options.step,g=this._valueMin()+i-b;if(b>(this.options.step/2)){g+=this.options.step}return parseFloat(g.toFixed(5))},_start:function(d,c){var b={handle:this.handles[c],value:this.value()};if(this.options.values&&this.options.values.length){b.value=this.values(c);b.values=this.values()}this._trigger("start",d,b)},_slide:function(f,e,d){var g=this.handles[e];if(this.options.values&&this.options.values.length){var b=this.values(e?0:1);if((this.options.values.length==2&&this.options.range===true)&&((e==0&&d>b)||(e==1&&d<b))){d=b}if(d!=this.values(e)){var c=this.values();c[e]=d;var h=this._trigger("slide",f,{handle:this.handles[e],value:d,values:c});var b=this.values(e?0:1);if(h!==false){this.values(e,d,(f.type=="mousedown"&&this.options.animate),true)}}}else{if(d!=this.value()){var h=this._trigger("slide",f,{handle:this.handles[e],value:d});if(h!==false){this._setData("value",d,(f.type=="mousedown"&&this.options.animate))}}}},_stop:function(d,c){var b={handle:this.handles[c],value:this.value()};if(this.options.values&&this.options.values.length){b.value=this.values(c);b.values=this.values()}this._trigger("stop",d,b)},_change:function(d,c){var b={handle:this.handles[c],value:this.value()};if(this.options.values&&this.options.values.length){b.value=this.values(c);b.values=this.values()}this._trigger("change",d,b)},value:function(b){if(arguments.length){this._setData("value",b);this._change(null,0)}return this._value()},values:function(b,e,c,d){if(arguments.length>1){this.options.values[b]=e;this._refreshValue(c);if(!d){this._change(null,b)}}if(arguments.length){if(this.options.values&&this.options.values.length){return this._values(b)}else{return this.value()}}else{return this._values()}},_setData:function(b,d,c){a.widget.prototype._setData.apply(this,arguments);switch(b){case"disabled":if(d){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled")}else{this.handles.removeAttr("disabled")}case"orientation":this._detectOrientation();this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue(c);break;case"value":this._refreshValue(c);break}},_step:function(){var b=this.options.step;return b},_value:function(){var b=this.options.value;if(b<this._valueMin()){b=this._valueMin()}if(b>this._valueMax()){b=this._valueMax()}return b},_values:function(b){if(arguments.length){var c=this.options.values[b];if(c<this._valueMin()){c=this._valueMin()}if(c>this._valueMax()){c=this._valueMax()}return c}else{return this.options.values}},_valueMin:function(){var b=this.options.min;return b},_valueMax:function(){var b=this.options.max;return b},_refreshValue:function(c){var f=this.options.range,d=this.options,l=this;if(this.options.values&&this.options.values.length){var i,h;this.handles.each(function(p,n){var o=(l.values(p)-l._valueMin())/(l._valueMax()-l._valueMin())*100;var m={};m[l.orientation=="horizontal"?"left":"bottom"]=o+"%";a(this).stop(1,1)[c?"animate":"css"](m,d.animate);if(l.options.range===true){if(l.orientation=="horizontal"){(p==0)&&l.range.stop(1,1)[c?"animate":"css"]({left:o+"%"},d.animate);(p==1)&&l.range[c?"animate":"css"]({width:(o-lastValPercent)+"%"},{queue:false,duration:d.animate})}else{(p==0)&&l.range.stop(1,1)[c?"animate":"css"]({bottom:(o)+"%"},d.animate);(p==1)&&l.range[c?"animate":"css"]({height:(o-lastValPercent)+"%"},{queue:false,duration:d.animate})}}lastValPercent=o})}else{var j=this.value(),g=this._valueMin(),k=this._valueMax(),e=k!=g?(j-g)/(k-g)*100:0;var b={};b[l.orientation=="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[c?"animate":"css"](b,d.animate);(f=="min")&&(this.orientation=="horizontal")&&this.range.stop(1,1)[c?"animate":"css"]({width:e+"%"},d.animate);(f=="max")&&(this.orientation=="horizontal")&&this.range[c?"animate":"css"]({width:(100-e)+"%"},{queue:false,duration:d.animate});(f=="min")&&(this.orientation=="vertical")&&this.range.stop(1,1)[c?"animate":"css"]({height:e+"%"},d.animate);(f=="max")&&(this.orientation=="vertical")&&this.range[c?"animate":"css"]({height:(100-e)+"%"},{queue:false,duration:d.animate})}}}));a.extend(a.ui.slider,{getter:"value values",version:"1.7.2",eventPrefix:"slide",defaults:{animate:false,delay:0,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null}})})(jQuery);;/* + * jQuery UI Tabs 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Tabs + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.tabs",{_init:function(){if(this.options.deselectable!==undefined){this.options.collapsible=this.options.deselectable}this._tabify(true)},_setData:function(b,c){if(b=="selected"){if(this.options.collapsible&&c==this.options.selected){return}this.select(c)}else{this.options[b]=c;if(b=="deselectable"){this.options.collapsible=c}this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^A-Za-z0-9\-_:\.]/g,"")||this.options.idPrefix+a.data(b)},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+a.data(this.list[0]));return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(c,b){return{tab:c,panel:b,index:this.anchors.index(c)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(n){this.list=this.element.children("ul:first");this.lis=a("li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return a("a",this)[0]});this.panels=a([]);var p=this,d=this.options;var c=/^#.+/;this.anchors.each(function(r,o){var q=a(o).attr("href");var s=q.split("#")[0],u;if(s&&(s===location.toString().split("#")[0]||(u=a("base")[0])&&s===u.href)){q=o.hash;o.href=q}if(c.test(q)){p.panels=p.panels.add(p._sanitizeSelector(q))}else{if(q!="#"){a.data(o,"href.tabs",q);a.data(o,"load.tabs",q.replace(/#.*$/,""));var w=p._tabId(o);o.href="#"+w;var v=a("#"+w);if(!v.length){v=a(d.panelTemplate).attr("id",w).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(p.panels[r-1]||p.list);v.data("destroy.tabs",true)}p.panels=p.panels.add(v)}else{d.disabled.push(r)}}});if(n){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(d.selected===undefined){if(location.hash){this.anchors.each(function(q,o){if(o.hash==location.hash){d.selected=q;return false}})}if(typeof d.selected!="number"&&d.cookie){d.selected=parseInt(p._cookie(),10)}if(typeof d.selected!="number"&&this.lis.filter(".ui-tabs-selected").length){d.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}d.selected=d.selected||0}else{if(d.selected===null){d.selected=-1}}d.selected=((d.selected>=0&&this.anchors[d.selected])||d.selected<0)?d.selected:0;d.disabled=a.unique(d.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(q,o){return p.lis.index(q)}))).sort();if(a.inArray(d.selected,d.disabled)!=-1){d.disabled.splice(a.inArray(d.selected,d.disabled),1)}this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");if(d.selected>=0&&this.anchors.length){this.panels.eq(d.selected).removeClass("ui-tabs-hide");this.lis.eq(d.selected).addClass("ui-tabs-selected ui-state-active");p.element.queue("tabs",function(){p._trigger("show",null,p._ui(p.anchors[d.selected],p.panels[d.selected]))});this.load(d.selected)}a(window).bind("unload",function(){p.lis.add(p.anchors).unbind(".tabs");p.lis=p.anchors=p.panels=null})}else{d.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}this.element[d.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");if(d.cookie){this._cookie(d.selected,d.cookie)}for(var g=0,m;(m=this.lis[g]);g++){a(m)[a.inArray(g,d.disabled)!=-1&&!a(m).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled")}if(d.cache===false){this.anchors.removeData("cache.tabs")}this.lis.add(this.anchors).unbind(".tabs");if(d.event!="mouseover"){var f=function(o,i){if(i.is(":not(.ui-state-disabled)")){i.addClass("ui-state-"+o)}};var j=function(o,i){i.removeClass("ui-state-"+o)};this.lis.bind("mouseover.tabs",function(){f("hover",a(this))});this.lis.bind("mouseout.tabs",function(){j("hover",a(this))});this.anchors.bind("focus.tabs",function(){f("focus",a(this).closest("li"))});this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var b,h;if(d.fx){if(a.isArray(d.fx)){b=d.fx[0];h=d.fx[1]}else{b=h=d.fx}}function e(i,o){i.css({display:""});if(a.browser.msie&&o.opacity){i[0].style.removeAttribute("filter")}}var k=h?function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.hide().removeClass("ui-tabs-hide").animate(h,h.duration||"normal",function(){e(o,h);p._trigger("show",null,p._ui(i,o[0]))})}:function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.removeClass("ui-tabs-hide");p._trigger("show",null,p._ui(i,o[0]))};var l=b?function(o,i){i.animate(b,b.duration||"normal",function(){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");e(i,b);p.element.dequeue("tabs")})}:function(o,i,q){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");p.element.dequeue("tabs")};this.anchors.bind(d.event+".tabs",function(){var o=this,r=a(this).closest("li"),i=p.panels.filter(":not(.ui-tabs-hide)"),q=a(p._sanitizeSelector(this.hash));if((r.hasClass("ui-tabs-selected")&&!d.collapsible)||r.hasClass("ui-state-disabled")||r.hasClass("ui-state-processing")||p._trigger("select",null,p._ui(this,q[0]))===false){this.blur();return false}d.selected=p.anchors.index(this);p.abort();if(d.collapsible){if(r.hasClass("ui-tabs-selected")){d.selected=-1;if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){l(o,i)}).dequeue("tabs");this.blur();return false}else{if(!i.length){if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this));this.blur();return false}}}if(d.cookie){p._cookie(d.selected,d.cookie)}if(q.length){if(i.length){p.element.queue("tabs",function(){l(o,i)})}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this))}else{throw"jQuery UI Tabs: Mismatching fragment identifier."}if(a.browser.msie){this.blur()}});this.anchors.bind("click.tabs",function(){return false})},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var c=a.data(this,"href.tabs");if(c){this.href=c}var d=a(this).unbind(".tabs");a.each(["href","load","cache"],function(e,f){d.removeData(f+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){if(a.data(this,"destroy.tabs")){a(this).remove()}else{a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}});if(b.cookie){this._cookie(null,b.cookie)}},add:function(e,d,c){if(c===undefined){c=this.anchors.length}var b=this,g=this.options,i=a(g.tabTemplate.replace(/#\{href\}/g,e).replace(/#\{label\}/g,d)),h=!e.indexOf("#")?e.replace("#",""):this._tabId(a("a",i)[0]);i.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var f=a("#"+h);if(!f.length){f=a(g.panelTemplate).attr("id",h).data("destroy.tabs",true)}f.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(c>=this.lis.length){i.appendTo(this.list);f.appendTo(this.list[0].parentNode)}else{i.insertBefore(this.lis[c]);f.insertBefore(this.panels[c])}g.disabled=a.map(g.disabled,function(k,j){return k>=c?++k:k});this._tabify();if(this.anchors.length==1){i.addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){b._trigger("show",null,b._ui(b.anchors[0],b.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[c],this.panels[c]))},remove:function(b){var d=this.options,e=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();if(e.hasClass("ui-tabs-selected")&&this.anchors.length>1){this.select(b+(b+1<this.anchors.length?1:-1))}d.disabled=a.map(a.grep(d.disabled,function(g,f){return g!=b}),function(g,f){return g>=b?--g:g});this._tabify();this._trigger("remove",null,this._ui(e.find("a")[0],c[0]))},enable:function(b){var c=this.options;if(a.inArray(b,c.disabled)==-1){return}this.lis.eq(b).removeClass("ui-state-disabled");c.disabled=a.grep(c.disabled,function(e,d){return e!=b});this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b]))},disable:function(c){var b=this,d=this.options;if(c!=d.selected){this.lis.eq(c).addClass("ui-state-disabled");d.disabled.push(c);d.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[c],this.panels[c]))}},select:function(b){if(typeof b=="string"){b=this.anchors.index(this.anchors.filter("[href$="+b+"]"))}else{if(b===null){b=-1}}if(b==-1&&this.options.collapsible){b=this.options.selected}this.anchors.eq(b).trigger(this.options.event+".tabs")},load:function(e){var c=this,g=this.options,b=this.anchors.eq(e)[0],d=a.data(b,"load.tabs");this.abort();if(!d||this.element.queue("tabs").length!==0&&a.data(b,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(e).addClass("ui-state-processing");if(g.spinner){var f=a("span",b);f.data("label.tabs",f.html()).html(g.spinner)}this.xhr=a.ajax(a.extend({},g.ajaxOptions,{url:d,success:function(i,h){a(c._sanitizeSelector(b.hash)).html(i);c._cleanup();if(g.cache){a.data(b,"cache.tabs",true)}c._trigger("load",null,c._ui(c.anchors[e],c.panels[e]));try{g.ajaxOptions.success(i,h)}catch(j){}c.element.dequeue("tabs")}}))},abort:function(){this.element.queue([]);this.panels.stop(false,true);if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup()},url:function(c,b){this.anchors.eq(c).removeData("cache.tabs").data("load.tabs",b)},length:function(){return this.anchors.length}});a.extend(a.ui.tabs,{version:"1.7.2",getter:"length",defaults:{ajaxOptions:null,cache:false,cookie:null,collapsible:false,disabled:[],event:"click",fx:null,idPrefix:"ui-tabs-",panelTemplate:"<div></div>",spinner:"<em>Loading…</em>",tabTemplate:'<li><a href="#{href}"><span>#{label}</span></a></li>'}});a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(d,f){var b=this,g=this.options;var c=b._rotate||(b._rotate=function(h){clearTimeout(b.rotation);b.rotation=setTimeout(function(){var i=g.selected;b.select(++i<b.anchors.length?i:0)},d);if(h){h.stopPropagation()}});var e=b._unrotate||(b._unrotate=!f?function(h){if(h.clientX){b.rotate(null)}}:function(h){t=g.selected;c()});if(d){this.element.bind("tabsshow",c);this.anchors.bind(g.event+".tabs",e);c()}else{clearTimeout(b.rotation);this.element.unbind("tabsshow",c);this.anchors.unbind(g.event+".tabs",e);delete this._rotate;delete this._unrotate}}})})(jQuery);;/* + * jQuery UI Datepicker 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Datepicker + * + * Depends: + * ui.core.js + */ +(function($){$.extend($.ui,{datepicker:{version:"1.7.2"}});var PROP_NAME="datepicker";function Datepicker(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._datepickerShowing=false;this._inDialog=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass="ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],dateFormat:"mm/dd/yy",firstDay:0,isRTL:false};this._defaults={showOn:"focus",showAnim:"show",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,showMonthAfterYear:false,yearRange:"-10:+10",showOtherMonths:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"normal",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false};$.extend(this._defaults,this.regional[""]);this.dpDiv=$('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible"></div>')}$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",log:function(){if(this.debug){console.log.apply("",arguments)}},setDefaults:function(settings){extendRemove(this._defaults,settings||{});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();var inline=(nodeName=="div"||nodeName=="span");if(!target.id){target.id="dp"+(++this.uuid)}var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{});if(nodeName=="input"){this._connectDatepicker(target,inst)}else{if(inline){this._inlineDatepicker(target,inst)}}},_newInst:function(target,inline){var id=target[0].id.replace(/([:\[\]\.])/g,"\\\\$1");return{id:id,input:target,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:inline,dpDiv:(!inline?this.dpDiv:$('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}},_connectDatepicker:function(target,inst){var input=$(target);inst.append=$([]);inst.trigger=$([]);if(input.hasClass(this.markerClassName)){return}var appendText=this._get(inst,"appendText");var isRTL=this._get(inst,"isRTL");if(appendText){inst.append=$('<span class="'+this._appendClass+'">'+appendText+"</span>");input[isRTL?"before":"after"](inst.append)}var showOn=this._get(inst,"showOn");if(showOn=="focus"||showOn=="both"){input.focus(this._showDatepicker)}if(showOn=="button"||showOn=="both"){var buttonText=this._get(inst,"buttonText");var buttonImage=this._get(inst,"buttonImage");inst.trigger=$(this._get(inst,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:buttonImage,alt:buttonText,title:buttonText}):$('<button type="button"></button>').addClass(this._triggerClass).html(buttonImage==""?buttonText:$("<img/>").attr({src:buttonImage,alt:buttonText,title:buttonText})));input[isRTL?"before":"after"](inst.trigger);inst.trigger.click(function(){if($.datepicker._datepickerShowing&&$.datepicker._lastInput==target){$.datepicker._hideDatepicker()}else{$.datepicker._showDatepicker(target)}return false})}input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst)},_inlineDatepicker:function(target,inst){var divSpan=$(target);if(divSpan.hasClass(this.markerClassName)){return}divSpan.addClass(this.markerClassName).append(inst.dpDiv).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst);this._setDate(inst,this._getDefaultDate(inst));this._updateDatepicker(inst);this._updateAlternate(inst)},_dialogDatepicker:function(input,dateText,onSelect,settings,pos){var inst=this._dialogInst;if(!inst){var id="dp"+(++this.uuid);this._dialogInput=$('<input type="text" id="'+id+'" size="1" style="position: absolute; top: -100px;"/>');this._dialogInput.keydown(this._doKeyDown);$("body").append(this._dialogInput);inst=this._dialogInst=this._newInst(this._dialogInput,false);inst.settings={};$.data(this._dialogInput[0],PROP_NAME,inst)}extendRemove(inst.settings,settings||{});this._dialogInput.val(dateText);this._pos=(pos?(pos.length?pos:[pos.pageX,pos.pageY]):null);if(!this._pos){var browserWidth=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;var browserHeight=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;var scrollX=document.documentElement.scrollLeft||document.body.scrollLeft;var scrollY=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[(browserWidth/2)-100+scrollX,(browserHeight/2)-150+scrollY]}this._dialogInput.css("left",this._pos[0]+"px").css("top",this._pos[1]+"px");inst.settings.onSelect=onSelect;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);if($.blockUI){$.blockUI(this.dpDiv)}$.data(this._dialogInput[0],PROP_NAME,inst);return this},_destroyDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();$.removeData(target,PROP_NAME);if(nodeName=="input"){inst.append.remove();inst.trigger.remove();$target.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress)}else{if(nodeName=="div"||nodeName=="span"){$target.removeClass(this.markerClassName).empty()}}},_enableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=false;inst.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().removeClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)})},_disableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=true;inst.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().addClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)});this._disabledInputs[this._disabledInputs.length]=target},_isDisabledDatepicker:function(target){if(!target){return false}for(var i=0;i<this._disabledInputs.length;i++){if(this._disabledInputs[i]==target){return true}}return false},_getInst:function(target){try{return $.data(target,PROP_NAME)}catch(err){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(target,name,value){var inst=this._getInst(target);if(arguments.length==2&&typeof name=="string"){return(name=="defaults"?$.extend({},$.datepicker._defaults):(inst?(name=="all"?$.extend({},inst.settings):this._get(inst,name)):null))}var settings=name||{};if(typeof name=="string"){settings={};settings[name]=value}if(inst){if(this._curInst==inst){this._hideDatepicker(null)}var date=this._getDateDatepicker(target);extendRemove(inst.settings,settings);this._setDateDatepicker(target,date);this._updateDatepicker(inst)}},_changeDatepicker:function(target,name,value){this._optionDatepicker(target,name,value)},_refreshDatepicker:function(target){var inst=this._getInst(target);if(inst){this._updateDatepicker(inst)}},_setDateDatepicker:function(target,date,endDate){var inst=this._getInst(target);if(inst){this._setDate(inst,date,endDate);this._updateDatepicker(inst);this._updateAlternate(inst)}},_getDateDatepicker:function(target){var inst=this._getInst(target);if(inst&&!inst.inline){this._setDateFromField(inst)}return(inst?this._getDate(inst):null)},_doKeyDown:function(event){var inst=$.datepicker._getInst(event.target);var handled=true;var isRTL=inst.dpDiv.is(".ui-datepicker-rtl");inst._keyEvent=true;if($.datepicker._datepickerShowing){switch(event.keyCode){case 9:$.datepicker._hideDatepicker(null,"");break;case 13:var sel=$("td."+$.datepicker._dayOverClass+", td."+$.datepicker._currentClass,inst.dpDiv);if(sel[0]){$.datepicker._selectDay(event.target,inst.selectedMonth,inst.selectedYear,sel[0])}else{$.datepicker._hideDatepicker(null,$.datepicker._get(inst,"duration"))}return false;break;case 27:$.datepicker._hideDatepicker(null,$.datepicker._get(inst,"duration"));break;case 33:$.datepicker._adjustDate(event.target,(event.ctrlKey?-$.datepicker._get(inst,"stepBigMonths"):-$.datepicker._get(inst,"stepMonths")),"M");break;case 34:$.datepicker._adjustDate(event.target,(event.ctrlKey?+$.datepicker._get(inst,"stepBigMonths"):+$.datepicker._get(inst,"stepMonths")),"M");break;case 35:if(event.ctrlKey||event.metaKey){$.datepicker._clearDate(event.target)}handled=event.ctrlKey||event.metaKey;break;case 36:if(event.ctrlKey||event.metaKey){$.datepicker._gotoToday(event.target)}handled=event.ctrlKey||event.metaKey;break;case 37:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,(isRTL?+1:-1),"D")}handled=event.ctrlKey||event.metaKey;if(event.originalEvent.altKey){$.datepicker._adjustDate(event.target,(event.ctrlKey?-$.datepicker._get(inst,"stepBigMonths"):-$.datepicker._get(inst,"stepMonths")),"M")}break;case 38:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,-7,"D")}handled=event.ctrlKey||event.metaKey;break;case 39:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,(isRTL?-1:+1),"D")}handled=event.ctrlKey||event.metaKey;if(event.originalEvent.altKey){$.datepicker._adjustDate(event.target,(event.ctrlKey?+$.datepicker._get(inst,"stepBigMonths"):+$.datepicker._get(inst,"stepMonths")),"M")}break;case 40:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,+7,"D")}handled=event.ctrlKey||event.metaKey;break;default:handled=false}}else{if(event.keyCode==36&&event.ctrlKey){$.datepicker._showDatepicker(this)}else{handled=false}}if(handled){event.preventDefault();event.stopPropagation()}},_doKeyPress:function(event){var inst=$.datepicker._getInst(event.target);if($.datepicker._get(inst,"constrainInput")){var chars=$.datepicker._possibleChars($.datepicker._get(inst,"dateFormat"));var chr=String.fromCharCode(event.charCode==undefined?event.keyCode:event.charCode);return event.ctrlKey||(chr<" "||!chars||chars.indexOf(chr)>-1)}},_showDatepicker:function(input){input=input.target||input;if(input.nodeName.toLowerCase()!="input"){input=$("input",input.parentNode)[0]}if($.datepicker._isDisabledDatepicker(input)||$.datepicker._lastInput==input){return}var inst=$.datepicker._getInst(input);var beforeShow=$.datepicker._get(inst,"beforeShow");extendRemove(inst.settings,(beforeShow?beforeShow.apply(input,[input,inst]):{}));$.datepicker._hideDatepicker(null,"");$.datepicker._lastInput=input;$.datepicker._setDateFromField(inst);if($.datepicker._inDialog){input.value=""}if(!$.datepicker._pos){$.datepicker._pos=$.datepicker._findPos(input);$.datepicker._pos[1]+=input.offsetHeight}var isFixed=false;$(input).parents().each(function(){isFixed|=$(this).css("position")=="fixed";return !isFixed});if(isFixed&&$.browser.opera){$.datepicker._pos[0]-=document.documentElement.scrollLeft;$.datepicker._pos[1]-=document.documentElement.scrollTop}var offset={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null;inst.rangeStart=null;inst.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});$.datepicker._updateDatepicker(inst);offset=$.datepicker._checkOffset(inst,offset,isFixed);inst.dpDiv.css({position:($.datepicker._inDialog&&$.blockUI?"static":(isFixed?"fixed":"absolute")),display:"none",left:offset.left+"px",top:offset.top+"px"});if(!inst.inline){var showAnim=$.datepicker._get(inst,"showAnim")||"show";var duration=$.datepicker._get(inst,"duration");var postProcess=function(){$.datepicker._datepickerShowing=true;if($.browser.msie&&parseInt($.browser.version,10)<7){$("iframe.ui-datepicker-cover").css({width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4})}};if($.effects&&$.effects[showAnim]){inst.dpDiv.show(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[showAnim](duration,postProcess)}if(duration==""){postProcess()}if(inst.input[0].type!="hidden"){inst.input[0].focus()}$.datepicker._curInst=inst}},_updateDatepicker:function(inst){var dims={width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4};var self=this;inst.dpDiv.empty().append(this._generateHTML(inst)).find("iframe.ui-datepicker-cover").css({width:dims.width,height:dims.height}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){$(this).removeClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).removeClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).removeClass("ui-datepicker-next-hover")}}).bind("mouseover",function(){if(!self._isDisabledDatepicker(inst.inline?inst.dpDiv.parent()[0]:inst.input[0])){$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");$(this).addClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).addClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).addClass("ui-datepicker-next-hover")}}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();var numMonths=this._getNumberOfMonths(inst);var cols=numMonths[1];var width=17;if(cols>1){inst.dpDiv.addClass("ui-datepicker-multi-"+cols).css("width",(width*cols)+"em")}else{inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("")}inst.dpDiv[(numMonths[0]!=1||numMonths[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");inst.dpDiv[(this._get(inst,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");if(inst.input&&inst.input[0].type!="hidden"&&inst==$.datepicker._curInst){$(inst.input[0]).focus()}},_checkOffset:function(inst,offset,isFixed){var dpWidth=inst.dpDiv.outerWidth();var dpHeight=inst.dpDiv.outerHeight();var inputWidth=inst.input?inst.input.outerWidth():0;var inputHeight=inst.input?inst.input.outerHeight():0;var viewWidth=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)+$(document).scrollLeft();var viewHeight=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)+$(document).scrollTop();offset.left-=(this._get(inst,"isRTL")?(dpWidth-inputWidth):0);offset.left-=(isFixed&&offset.left==inst.input.offset().left)?$(document).scrollLeft():0;offset.top-=(isFixed&&offset.top==(inst.input.offset().top+inputHeight))?$(document).scrollTop():0;offset.left-=(offset.left+dpWidth>viewWidth&&viewWidth>dpWidth)?Math.abs(offset.left+dpWidth-viewWidth):0;offset.top-=(offset.top+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(offset.top+dpHeight+inputHeight*2-viewHeight):0;return offset},_findPos:function(obj){while(obj&&(obj.type=="hidden"||obj.nodeType!=1)){obj=obj.nextSibling}var position=$(obj).offset();return[position.left,position.top]},_hideDatepicker:function(input,duration){var inst=this._curInst;if(!inst||(input&&inst!=$.data(input,PROP_NAME))){return}if(inst.stayOpen){this._selectDate("#"+inst.id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear))}inst.stayOpen=false;if(this._datepickerShowing){duration=(duration!=null?duration:this._get(inst,"duration"));var showAnim=this._get(inst,"showAnim");var postProcess=function(){$.datepicker._tidyDialog(inst)};if(duration!=""&&$.effects&&$.effects[showAnim]){inst.dpDiv.hide(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[(duration==""?"hide":(showAnim=="slideDown"?"slideUp":(showAnim=="fadeIn"?"fadeOut":"hide")))](duration,postProcess)}if(duration==""){this._tidyDialog(inst)}var onClose=this._get(inst,"onClose");if(onClose){onClose.apply((inst.input?inst.input[0]:null),[(inst.input?inst.input.val():""),inst])}this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if($.blockUI){$.unblockUI();$("body").append(this.dpDiv)}}this._inDialog=false}this._curInst=null},_tidyDialog:function(inst){inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(event){if(!$.datepicker._curInst){return}var $target=$(event.target);if(($target.parents("#"+$.datepicker._mainDivId).length==0)&&!$target.hasClass($.datepicker.markerClassName)&&!$target.hasClass($.datepicker._triggerClass)&&$.datepicker._datepickerShowing&&!($.datepicker._inDialog&&$.blockUI)){$.datepicker._hideDatepicker(null,"")}},_adjustDate:function(id,offset,period){var target=$(id);var inst=this._getInst(target[0]);if(this._isDisabledDatepicker(target[0])){return}this._adjustInstDate(inst,offset+(period=="M"?this._get(inst,"showCurrentAtPos"):0),period);this._updateDatepicker(inst)},_gotoToday:function(id){var target=$(id);var inst=this._getInst(target[0]);if(this._get(inst,"gotoCurrent")&&inst.currentDay){inst.selectedDay=inst.currentDay;inst.drawMonth=inst.selectedMonth=inst.currentMonth;inst.drawYear=inst.selectedYear=inst.currentYear}else{var date=new Date();inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear()}this._notifyChange(inst);this._adjustDate(target)},_selectMonthYear:function(id,select,period){var target=$(id);var inst=this._getInst(target[0]);inst._selectingMonthYear=false;inst["selected"+(period=="M"?"Month":"Year")]=inst["draw"+(period=="M"?"Month":"Year")]=parseInt(select.options[select.selectedIndex].value,10);this._notifyChange(inst);this._adjustDate(target)},_clickMonthYear:function(id){var target=$(id);var inst=this._getInst(target[0]);if(inst.input&&inst._selectingMonthYear&&!$.browser.msie){inst.input[0].focus()}inst._selectingMonthYear=!inst._selectingMonthYear},_selectDay:function(id,month,year,td){var target=$(id);if($(td).hasClass(this._unselectableClass)||this._isDisabledDatepicker(target[0])){return}var inst=this._getInst(target[0]);inst.selectedDay=inst.currentDay=$("a",td).html();inst.selectedMonth=inst.currentMonth=month;inst.selectedYear=inst.currentYear=year;if(inst.stayOpen){inst.endDay=inst.endMonth=inst.endYear=null}this._selectDate(id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear));if(inst.stayOpen){inst.rangeStart=this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay));this._updateDatepicker(inst)}},_clearDate:function(id){var target=$(id);var inst=this._getInst(target[0]);inst.stayOpen=false;inst.endDay=inst.endMonth=inst.endYear=inst.rangeStart=null;this._selectDate(target,"")},_selectDate:function(id,dateStr){var target=$(id);var inst=this._getInst(target[0]);dateStr=(dateStr!=null?dateStr:this._formatDate(inst));if(inst.input){inst.input.val(dateStr)}this._updateAlternate(inst);var onSelect=this._get(inst,"onSelect");if(onSelect){onSelect.apply((inst.input?inst.input[0]:null),[dateStr,inst])}else{if(inst.input){inst.input.trigger("change")}}if(inst.inline){this._updateDatepicker(inst)}else{if(!inst.stayOpen){this._hideDatepicker(null,this._get(inst,"duration"));this._lastInput=inst.input[0];if(typeof(inst.input[0])!="object"){inst.input[0].focus()}this._lastInput=null}}},_updateAlternate:function(inst){var altField=this._get(inst,"altField");if(altField){var altFormat=this._get(inst,"altFormat")||this._get(inst,"dateFormat");var date=this._getDate(inst);dateStr=this.formatDate(altFormat,date,this._getFormatConfig(inst));$(altField).each(function(){$(this).val(dateStr)})}},noWeekends:function(date){var day=date.getDay();return[(day>0&&day<6),""]},iso8601Week:function(date){var checkDate=new Date(date.getFullYear(),date.getMonth(),date.getDate());var firstMon=new Date(checkDate.getFullYear(),1-1,4);var firstDay=firstMon.getDay()||7;firstMon.setDate(firstMon.getDate()+1-firstDay);if(firstDay<4&&checkDate<firstMon){checkDate.setDate(checkDate.getDate()-3);return $.datepicker.iso8601Week(checkDate)}else{if(checkDate>new Date(checkDate.getFullYear(),12-1,28)){firstDay=new Date(checkDate.getFullYear()+1,1-1,4).getDay()||7;if(firstDay>4&&(checkDate.getDay()||7)<firstDay-3){return 1}}}return Math.floor(((checkDate-firstMon)/86400000)/7)+1},parseDate:function(format,value,settings){if(format==null||value==null){throw"Invalid arguments"}value=(typeof value=="object"?value.toString():value+"");if(value==""){return null}var shortYearCutoff=(settings?settings.shortYearCutoff:null)||this._defaults.shortYearCutoff;var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var year=-1;var month=-1;var day=-1;var doy=-1;var literal=false;var lookAhead=function(match){var matches=(iFormat+1<format.length&&format.charAt(iFormat+1)==match);if(matches){iFormat++}return matches};var getNumber=function(match){lookAhead(match);var origSize=(match=="@"?14:(match=="y"?4:(match=="o"?3:2)));var size=origSize;var num=0;while(size>0&&iValue<value.length&&value.charAt(iValue)>="0"&&value.charAt(iValue)<="9"){num=num*10+parseInt(value.charAt(iValue++),10);size--}if(size==origSize){throw"Missing number at position "+iValue}return num};var getName=function(match,shortNames,longNames){var names=(lookAhead(match)?longNames:shortNames);var size=0;for(var j=0;j<names.length;j++){size=Math.max(size,names[j].length)}var name="";var iInit=iValue;while(size>0&&iValue<value.length){name+=value.charAt(iValue++);for(var i=0;i<names.length;i++){if(name==names[i]){return i+1}}size--}throw"Unknown name at position "+iInit};var checkLiteral=function(){if(value.charAt(iValue)!=format.charAt(iFormat)){throw"Unexpected literal at position "+iValue}iValue++};var iValue=0;for(var iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)=="'"&&!lookAhead("'")){literal=false}else{checkLiteral()}}else{switch(format.charAt(iFormat)){case"d":day=getNumber("d");break;case"D":getName("D",dayNamesShort,dayNames);break;case"o":doy=getNumber("o");break;case"m":month=getNumber("m");break;case"M":month=getName("M",monthNamesShort,monthNames);break;case"y":year=getNumber("y");break;case"@":var date=new Date(getNumber("@"));year=date.getFullYear();month=date.getMonth()+1;day=date.getDate();break;case"'":if(lookAhead("'")){checkLiteral()}else{literal=true}break;default:checkLiteral()}}}if(year==-1){year=new Date().getFullYear()}else{if(year<100){year+=new Date().getFullYear()-new Date().getFullYear()%100+(year<=shortYearCutoff?0:-100)}}if(doy>-1){month=1;day=doy;do{var dim=this._getDaysInMonth(year,month-1);if(day<=dim){break}month++;day-=dim}while(true)}var date=this._daylightSavingAdjust(new Date(year,month-1,day));if(date.getFullYear()!=year||date.getMonth()+1!=month||date.getDate()!=day){throw"Invalid date"}return date},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",TIMESTAMP:"@",W3C:"yy-mm-dd",formatDate:function(format,date,settings){if(!date){return""}var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var lookAhead=function(match){var matches=(iFormat+1<format.length&&format.charAt(iFormat+1)==match);if(matches){iFormat++}return matches};var formatNumber=function(match,value,len){var num=""+value;if(lookAhead(match)){while(num.length<len){num="0"+num}}return num};var formatName=function(match,value,shortNames,longNames){return(lookAhead(match)?longNames[value]:shortNames[value])};var output="";var literal=false;if(date){for(var iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)=="'"&&!lookAhead("'")){literal=false}else{output+=format.charAt(iFormat)}}else{switch(format.charAt(iFormat)){case"d":output+=formatNumber("d",date.getDate(),2);break;case"D":output+=formatName("D",date.getDay(),dayNamesShort,dayNames);break;case"o":var doy=date.getDate();for(var m=date.getMonth()-1;m>=0;m--){doy+=this._getDaysInMonth(date.getFullYear(),m)}output+=formatNumber("o",doy,3);break;case"m":output+=formatNumber("m",date.getMonth()+1,2);break;case"M":output+=formatName("M",date.getMonth(),monthNamesShort,monthNames);break;case"y":output+=(lookAhead("y")?date.getFullYear():(date.getYear()%100<10?"0":"")+date.getYear()%100);break;case"@":output+=date.getTime();break;case"'":if(lookAhead("'")){output+="'"}else{literal=true}break;default:output+=format.charAt(iFormat)}}}}return output},_possibleChars:function(format){var chars="";var literal=false;for(var iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)=="'"&&!lookAhead("'")){literal=false}else{chars+=format.charAt(iFormat)}}else{switch(format.charAt(iFormat)){case"d":case"m":case"y":case"@":chars+="0123456789";break;case"D":case"M":return null;case"'":if(lookAhead("'")){chars+="'"}else{literal=true}break;default:chars+=format.charAt(iFormat)}}}return chars},_get:function(inst,name){return inst.settings[name]!==undefined?inst.settings[name]:this._defaults[name]},_setDateFromField:function(inst){var dateFormat=this._get(inst,"dateFormat");var dates=inst.input?inst.input.val():null;inst.endDay=inst.endMonth=inst.endYear=null;var date=defaultDate=this._getDefaultDate(inst);var settings=this._getFormatConfig(inst);try{date=this.parseDate(dateFormat,dates,settings)||defaultDate}catch(event){this.log(event);date=defaultDate}inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();inst.currentDay=(dates?date.getDate():0);inst.currentMonth=(dates?date.getMonth():0);inst.currentYear=(dates?date.getFullYear():0);this._adjustInstDate(inst)},_getDefaultDate:function(inst){var date=this._determineDate(this._get(inst,"defaultDate"),new Date());var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");date=(minDate&&date<minDate?minDate:date);date=(maxDate&&date>maxDate?maxDate:date);return date},_determineDate:function(date,defaultDate){var offsetNumeric=function(offset){var date=new Date();date.setDate(date.getDate()+offset);return date};var offsetString=function(offset,getDaysInMonth){var date=new Date();var year=date.getFullYear();var month=date.getMonth();var day=date.getDate();var pattern=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;var matches=pattern.exec(offset);while(matches){switch(matches[2]||"d"){case"d":case"D":day+=parseInt(matches[1],10);break;case"w":case"W":day+=parseInt(matches[1],10)*7;break;case"m":case"M":month+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break;case"y":case"Y":year+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break}matches=pattern.exec(offset)}return new Date(year,month,day)};date=(date==null?defaultDate:(typeof date=="string"?offsetString(date,this._getDaysInMonth):(typeof date=="number"?(isNaN(date)?defaultDate:offsetNumeric(date)):date)));date=(date&&date.toString()=="Invalid Date"?defaultDate:date);if(date){date.setHours(0);date.setMinutes(0);date.setSeconds(0);date.setMilliseconds(0)}return this._daylightSavingAdjust(date)},_daylightSavingAdjust:function(date){if(!date){return null}date.setHours(date.getHours()>12?date.getHours()+2:0);return date},_setDate:function(inst,date,endDate){var clear=!(date);var origMonth=inst.selectedMonth;var origYear=inst.selectedYear;date=this._determineDate(date,new Date());inst.selectedDay=inst.currentDay=date.getDate();inst.drawMonth=inst.selectedMonth=inst.currentMonth=date.getMonth();inst.drawYear=inst.selectedYear=inst.currentYear=date.getFullYear();if(origMonth!=inst.selectedMonth||origYear!=inst.selectedYear){this._notifyChange(inst)}this._adjustInstDate(inst);if(inst.input){inst.input.val(clear?"":this._formatDate(inst))}},_getDate:function(inst){var startDate=(!inst.currentYear||(inst.input&&inst.input.val()=="")?null:this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return startDate},_generateHTML:function(inst){var today=new Date();today=this._daylightSavingAdjust(new Date(today.getFullYear(),today.getMonth(),today.getDate()));var isRTL=this._get(inst,"isRTL");var showButtonPanel=this._get(inst,"showButtonPanel");var hideIfNoPrevNext=this._get(inst,"hideIfNoPrevNext");var navigationAsDateFormat=this._get(inst,"navigationAsDateFormat");var numMonths=this._getNumberOfMonths(inst);var showCurrentAtPos=this._get(inst,"showCurrentAtPos");var stepMonths=this._get(inst,"stepMonths");var stepBigMonths=this._get(inst,"stepBigMonths");var isMultiMonth=(numMonths[0]!=1||numMonths[1]!=1);var currentDate=this._daylightSavingAdjust((!inst.currentDay?new Date(9999,9,9):new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");var drawMonth=inst.drawMonth-showCurrentAtPos;var drawYear=inst.drawYear;if(drawMonth<0){drawMonth+=12;drawYear--}if(maxDate){var maxDraw=this._daylightSavingAdjust(new Date(maxDate.getFullYear(),maxDate.getMonth()-numMonths[1]+1,maxDate.getDate()));maxDraw=(minDate&&maxDraw<minDate?minDate:maxDraw);while(this._daylightSavingAdjust(new Date(drawYear,drawMonth,1))>maxDraw){drawMonth--;if(drawMonth<0){drawMonth=11;drawYear--}}}inst.drawMonth=drawMonth;inst.drawYear=drawYear;var prevText=this._get(inst,"prevText");prevText=(!navigationAsDateFormat?prevText:this.formatDate(prevText,this._daylightSavingAdjust(new Date(drawYear,drawMonth-stepMonths,1)),this._getFormatConfig(inst)));var prev=(this._canAdjustMonth(inst,-1,drawYear,drawMonth)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery.datepicker._adjustDate(\'#'+inst.id+"', -"+stepMonths+", 'M');\" title=\""+prevText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"e":"w")+'">'+prevText+"</span></a>":(hideIfNoPrevNext?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+prevText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"e":"w")+'">'+prevText+"</span></a>"));var nextText=this._get(inst,"nextText");nextText=(!navigationAsDateFormat?nextText:this.formatDate(nextText,this._daylightSavingAdjust(new Date(drawYear,drawMonth+stepMonths,1)),this._getFormatConfig(inst)));var next=(this._canAdjustMonth(inst,+1,drawYear,drawMonth)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery.datepicker._adjustDate(\'#'+inst.id+"', +"+stepMonths+", 'M');\" title=\""+nextText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"w":"e")+'">'+nextText+"</span></a>":(hideIfNoPrevNext?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+nextText+'"><span class="ui-icon ui-icon-circle-triangle-'+(isRTL?"w":"e")+'">'+nextText+"</span></a>"));var currentText=this._get(inst,"currentText");var gotoDate=(this._get(inst,"gotoCurrent")&&inst.currentDay?currentDate:today);currentText=(!navigationAsDateFormat?currentText:this.formatDate(currentText,gotoDate,this._getFormatConfig(inst)));var controls=(!inst.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery.datepicker._hideDatepicker();">'+this._get(inst,"closeText")+"</button>":"");var buttonPanel=(showButtonPanel)?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(isRTL?controls:"")+(this._isInRange(inst,gotoDate)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery.datepicker._gotoToday(\'#'+inst.id+"');\">"+currentText+"</button>":"")+(isRTL?"":controls)+"</div>":"";var firstDay=parseInt(this._get(inst,"firstDay"),10);firstDay=(isNaN(firstDay)?0:firstDay);var dayNames=this._get(inst,"dayNames");var dayNamesShort=this._get(inst,"dayNamesShort");var dayNamesMin=this._get(inst,"dayNamesMin");var monthNames=this._get(inst,"monthNames");var monthNamesShort=this._get(inst,"monthNamesShort");var beforeShowDay=this._get(inst,"beforeShowDay");var showOtherMonths=this._get(inst,"showOtherMonths");var calculateWeek=this._get(inst,"calculateWeek")||this.iso8601Week;var endDate=inst.endDay?this._daylightSavingAdjust(new Date(inst.endYear,inst.endMonth,inst.endDay)):currentDate;var defaultDate=this._getDefaultDate(inst);var html="";for(var row=0;row<numMonths[0];row++){var group="";for(var col=0;col<numMonths[1];col++){var selectedDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,inst.selectedDay));var cornerClass=" ui-corner-all";var calender="";if(isMultiMonth){calender+='<div class="ui-datepicker-group ui-datepicker-group-';switch(col){case 0:calender+="first";cornerClass=" ui-corner-"+(isRTL?"right":"left");break;case numMonths[1]-1:calender+="last";cornerClass=" ui-corner-"+(isRTL?"left":"right");break;default:calender+="middle";cornerClass="";break}calender+='">'}calender+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+cornerClass+'">'+(/all|left/.test(cornerClass)&&row==0?(isRTL?next:prev):"")+(/all|right/.test(cornerClass)&&row==0?(isRTL?prev:next):"")+this._generateMonthYearHeader(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,row>0||col>0,monthNames,monthNamesShort)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var thead="";for(var dow=0;dow<7;dow++){var day=(dow+firstDay)%7;thead+="<th"+((dow+firstDay+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+dayNames[day]+'">'+dayNamesMin[day]+"</span></th>"}calender+=thead+"</tr></thead><tbody>";var daysInMonth=this._getDaysInMonth(drawYear,drawMonth);if(drawYear==inst.selectedYear&&drawMonth==inst.selectedMonth){inst.selectedDay=Math.min(inst.selectedDay,daysInMonth)}var leadDays=(this._getFirstDayOfMonth(drawYear,drawMonth)-firstDay+7)%7;var numRows=(isMultiMonth?6:Math.ceil((leadDays+daysInMonth)/7));var printDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,1-leadDays));for(var dRow=0;dRow<numRows;dRow++){calender+="<tr>";var tbody="";for(var dow=0;dow<7;dow++){var daySettings=(beforeShowDay?beforeShowDay.apply((inst.input?inst.input[0]:null),[printDate]):[true,""]);var otherMonth=(printDate.getMonth()!=drawMonth);var unselectable=otherMonth||!daySettings[0]||(minDate&&printDate<minDate)||(maxDate&&printDate>maxDate);tbody+='<td class="'+((dow+firstDay+6)%7>=5?" ui-datepicker-week-end":"")+(otherMonth?" ui-datepicker-other-month":"")+((printDate.getTime()==selectedDate.getTime()&&drawMonth==inst.selectedMonth&&inst._keyEvent)||(defaultDate.getTime()==printDate.getTime()&&defaultDate.getTime()==selectedDate.getTime())?" "+this._dayOverClass:"")+(unselectable?" "+this._unselectableClass+" ui-state-disabled":"")+(otherMonth&&!showOtherMonths?"":" "+daySettings[1]+(printDate.getTime()>=currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" "+this._currentClass:"")+(printDate.getTime()==today.getTime()?" ui-datepicker-today":""))+'"'+((!otherMonth||showOtherMonths)&&daySettings[2]?' title="'+daySettings[2]+'"':"")+(unselectable?"":" onclick=\"DP_jQuery.datepicker._selectDay('#"+inst.id+"',"+drawMonth+","+drawYear+', this);return false;"')+">"+(otherMonth?(showOtherMonths?printDate.getDate():" "):(unselectable?'<span class="ui-state-default">'+printDate.getDate()+"</span>":'<a class="ui-state-default'+(printDate.getTime()==today.getTime()?" ui-state-highlight":"")+(printDate.getTime()>=currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" ui-state-active":"")+'" href="#">'+printDate.getDate()+"</a>"))+"</td>";printDate.setDate(printDate.getDate()+1);printDate=this._daylightSavingAdjust(printDate)}calender+=tbody+"</tr>"}drawMonth++;if(drawMonth>11){drawMonth=0;drawYear++}calender+="</tbody></table>"+(isMultiMonth?"</div>"+((numMonths[0]>0&&col==numMonths[1]-1)?'<div class="ui-datepicker-row-break"></div>':""):"");group+=calender}html+=group}html+=buttonPanel+($.browser.msie&&parseInt($.browser.version,10)<7&&!inst.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':"");inst._keyEvent=false;return html},_generateMonthYearHeader:function(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,secondary,monthNames,monthNamesShort){minDate=(inst.rangeStart&&minDate&&selectedDate<minDate?selectedDate:minDate);var changeMonth=this._get(inst,"changeMonth");var changeYear=this._get(inst,"changeYear");var showMonthAfterYear=this._get(inst,"showMonthAfterYear");var html='<div class="ui-datepicker-title">';var monthHtml="";if(secondary||!changeMonth){monthHtml+='<span class="ui-datepicker-month">'+monthNames[drawMonth]+"</span> "}else{var inMinYear=(minDate&&minDate.getFullYear()==drawYear);var inMaxYear=(maxDate&&maxDate.getFullYear()==drawYear);monthHtml+='<select class="ui-datepicker-month" onchange="DP_jQuery.datepicker._selectMonthYear(\'#'+inst.id+"', this, 'M');\" onclick=\"DP_jQuery.datepicker._clickMonthYear('#"+inst.id+"');\">";for(var month=0;month<12;month++){if((!inMinYear||month>=minDate.getMonth())&&(!inMaxYear||month<=maxDate.getMonth())){monthHtml+='<option value="'+month+'"'+(month==drawMonth?' selected="selected"':"")+">"+monthNamesShort[month]+"</option>"}}monthHtml+="</select>"}if(!showMonthAfterYear){html+=monthHtml+((secondary||changeMonth||changeYear)&&(!(changeMonth&&changeYear))?" ":"")}if(secondary||!changeYear){html+='<span class="ui-datepicker-year">'+drawYear+"</span>"}else{var years=this._get(inst,"yearRange").split(":");var year=0;var endYear=0;if(years.length!=2){year=drawYear-10;endYear=drawYear+10}else{if(years[0].charAt(0)=="+"||years[0].charAt(0)=="-"){year=drawYear+parseInt(years[0],10);endYear=drawYear+parseInt(years[1],10)}else{year=parseInt(years[0],10);endYear=parseInt(years[1],10)}}year=(minDate?Math.max(year,minDate.getFullYear()):year);endYear=(maxDate?Math.min(endYear,maxDate.getFullYear()):endYear);html+='<select class="ui-datepicker-year" onchange="DP_jQuery.datepicker._selectMonthYear(\'#'+inst.id+"', this, 'Y');\" onclick=\"DP_jQuery.datepicker._clickMonthYear('#"+inst.id+"');\">";for(;year<=endYear;year++){html+='<option value="'+year+'"'+(year==drawYear?' selected="selected"':"")+">"+year+"</option>"}html+="</select>"}if(showMonthAfterYear){html+=(secondary||changeMonth||changeYear?" ":"")+monthHtml}html+="</div>";return html},_adjustInstDate:function(inst,offset,period){var year=inst.drawYear+(period=="Y"?offset:0);var month=inst.drawMonth+(period=="M"?offset:0);var day=Math.min(inst.selectedDay,this._getDaysInMonth(year,month))+(period=="D"?offset:0);var date=this._daylightSavingAdjust(new Date(year,month,day));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");date=(minDate&&date<minDate?minDate:date);date=(maxDate&&date>maxDate?maxDate:date);inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();if(period=="M"||period=="Y"){this._notifyChange(inst)}},_notifyChange:function(inst){var onChange=this._get(inst,"onChangeMonthYear");if(onChange){onChange.apply((inst.input?inst.input[0]:null),[inst.selectedYear,inst.selectedMonth+1,inst])}},_getNumberOfMonths:function(inst){var numMonths=this._get(inst,"numberOfMonths");return(numMonths==null?[1,1]:(typeof numMonths=="number"?[1,numMonths]:numMonths))},_getMinMaxDate:function(inst,minMax,checkRange){var date=this._determineDate(this._get(inst,minMax+"Date"),null);return(!checkRange||!inst.rangeStart?date:(!date||inst.rangeStart>date?inst.rangeStart:date))},_getDaysInMonth:function(year,month){return 32-new Date(year,month,32).getDate()},_getFirstDayOfMonth:function(year,month){return new Date(year,month,1).getDay()},_canAdjustMonth:function(inst,offset,curYear,curMonth){var numMonths=this._getNumberOfMonths(inst);var date=this._daylightSavingAdjust(new Date(curYear,curMonth+(offset<0?offset:numMonths[1]),1));if(offset<0){date.setDate(this._getDaysInMonth(date.getFullYear(),date.getMonth()))}return this._isInRange(inst,date)},_isInRange:function(inst,date){var newMinDate=(!inst.rangeStart?null:this._daylightSavingAdjust(new Date(inst.selectedYear,inst.selectedMonth,inst.selectedDay)));newMinDate=(newMinDate&&inst.rangeStart<newMinDate?inst.rangeStart:newMinDate);var minDate=newMinDate||this._getMinMaxDate(inst,"min");var maxDate=this._getMinMaxDate(inst,"max");return((!minDate||date>=minDate)&&(!maxDate||date<=maxDate))},_getFormatConfig:function(inst){var shortYearCutoff=this._get(inst,"shortYearCutoff");shortYearCutoff=(typeof shortYearCutoff!="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));return{shortYearCutoff:shortYearCutoff,dayNamesShort:this._get(inst,"dayNamesShort"),dayNames:this._get(inst,"dayNames"),monthNamesShort:this._get(inst,"monthNamesShort"),monthNames:this._get(inst,"monthNames")}},_formatDate:function(inst,day,month,year){if(!day){inst.currentDay=inst.selectedDay;inst.currentMonth=inst.selectedMonth;inst.currentYear=inst.selectedYear}var date=(day?(typeof day=="object"?day:this._daylightSavingAdjust(new Date(year,month,day))):this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return this.formatDate(this._get(inst,"dateFormat"),date,this._getFormatConfig(inst))}});function extendRemove(target,props){$.extend(target,props);for(var name in props){if(props[name]==null||props[name]==undefined){target[name]=props[name]}}return target}function isArray(a){return(a&&(($.browser.safari&&typeof a=="object"&&a.length)||(a.constructor&&a.constructor.toString().match(/\Array\(\)/))))}$.fn.datepicker=function(options){if(!$.datepicker.initialized){$(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv);$.datepicker.initialized=true}var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options=="string"&&(options=="isDisabled"||options=="getDate")){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}if(options=="option"&&arguments.length==2&&typeof arguments[1]=="string"){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}return this.each(function(){typeof options=="string"?$.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this].concat(otherArgs)):$.datepicker._attachDatepicker(this,options)})};$.datepicker=new Datepicker();$.datepicker.initialized=false;$.datepicker.uuid=new Date().getTime();$.datepicker.version="1.7.2";window.DP_jQuery=$})(jQuery);;/* + * jQuery UI Progressbar 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Progressbar + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.progressbar",{_init:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this._valueMin(),"aria-valuemax":this._valueMax(),"aria-valuenow":this._value()});this.valueDiv=a('<div class="ui-progressbar-value ui-widget-header ui-corner-left"></div>').appendTo(this.element);this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow").removeData("progressbar").unbind(".progressbar");this.valueDiv.remove();a.widget.prototype.destroy.apply(this,arguments)},value:function(b){if(b===undefined){return this._value()}this._setData("value",b);return this},_setData:function(b,c){switch(b){case"value":this.options.value=c;this._refreshValue();this._trigger("change",null,{});break}a.widget.prototype._setData.apply(this,arguments)},_value:function(){var b=this.options.value;if(b<this._valueMin()){b=this._valueMin()}if(b>this._valueMax()){b=this._valueMax()}return b},_valueMin:function(){var b=0;return b},_valueMax:function(){var b=100;return b},_refreshValue:function(){var b=this.value();this.valueDiv[b==this._valueMax()?"addClass":"removeClass"]("ui-corner-right");this.valueDiv.width(b+"%");this.element.attr("aria-valuenow",b)}});a.extend(a.ui.progressbar,{version:"1.7.2",defaults:{value:0}})})(jQuery);;/* + * jQuery UI Effects 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/ + */ +jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(var f=0;f<h.length;f++){if(h[f]!==null){g.data("ec.storage."+h[f],g[0].style[h[f]])}}},restore:function(g,h){for(var f=0;f<h.length;f++){if(h[f]!==null){g.css(h[f],g.data("ec.storage."+h[f]))}}},setMode:function(f,g){if(g=="toggle"){g=f.is(":hidden")?"show":"hide"}return g},getBaseline:function(g,h){var i,f;switch(g[0]){case"top":i=0;break;case"middle":i=0.5;break;case"bottom":i=1;break;default:i=g[0]/h.height}switch(g[1]){case"left":f=0;break;case"center":f=0.5;break;case"right":f=1;break;default:f=g[1]/h.width}return{x:f,y:i}},createWrapper:function(f){if(f.parent().is(".ui-effects-wrapper")){return f.parent()}var g={width:f.outerWidth(true),height:f.outerHeight(true),"float":f.css("float")};f.wrap('<div class="ui-effects-wrapper" style="font-size:100%;background:transparent;border:none;margin:0;padding:0"></div>');var j=f.parent();if(f.css("position")=="static"){j.css({position:"relative"});f.css({position:"relative"})}else{var i=f.css("top");if(isNaN(parseInt(i,10))){i="auto"}var h=f.css("left");if(isNaN(parseInt(h,10))){h="auto"}j.css({position:f.css("position"),top:i,left:h,zIndex:f.css("z-index")}).show();f.css({position:"relative",top:0,left:0})}j.css(g);return j},removeWrapper:function(f){if(f.parent().is(".ui-effects-wrapper")){return f.parent().replaceWith(f)}return f},setTransition:function(g,i,f,h){h=h||{};d.each(i,function(k,j){unit=g.cssUnit(j);if(unit[0]>0){h[j]=unit[0]*f+unit[1]}});return h},animateClass:function(h,i,k,j){var f=(typeof k=="function"?k:(j?j:null));var g=(typeof k=="string"?k:null);return this.each(function(){var q={};var o=d(this);var p=o.attr("style")||"";if(typeof p=="object"){p=p.cssText}if(h.toggle){o.hasClass(h.toggle)?h.remove=h.toggle:h.add=h.toggle}var l=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.addClass(h.add)}if(h.remove){o.removeClass(h.remove)}var m=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.removeClass(h.add)}if(h.remove){o.addClass(h.remove)}for(var r in m){if(typeof m[r]!="function"&&m[r]&&r.indexOf("Moz")==-1&&r.indexOf("length")==-1&&m[r]!=l[r]&&(r.match(/color/i)||(!r.match(/color/i)&&!isNaN(parseInt(m[r],10))))&&(l.position!="static"||(l.position=="static"&&!r.match(/left|top|bottom|right/)))){q[r]=m[r]}}o.animate(q,i,g,function(){if(typeof d(this).attr("style")=="object"){d(this).attr("style")["cssText"]="";d(this).attr("style")["cssText"]=p}else{d(this).attr("style",p)}if(h.add){d(this).addClass(h.add)}if(h.remove){d(this).removeClass(h.remove)}if(f){f.apply(this,arguments)}})})}};function c(g,f){var i=g[1]&&g[1].constructor==Object?g[1]:{};if(f){i.mode=f}var h=g[1]&&g[1].constructor!=Object?g[1]:(i.duration?i.duration:g[2]);h=d.fx.off?0:typeof h==="number"?h:d.fx.speeds[h]||d.fx.speeds._default;var j=i.callback||(d.isFunction(g[1])&&g[1])||(d.isFunction(g[2])&&g[2])||(d.isFunction(g[3])&&g[3]);return[g[0],i,h,j]}d.fn.extend({_show:d.fn.show,_hide:d.fn.hide,__toggle:d.fn.toggle,_addClass:d.fn.addClass,_removeClass:d.fn.removeClass,_toggleClass:d.fn.toggleClass,effect:function(g,f,h,i){return d.effects[g]?d.effects[g].call(this,{method:g,options:f||{},duration:h,callback:i}):null},show:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._show.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"show"))}},hide:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._hide.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"hide"))}},toggle:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))||(d.isFunction(arguments[0])||typeof arguments[0]=="boolean")){return this.__toggle.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"toggle"))}},addClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{add:g},f,i,h]):this._addClass(g)},removeClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{remove:g},f,i,h]):this._removeClass(g)},toggleClass:function(g,f,i,h){return((typeof f!=="boolean")&&f)?d.effects.animateClass.apply(this,[{toggle:g},f,i,h]):this._toggleClass(g,f)},morph:function(f,h,g,j,i){return d.effects.animateClass.apply(this,[{add:h,remove:f},g,j,i])},switchClass:function(){return this.morph.apply(this,arguments)},cssUnit:function(f){var g=this.css(f),h=[];d.each(["em","px","%","pt"],function(j,k){if(g.indexOf(k)>0){h=[parseFloat(g),k]}});return h}});d.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(g,f){d.fx.step[f]=function(h){if(h.state==0){h.start=e(h.elem,f);h.end=b(h.end)}h.elem.style[f]="rgb("+[Math.max(Math.min(parseInt((h.pos*(h.end[0]-h.start[0]))+h.start[0],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[1]-h.start[1]))+h.start[1],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[2]-h.start[2]))+h.start[2],10),255),0)].join(",")+")"}});function b(g){var f;if(g&&g.constructor==Array&&g.length==3){return g}if(f=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(g)){return[parseInt(f[1],10),parseInt(f[2],10),parseInt(f[3],10)]}if(f=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(g)){return[parseFloat(f[1])*2.55,parseFloat(f[2])*2.55,parseFloat(f[3])*2.55]}if(f=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(g)){return[parseInt(f[1],16),parseInt(f[2],16),parseInt(f[3],16)]}if(f=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(g)){return[parseInt(f[1]+f[1],16),parseInt(f[2]+f[2],16),parseInt(f[3]+f[3],16)]}if(f=/rgba\(0, 0, 0, 0\)/.exec(g)){return a.transparent}return a[d.trim(g).toLowerCase()]}function e(h,f){var g;do{g=d.curCSS(h,f);if(g!=""&&g!="transparent"||d.nodeName(h,"body")){break}f="backgroundColor"}while(h=h.parentNode);return b(g)}var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]};d.easing.jswing=d.easing.swing;d.extend(d.easing,{def:"easeOutQuad",swing:function(g,h,f,j,i){return d.easing[d.easing.def](g,h,f,j,i)},easeInQuad:function(g,h,f,j,i){return j*(h/=i)*h+f},easeOutQuad:function(g,h,f,j,i){return -j*(h/=i)*(h-2)+f},easeInOutQuad:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h+f}return -j/2*((--h)*(h-2)-1)+f},easeInCubic:function(g,h,f,j,i){return j*(h/=i)*h*h+f},easeOutCubic:function(g,h,f,j,i){return j*((h=h/i-1)*h*h+1)+f},easeInOutCubic:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h+f}return j/2*((h-=2)*h*h+2)+f},easeInQuart:function(g,h,f,j,i){return j*(h/=i)*h*h*h+f},easeOutQuart:function(g,h,f,j,i){return -j*((h=h/i-1)*h*h*h-1)+f},easeInOutQuart:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h+f}return -j/2*((h-=2)*h*h*h-2)+f},easeInQuint:function(g,h,f,j,i){return j*(h/=i)*h*h*h*h+f},easeOutQuint:function(g,h,f,j,i){return j*((h=h/i-1)*h*h*h*h+1)+f},easeInOutQuint:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h*h+f}return j/2*((h-=2)*h*h*h*h+2)+f},easeInSine:function(g,h,f,j,i){return -j*Math.cos(h/i*(Math.PI/2))+j+f},easeOutSine:function(g,h,f,j,i){return j*Math.sin(h/i*(Math.PI/2))+f},easeInOutSine:function(g,h,f,j,i){return -j/2*(Math.cos(Math.PI*h/i)-1)+f},easeInExpo:function(g,h,f,j,i){return(h==0)?f:j*Math.pow(2,10*(h/i-1))+f},easeOutExpo:function(g,h,f,j,i){return(h==i)?f+j:j*(-Math.pow(2,-10*h/i)+1)+f},easeInOutExpo:function(g,h,f,j,i){if(h==0){return f}if(h==i){return f+j}if((h/=i/2)<1){return j/2*Math.pow(2,10*(h-1))+f}return j/2*(-Math.pow(2,-10*--h)+2)+f},easeInCirc:function(g,h,f,j,i){return -j*(Math.sqrt(1-(h/=i)*h)-1)+f},easeOutCirc:function(g,h,f,j,i){return j*Math.sqrt(1-(h=h/i-1)*h)+f},easeInOutCirc:function(g,h,f,j,i){if((h/=i/2)<1){return -j/2*(Math.sqrt(1-h*h)-1)+f}return j/2*(Math.sqrt(1-(h-=2)*h)+1)+f},easeInElastic:function(g,i,f,m,l){var j=1.70158;var k=0;var h=m;if(i==0){return f}if((i/=l)==1){return f+m}if(!k){k=l*0.3}if(h<Math.abs(m)){h=m;var j=k/4}else{var j=k/(2*Math.PI)*Math.asin(m/h)}return -(h*Math.pow(2,10*(i-=1))*Math.sin((i*l-j)*(2*Math.PI)/k))+f},easeOutElastic:function(g,i,f,m,l){var j=1.70158;var k=0;var h=m;if(i==0){return f}if((i/=l)==1){return f+m}if(!k){k=l*0.3}if(h<Math.abs(m)){h=m;var j=k/4}else{var j=k/(2*Math.PI)*Math.asin(m/h)}return h*Math.pow(2,-10*i)*Math.sin((i*l-j)*(2*Math.PI)/k)+m+f},easeInOutElastic:function(g,i,f,m,l){var j=1.70158;var k=0;var h=m;if(i==0){return f}if((i/=l/2)==2){return f+m}if(!k){k=l*(0.3*1.5)}if(h<Math.abs(m)){h=m;var j=k/4}else{var j=k/(2*Math.PI)*Math.asin(m/h)}if(i<1){return -0.5*(h*Math.pow(2,10*(i-=1))*Math.sin((i*l-j)*(2*Math.PI)/k))+f}return h*Math.pow(2,-10*(i-=1))*Math.sin((i*l-j)*(2*Math.PI)/k)*0.5+m+f},easeInBack:function(g,h,f,k,j,i){if(i==undefined){i=1.70158}return k*(h/=j)*h*((i+1)*h-i)+f},easeOutBack:function(g,h,f,k,j,i){if(i==undefined){i=1.70158}return k*((h=h/j-1)*h*((i+1)*h+i)+1)+f},easeInOutBack:function(g,h,f,k,j,i){if(i==undefined){i=1.70158}if((h/=j/2)<1){return k/2*(h*h*(((i*=(1.525))+1)*h-i))+f}return k/2*((h-=2)*h*(((i*=(1.525))+1)*h+i)+2)+f},easeInBounce:function(g,h,f,j,i){return j-d.easing.easeOutBounce(g,i-h,0,j,i)+f},easeOutBounce:function(g,h,f,j,i){if((h/=i)<(1/2.75)){return j*(7.5625*h*h)+f}else{if(h<(2/2.75)){return j*(7.5625*(h-=(1.5/2.75))*h+0.75)+f}else{if(h<(2.5/2.75)){return j*(7.5625*(h-=(2.25/2.75))*h+0.9375)+f}else{return j*(7.5625*(h-=(2.625/2.75))*h+0.984375)+f}}}},easeInOutBounce:function(g,h,f,j,i){if(h<i/2){return d.easing.easeInBounce(g,h*2,0,j,i)*0.5+f}return d.easing.easeOutBounce(g,h*2-i,0,j,i)*0.5+j*0.5+f}})})(jQuery);;/* + * jQuery UI Effects Blind 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Blind + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.blind=function(b){return this.queue(function(){var d=a(this),c=["position","top","left"];var h=a.effects.setMode(d,b.options.mode||"hide");var g=b.options.direction||"vertical";a.effects.save(d,c);d.show();var j=a.effects.createWrapper(d).css({overflow:"hidden"});var e=(g=="vertical")?"height":"width";var i=(g=="vertical")?j.height():j.width();if(h=="show"){j.css(e,0)}var f={};f[e]=h=="show"?i:0;j.animate(f,b.duration,b.options.easing,function(){if(h=="hide"){d.hide()}a.effects.restore(d,c);a.effects.removeWrapper(d);if(b.callback){b.callback.apply(d[0],arguments)}d.dequeue()})})}})(jQuery);;/* + * jQuery UI Effects Bounce 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Bounce + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.bounce=function(b){return this.queue(function(){var e=a(this),l=["position","top","left"];var k=a.effects.setMode(e,b.options.mode||"effect");var n=b.options.direction||"up";var c=b.options.distance||20;var d=b.options.times||5;var g=b.duration||250;if(/show|hide/.test(k)){l.push("opacity")}a.effects.save(e,l);e.show();a.effects.createWrapper(e);var f=(n=="up"||n=="down")?"top":"left";var p=(n=="up"||n=="left")?"pos":"neg";var c=b.options.distance||(f=="top"?e.outerHeight({margin:true})/3:e.outerWidth({margin:true})/3);if(k=="show"){e.css("opacity",0).css(f,p=="pos"?-c:c)}if(k=="hide"){c=c/(d*2)}if(k!="hide"){d--}if(k=="show"){var h={opacity:1};h[f]=(p=="pos"?"+=":"-=")+c;e.animate(h,g/2,b.options.easing);c=c/2;d--}for(var j=0;j<d;j++){var o={},m={};o[f]=(p=="pos"?"-=":"+=")+c;m[f]=(p=="pos"?"+=":"-=")+c;e.animate(o,g/2,b.options.easing).animate(m,g/2,b.options.easing);c=(k=="hide")?c*2:c/2}if(k=="hide"){var h={opacity:0};h[f]=(p=="pos"?"-=":"+=")+c;e.animate(h,g/2,b.options.easing,function(){e.hide();a.effects.restore(e,l);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}})}else{var o={},m={};o[f]=(p=="pos"?"-=":"+=")+c;m[f]=(p=="pos"?"+=":"-=")+c;e.animate(o,g/2,b.options.easing).animate(m,g/2,b.options.easing,function(){a.effects.restore(e,l);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}})}e.queue("fx",function(){e.dequeue()});e.dequeue()})}})(jQuery);;/* + * jQuery UI Effects Clip 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Clip + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.clip=function(b){return this.queue(function(){var f=a(this),j=["position","top","left","height","width"];var i=a.effects.setMode(f,b.options.mode||"hide");var k=b.options.direction||"vertical";a.effects.save(f,j);f.show();var c=a.effects.createWrapper(f).css({overflow:"hidden"});var e=f[0].tagName=="IMG"?c:f;var g={size:(k=="vertical")?"height":"width",position:(k=="vertical")?"top":"left"};var d=(k=="vertical")?e.height():e.width();if(i=="show"){e.css(g.size,0);e.css(g.position,d/2)}var h={};h[g.size]=i=="show"?d:0;h[g.position]=i=="show"?0:d/2;e.animate(h,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(i=="hide"){f.hide()}a.effects.restore(f,j);a.effects.removeWrapper(f);if(b.callback){b.callback.apply(f[0],arguments)}f.dequeue()}})})}})(jQuery);;/* + * jQuery UI Effects Drop 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Drop + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.drop=function(b){return this.queue(function(){var e=a(this),d=["position","top","left","opacity"];var i=a.effects.setMode(e,b.options.mode||"hide");var h=b.options.direction||"left";a.effects.save(e,d);e.show();a.effects.createWrapper(e);var f=(h=="up"||h=="down")?"top":"left";var c=(h=="up"||h=="left")?"pos":"neg";var j=b.options.distance||(f=="top"?e.outerHeight({margin:true})/2:e.outerWidth({margin:true})/2);if(i=="show"){e.css("opacity",0).css(f,c=="pos"?-j:j)}var g={opacity:i=="show"?1:0};g[f]=(i=="show"?(c=="pos"?"+=":"-="):(c=="pos"?"-=":"+="))+j;e.animate(g,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(i=="hide"){e.hide()}a.effects.restore(e,d);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}e.dequeue()}})})}})(jQuery);;/* + * jQuery UI Effects Explode 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Explode + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.explode=function(b){return this.queue(function(){var k=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3;var e=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3;b.options.mode=b.options.mode=="toggle"?(a(this).is(":visible")?"hide":"show"):b.options.mode;var h=a(this).show().css("visibility","hidden");var l=h.offset();l.top-=parseInt(h.css("marginTop"),10)||0;l.left-=parseInt(h.css("marginLeft"),10)||0;var g=h.outerWidth(true);var c=h.outerHeight(true);for(var f=0;f<k;f++){for(var d=0;d<e;d++){h.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-d*(g/e),top:-f*(c/k)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/e,height:c/k,left:l.left+d*(g/e)+(b.options.mode=="show"?(d-Math.floor(e/2))*(g/e):0),top:l.top+f*(c/k)+(b.options.mode=="show"?(f-Math.floor(k/2))*(c/k):0),opacity:b.options.mode=="show"?0:1}).animate({left:l.left+d*(g/e)+(b.options.mode=="show"?0:(d-Math.floor(e/2))*(g/e)),top:l.top+f*(c/k)+(b.options.mode=="show"?0:(f-Math.floor(k/2))*(c/k)),opacity:b.options.mode=="show"?1:0},b.duration||500)}}setTimeout(function(){b.options.mode=="show"?h.css({visibility:"visible"}):h.css({visibility:"visible"}).hide();if(b.callback){b.callback.apply(h[0])}h.dequeue();a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery);;/* + * jQuery UI Effects Fold 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Fold + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.fold=function(b){return this.queue(function(){var e=a(this),k=["position","top","left"];var h=a.effects.setMode(e,b.options.mode||"hide");var o=b.options.size||15;var n=!(!b.options.horizFirst);var g=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(e,k);e.show();var d=a.effects.createWrapper(e).css({overflow:"hidden"});var i=((h=="show")!=n);var f=i?["width","height"]:["height","width"];var c=i?[d.width(),d.height()]:[d.height(),d.width()];var j=/([0-9]+)%/.exec(o);if(j){o=parseInt(j[1],10)/100*c[h=="hide"?0:1]}if(h=="show"){d.css(n?{height:0,width:o}:{height:o,width:0})}var m={},l={};m[f[0]]=h=="show"?c[0]:o;l[f[1]]=h=="show"?c[1]:0;d.animate(m,g,b.options.easing).animate(l,g,b.options.easing,function(){if(h=="hide"){e.hide()}a.effects.restore(e,k);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(e[0],arguments)}e.dequeue()})})}})(jQuery);;/* + * jQuery UI Effects Highlight 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Highlight + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.highlight=function(b){return this.queue(function(){var e=a(this),d=["backgroundImage","backgroundColor","opacity"];var h=a.effects.setMode(e,b.options.mode||"show");var c=b.options.color||"#ffff99";var g=e.css("backgroundColor");a.effects.save(e,d);e.show();e.css({backgroundImage:"none",backgroundColor:c});var f={backgroundColor:g};if(h=="hide"){f.opacity=0}e.animate(f,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(h=="hide"){e.hide()}a.effects.restore(e,d);if(h=="show"&&a.browser.msie){this.style.removeAttribute("filter")}if(b.callback){b.callback.apply(this,arguments)}e.dequeue()}})})}})(jQuery);;/* + * jQuery UI Effects Pulsate 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Pulsate + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.pulsate=function(b){return this.queue(function(){var d=a(this);var g=a.effects.setMode(d,b.options.mode||"show");var f=b.options.times||5;var e=b.duration?b.duration/2:a.fx.speeds._default/2;if(g=="hide"){f--}if(d.is(":hidden")){d.css("opacity",0);d.show();d.animate({opacity:1},e,b.options.easing);f=f-2}for(var c=0;c<f;c++){d.animate({opacity:0},e,b.options.easing).animate({opacity:1},e,b.options.easing)}if(g=="hide"){d.animate({opacity:0},e,b.options.easing,function(){d.hide();if(b.callback){b.callback.apply(this,arguments)}})}else{d.animate({opacity:0},e,b.options.easing).animate({opacity:1},e,b.options.easing,function(){if(b.callback){b.callback.apply(this,arguments)}})}d.queue("fx",function(){d.dequeue()});d.dequeue()})}})(jQuery);;/* + * jQuery UI Effects Scale 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Scale + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.puff=function(b){return this.queue(function(){var f=a(this);var c=a.extend(true,{},b.options);var h=a.effects.setMode(f,b.options.mode||"hide");var g=parseInt(b.options.percent,10)||150;c.fade=true;var e={height:f.height(),width:f.width()};var d=g/100;f.from=(h=="hide")?e:{height:e.height*d,width:e.width*d};c.from=f.from;c.percent=(h=="hide")?g:100;c.mode=h;f.effect("scale",c,b.duration,b.callback);f.dequeue()})};a.effects.scale=function(b){return this.queue(function(){var g=a(this);var d=a.extend(true,{},b.options);var j=a.effects.setMode(g,b.options.mode||"effect");var h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:(j=="hide"?0:100));var i=b.options.direction||"both";var c=b.options.origin;if(j!="effect"){d.origin=c||["middle","center"];d.restore=true}var f={height:g.height(),width:g.width()};g.from=b.options.from||(j=="show"?{height:0,width:0}:f);var e={y:i!="horizontal"?(h/100):1,x:i!="vertical"?(h/100):1};g.to={height:f.height*e.y,width:f.width*e.x};if(b.options.fade){if(j=="show"){g.from.opacity=0;g.to.opacity=1}if(j=="hide"){g.from.opacity=1;g.to.opacity=0}}d.from=g.from;d.to=g.to;d.mode=j;g.effect("size",d,b.duration,b.callback);g.dequeue()})};a.effects.size=function(b){return this.queue(function(){var c=a(this),n=["position","top","left","width","height","overflow","opacity"];var m=["position","top","left","overflow","opacity"];var j=["width","height","overflow"];var p=["fontSize"];var k=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"];var f=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"];var g=a.effects.setMode(c,b.options.mode||"effect");var i=b.options.restore||false;var e=b.options.scale||"both";var o=b.options.origin;var d={height:c.height(),width:c.width()};c.from=b.options.from||d;c.to=b.options.to||d;if(o){var h=a.effects.getBaseline(o,d);c.from.top=(d.height-c.from.height)*h.y;c.from.left=(d.width-c.from.width)*h.x;c.to.top=(d.height-c.to.height)*h.y;c.to.left=(d.width-c.to.width)*h.x}var l={from:{y:c.from.height/d.height,x:c.from.width/d.width},to:{y:c.to.height/d.height,x:c.to.width/d.width}};if(e=="box"||e=="both"){if(l.from.y!=l.to.y){n=n.concat(k);c.from=a.effects.setTransition(c,k,l.from.y,c.from);c.to=a.effects.setTransition(c,k,l.to.y,c.to)}if(l.from.x!=l.to.x){n=n.concat(f);c.from=a.effects.setTransition(c,f,l.from.x,c.from);c.to=a.effects.setTransition(c,f,l.to.x,c.to)}}if(e=="content"||e=="both"){if(l.from.y!=l.to.y){n=n.concat(p);c.from=a.effects.setTransition(c,p,l.from.y,c.from);c.to=a.effects.setTransition(c,p,l.to.y,c.to)}}a.effects.save(c,i?n:m);c.show();a.effects.createWrapper(c);c.css("overflow","hidden").css(c.from);if(e=="content"||e=="both"){k=k.concat(["marginTop","marginBottom"]).concat(p);f=f.concat(["marginLeft","marginRight"]);j=n.concat(k).concat(f);c.find("*[width]").each(function(){child=a(this);if(i){a.effects.save(child,j)}var q={height:child.height(),width:child.width()};child.from={height:q.height*l.from.y,width:q.width*l.from.x};child.to={height:q.height*l.to.y,width:q.width*l.to.x};if(l.from.y!=l.to.y){child.from=a.effects.setTransition(child,k,l.from.y,child.from);child.to=a.effects.setTransition(child,k,l.to.y,child.to)}if(l.from.x!=l.to.x){child.from=a.effects.setTransition(child,f,l.from.x,child.from);child.to=a.effects.setTransition(child,f,l.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){if(i){a.effects.restore(child,j)}})})}c.animate(c.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(g=="hide"){c.hide()}a.effects.restore(c,i?n:m);a.effects.removeWrapper(c);if(b.callback){b.callback.apply(this,arguments)}c.dequeue()}})})}})(jQuery);;/* + * jQuery UI Effects Shake 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Shake + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.shake=function(b){return this.queue(function(){var e=a(this),l=["position","top","left"];var k=a.effects.setMode(e,b.options.mode||"effect");var n=b.options.direction||"left";var c=b.options.distance||20;var d=b.options.times||3;var g=b.duration||b.options.duration||140;a.effects.save(e,l);e.show();a.effects.createWrapper(e);var f=(n=="up"||n=="down")?"top":"left";var p=(n=="up"||n=="left")?"pos":"neg";var h={},o={},m={};h[f]=(p=="pos"?"-=":"+=")+c;o[f]=(p=="pos"?"+=":"-=")+c*2;m[f]=(p=="pos"?"-=":"+=")+c*2;e.animate(h,g,b.options.easing);for(var j=1;j<d;j++){e.animate(o,g,b.options.easing).animate(m,g,b.options.easing)}e.animate(o,g,b.options.easing).animate(h,g/2,b.options.easing,function(){a.effects.restore(e,l);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}});e.queue("fx",function(){e.dequeue()});e.dequeue()})}})(jQuery);;/* + * jQuery UI Effects Slide 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Slide + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.slide=function(b){return this.queue(function(){var e=a(this),d=["position","top","left"];var i=a.effects.setMode(e,b.options.mode||"show");var h=b.options.direction||"left";a.effects.save(e,d);e.show();a.effects.createWrapper(e).css({overflow:"hidden"});var f=(h=="up"||h=="down")?"top":"left";var c=(h=="up"||h=="left")?"pos":"neg";var j=b.options.distance||(f=="top"?e.outerHeight({margin:true}):e.outerWidth({margin:true}));if(i=="show"){e.css(f,c=="pos"?-j:j)}var g={};g[f]=(i=="show"?(c=="pos"?"+=":"-="):(c=="pos"?"-=":"+="))+j;e.animate(g,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(i=="hide"){e.hide()}a.effects.restore(e,d);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}e.dequeue()}})})}})(jQuery);;/* + * jQuery UI Effects Transfer 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Transfer + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.transfer=function(b){return this.queue(function(){var f=a(this),h=a(b.options.to),e=h.offset(),g={top:e.top,left:e.left,height:h.innerHeight(),width:h.innerWidth()},d=f.offset(),c=a('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(b.options.className).css({top:d.top,left:d.left,height:f.innerHeight(),width:f.innerWidth(),position:"absolute"}).animate(g,b.duration,b.options.easing,function(){c.remove();(b.callback&&b.callback.apply(f[0],arguments));f.dequeue()})})}})(jQuery);; +\ No newline at end of file diff --git a/server/hms/static/js/jquery.autocomplete.js b/server/hms/static/js/jquery.autocomplete.js @@ -0,0 +1,808 @@ +/* + * jQuery Autocomplete plugin 1.1 + * + * Copyright (c) 2009 Jörn Zaefferer + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $ + */ + +;(function($) { + +$.fn.extend({ + autocomplete: function(urlOrData, options) { + var isUrl = typeof urlOrData == "string"; + options = $.extend({}, $.Autocompleter.defaults, { + url: isUrl ? urlOrData : null, + data: isUrl ? null : urlOrData, + delay: isUrl ? $.Autocompleter.defaults.delay : 10, + max: options && !options.scroll ? 10 : 150 + }, options); + + // if highlight is set to false, replace it with a do-nothing function + options.highlight = options.highlight || function(value) { return value; }; + + // if the formatMatch option is not specified, then use formatItem for backwards compatibility + options.formatMatch = options.formatMatch || options.formatItem; + + return this.each(function() { + new $.Autocompleter(this, options); + }); + }, + result: function(handler) { + return this.bind("result", handler); + }, + search: function(handler) { + return this.trigger("search", [handler]); + }, + flushCache: function() { + return this.trigger("flushCache"); + }, + setOptions: function(options){ + return this.trigger("setOptions", [options]); + }, + unautocomplete: function() { + return this.trigger("unautocomplete"); + } +}); + +$.Autocompleter = function(input, options) { + + var KEY = { + UP: 38, + DOWN: 40, + DEL: 46, + TAB: 9, + RETURN: 13, + ESC: 27, + COMMA: 188, + PAGEUP: 33, + PAGEDOWN: 34, + BACKSPACE: 8 + }; + + // Create $ object for input element + var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass); + + var timeout; + var previousValue = ""; + var cache = $.Autocompleter.Cache(options); + var hasFocus = 0; + var lastKeyPressCode; + var config = { + mouseDownOnSelect: false + }; + var select = $.Autocompleter.Select(options, input, selectCurrent, config); + + var blockSubmit; + + // prevent form submit in opera when selecting with return key + $.browser.opera && $(input.form).bind("submit.autocomplete", function() { + if (blockSubmit) { + blockSubmit = false; + return false; + } + }); + + // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all + $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) { + // a keypress means the input has focus + // avoids issue where input had focus before the autocomplete was applied + hasFocus = 1; + // track last key pressed + lastKeyPressCode = event.keyCode; + switch(event.keyCode) { + + case KEY.UP: + event.preventDefault(); + if ( select.visible() ) { + select.prev(); + } else { + onChange(0, true); + } + break; + + case KEY.DOWN: + event.preventDefault(); + if ( select.visible() ) { + select.next(); + } else { + onChange(0, true); + } + break; + + case KEY.PAGEUP: + event.preventDefault(); + if ( select.visible() ) { + select.pageUp(); + } else { + onChange(0, true); + } + break; + + case KEY.PAGEDOWN: + event.preventDefault(); + if ( select.visible() ) { + select.pageDown(); + } else { + onChange(0, true); + } + break; + + // matches also semicolon + case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA: + case KEY.TAB: + case KEY.RETURN: + if( selectCurrent() ) { + // stop default to prevent a form submit, Opera needs special handling + event.preventDefault(); + blockSubmit = true; + return false; + } + break; + + case KEY.ESC: + select.hide(); + break; + + default: + clearTimeout(timeout); + timeout = setTimeout(onChange, options.delay); + break; + } + }).focus(function(){ + // track whether the field has focus, we shouldn't process any + // results if the field no longer has focus + hasFocus++; + }).blur(function() { + hasFocus = 0; + if (!config.mouseDownOnSelect) { + hideResults(); + } + }).click(function() { + // show select when clicking in a focused field + if ( hasFocus++ > 1 && !select.visible() ) { + onChange(0, true); + } + }).bind("search", function() { + // TODO why not just specifying both arguments? + var fn = (arguments.length > 1) ? arguments[1] : null; + function findValueCallback(q, data) { + var result; + if( data && data.length ) { + for (var i=0; i < data.length; i++) { + if( data[i].result.toLowerCase() == q.toLowerCase() ) { + result = data[i]; + break; + } + } + } + if( typeof fn == "function" ) fn(result); + else $input.trigger("result", result && [result.data, result.value]); + } + $.each(trimWords($input.val()), function(i, value) { + request(value, findValueCallback, findValueCallback); + }); + }).bind("flushCache", function() { + cache.flush(); + }).bind("setOptions", function() { + $.extend(options, arguments[1]); + // if we've updated the data, repopulate + if ( "data" in arguments[1] ) + cache.populate(); + }).bind("unautocomplete", function() { + select.unbind(); + $input.unbind(); + $(input.form).unbind(".autocomplete"); + }); + + + function selectCurrent() { + var selected = select.selected(); + if( !selected ) + return false; + + var v = selected.result; + previousValue = v; + + if ( options.multiple ) { + var words = trimWords($input.val()); + if ( words.length > 1 ) { + var seperator = options.multipleSeparator.length; + var cursorAt = $(input).selection().start; + var wordAt, progress = 0; + $.each(words, function(i, word) { + progress += word.length; + if (cursorAt <= progress) { + wordAt = i; + return false; + } + progress += seperator; + }); + words[wordAt] = v; + // TODO this should set the cursor to the right position, but it gets overriden somewhere + //$.Autocompleter.Selection(input, progress + seperator, progress + seperator); + v = words.join( options.multipleSeparator ); + } + v += options.multipleSeparator; + } + + $input.val(v); + hideResultsNow(); + $input.trigger("result", [selected.data, selected.value]); + return true; + } + + function onChange(crap, skipPrevCheck) { + if( lastKeyPressCode == KEY.DEL ) { + select.hide(); + return; + } + + var currentValue = $input.val(); + + if ( !skipPrevCheck && currentValue == previousValue ) + return; + + previousValue = currentValue; + + currentValue = lastWord(currentValue); + if ( currentValue.length >= options.minChars) { + $input.addClass(options.loadingClass); + if (!options.matchCase) + currentValue = currentValue.toLowerCase(); + request(currentValue, receiveData, hideResultsNow); + } else { + stopLoading(); + select.hide(); + } + }; + + function trimWords(value) { + if (!value) + return [""]; + if (!options.multiple) + return [$.trim(value)]; + return $.map(value.split(options.multipleSeparator), function(word) { + return $.trim(value).length ? $.trim(word) : null; + }); + } + + function lastWord(value) { + if ( !options.multiple ) + return value; + var words = trimWords(value); + if (words.length == 1) + return words[0]; + var cursorAt = $(input).selection().start; + if (cursorAt == value.length) { + words = trimWords(value) + } else { + words = trimWords(value.replace(value.substring(cursorAt), "")); + } + return words[words.length - 1]; + } + + // fills in the input box w/the first match (assumed to be the best match) + // q: the term entered + // sValue: the first matching result + function autoFill(q, sValue){ + // autofill in the complete box w/the first match as long as the user hasn't entered in more data + // if the last user key pressed was backspace, don't autofill + if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) { + // fill in the value (keep the case the user has typed) + $input.val($input.val() + sValue.substring(lastWord(previousValue).length)); + // select the portion of the value not typed by the user (so the next character will erase) + $(input).selection(previousValue.length, previousValue.length + sValue.length); + } + }; + + function hideResults() { + clearTimeout(timeout); + timeout = setTimeout(hideResultsNow, 200); + }; + + function hideResultsNow() { + var wasVisible = select.visible(); + select.hide(); + clearTimeout(timeout); + stopLoading(); + if (options.mustMatch) { + // call search and run callback + $input.search( + function (result){ + // if no value found, clear the input box + if( !result ) { + if (options.multiple) { + var words = trimWords($input.val()).slice(0, -1); + $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") ); + } + else { + $input.val( "" ); + $input.trigger("result", null); + } + } + } + ); + } + }; + + function receiveData(q, data) { + if ( data && data.length && hasFocus ) { + stopLoading(); + select.display(data, q); + autoFill(q, data[0].value); + select.show(); + } else { + hideResultsNow(); + } + }; + + function request(term, success, failure) { + if (!options.matchCase) + term = term.toLowerCase(); + var data = cache.load(term); + // recieve the cached data + if (data && data.length) { + success(term, data); + // if an AJAX url has been supplied, try loading the data now + } else if( (typeof options.url == "string") && (options.url.length > 0) ){ + + var extraParams = { + timestamp: +new Date() + }; + $.each(options.extraParams, function(key, param) { + extraParams[key] = typeof param == "function" ? param() : param; + }); + + $.ajax({ + // try to leverage ajaxQueue plugin to abort previous requests + mode: "abort", + // limit abortion to this input + port: "autocomplete" + input.name, + dataType: options.dataType, + url: options.url, + data: $.extend({ + q: lastWord(term), + limit: options.max + }, extraParams), + success: function(data) { + var parsed = options.parse && options.parse(data) || parse(data); + cache.add(term, parsed); + success(term, parsed); + } + }); + } else { + // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match + select.emptyList(); + failure(term); + } + }; + + function parse(data) { + var parsed = []; + var rows = data.split("\n"); + for (var i=0; i < rows.length; i++) { + var row = $.trim(rows[i]); + if (row) { + row = row.split("|"); + parsed[parsed.length] = { + data: row, + value: row[0], + result: options.formatResult && options.formatResult(row, row[0]) || row[0] + }; + } + } + return parsed; + }; + + function stopLoading() { + $input.removeClass(options.loadingClass); + }; + +}; + +$.Autocompleter.defaults = { + inputClass: "ac_input", + resultsClass: "ac_results", + loadingClass: "ac_loading", + minChars: 1, + delay: 400, + matchCase: false, + matchSubset: true, + matchContains: false, + cacheLength: 10, + max: 100, + mustMatch: false, + extraParams: {}, + selectFirst: true, + formatItem: function(row) { return row[0]; }, + formatMatch: null, + autoFill: false, + width: 0, + multiple: false, + multipleSeparator: ", ", + highlight: function(value, term) { + return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>"); + }, + scroll: true, + scrollHeight: 180 +}; + +$.Autocompleter.Cache = function(options) { + + var data = {}; + var length = 0; + + function matchSubset(s, sub) { + if (!options.matchCase) + s = s.toLowerCase(); + var i = s.indexOf(sub); + if (options.matchContains == "word"){ + i = s.toLowerCase().search("\\b" + sub.toLowerCase()); + } + if (i == -1) return false; + return i == 0 || options.matchContains; + }; + + function add(q, value) { + if (length > options.cacheLength){ + flush(); + } + if (!data[q]){ + length++; + } + data[q] = value; + } + + function populate(){ + if( !options.data ) return false; + // track the matches + var stMatchSets = {}, + nullData = 0; + + // no url was specified, we need to adjust the cache length to make sure it fits the local data store + if( !options.url ) options.cacheLength = 1; + + // track all options for minChars = 0 + stMatchSets[""] = []; + + // loop through the array and create a lookup structure + for ( var i = 0, ol = options.data.length; i < ol; i++ ) { + var rawValue = options.data[i]; + // if rawValue is a string, make an array otherwise just reference the array + rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue; + + var value = options.formatMatch(rawValue, i+1, options.data.length); + if ( value === false ) + continue; + + var firstChar = value.charAt(0).toLowerCase(); + // if no lookup array for this character exists, look it up now + if( !stMatchSets[firstChar] ) + stMatchSets[firstChar] = []; + + // if the match is a string + var row = { + value: value, + data: rawValue, + result: options.formatResult && options.formatResult(rawValue) || value + }; + + // push the current match into the set list + stMatchSets[firstChar].push(row); + + // keep track of minChars zero items + if ( nullData++ < options.max ) { + stMatchSets[""].push(row); + } + }; + + // add the data items to the cache + $.each(stMatchSets, function(i, value) { + // increase the cache size + options.cacheLength++; + // add to the cache + add(i, value); + }); + } + + // populate any existing data + setTimeout(populate, 25); + + function flush(){ + data = {}; + length = 0; + } + + return { + flush: flush, + add: add, + populate: populate, + load: function(q) { + if (!options.cacheLength || !length) + return null; + /* + * if dealing w/local data and matchContains than we must make sure + * to loop through all the data collections looking for matches + */ + if( !options.url && options.matchContains ){ + // track all matches + var csub = []; + // loop through all the data grids for matches + for( var k in data ){ + // don't search through the stMatchSets[""] (minChars: 0) cache + // this prevents duplicates + if( k.length > 0 ){ + var c = data[k]; + $.each(c, function(i, x) { + // if we've got a match, add it to the array + if (matchSubset(x.value, q)) { + csub.push(x); + } + }); + } + } + return csub; + } else + // if the exact item exists, use it + if (data[q]){ + return data[q]; + } else + if (options.matchSubset) { + for (var i = q.length - 1; i >= options.minChars; i--) { + var c = data[q.substr(0, i)]; + if (c) { + var csub = []; + $.each(c, function(i, x) { + if (matchSubset(x.value, q)) { + csub[csub.length] = x; + } + }); + return csub; + } + } + } + return null; + } + }; +}; + +$.Autocompleter.Select = function (options, input, select, config) { + var CLASSES = { + ACTIVE: "ac_over" + }; + + var listItems, + active = -1, + data, + term = "", + needsInit = true, + element, + list; + + // Create results + function init() { + if (!needsInit) + return; + element = $("<div/>") + .hide() + .addClass(options.resultsClass) + .css("position", "absolute") + .appendTo(document.body); + + list = $("<ul/>").appendTo(element).mouseover( function(event) { + if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') { + active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event)); + $(target(event)).addClass(CLASSES.ACTIVE); + } + }).click(function(event) { + $(target(event)).addClass(CLASSES.ACTIVE); + select(); + // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus + input.focus(); + return false; + }).mousedown(function() { + config.mouseDownOnSelect = true; + }).mouseup(function() { + config.mouseDownOnSelect = false; + }); + + if( options.width > 0 ) + element.css("width", options.width); + + needsInit = false; + } + + function target(event) { + var element = event.target; + while(element && element.tagName != "LI") + element = element.parentNode; + // more fun with IE, sometimes event.target is empty, just ignore it then + if(!element) + return []; + return element; + } + + function moveSelect(step) { + listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE); + movePosition(step); + var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE); + if(options.scroll) { + var offset = 0; + listItems.slice(0, active).each(function() { + offset += this.offsetHeight; + }); + if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) { + list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight()); + } else if(offset < list.scrollTop()) { + list.scrollTop(offset); + } + } + }; + + function movePosition(step) { + active += step; + if (active < 0) { + active = listItems.size() - 1; + } else if (active >= listItems.size()) { + active = 0; + } + } + + function limitNumberOfItems(available) { + return options.max && options.max < available + ? options.max + : available; + } + + function fillList() { + list.empty(); + var max = limitNumberOfItems(data.length); + for (var i=0; i < max; i++) { + if (!data[i]) + continue; + var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term); + if ( formatted === false ) + continue; + var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0]; + $.data(li, "ac_data", data[i]); + } + listItems = list.find("li"); + if ( options.selectFirst ) { + listItems.slice(0, 1).addClass(CLASSES.ACTIVE); + active = 0; + } + // apply bgiframe if available + if ( $.fn.bgiframe ) + list.bgiframe(); + } + + return { + display: function(d, q) { + init(); + data = d; + term = q; + fillList(); + }, + next: function() { + moveSelect(1); + }, + prev: function() { + moveSelect(-1); + }, + pageUp: function() { + if (active != 0 && active - 8 < 0) { + moveSelect( -active ); + } else { + moveSelect(-8); + } + }, + pageDown: function() { + if (active != listItems.size() - 1 && active + 8 > listItems.size()) { + moveSelect( listItems.size() - 1 - active ); + } else { + moveSelect(8); + } + }, + hide: function() { + element && element.hide(); + listItems && listItems.removeClass(CLASSES.ACTIVE); + active = -1; + }, + visible : function() { + return element && element.is(":visible"); + }, + current: function() { + return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]); + }, + show: function() { + var offset = $(input).offset(); + element.css({ + width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(), + top: offset.top + input.offsetHeight, + left: offset.left + }).show(); + if(options.scroll) { + list.scrollTop(0); + list.css({ + maxHeight: options.scrollHeight, + overflow: 'auto' + }); + + if($.browser.msie && typeof document.body.style.maxHeight === "undefined") { + var listHeight = 0; + listItems.each(function() { + listHeight += this.offsetHeight; + }); + var scrollbarsVisible = listHeight > options.scrollHeight; + list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight ); + if (!scrollbarsVisible) { + // IE doesn't recalculate width when scrollbar disappears + listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) ); + } + } + + } + }, + selected: function() { + var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE); + return selected && selected.length && $.data(selected[0], "ac_data"); + }, + emptyList: function (){ + list && list.empty(); + }, + unbind: function() { + element && element.remove(); + } + }; +}; + +$.fn.selection = function(start, end) { + if (start !== undefined) { + return this.each(function() { + if( this.createTextRange ){ + var selRange = this.createTextRange(); + if (end === undefined || start == end) { + selRange.move("character", start); + selRange.select(); + } else { + selRange.collapse(true); + selRange.moveStart("character", start); + selRange.moveEnd("character", end); + selRange.select(); + } + } else if( this.setSelectionRange ){ + this.setSelectionRange(start, end); + } else if( this.selectionStart ){ + this.selectionStart = start; + this.selectionEnd = end; + } + }); + } + var field = this[0]; + if ( field.createTextRange ) { + var range = document.selection.createRange(), + orig = field.value, + teststring = "<->", + textLength = range.text.length; + range.text = teststring; + var caretAt = field.value.indexOf(teststring); + field.value = orig; + this.selection(caretAt, caretAt + textLength); + return { + start: caretAt, + end: caretAt + textLength + } + } else if( field.selectionStart !== undefined ){ + return { + start: field.selectionStart, + end: field.selectionEnd + } + } +}; + +})(jQuery); +\ No newline at end of file diff --git a/server/hms/templates/base.html b/server/hms/templates/base.html @@ -0,0 +1,44 @@ +<html> +<head> + <title>{% block title %}Default title{% end %}</title> + <link type="text/css" href="/css/cupertino/jquery-ui-1.7.2.custom.css" rel="Stylesheet" /> + <link type="text/css" href="/css/jquery.autocomplete.css" rel="Stylesheet" /> + <link type="text/css" href="/css/site.css" rel="Stylesheet" /> + {% block head %} + {% end %} +</head> +<body> +<div id="navbar"> +{% if name %} +<a href="/">Home</a> + <strong>|</strong> +<a href="/user/">Users</a> +{% if name == "admin" %} + <strong>|</strong> +<a href="/source/">Media Sources</a> +{% end %} + <strong>|</strong> +<a href="/media/">Media Library</a> + +<div id="loginBox">{% if name %}Logged in as {{ name }} (<a href="/logout">LOGOUT</a>){% end %}</div> +{% end %} +</div> + + +{% block body %} +{% end %} + +<script type="text/javascript" src="/js/jquery-1.3.2.min.js"></script> +<script type="text/javascript" src="/js/jquery-ui-1.7.2.custom.min.js"></script> +<script type="text/javascript" src="/js/jquery.autocomplete.js"></script> +<script type="text/javascript"> +{% block script %} +{% end %} + +$(document).ready(function() { +{% block jquery %} +{% end %} +}); +</script> +</body> +</html> diff --git a/server/hms/templates/index.html b/server/hms/templates/index.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block title %}Home Media Server{% end %} + +{% block body %} + +<div id="user_lists"> +{% for list in lists %} + <div class="list_line"><a href="/media/list/{{ user_id }}/{{ list["id"] }}">{{ list["name"] }}</a></div> +{% end %} + +</div> + +{% end %} diff --git a/server/hms/templates/login.html b/server/hms/templates/login.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} + +{% block title %}Login - Home Media Server{% end %} + +{% block body %} +<form action="{{ request.path }}" method="post" id="loginForm"> + <div class="form-input"><label for="username">{{ _("Username") }}</label> + <input type="text" name="username" id="username"/> + </div> + <div class="form-input"> + <label for="password">{{ _("Password") }}</label> + <input type="password" name="password" id="password"/> + </div> + + <div class="submit"> + <input type="submit" value="{{ _("Sign in") }}"/> + </div> + {{ xsrf_form_html() }} +</form> +{% end %} diff --git a/server/hms/templates/media.html b/server/hms/templates/media.html @@ -0,0 +1,33 @@ +{% extends "base.html" %} + +{% block title %}Media Library - Home Media Server{% end %} + +{% block jquery %} + var listData = {{ json_encode(lists) }}; + $(".lists").autocomplete(listData); +{% end %} + +{% block body %} +<div id="Media"> +<form action="/list/update/{{ user_id }}" method="POST"> +<table> +{% for item in media %} + <tr> + <td>{{ escape(item["title"] or basename(item["path"])) }}</td> + <td><input type="text" class="lists" name="list-{{item["id"]}}" value="{{item["listname"]}}" /> + + <td> + {% if name == 'admin' %} + <a href="/media/edit/{{item["id"]}}">EDIT</a> + <a href="/media/delete/{{item["id"]}}">DELETE</a> + {% end %} + </td> + </tr> +{% end %} +</table> +<button type="submit" id="update">Update</button> +{{ xsrf_form_html() }} +</form> +</div> + +{% end %} diff --git a/server/hms/templates/mediaedit.html b/server/hms/templates/mediaedit.html @@ -0,0 +1,195 @@ +{% extends "base.html" %} +{% block title %}Edit Media - Home Media Server{% end %} + +{% block head %} +<link type="text/css" href="/css/mediaedit.css" rel="Stylesheet" /> +{% end %} + +{% block jquery %} + $('#releaseDate').datepicker(); + + {% if metadata["streamQuality"] == "HD" %} + $(".sd").hide(); + $(".hd").show(); + {% else %} + $(".sd").show(); + $(".hd").hide(); + {% end %} + + $('#streamQuality').change(function(){ + $(".sd").toggle(); + $(".hd").toggle(); + }); +{% end %} + +{% block body %} +<form action="/tmdb/search/{{ metadata["id"] }}" method="post" class="ui-dialog" id="searchForm"> +<fieldset id="search_themoviedb"> + <legend>Search themoviedb.org</legend> + <div class="form-input"><label for="searchTitle">Title</label> + <input type="text" size="40" name="searchTitle"> + </div> + <input type="submit" value="{{ _("Search") }}"/> + + {{ xsrf_form_html() }} +</form> +</fieldset> + +<form enctype="multipart/form-data" action="/media/edit/{{ metadata["id"] }}" method="post" class="ui-dialog" id="mediaForm"> + <fieldset id="media_images"> + <legend>Images</legend> + + {% if not metadata["sdPosterUrl"] %} + <img src="/media/image/sd/{{ metadata["id"] }}" /> + <div class="form-input"><label for="sdPosterImage">SD Image</label> + <input name="sdPosterImage" type="file" /> + </div> + <img src="/media/image/hd/{{ metadata["id"] }}" /> + <div class="form-input"><label for="hdPosterImage">HD Image</label> + <input name="hdPosterImage" type="file" /> + </div> + {% else %} + <div class="covers"> + {% for poster in metadata["posters"]["cover"] %} + <div class="cover-selection"> + <img src="{{ poster["url"] }}" width="150" /> + <input type="radio" name="sdPosterUrl" value="{{ poster["url"] }}" /> + </div> + {% end %} + </div> + {% end %} + </fieldset> + <fieldset id="movie_details"> + <legend>Movie Details</legend> + <select name="contentType"> + <option value="movie" {% if metadata["contentType"] == "movie" %}selected{% end %}>Movie</option> + <option value="episode" {% if metadata["contentType"] == "episode" %}selected{% end %}>Episode</option> + <option value="season" {% if metadata["contentType"] == "season" %}selected{% end %}>Season</option> + <option value="series" {% if metadata["contentType"] == "series" %}selected{% end %}>Series</option> + <option value="audio" {% if metadata["contentType"] == "audio" %}selected{% end %}>Audio</option> + </select> + + <div class="form-input"><label for="title">Title or Episode Name</label> + <input type="text" size="80" name="title" value="{{ metadata["title"] or "" }}" /> + </div> + + <div class="form-input"><label for="episodeNumber">Episode #</label> + <input type="text" name="episodeNumber" value="{{ metadata["episodeNumber"] or "" }}" /> + </div> + + <div class="form-input"><label for="titleSeason">Season Title</label> + <input type="text" size="80" name="titleSeason" value="{{ metadata["titleSeason"] or "" }}" /> + </div> + + <div class="form-input"><label for="shortDescriptionLine1">Short desc. #1</label> + <input type="text" size="80" name="shortDescriptionLine1" value="{{ metadata["shortDescriptionLine1"] or ""}}" /> + </div> + <div class="form-input"><label for="shortDescriptionLine2">Short desc. #2</label> + <input type="text" size="80" name="shortDescriptionLine2" value="{{ metadata["shortDescriptionLine2"] or ""}}" /> + </div> + + <div class="form-input"><label for="description">Description</label> + <textarea cols="80" rows="5" name="description"> + {{ metadata["description"] or "" }} + </textarea> + </div> + + <div class="form-input"><label for="actors">Actor(s)</label> + <input type="text" size="80" name="actors" value="{{ metadata["actors"] or "" }}" /> + </div> + + <div class="form-input"><label for="director">Director(s)</label> + <input type="text" size="80" name="director" value="{{ metadata["director"] or "" }}" /> + </div> + + <div class="form-input"><label for="categories">Categories</label> + <input type="text" size="80" name="categories" value="{{ metadata["categories"] or "" }}" /> + </div> + + <div class="form-input"><label for="releaseDate">Release Date</label> + <input type="text" name="releaseDate" id="releaseDate" value="{{ metadata["releaseDate"] }}" /></div> + + <select name="rating"> + {% for rating in ratings %} + <option value="{{ rating }}" {% if metadata["rating"] == rating %}selected{% end %}>{{ rating }}</option> + {% end %} + </select> + + <div class="form-input"><label for="starRating">Rating (0-100)</label> + <input type="text" name="starRating" value="{{ metadata["starRating"] or "" }}" /> + </div> + + <div class="form-input"><label for="userStarRating">User Rating (0-100)</label> + <input type="text" name="userStarRating" value="{{ metadata["userStarRating"] or "" }}" /> + </div> + </fieldset> + + <fieldset id="file_details"> + <legend>File Details</legend> + <div class="form-input"><label for="path">Path</label> + <input type="text" size="80" name="path" value="{{ metadata["path"] or "" }}" readonly /> + </div> + + <select name="streamFormat"> + <option value="mp4" {% if metadata["streamFormat"] == "mp4" %}selected{% end %}>mp4</option> + <option value="wmv" {% if metadata["streamFormat"] == "wmv" %}selected{% end %}>wmv</option> + <option value="mp3" {% if metadata["streamFormat"] == "mp3" %}selected{% end %}>mp3</option> + <option value="wma" {% if metadata["streamFormat"] == "wma" %}selected{% end %}>wma</option> + </select> + + <div class="form-input"><label for="bitrate">Bitrate (kbps)</label> + <input type="text" size="10" name="bitrate" value="{{ metadata["bitrate"] or "0" }}" /> + </div> + + <div class="form-input"><label for="legth">Length (secs)</label> + <input type="text" size="10" name="length" value="{{ metadata["length"] or "0"}}" /> + </div> + + <div class="form-input"><label for="media_description">Media Details</label> + <input type="text" size="80" name="media_description" value="{{ metadata["media_description"] or ""}}" /> + </div> + + <div class="form-input"><label for="live">Live Stream</label> + <input type="checkbox" name="live" {% if metadata["live"] %}checked{% end %} /> + </div> + </fieldset> + + <fieldset id="stream_quality"> + <legend>Stream Quality</legend> + <select name="streamQuality" id="streamQuality"> + <option value="SD" {% if metadata["streamQuality"] == "SD" %}selected{% end %}>SD</option> + <option value="HD" {% if metadata["streamQuality"] == "HD" %}selected{% end %}>HD</option> + </select> + + <div class="form-input, sd"><label for="sdBifUrl">SD BIF File</label> + <input type="text" size="80" name="sdBifUrl" value="{{ metadata["sdBifUrl"] or "" }}" /> + </div> + + <div class="form-input, hd"><label for="hdBifUrl">HD BIF File</label> + <input type="text" size="80" name="hdBifUrl" value="{{ metadata["hdBifUrl"] or "" }}" /> + </div> + + <div class="form-input, hd"><label for="hdPosterUrl">HD Cover URL</label> + + <div class="form-input, hd"><label for="hdBranded">HD Branded</label> + <input type="checkbox" name="hdBranded" {% if metadata["hdBranded"] %}checked{% end %} /></div> + + <div class="form-input, hd"><label for="isHD">is HD</label> + <input type="checkbox" name="isHD" {% if metadata["isHD"] %}checked{% end %} /></div> + </fieldset> + + <fieldset id="audio"> + <legend>Audio</legend> + <div class="form-input"><label for="album">Album</label> + <input type="text" size="80" name="album" value="{{ metadata["album"] or "" }}" /></div> + + <div class="form-input"><label for="artist">Artist</label> + <input type="text" size="80" name="artist" value="{{ metadata["artist"] or "" }}" /></div> + </fieldset> + + <input type="submit" value="{{ _("Update") }}"/> + + {{ xsrf_form_html() }} +</form> +</div> +{% end %} diff --git a/server/hms/templates/medialist.html b/server/hms/templates/medialist.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block title %}Media List - Home Media Server{% end %} + +{% block body %} + +<div id="media_list"> +{% for item in media %} + <div class="media_line"><a href="{{ item["url"] }}">{{ item["title"] }}</a></div> +{% end %} + +</div> + +{% end %} diff --git a/server/hms/templates/sources.html b/server/hms/templates/sources.html @@ -0,0 +1,44 @@ +{% extends "base.html" %} + +{% block title %}Media Sources{% end %} + +{% block body %} +<div id="Sources"> +<fieldset> +<legend>Add Media Source</legend> +<form action="{{ request.path }}add" method="post" id="sourceForm"> + <div class="form-input"> + <label for="name">{{ _("Source Name") }}</label> + <input type="text" name="name" id="name" size="40"/> + </div> + + <div class="form-input"> + <label for="type">{{ _("Type") }}</label> + <select name="type" id="type"> + <option value="local">Local Directory</option> + <option value="remote">Remote URL</option> + </select> + </div> + + <div class="form-input"> + <label for="path">{{ _("Path") }}</label> + <input type="text" name="path" id="path" size="40"/> + </div> + + <div class="submit"> + <input type="submit" value="{{ _("Add Source") }}"/> + </div> + {{ xsrf_form_html() }} +</form> +</fieldset> + +{% for source in sources %} + <li>{{ escape(source[1]) }} - {{ escape(source[3]) }} + <a href="/media/import/{{ source[0] }}">Import New Media</a> + <a href="{{ request.path }}delete/{{ source[0] }}">Delete</a> + <a href="{{ request.path }}edit/{{ source[0] }}">Edit</a> + </li> +{% end %} +</div> + +{% end %} diff --git a/server/hms/templates/tmdbsearch.html b/server/hms/templates/tmdbsearch.html @@ -0,0 +1,35 @@ +{% extends "base.html" %} +{% block title %}Search TMDB - Home Media Server{% end %} + +{% block head %} +<link type="text/css" href="/css/mediaedit.css" rel="Stylesheet" /> +{% end %} + +{% block jquery %} +{% end %} + +{% block body %} +<form action="/tmdb/search/{{ media_id }}" method="post" class="ui-dialog" id="searchForm"> +<fieldset id="search_themoviedb"> + <legend>Search themoviedb.org</legend> + <div class="form-input"><label for="searchTitle">Title</label> + <input type="text" size="40" name="searchTitle"> + </div> + <input type="submit" value="{{ _("Search") }}"/> + + {{ xsrf_form_html() }} +</form> +</fieldset> + +{% for movie in movies %} +<form action="/tmdb/update/{{ media_id }}/{{ movie["id"] }}" method="post"> + <fieldset> + <legend>{{ movie["name"] }}</legend> + <img src="{{ movie["posters"]["cover"]["url"] }}" /> + <input type="submit" value="{{ _("Select") }}"/> + {{ xsrf_form_html() }} + </fieldset> +</form> +{% end %} +{% end %} + diff --git a/server/hms/templates/users.html b/server/hms/templates/users.html @@ -0,0 +1,51 @@ +{% extends "base.html" %} + +{% block title %}Users - Home Media Server{% end %} + +{% block body %} +<div id="Home"> +<fieldset> +<legend>Add New User</legend> +<form action="{{ request.path }}add" method="post" id="userForm"> + <div class="form-input"> + <label for="username">{{ _("Name") }}</label> + <input type="text" name="username" id="username"/> + </div> + <div class="form-input"> + <label for="password">{{ _("Password") }}</label> + <input type="password" name="password" id="password" /> + </div> + + <div class="form-input"> + <label for="password2">{{ _("Confirm") }}</label> + <input type="password" name="password2" id="password2" /> + </div> + + <div class="form-input"> + <label for="email">{{ _("email") }}</label> + <input type="text" name="email" id="email" /> + </div> + + <div class="submit"> + <input type="submit" value="{{ _("Add User") }}"/> + </div> + {{ xsrf_form_html() }} +</form> +</fieldset> + +{% for user in users %} + <li><img src="{{ request.path }}image/{{ user[0]}}" /> + {{ escape(user[1]) }} - {{ user[2] }} + <a href="{{ request.path }}delete/{{ user[0] }}">Delete</a> + <a href="{{ request.path }}edit/{{ user[0] }}">Edit</a> + <form enctype="multipart/form-data" action="{{ request.path }}image/{{ user[0] }}" method="POST"> + Image: <input name="imagefile" type="file" /> + <input type="submit" value="Upload" /> + {{ xsrf_form_html() }} + </form> + </li> +{% end %} +</div> + + +{% end %} diff --git a/server/hms/templates/xmllist.html b/server/hms/templates/xmllist.html @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<feed> + <!-- resultLength indicates the total number of results for this feed --> + <resultLength>{{ len(media) }}</resultLength> + <!-- endIndix indicates the number of results for this *paged* section of the feed --> + <endIndex>{{ len(media) }}</endIndex> + +{% for metadata in media %} +<item sdPosterUrl="{{ metadata["sdPosterUrl"] }}" hdPosterUrl="{{ metadata["hdPosterUrl"] }}"> + <contentType>{{ metadata["contentType"] }}</contentType> + <title>{{ metadata["title"] or "" }}</title> + <titleSeason>{{ metadata["titleSeason"] or "" }}</titleSeason> + <description>{{ metadata["description"] or "" }}</description> + <contentId>{{ metadata["id"] }}</contentId> + <sdBifUrl>{{ metadata["sdbifurl"] }}</sdBifUrl> + <hdBifUrl>{{ metadata["hdbifurl"] }}</hdBifUrl> + + {% for stream in metadata["streams"] %} + <media> + <streamFormat>{{ stream["format"] }}</streamFormat> + <streamQuality>{{ stream["quality"] }}</streamQuality> + <streamBitrate>{{ stream["bitrate"] }}</streamBitrate> + <streamUrl>{{ stream["url"] }}</streamUrl> + </media> + {% end %} + <streamFormat>{{ metadata["streamFormat"] }}</streamFormat> + <length>{{ metadata["length"] }}</length> + <releaseDate>{{ metadata["releaseDate"] or "" }}</releaseDate> + <rating>{{ metadata["rating"] or "" }}</rating> + <starRating>{{ metadata["starRating"] or "0"}}</starRating> + <userStarRating>{{ metadata["userStarRating"] or "0"}}</userStarRating> + <shortDescriptionLine1>{{ metadata["shortDescriptionLine1"] or metadata["title"] or "" }}</shortDescriptionLine1> + <shortDescriptionLine2>{{ metadata["shortDescriptionLine2"] or "" }}</shortDescriptionLine2> + <episodeNumber>{{ metadata["episodeNumber"] or "" }}</episodeNumber> + {% for actor in metadata["actors"] %} + <actor>{{ actor }}</actor>{% end %} + {% for director in metadata["directors"] %} + <director>{{ director }}</director>{% end %} + {% for category in metadata["categories"] %} + <category>{{ category }}</category>{% end %} + <hdBranded>{{ metadata["hdBranded"] }}</hdBranded> + <isHD>{{ metadata["isHD"] }}</isHD> + <textOverlayUL>{{ metadata["textOverlayUL"] or "" }}</textOverlayUL> + <textOverlayUR>{{ metadata["textOverlayUR"] or "" }}</textOverlayUR> + <textOverlayBody>{{ metadata["textOverlayBody"] or "" }}</textOverlayBody> + <album>{{ metadata["album"] or "" }}</album> + <artist>{{ metadata["artist"] or "" }}</artist> +</item> +{% end %} +</feed> diff --git a/server/hms/templates/xmlusers.html b/server/hms/templates/xmlusers.html @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<categories> + + <!-- banner_ad: optional element which displays an at the top level category screen --> + <banner_ad sd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/missing.png" hd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/missing.png"/> + +{% for user in users %} + <category title="{{ user[1] }}" description="" sd_img="{{ host }}/user/image/{{ user[0]}}" hd_img="{{ host }}/user/image/{{ user[0]}}"> + {% for list in user[2] %} + <categoryLeaf title="{{ list[1] }}" description="" feed="{{ host }}/xml/list/{{ user[0] }}/{{ list[0] }}"/> + {% end %} + </category> +{% end %} +</categories> diff --git a/server/hms/tornado.pip b/server/hms/tornado.pip @@ -0,0 +1,3 @@ +pycurl==7.16.4 +simplejson==2.0.9 +-e git://github.com/facebook/tornado.git@b3d98c4a369e50eddb0411af9174b232f8b6ad28#egg=tornado-0.2-py2.6-dev diff --git a/server/hms/translations/README b/server/hms/translations/README diff --git a/server/scripts/makebif.py b/server/scripts/makebif.py @@ -0,0 +1,165 @@ +#!/bin/env python +""" +Create .bif files for Roku video streaming +Copyright 2009 by Brian C. Lane <bcl@brianlane.com> +All Rights Reserved + + +makebif.py --help for arguments + +Requires ffmpeg to be in the path + +After creating the .bif files run the staticvideo.py script to regenerate XML with the +URLs for the bif files included. + +NOTE: The jpg image sizes are set to the values posted by bbefilms in the Roku + development forums. They may or may not be correct for your video aspect ratio. + They don't look right for me when I set the video height to 480 +""" +import os +import sys +import tempfile +from subprocess import Popen, PIPE +import struct +import array +import shutil +from optparse import OptionParser + +# for mode 0, 1, 2, 3 +videoSizes = ["320x240", "240x180", "320x180", "240x136"] + +# Extension to add to the file for mode 0, 1, 2, 3 +modeExtension = ['SD', 'HD', 'SD', 'HD'] + + + +def getMP4Info(filename): + """ + Get mp4 info about the video + """ + details = { 'type':"", 'length':0, 'bitrate':1500, 'format':"", 'size':""} + cmd = "mp4info %s" % (filename) + p = Popen( cmd, shell=True, stdout=PIPE, stderr=PIPE, stdin=PIPE ) + (stdout, stderr) = p.communicate() + # Parse the results + for line in stdout.split('\n'): + fields = line.split(None, 2) + try: + if fields[1] == 'video': + # parse the video info + # MPEG-4 Simple @ L3, 5706.117 secs, 897 kbps, 712x480 @ 23.9760 24 fps + videoFields = fields[2].split(',') + details['type'] = videoFields[0] + details['length'] = float(videoFields[1].split()[0]) + details['bitrate'] = float(videoFields[2].split()[0]) + details['format'] = videoFields[3] + details['size'] = videoFields[3].split('@')[0].strip() + except: + pass + + return details + + +def extractImages( videoFile, directory, interval, mode=0 ): + """ + Extract images from the video at 'interval' seconds + + @param mode 0=SD 4:3 1=HD 4:3 2=SD 16:9 3=HD 16:9 + @param directory Directory to write images into + @param interval interval to extract images at, in seconds + + """ + cmd = "ffmpeg -i %s -r %0.2f -s %s %s/%%08d.jpg" % (videoFile, interval/100.0, videoSizes[mode], directory) + print cmd + p = Popen( cmd, shell=True, stdout=PIPE, stdin=PIPE) + (stdout, stderr) = p.communicate() + print stderr + + +def makeBIF( filename, directory, interval ): + """ + Build a .bif file for the Roku Player Tricks Mode + + @param filename name of .bif file to create + @param directory Directory of image files 00000001.jpg + @param interval Time, in seconds, between the images + """ + magic = [0x89,0x42,0x49,0x46,0x0d,0x0a,0x1a,0x0a] + version = 0 + + files = os.listdir("%s" % (directory)) + images = [] + for image in files: + if image[-4:] == '.jpg': + images.append(image) + images.sort() + + f = open(filename, "wb") + array.array('B', magic).tofile(f) + f.write(struct.pack("<I1", version)) + f.write(struct.pack("<I1", len(images))) + f.write(struct.pack("<I1", 1000 * interval)) + array.array('B', [0x00 for x in xrange(20,64)]).tofile(f) + + bifTableSize = 8 + (8 * len(images)) + imageIndex = 64 + bifTableSize + timestamp = 1 + + # Get the length of each image + for image in images: + statinfo = os.stat("%s/%s" % (directory, image)) + f.write(struct.pack("<I1", timestamp)) + f.write(struct.pack("<I1", imageIndex)) + + timestamp += 1 + imageIndex += statinfo.st_size + + f.write(struct.pack("<I1", 0xffffffff)) + f.write(struct.pack("<I1", imageIndex)) + + # Now copy the images + for image in images: + data = open("%s/%s" % (directory, image), "rb").read() + f.write(data) + + f.close() + + +def main(): + """ + Extract jpg images from the video and create a .bif file + """ + parser = OptionParser() + parser.add_option( "-m", "--mode", dest="mode", type='int', default=0, + help="(0=SD) 4:3 1=HD 4:3 2=SD 16:9 3=HD 16:9") + parser.add_option( "-i", "--interval", dest="interval", type='int', default=10, + help="Interval between images in seconds (default is 10)") + + (options, args) = parser.parse_args() + + # Get the video file to operate on + videoFile = args[0] + print "Creating .BIF file for %s" % (videoFile) + + # This may be useful for determining the video format + # Get info about the video file +# videoInfo = getMP4Info(videoFile) +# print videoInfo + + tmpDirectory = tempfile.mkdtemp() + + # Extract jpg images from the video file + extractImages( videoFile, tmpDirectory, options.interval, options.mode ) + + bifFile = "%s-%s.bif" % (os.path.basename(videoFile).rsplit('.',1)[0], modeExtension[options.mode]) + + # Create the BIF file + makeBIF( bifFile, tmpDirectory, options.interval ) + + # Clean up the temporary directory + shutil.rmtree(tmpDirectory) + + +if __name__ == '__main__': + main() + diff --git a/server/scripts/staticvideo.py b/server/scripts/staticvideo.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +staticvideo.py + +Created by Brian Lane on 2009-12-20. +Copyright (c) 2009 Nexus Computing. All rights reserved. + + +Categories example XML: + +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<categories> + <banner_ad sd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/missing.png" hd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/missing.png"/> + +<category title="Technology" description="TED Talks on Technology" sd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/TED_Technology.png" hd_img="http://rokudev.roku.com/rokudev/examples/videoplayer/images/TED_Technology.png"> + <categoryLeaf title="The Mind" description="" feed="http://rokudev.roku.com/rokudev/examples/videoplayer/xml/themind.xml"/> + <categoryLeaf title="Global Issues" description="" feed="http://rokudev.roku.com/rokudev/examples/videoplayer/xml/globalissues.xml" /> +</category> + +</categories> + +Example Feed XML: + +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<feed> + <!-- resultLength indicates the total number of results for this feed --> + <resultLength>4</resultLength> + <!-- endIndix indicates the number of results for this *paged* section of the feed --> + <endIndex>4</endIndex> + <item sdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/JeffHan.jpg" hdImg="http://rokudev.roku.com/rokudev/examples/videoplayer/images/JeffHan.jpg"> + <title>Jeff Han demos his breakthrough touchscreen</title> + <contentId>10061</contentId> + <contentType>Talk</contentType> + <contentQuality>SD</contentQuality> + <media> + <streamFormat>mp4</streamFormat> + <streamQuality>SD</streamQuality> + <streamBitrate>1500</streamBitrate> + <streamUrl>http://video.ted.com/talks/podcast/JeffHan_2006_480.mp4</streamUrl> + </media> + <synopsis>After years of research on touch-driven computer displays, Jeff Han has created a simple, multi-touch, multi-user screen interface that just might herald the end of the point-and-click era.</synopsis> + <genres>Design</genres> + <runtime>531</runtime> + </item> +</feed> + + + +1st pass: + * create a sqlite database someplace + * --add command to add a new movie + * generate static XML + + +""" + +import sys +import os +import sqlite3 +from optparse import OptionParser +from subprocess import Popen, PIPE + +BASE_URL="http://wyatt.home/movies/" + +def setup_config(path): + """ + Create the configuration directory + Setup the SQLite database + Ask for the Amazon AWS credentials + + + """ + pass +# os.mkdir(path, 0700) +# conn = sqlite3.connect(os.path.join(path,"homevideo.db")) +# c = conn.cursor() +# c.execute('''create table stocks +# (date text, trans text, symbol text, +# qty real, price real)''') +# +# conn.commit() +# c.close() + + +def getMP4Info(filename): + """ + Get mp4 info about the video + """ + details = { 'type':"", 'length':0, 'bitrate':1500, 'format':""} + cmd = "mp4info %s" % (filename) + p = Popen( cmd, shell=True, stdout=PIPE, stderr=PIPE, stdin=PIPE ) + (stdout, stderr) = p.communicate() + + # Parse the results + for line in stdout.split('\n'): + fields = line.split(None, 2) + try: + if fields[1] == 'video': + # parse the video info + # MPEG-4 Simple @ L3, 5706.117 secs, 897 kbps, 712x480 @ 23.976024 fps + videoFields = fields[2].split(',') + details['type'] = videoFields[0] + details['length'] = float(videoFields[1].split()[0]) + details['bitrate'] = float(videoFields[2].split()[0]) + details['format'] = videoFields[3] + except: + pass + + return details + + +def makeFeedNode(filename): + """ + Create a simple XML node using the filename + """ + details = getMP4Info(filename) + + coverImage = "default.jpg" + title = filename[:-4] + contentID = 100 + contentType = "Movie" + contentQuality = "SD" + streamFormat = "mp4" + streamQuality = "SD" + streamBitrate = details['bitrate'] + runtime = int(details['length']) + genres = ["Unknown"] + sdBifUrl = None + hdBifUrl = None + synopsis = "%s %s %d kbps" % (details['type'], details['format'], details['bitrate']) + + bifname = "%s-SD.bif" % (filename.rsplit('.', 1)[0]) + if (os.path.isfile(bifname)): + sdBifUrl = bifname + bifname = "%s-HD.bif" % (filename.rsplit('.', 1)[0]) + if (os.path.isfile(bifname)): + hdBifUrl = bifname + + xml = '<item sdImg="%simages/%s" hdImg="%simages/%s">\n' % (BASE_URL, coverImage, BASE_URL, coverImage) + xml += ' <title>%s</title>\n' % (title) + xml += ' <contentId>%d</contentId>\n' % (contentID) + xml += ' <contentType>%s</contentType>\n' % (contentType) + xml += ' <contentQuality>%s</contentQuality>\n' % (contentQuality) + xml += ' <media>\n' + xml += ' <streamFormat>%s</streamFormat>\n' % (streamFormat) + xml += ' <streamQuality>%s</streamQuality>\n' % (streamQuality) + xml += ' <streamBitrate>%d</streamBitrate>\n' % (streamBitrate) + xml += ' <streamUrl>%s%s</streamUrl>\n' % (BASE_URL, filename) + xml += ' </media>\n' + + if sdBifUrl: + xml += ' <sdBifUrl>%s%s</sdBifUrl>\n' % (BASE_URL, sdBifUrl) + if hdBifUrl: + xml += ' <hdBifUrl>%s%s</hdBifUrl>\n' % (BASE_URL, hdBifUrl) + + xml += ' <synopsis>%s</synopsis>\n' % (synopsis) + xml += ' <genres>%s</genres>\n' % (','.join(genres)) + xml += ' <runtime>%d</runtime>\n' % (runtime) + xml += '</item>\n' + + return xml + + +def makeDirXml(): + """ + Make an XML file of the video in the current directory + + mp4, m4v extensions + """ + nodes = [] + files = os.listdir(".") + files.sort() + for f in files: + if f[-3:] in ['mp4', 'm4v']: + nodes.append( makeFeedNode(f) ) + + feedXML = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n' + feedXML += '<feed>\n' + feedXML += '<resultLength>%d</resultLength>\n' % (len(nodes)) + feedXML += '<endIndex>%d</endIndex>\n' % (len(nodes)) + for n in nodes: + feedXML += n + feedXML += '</feed>\n' + + print feedXML + + + +def main(): + """ + Setup environment if it is missing + + Parse command line options + """ + if os.getuid() == 0: + sys.stderr.write("Please do not run as root, use an unprivledged user") + sys.exit(-1) + + + parser = OptionParser(version="%prog $Id$") + parser.add_option("-a", "--add", dest="add", + help="add a movie") + parser.add_option("-d", "--directory", dest="dir", + default="~/.homevideo", + help="Directory for config and sqlite db") + + (options, args) = parser.parse_args() + + if not os.path.isdir(options.dir): +# print("Creating config directory: %s" % (options.dir)) + setup_config(options.dir) + + if options.add: + print("Add a movie: %s" % (options.add)) + + + makeDirXml() + + + +if __name__ == '__main__': + main() +