From 23d0180b20f211402bb2974325512a01f43c306e Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Tue, 30 Apr 2013 20:19:03 -0400 Subject: [PATCH] More loops to tackle. --- src/StepsUtil.cpp | 729 +++++++++++++++++++++++----------------------- 1 file changed, 361 insertions(+), 368 deletions(-) diff --git a/src/StepsUtil.cpp b/src/StepsUtil.cpp index b1bdf75d50..f9c4ee8676 100644 --- a/src/StepsUtil.cpp +++ b/src/StepsUtil.cpp @@ -1,368 +1,361 @@ -#include "global.h" -#include "StepsUtil.h" -#include "Steps.h" -#include "ProfileManager.h" -#include "Profile.h" -#include "Song.h" -#include "SongManager.h" -#include "GameManager.h" -#include "XmlFile.h" -#include "UnlockManager.h" -#include "SongUtil.h" - - -bool StepsCriteria::Matches( const Song *pSong, const Steps *pSteps ) const -{ - if( m_difficulty != Difficulty_Invalid && pSteps->GetDifficulty() != m_difficulty ) - return false; - if( m_iLowMeter != -1 && pSteps->GetMeter() < m_iLowMeter ) - return false; - if( m_iHighMeter != -1 && pSteps->GetMeter() > m_iHighMeter ) - return false; - if( m_st != StepsType_Invalid && pSteps->m_StepsType != m_st ) - return false; - switch( m_Locked ) - { - DEFAULT_FAIL(m_Locked); - case Locked_Locked: - if( UNLOCKMAN && !UNLOCKMAN->StepsIsLocked(pSong,pSteps) ) - return false; - break; - case Locked_Unlocked: - if( UNLOCKMAN && UNLOCKMAN->StepsIsLocked(pSong,pSteps) ) - return false; - break; - case Locked_DontCare: - break; - } - - return true; -} - -void StepsUtil::GetAllMatching( const SongCriteria &soc, const StepsCriteria &stc, vector &out ) -{ - const RString &sGroupName = soc.m_sGroupName.empty()? GROUP_ALL:soc.m_sGroupName; - const vector &songs = SONGMAN->GetSongs( sGroupName ); - - FOREACH_CONST( Song*, songs, so ) - { - if( !soc.Matches(*so) ) - continue; - GetAllMatching( *so, stc, out ); - } -} - -void StepsUtil::GetAllMatching( Song *pSong, const StepsCriteria &stc, vector &out ) -{ - const vector &vSteps = ( stc.m_st == StepsType_Invalid ? pSong->GetAllSteps() : - pSong->GetStepsByStepsType(stc.m_st) ); - - FOREACH_CONST( Steps*, vSteps, st ) - if( stc.Matches(pSong, *st) ) - out.push_back( SongAndSteps(pSong, *st) ); -} - -bool StepsUtil::HasMatching( const SongCriteria &soc, const StepsCriteria &stc ) -{ - const RString &sGroupName = soc.m_sGroupName.empty()? GROUP_ALL:soc.m_sGroupName; - const vector &songs = SONGMAN->GetSongs( sGroupName ); - - FOREACH_CONST( Song*, songs, so ) - { - if( soc.Matches(*so) && HasMatching(*so, stc) ) - return true; - } - return false; -} - -bool StepsUtil::HasMatching( const Song *pSong, const StepsCriteria &stc ) -{ - const vector &vSteps = stc.m_st == StepsType_Invalid? pSong->GetAllSteps():pSong->GetStepsByStepsType( stc.m_st ); - - FOREACH_CONST( Steps*, vSteps, st ) - { - if( stc.Matches(pSong, *st) ) - return true; - } - return false; -} - -// Sorting stuff -map steps_sort_val; - -static bool CompareStepsPointersBySortValueAscending(const Steps *pSteps1, const Steps *pSteps2) -{ - return steps_sort_val[pSteps1] < steps_sort_val[pSteps2]; -} - -static bool CompareStepsPointersBySortValueDescending(const Steps *pSteps1, const Steps *pSteps2) -{ - return steps_sort_val[pSteps1] > steps_sort_val[pSteps2]; -} - -void StepsUtil::SortStepsPointerArrayByNumPlays( vector &vStepsPointers, ProfileSlot slot, bool bDescending ) -{ - if( !PROFILEMAN->IsPersistentProfile(slot) ) - return; // nothing to do since we don't have data - Profile* pProfile = PROFILEMAN->GetProfile(slot); - SortStepsPointerArrayByNumPlays( vStepsPointers, pProfile, bDescending ); -} - -void StepsUtil::SortStepsPointerArrayByNumPlays( vector &vStepsPointers, const Profile* pProfile, bool bDecending ) -{ - // ugly... - vector vpSongs = SONGMAN->GetAllSongs(); - vector vpAllSteps; - map mapStepsToSong; - { - for( unsigned i=0; i vpSteps = pSong->GetAllSteps(); - for( unsigned j=0; jIsAutogen() ) - continue; // skip - vpAllSteps.push_back( pSteps ); - mapStepsToSong[pSteps] = pSong; - } - } - } - - ASSERT( pProfile != NULL ); - for(unsigned i = 0; i < vStepsPointers.size(); ++i) - { - Steps* pSteps = vStepsPointers[i]; - Song* pSong = mapStepsToSong[pSteps]; - steps_sort_val[vStepsPointers[i]] = ssprintf("%9i", pProfile->GetStepsNumTimesPlayed(pSong,pSteps)); - } - stable_sort( vStepsPointers.begin(), vStepsPointers.end(), bDecending ? CompareStepsPointersBySortValueDescending : CompareStepsPointersBySortValueAscending ); - steps_sort_val.clear(); -} - -bool StepsUtil::CompareNotesPointersByRadarValues(const Steps* pSteps1, const Steps* pSteps2) -{ - float fScore1 = 0; - float fScore2 = 0; - - fScore1 += pSteps1->GetRadarValues( PLAYER_1 )[RadarCategory_TapsAndHolds]; - fScore2 += pSteps2->GetRadarValues( PLAYER_1 )[RadarCategory_TapsAndHolds]; - - return fScore1 < fScore2; -} - -bool StepsUtil::CompareNotesPointersByMeter(const Steps *pSteps1, const Steps* pSteps2) -{ - return pSteps1->GetMeter() < pSteps2->GetMeter(); -} - -bool StepsUtil::CompareNotesPointersByDifficulty(const Steps *pSteps1, const Steps *pSteps2) -{ - return pSteps1->GetDifficulty() < pSteps2->GetDifficulty(); -} - -void StepsUtil::SortNotesArrayByDifficulty( vector &arraySteps ) -{ - /* Sort in reverse order of priority. Sort by description first, to get - * a predictable order for songs with no radar values (edits). */ - stable_sort( arraySteps.begin(), arraySteps.end(), CompareStepsPointersByDescription ); - stable_sort( arraySteps.begin(), arraySteps.end(), CompareNotesPointersByRadarValues ); - stable_sort( arraySteps.begin(), arraySteps.end(), CompareNotesPointersByMeter ); - stable_sort( arraySteps.begin(), arraySteps.end(), CompareNotesPointersByDifficulty ); -} - -bool StepsUtil::CompareStepsPointersByTypeAndDifficulty(const Steps *pStep1, const Steps *pStep2) -{ - if( pStep1->m_StepsType < pStep2->m_StepsType ) - return true; - if( pStep1->m_StepsType > pStep2->m_StepsType ) - return false; - return pStep1->GetDifficulty() < pStep2->GetDifficulty(); -} - -void StepsUtil::SortStepsByTypeAndDifficulty( vector &arraySongPointers ) -{ - sort( arraySongPointers.begin(), arraySongPointers.end(), CompareStepsPointersByTypeAndDifficulty ); -} - -bool StepsUtil::CompareStepsPointersByDescription(const Steps *pStep1, const Steps *pStep2) -{ - return pStep1->GetDescription().CompareNoCase( pStep2->GetDescription() ) < 0; -} - -void StepsUtil::SortStepsByDescription( vector &arraySongPointers ) -{ - sort( arraySongPointers.begin(), arraySongPointers.end(), CompareStepsPointersByDescription ); -} - -void StepsUtil::RemoveLockedSteps( const Song *pSong, vector &vpSteps ) -{ - for( int i=vpSteps.size()-1; i>=0; i-- ) - { - if( UNLOCKMAN->StepsIsLocked(pSong, vpSteps[i]) ) - vpSteps.erase( vpSteps.begin()+i ); - } -} - - -//////////////////////////////// -// StepsID -//////////////////////////////// - -void StepsID::FromSteps( const Steps *p ) -{ - if( p == NULL ) - { - st = StepsType_Invalid; - dc = Difficulty_Invalid; - sDescription = ""; - uHash = 0; - } - else - { - st = p->m_StepsType; - dc = p->GetDifficulty(); - if( dc == Difficulty_Edit ) - { - sDescription = p->GetDescription(); - uHash = p->GetHash(); - } - else - { - sDescription = ""; - uHash = 0; - } - } - - m_Cache.Unset(); -} - -/* XXX: Don't allow duplicate edit descriptions, and don't allow edit descriptions - * to be difficulty names (eg. "Hard"). If we do that, this will be completely unambiguous. - * - * XXX: Unless two memcards are inserted and there's overlap in the names. In that - * case, maybe both edits should be renamed to "Pn: foo"; as long as we don't write - * them back out (which we don't do except in the editor), it won't be permanent. - * We could do this during the actual Steps::GetID() call, instead, but then it'd have - * to have access to Song::m_LoadedFromProfile. */ - -Steps *StepsID::ToSteps( const Song *p, bool bAllowNull ) const -{ - if( st == StepsType_Invalid || dc == Difficulty_Invalid ) - return NULL; - - SongID songID; - songID.FromSong( p ); - - Steps *pRet = NULL; - if( dc == Difficulty_Edit ) - { - pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, sDescription, "", uHash, true ); - } - else - { - pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, "", "", 0, true ); - } - - if( !bAllowNull && pRet == NULL ) - FAIL_M( ssprintf("%i, %i, \"%s\"", st, dc, sDescription.c_str()) ); - - m_Cache.Set( pRet ); - - return pRet; -} - -XNode* StepsID::CreateNode() const -{ - XNode* pNode = new XNode( "Steps" ); - - pNode->AppendAttr( "StepsType", GAMEMAN->GetStepsTypeInfo(st).szName ); - pNode->AppendAttr( "Difficulty", DifficultyToString(dc) ); - if( dc == Difficulty_Edit ) - { - pNode->AppendAttr( "Description", sDescription ); - pNode->AppendAttr( "Hash", uHash ); - } - - return pNode; -} - -void StepsID::LoadFromNode( const XNode* pNode ) -{ - ASSERT( pNode->GetName() == "Steps" ); - - RString sTemp; - - pNode->GetAttrValue( "StepsType", sTemp ); - st = GAMEMAN->StringToStepsType( sTemp ); - - pNode->GetAttrValue( "Difficulty", sTemp ); - dc = StringToDifficulty( sTemp ); - - if( dc == Difficulty_Edit ) - { - pNode->GetAttrValue( "Description", sDescription ); - pNode->GetAttrValue( "Hash", uHash ); - } - else - { - sDescription = ""; - uHash = 0; - } - - m_Cache.Unset(); -} - -RString StepsID::ToString() const -{ - RString s = GAMEMAN->GetStepsTypeInfo( st ).szName; - s += " " + DifficultyToString( dc ); - if( dc == Difficulty_Edit ) - { - s += " " + sDescription; - s += ssprintf(" %u", uHash ); - } - return s; -} - -bool StepsID::IsValid() const -{ - return st != StepsType_Invalid && dc != Difficulty_Invalid; -} - -bool StepsID::operator<( const StepsID &rhs ) const -{ -#define COMP(a) if(arhs.a) return false; - COMP(st); - COMP(dc); - COMP(sDescription); - COMP(uHash); -#undef COMP - return false; -} - -/* - * (c) 2001-2004 Chris Danford, Glenn Maynard - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#include "global.h" +#include "StepsUtil.h" +#include "Steps.h" +#include "ProfileManager.h" +#include "Profile.h" +#include "Song.h" +#include "SongManager.h" +#include "GameManager.h" +#include "XmlFile.h" +#include "UnlockManager.h" +#include "SongUtil.h" + + +bool StepsCriteria::Matches( const Song *pSong, const Steps *pSteps ) const +{ + if( m_difficulty != Difficulty_Invalid && pSteps->GetDifficulty() != m_difficulty ) + return false; + if( m_iLowMeter != -1 && pSteps->GetMeter() < m_iLowMeter ) + return false; + if( m_iHighMeter != -1 && pSteps->GetMeter() > m_iHighMeter ) + return false; + if( m_st != StepsType_Invalid && pSteps->m_StepsType != m_st ) + return false; + switch( m_Locked ) + { + DEFAULT_FAIL(m_Locked); + case Locked_Locked: + if( UNLOCKMAN && !UNLOCKMAN->StepsIsLocked(pSong,pSteps) ) + return false; + break; + case Locked_Unlocked: + if( UNLOCKMAN && UNLOCKMAN->StepsIsLocked(pSong,pSteps) ) + return false; + break; + case Locked_DontCare: + break; + } + + return true; +} + +void StepsUtil::GetAllMatching( const SongCriteria &soc, const StepsCriteria &stc, vector &out ) +{ + const RString &sGroupName = soc.m_sGroupName.empty()? GROUP_ALL:soc.m_sGroupName; + const vector &songs = SONGMAN->GetSongs( sGroupName ); + + for (Song *so : songs) + { + if( !soc.Matches(so) ) + continue; + GetAllMatching( so, stc, out ); // TODO: Look into why this can't be const. + } +} + +void StepsUtil::GetAllMatching( Song *pSong, const StepsCriteria &stc, vector &out ) +{ + const vector &vSteps = ( stc.m_st == StepsType_Invalid ? pSong->GetAllSteps() : + pSong->GetStepsByStepsType(stc.m_st) ); + + for (Steps *st : vSteps) + if( stc.Matches(pSong, st) ) + out.push_back( SongAndSteps(pSong, st) ); +} + +bool StepsUtil::HasMatching( const SongCriteria &soc, const StepsCriteria &stc ) +{ + const RString &sGroupName = soc.m_sGroupName.empty()? GROUP_ALL:soc.m_sGroupName; + const vector &songs = SONGMAN->GetSongs( sGroupName ); + + return std::any_of(songs.begin(), songs.end(), [&](Song const *so) { + return soc.Matches(so) && HasMatching(so, stc); + }); +} + +bool StepsUtil::HasMatching( const Song *pSong, const StepsCriteria &stc ) +{ + const vector &vSteps = stc.m_st == StepsType_Invalid? pSong->GetAllSteps():pSong->GetStepsByStepsType( stc.m_st ); + return std::any_of(vSteps.begin(), vSteps.end(), [&](Steps const *st) { + return stc.Matches(pSong, st); + }); +} + +// Sorting stuff +map steps_sort_val; + +static bool CompareStepsPointersBySortValueAscending(const Steps *pSteps1, const Steps *pSteps2) +{ + return steps_sort_val[pSteps1] < steps_sort_val[pSteps2]; +} + +static bool CompareStepsPointersBySortValueDescending(const Steps *pSteps1, const Steps *pSteps2) +{ + return steps_sort_val[pSteps1] > steps_sort_val[pSteps2]; +} + +void StepsUtil::SortStepsPointerArrayByNumPlays( vector &vStepsPointers, ProfileSlot slot, bool bDescending ) +{ + if( !PROFILEMAN->IsPersistentProfile(slot) ) + return; // nothing to do since we don't have data + Profile* pProfile = PROFILEMAN->GetProfile(slot); + SortStepsPointerArrayByNumPlays( vStepsPointers, pProfile, bDescending ); +} + +void StepsUtil::SortStepsPointerArrayByNumPlays( vector &vStepsPointers, const Profile* pProfile, bool bDecending ) +{ + // ugly... + vector vpSongs = SONGMAN->GetAllSongs(); + vector vpAllSteps; + map mapStepsToSong; + { + for( unsigned i=0; i vpSteps = pSong->GetAllSteps(); + for( unsigned j=0; jIsAutogen() ) + continue; // skip + vpAllSteps.push_back( pSteps ); + mapStepsToSong[pSteps] = pSong; + } + } + } + + ASSERT( pProfile != NULL ); + for(unsigned i = 0; i < vStepsPointers.size(); ++i) + { + Steps* pSteps = vStepsPointers[i]; + Song* pSong = mapStepsToSong[pSteps]; + steps_sort_val[vStepsPointers[i]] = ssprintf("%9i", pProfile->GetStepsNumTimesPlayed(pSong,pSteps)); + } + stable_sort( vStepsPointers.begin(), vStepsPointers.end(), bDecending ? CompareStepsPointersBySortValueDescending : CompareStepsPointersBySortValueAscending ); + steps_sort_val.clear(); +} + +bool StepsUtil::CompareNotesPointersByRadarValues(const Steps* pSteps1, const Steps* pSteps2) +{ + float fScore1 = 0; + float fScore2 = 0; + + fScore1 += pSteps1->GetRadarValues( PLAYER_1 )[RadarCategory_TapsAndHolds]; + fScore2 += pSteps2->GetRadarValues( PLAYER_1 )[RadarCategory_TapsAndHolds]; + + return fScore1 < fScore2; +} + +bool StepsUtil::CompareNotesPointersByMeter(const Steps *pSteps1, const Steps* pSteps2) +{ + return pSteps1->GetMeter() < pSteps2->GetMeter(); +} + +bool StepsUtil::CompareNotesPointersByDifficulty(const Steps *pSteps1, const Steps *pSteps2) +{ + return pSteps1->GetDifficulty() < pSteps2->GetDifficulty(); +} + +void StepsUtil::SortNotesArrayByDifficulty( vector &arraySteps ) +{ + /* Sort in reverse order of priority. Sort by description first, to get + * a predictable order for songs with no radar values (edits). */ + stable_sort( arraySteps.begin(), arraySteps.end(), CompareStepsPointersByDescription ); + stable_sort( arraySteps.begin(), arraySteps.end(), CompareNotesPointersByRadarValues ); + stable_sort( arraySteps.begin(), arraySteps.end(), CompareNotesPointersByMeter ); + stable_sort( arraySteps.begin(), arraySteps.end(), CompareNotesPointersByDifficulty ); +} + +bool StepsUtil::CompareStepsPointersByTypeAndDifficulty(const Steps *pStep1, const Steps *pStep2) +{ + if( pStep1->m_StepsType < pStep2->m_StepsType ) + return true; + if( pStep1->m_StepsType > pStep2->m_StepsType ) + return false; + return pStep1->GetDifficulty() < pStep2->GetDifficulty(); +} + +void StepsUtil::SortStepsByTypeAndDifficulty( vector &arraySongPointers ) +{ + sort( arraySongPointers.begin(), arraySongPointers.end(), CompareStepsPointersByTypeAndDifficulty ); +} + +bool StepsUtil::CompareStepsPointersByDescription(const Steps *pStep1, const Steps *pStep2) +{ + return pStep1->GetDescription().CompareNoCase( pStep2->GetDescription() ) < 0; +} + +void StepsUtil::SortStepsByDescription( vector &arraySongPointers ) +{ + sort( arraySongPointers.begin(), arraySongPointers.end(), CompareStepsPointersByDescription ); +} + +void StepsUtil::RemoveLockedSteps( const Song *pSong, vector &vpSteps ) +{ + for( int i=vpSteps.size()-1; i>=0; i-- ) + { + if( UNLOCKMAN->StepsIsLocked(pSong, vpSteps[i]) ) + vpSteps.erase( vpSteps.begin()+i ); + } +} + + +//////////////////////////////// +// StepsID +//////////////////////////////// + +void StepsID::FromSteps( const Steps *p ) +{ + if( p == NULL ) + { + st = StepsType_Invalid; + dc = Difficulty_Invalid; + sDescription = ""; + uHash = 0; + } + else + { + st = p->m_StepsType; + dc = p->GetDifficulty(); + if( dc == Difficulty_Edit ) + { + sDescription = p->GetDescription(); + uHash = p->GetHash(); + } + else + { + sDescription = ""; + uHash = 0; + } + } + + m_Cache.Unset(); +} + +/* XXX: Don't allow duplicate edit descriptions, and don't allow edit descriptions + * to be difficulty names (eg. "Hard"). If we do that, this will be completely unambiguous. + * + * XXX: Unless two memcards are inserted and there's overlap in the names. In that + * case, maybe both edits should be renamed to "Pn: foo"; as long as we don't write + * them back out (which we don't do except in the editor), it won't be permanent. + * We could do this during the actual Steps::GetID() call, instead, but then it'd have + * to have access to Song::m_LoadedFromProfile. */ + +Steps *StepsID::ToSteps( const Song *p, bool bAllowNull ) const +{ + if( st == StepsType_Invalid || dc == Difficulty_Invalid ) + return NULL; + + SongID songID; + songID.FromSong( p ); + + Steps *pRet = NULL; + if( dc == Difficulty_Edit ) + { + pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, sDescription, "", uHash, true ); + } + else + { + pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, "", "", 0, true ); + } + + if( !bAllowNull && pRet == NULL ) + FAIL_M( ssprintf("%i, %i, \"%s\"", st, dc, sDescription.c_str()) ); + + m_Cache.Set( pRet ); + + return pRet; +} + +XNode* StepsID::CreateNode() const +{ + XNode* pNode = new XNode( "Steps" ); + + pNode->AppendAttr( "StepsType", GAMEMAN->GetStepsTypeInfo(st).szName ); + pNode->AppendAttr( "Difficulty", DifficultyToString(dc) ); + if( dc == Difficulty_Edit ) + { + pNode->AppendAttr( "Description", sDescription ); + pNode->AppendAttr( "Hash", uHash ); + } + + return pNode; +} + +void StepsID::LoadFromNode( const XNode* pNode ) +{ + ASSERT( pNode->GetName() == "Steps" ); + + RString sTemp; + + pNode->GetAttrValue( "StepsType", sTemp ); + st = GAMEMAN->StringToStepsType( sTemp ); + + pNode->GetAttrValue( "Difficulty", sTemp ); + dc = StringToDifficulty( sTemp ); + + if( dc == Difficulty_Edit ) + { + pNode->GetAttrValue( "Description", sDescription ); + pNode->GetAttrValue( "Hash", uHash ); + } + else + { + sDescription = ""; + uHash = 0; + } + + m_Cache.Unset(); +} + +RString StepsID::ToString() const +{ + RString s = GAMEMAN->GetStepsTypeInfo( st ).szName; + s += " " + DifficultyToString( dc ); + if( dc == Difficulty_Edit ) + { + s += " " + sDescription; + s += ssprintf(" %u", uHash ); + } + return s; +} + +bool StepsID::IsValid() const +{ + return st != StepsType_Invalid && dc != Difficulty_Invalid; +} + +bool StepsID::operator<( const StepsID &rhs ) const +{ +#define COMP(a) if(arhs.a) return false; + COMP(st); + COMP(dc); + COMP(sDescription); + COMP(uHash); +#undef COMP + return false; +} + +/* + * (c) 2001-2004 Chris Danford, Glenn Maynard + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */