2003-02-16 04:01:45 +00:00
|
|
|
#include "global.h"
|
2003-02-06 07:32:57 +00:00
|
|
|
#include "NoteSkinManager.h"
|
|
|
|
|
#include "RageLog.h"
|
|
|
|
|
#include "RageException.h"
|
|
|
|
|
#include "GameState.h"
|
2004-07-25 17:07:32 +00:00
|
|
|
#include "Game.h"
|
2003-02-06 07:32:57 +00:00
|
|
|
#include "StyleInput.h"
|
2004-06-28 07:26:00 +00:00
|
|
|
#include "Style.h"
|
2003-02-06 07:32:57 +00:00
|
|
|
#include "RageUtil.h"
|
2003-09-03 04:30:29 +00:00
|
|
|
#include "RageDisplay.h"
|
2004-06-10 22:47:51 +00:00
|
|
|
#include "arch/Dialog/Dialog.h"
|
2004-03-01 02:45:29 +00:00
|
|
|
#include "PrefsManager.h"
|
2004-07-30 06:32:24 +00:00
|
|
|
#include "Foreach.h"
|
2003-02-06 07:32:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
NoteSkinManager* NOTESKIN = NULL; // global object accessable from anywhere in the program
|
|
|
|
|
|
|
|
|
|
|
2003-12-10 09:26:05 +00:00
|
|
|
const CString NOTESKINS_DIR = "NoteSkins/";
|
2003-08-15 03:14:53 +00:00
|
|
|
const CString GAME_BASE_NOTESKIN_NAME = "default";
|
2003-12-10 09:26:05 +00:00
|
|
|
const CString GLOBAL_BASE_NOTESKIN_DIR = NOTESKINS_DIR + "common/default/";
|
2004-02-17 22:16:22 +00:00
|
|
|
static map<CString,CString> g_PathCache;
|
2003-02-06 07:32:57 +00:00
|
|
|
|
|
|
|
|
NoteSkinManager::NoteSkinManager()
|
|
|
|
|
{
|
2004-07-25 04:27:20 +00:00
|
|
|
m_pCurGame = NULL;
|
2003-02-06 07:32:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NoteSkinManager::~NoteSkinManager()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-06 02:30:50 +00:00
|
|
|
void NoteSkinManager::RefreshNoteSkinData( const Game* pGame )
|
2003-02-06 07:32:57 +00:00
|
|
|
{
|
2005-09-04 23:16:38 +00:00
|
|
|
if( m_pCurGame == pGame )
|
|
|
|
|
return;
|
2004-09-06 02:30:50 +00:00
|
|
|
m_pCurGame = pGame;
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2004-02-17 22:16:22 +00:00
|
|
|
// clear path cache
|
|
|
|
|
g_PathCache.clear();
|
|
|
|
|
|
2004-07-25 17:07:32 +00:00
|
|
|
CString sBaseSkinFolder = NOTESKINS_DIR + pGame->m_szName + "/";
|
2003-04-22 04:54:04 +00:00
|
|
|
CStringArray asNoteSkinNames;
|
|
|
|
|
GetDirListing( sBaseSkinFolder + "*", asNoteSkinNames, true );
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2005-06-23 08:05:09 +00:00
|
|
|
StripCvs( asNoteSkinNames );
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-04-22 04:54:04 +00:00
|
|
|
m_mapNameToData.clear();
|
2003-04-23 02:45:51 +00:00
|
|
|
for( unsigned j=0; j<asNoteSkinNames.size(); j++ )
|
2003-02-06 07:32:57 +00:00
|
|
|
{
|
2003-04-23 02:45:51 +00:00
|
|
|
CString sName = asNoteSkinNames[j];
|
2003-04-22 04:54:04 +00:00
|
|
|
sName.MakeLower();
|
|
|
|
|
m_mapNameToData[sName] = NoteSkinData();
|
|
|
|
|
LoadNoteSkinData( sName, m_mapNameToData[sName] );
|
2003-02-06 07:32:57 +00:00
|
|
|
}
|
2003-04-22 04:54:04 +00:00
|
|
|
}
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2004-07-30 06:32:24 +00:00
|
|
|
void NoteSkinManager::LoadNoteSkinData( const CString &sNoteSkinName, NoteSkinData& data_out )
|
2003-04-22 04:54:04 +00:00
|
|
|
{
|
|
|
|
|
data_out.sName = sNoteSkinName;
|
2005-01-07 14:28:00 +00:00
|
|
|
data_out.metrics.Clear();
|
2004-07-30 06:32:24 +00:00
|
|
|
data_out.vsDirSearchOrder.clear();
|
2003-02-09 00:47:11 +00:00
|
|
|
|
2003-08-15 03:14:53 +00:00
|
|
|
/* Load global NoteSkin defaults */
|
2004-05-23 02:27:51 +00:00
|
|
|
data_out.metrics.ReadFile( GLOBAL_BASE_NOTESKIN_DIR+"metrics.ini" );
|
2004-07-30 06:32:24 +00:00
|
|
|
data_out.vsDirSearchOrder.push_front( GLOBAL_BASE_NOTESKIN_DIR );
|
2003-08-15 03:14:53 +00:00
|
|
|
|
|
|
|
|
/* Load game NoteSkin defaults */
|
2004-05-23 02:27:51 +00:00
|
|
|
data_out.metrics.ReadFile( GetNoteSkinDir(GAME_BASE_NOTESKIN_NAME)+"metrics.ini" );
|
2004-07-30 06:32:24 +00:00
|
|
|
data_out.vsDirSearchOrder.push_front( GetNoteSkinDir(GAME_BASE_NOTESKIN_NAME) );
|
2003-08-15 03:14:53 +00:00
|
|
|
|
2004-07-30 06:32:24 +00:00
|
|
|
/* Read the current NoteSkin and all of its fallbacks */
|
|
|
|
|
LoadNoteSkinDataRecursive( sNoteSkinName, data_out );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteSkinManager::LoadNoteSkinDataRecursive( const CString &sNoteSkinName, NoteSkinData& data_out )
|
|
|
|
|
{
|
|
|
|
|
static int depth = 0;
|
|
|
|
|
depth++;
|
|
|
|
|
ASSERT_M( depth < 20, "Circular NoteSkin fallback references detected." );
|
|
|
|
|
|
|
|
|
|
CString sDir = GetNoteSkinDir(sNoteSkinName);
|
|
|
|
|
|
|
|
|
|
// read global fallback the current NoteSkin (if any)
|
|
|
|
|
CString sFallback;
|
|
|
|
|
IniFile ini;
|
|
|
|
|
ini.ReadFile( sDir+"metrics.ini" );
|
|
|
|
|
|
|
|
|
|
if( ini.GetValue("Global","FallbackNoteSkin",sFallback) )
|
|
|
|
|
LoadNoteSkinDataRecursive( sFallback, data_out );
|
|
|
|
|
|
|
|
|
|
data_out.metrics.ReadFile( sDir+"metrics.ini" );
|
|
|
|
|
data_out.vsDirSearchOrder.push_front( sDir );
|
|
|
|
|
|
|
|
|
|
depth--;
|
2003-04-22 04:54:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void NoteSkinManager::GetNoteSkinNames( CStringArray &AddTo )
|
|
|
|
|
{
|
2004-09-06 03:19:15 +00:00
|
|
|
GetNoteSkinNames( GAMESTATE->m_pCurGame, AddTo );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteSkinManager::GetNoteSkinNames( const Game* pGame, CStringArray &AddTo, bool bFilterDefault )
|
|
|
|
|
{
|
|
|
|
|
if( pGame == m_pCurGame )
|
|
|
|
|
{
|
|
|
|
|
/* Faster: */
|
|
|
|
|
for( map<CString,NoteSkinData>::const_iterator iter = m_mapNameToData.begin();
|
|
|
|
|
iter != m_mapNameToData.end(); ++iter )
|
|
|
|
|
{
|
|
|
|
|
AddTo.push_back( iter->second.sName );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2003-09-12 04:18:43 +00:00
|
|
|
{
|
2004-09-06 03:19:15 +00:00
|
|
|
CString sBaseSkinFolder = NOTESKINS_DIR + pGame->m_szName + "/";
|
|
|
|
|
GetDirListing( sBaseSkinFolder + "*", AddTo, true );
|
2005-06-23 08:05:09 +00:00
|
|
|
StripCvs( AddTo );
|
2003-09-12 04:18:43 +00:00
|
|
|
}
|
2003-10-29 10:43:18 +00:00
|
|
|
|
2004-02-17 22:23:07 +00:00
|
|
|
/* Move "default" to the front if it exists. */
|
2003-10-29 10:43:18 +00:00
|
|
|
{
|
|
|
|
|
CStringArray::iterator iter = find( AddTo.begin(), AddTo.end(), "default" );
|
|
|
|
|
if( iter != AddTo.end() )
|
|
|
|
|
{
|
|
|
|
|
AddTo.erase( iter );
|
2004-09-06 03:19:15 +00:00
|
|
|
if( !bFilterDefault || !PREFSMAN->m_bHideDefaultNoteSkin )
|
2004-03-01 02:45:29 +00:00
|
|
|
AddTo.insert( AddTo.begin(), "default" );
|
2003-10-29 10:43:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
2003-04-22 04:54:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-11-06 21:32:28 +00:00
|
|
|
bool NoteSkinManager::DoesNoteSkinExist( const CString &sSkinName )
|
2003-04-22 04:54:04 +00:00
|
|
|
{
|
|
|
|
|
CStringArray asSkinNames;
|
|
|
|
|
GetNoteSkinNames( asSkinNames );
|
|
|
|
|
for( unsigned i=0; i<asSkinNames.size(); i++ )
|
|
|
|
|
if( 0==stricmp(sSkinName, asSkinNames[i]) )
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
2003-02-06 07:32:57 +00:00
|
|
|
}
|
|
|
|
|
|
2004-07-30 06:32:24 +00:00
|
|
|
CString NoteSkinManager::GetNoteSkinDir( const CString &sSkinName )
|
2003-02-06 07:32:57 +00:00
|
|
|
{
|
2004-09-06 02:52:10 +00:00
|
|
|
CString sGame = m_pCurGame->m_szName;
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-12-10 09:44:16 +00:00
|
|
|
return NOTESKINS_DIR + sGame + "/" + sSkinName + "/";
|
2003-02-06 07:32:57 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-18 01:19:56 +00:00
|
|
|
CString NoteSkinManager::GetMetric( const CString &sButtonName, const CString &sValue )
|
2003-02-06 07:32:57 +00:00
|
|
|
{
|
2005-04-18 01:19:56 +00:00
|
|
|
ASSERT( !m_sCurrentNoteSkin.empty() );
|
|
|
|
|
CString sNoteSkinName = m_sCurrentNoteSkin;
|
2003-09-12 04:44:53 +00:00
|
|
|
sNoteSkinName.MakeLower();
|
2004-05-23 22:17:26 +00:00
|
|
|
map<CString,NoteSkinData>::const_iterator it = m_mapNameToData.find(sNoteSkinName);
|
|
|
|
|
ASSERT_M( it != m_mapNameToData.end(), sNoteSkinName ); // this NoteSkin doesn't exist!
|
|
|
|
|
const NoteSkinData& data = it->second;
|
|
|
|
|
|
2003-02-06 07:32:57 +00:00
|
|
|
CString sReturn;
|
2003-04-22 04:54:04 +00:00
|
|
|
if( data.metrics.GetValue( sButtonName, sValue, sReturn ) )
|
2003-02-08 23:47:47 +00:00
|
|
|
return sReturn;
|
2003-04-22 04:54:04 +00:00
|
|
|
if( !data.metrics.GetValue( "NoteDisplay", sValue, sReturn ) )
|
2005-10-04 19:45:45 +00:00
|
|
|
{
|
|
|
|
|
CString sError = ssprintf(
|
|
|
|
|
"Could not read metric '[%s] %s' or '[NoteDisplay] %s' in '%s'",
|
2003-07-20 21:23:20 +00:00
|
|
|
sButtonName.c_str(), sValue.c_str(), sValue.c_str(), sNoteSkinName.c_str() );
|
2005-10-04 19:45:45 +00:00
|
|
|
RageException::Throw( sError );
|
|
|
|
|
}
|
2003-02-06 07:32:57 +00:00
|
|
|
return sReturn;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-18 01:19:56 +00:00
|
|
|
int NoteSkinManager::GetMetricI( const CString &sButtonName, const CString &sValueName )
|
2003-09-12 04:08:03 +00:00
|
|
|
{
|
2005-04-18 01:19:56 +00:00
|
|
|
return atoi( GetMetric(sButtonName,sValueName) );
|
2003-09-12 04:08:03 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-18 01:19:56 +00:00
|
|
|
float NoteSkinManager::GetMetricF( const CString &sButtonName, const CString &sValueName )
|
2003-09-12 04:08:03 +00:00
|
|
|
{
|
2005-04-18 01:19:56 +00:00
|
|
|
return strtof( GetMetric(sButtonName,sValueName), NULL );
|
2003-09-12 04:08:03 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-18 01:19:56 +00:00
|
|
|
bool NoteSkinManager::GetMetricB( const CString &sButtonName, const CString &sValueName )
|
2003-09-12 04:08:03 +00:00
|
|
|
{
|
2005-04-18 01:19:56 +00:00
|
|
|
return atoi( GetMetric(sButtonName,sValueName) ) != 0;
|
2003-09-12 04:08:03 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-18 01:19:56 +00:00
|
|
|
apActorCommands NoteSkinManager::GetMetricA( const CString &sButtonName, const CString &sValueName )
|
2003-09-12 04:08:03 +00:00
|
|
|
{
|
2005-04-18 01:19:56 +00:00
|
|
|
return apActorCommands( new ActorCommands( GetMetric(sButtonName,sValueName) ) );
|
2003-09-12 04:08:03 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-18 01:19:56 +00:00
|
|
|
CString NoteSkinManager::GetPath( const CString &sButtonName, const CString &sElement )
|
2004-02-17 08:55:33 +00:00
|
|
|
{
|
2004-07-30 06:32:24 +00:00
|
|
|
try_again:
|
2005-04-18 01:19:56 +00:00
|
|
|
const CString CacheString = m_sCurrentNoteSkin + "/" + sButtonName + "/" + sElement;
|
2004-02-17 22:16:22 +00:00
|
|
|
map<CString,CString>::iterator it = g_PathCache.find( CacheString );
|
|
|
|
|
if( it != g_PathCache.end() )
|
|
|
|
|
return it->second;
|
|
|
|
|
|
2005-04-18 01:19:56 +00:00
|
|
|
map<CString,NoteSkinData>::const_iterator iter = m_mapNameToData.find( m_sCurrentNoteSkin );
|
|
|
|
|
ASSERT( iter != m_mapNameToData.end() );
|
|
|
|
|
const NoteSkinData &data = iter->second;
|
2004-07-30 06:32:24 +00:00
|
|
|
|
2005-04-18 01:19:56 +00:00
|
|
|
CString sPath; // fill this in below
|
2004-07-30 06:32:24 +00:00
|
|
|
FOREACHD_CONST( CString, data.vsDirSearchOrder, iter )
|
|
|
|
|
{
|
2005-10-05 06:05:53 +00:00
|
|
|
if( sButtonName.empty() )
|
|
|
|
|
sPath = GetPathFromDirAndFile( *iter, sElement );
|
|
|
|
|
else if( *iter == GLOBAL_BASE_NOTESKIN_DIR )
|
2005-10-05 05:49:50 +00:00
|
|
|
sPath = GetPathFromDirAndFile( *iter, "Fallback "+sElement );
|
|
|
|
|
else
|
|
|
|
|
sPath = GetPathFromDirAndFile( *iter, sButtonName+" "+sElement );
|
|
|
|
|
if( !sPath.empty() )
|
|
|
|
|
break; // done searching
|
2004-07-30 06:32:24 +00:00
|
|
|
}
|
2004-02-17 22:23:07 +00:00
|
|
|
|
2004-07-30 06:32:24 +00:00
|
|
|
if( sPath.empty() )
|
2004-02-17 08:55:33 +00:00
|
|
|
{
|
2004-07-30 06:32:24 +00:00
|
|
|
CString message = ssprintf(
|
|
|
|
|
"The NoteSkin element '%s %s' could not be found in '%s', '%s', or '%s'.",
|
2003-12-31 21:40:38 +00:00
|
|
|
sButtonName.c_str(), sElement.c_str(),
|
2005-04-18 01:19:56 +00:00
|
|
|
GetNoteSkinDir(m_sCurrentNoteSkin).c_str(),
|
2003-12-31 21:40:38 +00:00
|
|
|
GetNoteSkinDir(GAME_BASE_NOTESKIN_NAME).c_str(),
|
|
|
|
|
GLOBAL_BASE_NOTESKIN_DIR.c_str() );
|
2004-07-30 06:32:24 +00:00
|
|
|
|
|
|
|
|
if( Dialog::AbortRetryIgnore(message) == Dialog::retry )
|
|
|
|
|
{
|
|
|
|
|
FlushDirCache();
|
|
|
|
|
g_PathCache.clear();
|
|
|
|
|
goto try_again;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RageException::Throw( message );
|
2004-02-17 08:55:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while( GetExtension(sPath) == "redir" )
|
|
|
|
|
{
|
2005-05-17 02:20:43 +00:00
|
|
|
CString sNewFileName;
|
2005-05-20 00:12:43 +00:00
|
|
|
GetFileContents( sPath, sNewFileName, true );
|
2004-02-17 08:55:33 +00:00
|
|
|
CString sRealPath;
|
2004-07-30 06:32:24 +00:00
|
|
|
|
|
|
|
|
FOREACHD_CONST( CString, data.vsDirSearchOrder, iter )
|
|
|
|
|
{
|
2005-04-18 01:19:56 +00:00
|
|
|
sRealPath = GetPathFromDirAndFile( *iter, sNewFileName );
|
2004-07-30 06:32:24 +00:00
|
|
|
if( !sRealPath.empty() )
|
|
|
|
|
break; // done searching
|
|
|
|
|
}
|
2004-02-17 08:55:33 +00:00
|
|
|
|
|
|
|
|
if( sRealPath == "" )
|
|
|
|
|
{
|
|
|
|
|
CString message = ssprintf(
|
|
|
|
|
"NoteSkinManager: The redirect '%s' points to the file '%s', which does not exist. "
|
|
|
|
|
"Verify that this redirect is correct.",
|
|
|
|
|
sPath.c_str(), sNewFileName.c_str());
|
|
|
|
|
|
2004-06-10 22:47:51 +00:00
|
|
|
if( Dialog::AbortRetryIgnore(message) == Dialog::retry )
|
2004-02-17 08:55:33 +00:00
|
|
|
{
|
|
|
|
|
FlushDirCache();
|
2004-02-17 22:16:22 +00:00
|
|
|
g_PathCache.clear();
|
2004-07-30 06:32:24 +00:00
|
|
|
goto try_again;
|
2004-02-17 08:55:33 +00:00
|
|
|
}
|
|
|
|
|
|
2004-07-30 06:32:24 +00:00
|
|
|
RageException::Throw( message );
|
2004-02-17 08:55:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sPath = sRealPath;
|
|
|
|
|
}
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2004-02-17 22:16:22 +00:00
|
|
|
g_PathCache[CacheString] = sPath;
|
2004-02-17 08:55:33 +00:00
|
|
|
return sPath;
|
|
|
|
|
}
|
2004-02-17 08:25:32 +00:00
|
|
|
|
2005-04-18 01:19:56 +00:00
|
|
|
CString NoteSkinManager::GetPathFromDirAndFile( const CString &sDir, const CString &sFileName )
|
2003-02-06 07:32:57 +00:00
|
|
|
{
|
2003-09-03 04:30:29 +00:00
|
|
|
CStringArray matches; // fill this with the possible files
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2005-07-05 21:56:51 +00:00
|
|
|
GetDirListing( sDir+sFileName+"*", matches, false, true );
|
2003-02-06 07:32:57 +00:00
|
|
|
|
2003-09-03 04:30:29 +00:00
|
|
|
if( matches.empty() )
|
2005-09-04 16:55:21 +00:00
|
|
|
return CString();
|
2003-09-03 04:30:29 +00:00
|
|
|
|
|
|
|
|
if( matches.size() > 1 )
|
|
|
|
|
{
|
|
|
|
|
CString sError = "Multiple files match '"+sDir+sFileName+"'. Please remove all but one of these files.";
|
2004-06-10 22:47:51 +00:00
|
|
|
Dialog::OK( sError );
|
2003-09-03 04:30:29 +00:00
|
|
|
}
|
|
|
|
|
|
2004-02-17 08:55:33 +00:00
|
|
|
return matches[0];
|
2003-02-06 07:32:57 +00:00
|
|
|
}
|
2004-06-08 01:24:17 +00:00
|
|
|
|
2005-04-18 01:19:56 +00:00
|
|
|
// lua start
|
|
|
|
|
#include "LuaBinding.h"
|
|
|
|
|
|
2005-06-20 05:02:03 +00:00
|
|
|
class LunaNoteSkinManager: public Luna<NoteSkinManager>
|
2005-04-18 01:19:56 +00:00
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
LunaNoteSkinManager() { LUA->Register( Register ); }
|
|
|
|
|
|
|
|
|
|
static int GetPath( T* p, lua_State *L ) { lua_pushstring(L, p->GetPath(SArg(1),SArg(2)) ); return 1; }
|
|
|
|
|
|
|
|
|
|
static void Register(lua_State *L)
|
|
|
|
|
{
|
2005-09-10 02:47:04 +00:00
|
|
|
ADD_METHOD( GetPath );
|
|
|
|
|
|
2005-04-18 01:19:56 +00:00
|
|
|
Luna<T>::Register( L );
|
|
|
|
|
|
|
|
|
|
// Add global singleton if constructed already. If it's not constructed yet,
|
|
|
|
|
// then we'll register it later when we reinit Lua just before
|
|
|
|
|
// initializing the display.
|
|
|
|
|
if( NOTESKIN )
|
|
|
|
|
{
|
|
|
|
|
lua_pushstring(L, "NOTESKIN");
|
2005-06-15 02:27:16 +00:00
|
|
|
NOTESKIN->PushSelf( L );
|
2005-04-18 01:19:56 +00:00
|
|
|
lua_settable(L, LUA_GLOBALSINDEX);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
LUA_REGISTER_CLASS( NoteSkinManager )
|
|
|
|
|
// lua end
|
|
|
|
|
|
2004-06-08 01:24:17 +00:00
|
|
|
/*
|
|
|
|
|
* (c) 2003-2004 Chris Danford
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|