00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
#include <fcntl.h>
00026
#include <sys/types.h>
00027
#include <sys/stat.h>
00028
00029
00030
#include <connect.h>
00031
#include <dispatcher.h>
00032
#include <flowsystem.h>
00033
#include <soundserver.h>
00034
00035
00036
#include <qfile.h>
00037
#include <qfileinfo.h>
00038
#include <qiomanager.h>
00039
#include <qstringlist.h>
00040
#include <qtextstream.h>
00041
00042
00043
#include <dcopclient.h>
00044
#include <kaboutdata.h>
00045
#include <kartsdispatcher.h>
00046
#include <kartsserver.h>
00047
#include <kcmdlineargs.h>
00048
#include <kconfig.h>
00049
#include <kdebug.h>
00050
#include <kglobal.h>
00051
#include <klocale.h>
00052
#include <kmessagebox.h>
00053
#include <kpassivepopup.h>
00054
#include <kiconloader.h>
00055
#include <kmacroexpander.h>
00056
#include <kplayobjectfactory.h>
00057
#include <kaudiomanagerplay.h>
00058
#include <kprocess.h>
00059
#include <kstandarddirs.h>
00060
#include <kuniqueapplication.h>
00061
#include <kwin.h>
00062
00063
#include "knotify.h"
00064
#include "knotify.moc"
00065
00066
class KNotifyPrivate
00067 {
00068
public:
00069
KConfig* globalEvents;
00070
KConfig* globalConfig;
00071
QMap<QString, KConfig*> events;
00072
QMap<QString, KConfig*> configs;
00073
QString externalPlayer;
00074
KProcess *externalPlayerProc;
00075
00076
QPtrList<KDE::PlayObject> playObjects;
00077
QMap<KDE::PlayObject*,int> playObjectEventMap;
00078
int externalPlayerEventId;
00079
00080
bool useExternal;
00081
bool useArts;
00082
int volume;
00083
QTimer *playTimer;
00084
KAudioManagerPlay *audioManager;
00085 };
00086
00087
00088
00089
KArtsServer *soundServer;
00090
00091
extern "C"{
00092
00093
int kdemain(
int argc,
char **argv)
00094 {
00095
KAboutData aboutdata(
"knotify",
I18N_NOOP(
"KNotify"),
00096
"3.0",
I18N_NOOP(
"KDE Notification Server"),
00097 KAboutData::License_GPL,
"(C) 1997-2003, KDE Developers");
00098 aboutdata.addAuthor(
"Carsten Pfeiffer",
I18N_NOOP(
"Current Maintainer"),
"pfeiffer@kde.org");
00099 aboutdata.addAuthor(
"Christian Esken",0,
"esken@kde.org");
00100 aboutdata.addAuthor(
"Stefan Westerfeld",
I18N_NOOP(
"Sound support"),
"stefan@space.twc.de");
00101 aboutdata.addAuthor(
"Charles Samuels",
I18N_NOOP(
"Previous Maintainer"),
"charles@kde.org");
00102
00103
KCmdLineArgs::init( argc, argv, &aboutdata );
00104
KUniqueApplication::addCmdLineOptions();
00105
00106
00107
00108
if ( !
KUniqueApplication::start() ) {
00109
kdDebug() <<
"Running knotify found" <<
endl;
00110
return 0;
00111 }
00112
00113
KUniqueApplication app;
00114 app.
disableSessionManagement();
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
KConfigGroup config( KGlobal::config(),
"StartProgress" );
00126
KConfig artsKCMConfig(
"kcmartsrc" );
00127 artsKCMConfig.setGroup(
"Arts" );
00128
bool useArts = artsKCMConfig.readBoolEntry(
"StartServer",
true );
00129
if ( useArts )
00130 useArts = config.readBoolEntry(
"Use Arts",
true );
00131
bool ok = config.readBoolEntry(
"Arts Init",
true );
00132
00133
if ( useArts && !ok )
00134 {
00135
if (
KMessageBox::questionYesNo(
00136 0L,
00137 i18n(
"During the previous startup, KNotify crashed while creating "
00138
"Arts::Dispatcher. Do you want to try again or disable "
00139
"aRts sound output?"),
00140 i18n(
"KNotify Problem"),
00141 i18n(
"Try Again"),
00142 i18n(
"Disable aRts Output"),
00143
"KNotifyStartProgress",
00144 0
00145 )
00146 == KMessageBox::No )
00147 {
00148 useArts =
false;
00149 }
00150 }
00151
00152
00153 config.writeEntry(
"Arts Init",
false );
00154 config.writeEntry(
"Use Arts", useArts );
00155 config.sync();
00156
00157
KArtsDispatcher *dispatcher = 0;
00158
if ( useArts )
00159 {
00160 dispatcher =
new KArtsDispatcher;
00161 soundServer =
new KArtsServer;
00162 }
00163
00164
00165 config.writeEntry(
"Arts Init", useArts );
00166 config.sync();
00167
00168 ok = config.readBoolEntry(
"KNotify Init",
true );
00169
if ( useArts && !ok )
00170 {
00171
if (
KMessageBox::questionYesNo(
00172 0L,
00173 i18n(
"During the previous startup, KNotify crashed while instantiating "
00174
"KNotify. Do you want to try again or disable "
00175
"aRts sound output?"),
00176 i18n(
"KNotify Problem"),
00177 i18n(
"Try Again"),
00178 i18n(
"Disable aRts Output"),
00179
"KNotifyStartProgress",
00180 0
00181 )
00182 == KMessageBox::No )
00183 {
00184 useArts =
false;
00185
delete soundServer;
00186 soundServer = 0L;
00187
delete dispatcher;
00188 dispatcher = 0L;
00189 }
00190 }
00191
00192
00193 config.writeEntry(
"KNotify Init",
false );
00194 config.writeEntry(
"Use Arts", useArts );
00195 config.sync();
00196
00197
00198 KNotify notify( useArts );
00199
00200 config.writeEntry(
"KNotify Init",
true );
00201 config.sync();
00202
00203 app.
dcopClient()->setDefaultObject(
"Notify" );
00204 app.
dcopClient()->setDaemonMode(
true );
00205
00206
00207
int ret = app.
exec();
00208
delete soundServer;
00209
delete dispatcher;
00210
return ret;
00211 }
00212 }
00213
00214 KNotify::KNotify(
bool useArts )
00215 :
QObject(), DCOPObject(
"Notify")
00216 {
00217 d =
new KNotifyPrivate;
00218 d->globalEvents =
new KConfig(
"knotify/eventsrc",
true,
false,
"data");
00219 d->globalConfig =
new KConfig(
"knotify.eventsrc",
true,
false);
00220 d->externalPlayerProc = 0;
00221 d->useArts = useArts;
00222 d->playObjects.setAutoDelete(
true);
00223 d->audioManager = 0;
00224
if( useArts )
00225 {
00226 restartedArtsd();
00227
00228
00229
00230
connect( soundServer, SIGNAL( restartedServer() ),
this, SLOT( restartedArtsd() ) );
00231 }
00232
00233 d->volume = 100;
00234
00235 d->playTimer = 0;
00236
00237 loadConfig();
00238 }
00239
00240 KNotify::~KNotify()
00241 {
00242 reconfigure();
00243
00244 d->playObjects.clear();
00245
00246
delete d->globalEvents;
00247
delete d->globalConfig;
00248
delete d->externalPlayerProc;
00249
delete d->audioManager;
00250
delete d;
00251 }
00252
00253
00254
void KNotify::loadConfig() {
00255
00256
KConfig *kc =
KGlobal::config();
00257 kc->
setGroup(
"Misc");
00258 d->useExternal = kc->
readBoolEntry(
"Use external player",
false );
00259 d->externalPlayer = kc->
readPathEntry(
"External player");
00260
00261
00262
if ( d->externalPlayer.isEmpty() ) {
00263
QStringList players;
00264 players <<
"wavplay" <<
"aplay" <<
"auplay";
00265 QStringList::Iterator it = players.begin();
00266
while ( d->externalPlayer.isEmpty() && it != players.end() ) {
00267 d->externalPlayer =
KStandardDirs::findExe( *it );
00268 ++it;
00269 }
00270 }
00271
00272
00273 d->volume = kc->
readNumEntry(
"Volume", 100 );
00274 }
00275
00276
00277
void KNotify::reconfigure()
00278 {
00279 kapp->config()->reparseConfiguration();
00280 loadConfig();
00281
00282
00283 d->globalConfig->reparseConfiguration();
00284
for (
QMapIterator<QString,KConfig*> it = d->configs.begin(); it != d->configs.end(); ++it )
00285
delete it.
data();
00286 d->configs.clear();
00287 }
00288
00289
00290
void KNotify::notify(
const QString &event,
const QString &fromApp,
00291
const QString &text,
QString sound,
QString file,
00292
int present,
int level)
00293 {
00294 notify( event, fromApp, text, sound, file, present, level, 0, 1 );
00295 }
00296
00297
void KNotify::notify(
const QString &event,
const QString &fromApp,
00298
const QString &text,
QString sound,
QString file,
00299
int present,
int level,
int winId)
00300 {
00301 notify( event, fromApp, text, sound, file, present, level, winId, 1 );
00302 }
00303
00304
void KNotify::notify(
const QString &event,
const QString &fromApp,
00305
const QString &text,
QString sound,
QString file,
00306
int present,
int level,
int winId,
int eventId )
00307 {
00308
00309
00310
00311
QString commandline;
00312
00313
00314
if ( !
event.isEmpty() ) {
00315
00316
00317
KConfig *eventsFile;
00318
KConfig *configFile;
00319
if ( d->events.contains( fromApp ) ) {
00320 eventsFile = d->events[fromApp];
00321 }
else {
00322 eventsFile=
new KConfig(
locate(
"data", fromApp+
"/eventsrc"),
true,
false);
00323 d->events.insert( fromApp, eventsFile );
00324 }
00325
if ( d->configs.contains( fromApp) ) {
00326 configFile = d->configs[fromApp];
00327 }
else {
00328 configFile=
new KConfig(fromApp+
".eventsrc",
true,
false);
00329 d->configs.insert( fromApp, configFile );
00330 }
00331
00332
if ( !eventsFile->
hasGroup( event ) && isGlobal(event) )
00333 {
00334 eventsFile = d->globalEvents;
00335 configFile = d->globalConfig;
00336 }
00337
00338 eventsFile->
setGroup( event );
00339 configFile->
setGroup( event );
00340
00341
00342
if ( present==-1 )
00343 present = configFile->
readNumEntry(
"presentation", -1 );
00344
if ( present==-1 )
00345 present = eventsFile->
readNumEntry(
"default_presentation", 0 );
00346
00347
00348
if( present & KNotifyClient::Sound ) {
00349
QString theSound = configFile->
readPathEntry(
"soundfile" );
00350
if ( theSound.
isEmpty() )
00351 theSound = eventsFile->
readPathEntry(
"default_sound" );
00352
if ( !theSound.
isEmpty() )
00353 sound = theSound;
00354 }
00355
00356
00357
if( present & KNotifyClient::Logfile ) {
00358
QString theFile = configFile->
readPathEntry(
"logfile" );
00359
if ( theFile.
isEmpty() )
00360 theFile = eventsFile->
readPathEntry(
"default_logfile" );
00361
if ( !theFile.
isEmpty() )
00362 file = theFile;
00363 }
00364
00365
00366
if( present & KNotifyClient::Messagebox )
00367 level = eventsFile->
readNumEntry(
"level", 0 );
00368
00369
00370
if (present & KNotifyClient::Execute ) {
00371 commandline = configFile->
readPathEntry(
"commandline" );
00372
if ( commandline.
isEmpty() )
00373 commandline = eventsFile->
readPathEntry(
"default_commandline" );
00374 }
00375 }
00376
00377
00378
if ( present & KNotifyClient::Sound )
00379 notifyBySound( sound, fromApp, eventId );
00380
00381
if ( present & KNotifyClient::PassivePopup )
00382 notifyByPassivePopup( text, fromApp, checkWinId( fromApp, winId ));
00383
00384
else if ( present & KNotifyClient::Messagebox )
00385 notifyByMessagebox( text, level, checkWinId( fromApp, winId ));
00386
00387
if ( present & KNotifyClient::Logfile )
00388 notifyByLogfile( text, file );
00389
00390
if ( present & KNotifyClient::Stderr )
00391 notifyByStderr( text );
00392
00393
if ( present & KNotifyClient::Execute )
00394 notifyByExecute( commandline, event, fromApp, text, winId, eventId );
00395
00396
if ( present & KNotifyClient::Taskbar )
00397 notifyByTaskbar( checkWinId( fromApp, winId ));
00398
00399
QByteArray qbd;
00400
QDataStream ds(qbd, IO_WriteOnly);
00401 ds <<
event << fromApp << text << sound << file << present << level
00402 << winId << eventId;
00403 emitDCOPSignal(
"notifySignal(QString,QString,QString,QString,QString,int,int,int,int)", qbd);
00404
00405 }
00406
00407
00408
bool KNotify::notifyBySound(
const QString &sound,
const QString &appname,
int eventId )
00409 {
00410
if (sound.
isEmpty()) {
00411 soundFinished( eventId, NoSoundFile );
00412
return false;
00413 }
00414
00415
bool external = d->useExternal && !d->externalPlayer.isEmpty();
00416
00417
QString soundFile(sound);
00418
if (
QFileInfo(sound).isRelative() )
00419 {
00420
QString search =
QString(
"%1/sounds/%2").arg(appname).arg(sound);
00421 soundFile =
KGlobal::instance()->
dirs()->
findResource(
"data", search);
00422
if ( soundFile.isEmpty() )
00423 soundFile =
locate(
"sound", sound );
00424 }
00425
if ( soundFile.isEmpty() || isPlaying( soundFile ) )
00426 {
00427 soundFinished( eventId, soundFile.isEmpty() ? NoSoundFile : FileAlreadyPlaying );
00428
return false;
00429 }
00430
00431
00432
00433
00434
if (!external) {
00435
00436
00437
if (!d->useArts)
00438 {
00439 soundFinished( eventId, NoSoundSupport );
00440
return false;
00441 }
00442
00443
00444
while( d->playObjects.count()>5 )
00445 abortFirstPlayObject();
00446
00447
KDE::PlayObjectFactory factory(soundServer->
server());
00448
if( d->audioManager )
00449 factory.setAudioManagerPlay( d->audioManager );
00450
KURL soundURL;
00451 soundURL.
setPath(soundFile);
00452
KDE::PlayObject *playObject = factory.createPlayObject(soundURL,
false);
00453
00454
if (playObject->
isNull())
00455 {
00456 soundFinished( eventId, NoSoundSupport );
00457
delete playObject;
00458
return false;
00459 }
00460
00461
if ( d->volume != 100 )
00462 {
00463
00464
00465 Arts::StereoVolumeControl volumeControl = Arts::DynamicCast(soundServer->
server().createObject(
"Arts::StereoVolumeControl"));
00466 Arts::PlayObject player = playObject->
object();
00467 Arts::Synth_AMAN_PLAY ap = d->audioManager->amanPlay();
00468
if( ! volumeControl.isNull() && ! player.isNull() && ! ap.isNull() )
00469 {
00470 volumeControl.scaleFactor( d->volume/100.0 );
00471
00472 ap.stop();
00473 player._node()->stop();
00474 Arts::disconnect( player,
"left", ap,
"left" );
00475 Arts::disconnect( player,
"right", ap,
"right" );
00476
00477 ap.start();
00478 volumeControl.start();
00479 player._node()->start();
00480
00481 Arts::connect(player,
"left",volumeControl,
"inleft");
00482 Arts::connect(player,
"right",volumeControl,
"inright");
00483
00484 Arts::connect(volumeControl,
"outleft",ap,
"left");
00485 Arts::connect(volumeControl,
"outright",ap,
"right");
00486
00487 player._addChild( volumeControl,
"volume" );
00488 }
00489 }
00490
00491 playObject->
play();
00492 d->playObjects.append( playObject );
00493 d->playObjectEventMap.insert( playObject, eventId );
00494
00495
if ( !d->playTimer )
00496 {
00497 d->playTimer =
new QTimer(
this );
00498
connect( d->playTimer, SIGNAL( timeout() ), SLOT( playTimeout() ) );
00499 }
00500
if ( !d->playTimer->isActive() )
00501 d->playTimer->start( 1000 );
00502
00503
return true;
00504
00505 }
else if(!d->externalPlayer.isEmpty()) {
00506
00507
KProcess *proc = d->externalPlayerProc;
00508
if (!proc)
00509 {
00510 proc = d->externalPlayerProc =
new KProcess;
00511
connect( proc, SIGNAL( processExited(
KProcess * )),
00512 SLOT( slotPlayerProcessExited(
KProcess * )));
00513 }
00514
if (proc->
isRunning())
00515 {
00516 soundFinished( eventId, PlayerBusy );
00517
return false;
00518 }
00519 proc->
clearArguments();
00520 (*proc) << d->externalPlayer <<
QFile::encodeName( soundFile );
00521 d->externalPlayerEventId = eventId;
00522 proc->
start(KProcess::NotifyOnExit);
00523
return true;
00524 }
00525
00526 soundFinished( eventId, Unknown );
00527
return false;
00528 }
00529
00530
bool KNotify::notifyByMessagebox(
const QString &text,
int level, WId winId)
00531 {
00532
00533
if ( text.
isEmpty() )
00534
return false;
00535
00536
00537
switch( level ) {
00538
default:
00539
case KNotifyClient::Notification:
00540
KMessageBox::informationWId( winId, text, i18n(
"Notification"), 0,
false );
00541
break;
00542
case KNotifyClient::Warning:
00543
KMessageBox::sorryWId( winId, text, i18n(
"Warning"),
false );
00544
break;
00545
case KNotifyClient::Error:
00546
KMessageBox::errorWId( winId, text, i18n(
"Error"),
false );
00547
break;
00548
case KNotifyClient::Catastrophe:
00549
KMessageBox::errorWId( winId, text, i18n(
"Catastrophe!"),
false );
00550
break;
00551 }
00552
00553
return true;
00554 }
00555
00556
bool KNotify::notifyByPassivePopup(
const QString &text,
00557
const QString &appName,
00558 WId senderWinId )
00559 {
00560
KIconLoader iconLoader( appName );
00561
if ( d->events.find( appName ) != d->events.end() ) {
00562
KConfigGroup config( d->events[ appName ],
"!Global!" );
00563
QString iconName = config.readEntry(
"IconName", appName );
00564
QPixmap icon = iconLoader.loadIcon( iconName, KIcon::Small );
00565
QString title = config.readEntry(
"Comment", appName );
00566
KPassivePopup::message(title, text, icon, senderWinId);
00567 }
else
00568
kdError() <<
"No events for app " << appName <<
"defined!" <<
endl;
00569
00570
return true;
00571 }
00572
00573
bool KNotify::notifyByExecute(
const QString &command,
const QString& event,
00574
const QString& fromApp,
const QString& text,
00575
int winId,
int eventId) {
00576
if (!command.
isEmpty()) {
00577
00578
QMap<QChar,QString> subst;
00579 subst.
insert(
'e', event );
00580 subst.
insert(
'a', fromApp );
00581 subst.
insert(
's', text );
00582 subst.
insert(
'w', QString::number( winId ));
00583 subst.
insert(
'i', QString::number( eventId ));
00584
QString execLine =
KMacroExpander::expandMacrosShellQuote( command, subst );
00585
if ( execLine.
isEmpty() )
00586 execLine = command;
00587
00588
KProcess p;
00589 p.
setUseShell(
true);
00590 p << execLine;
00591 p.
start(KProcess::DontCare);
00592
return true;
00593 }
00594
return false;
00595 }
00596
00597
00598
bool KNotify::notifyByLogfile(
const QString &text,
const QString &file)
00599 {
00600
00601
if ( text.
isEmpty() )
00602
return true;
00603
00604
00605
QFile logFile(file);
00606
if ( !logFile.open(IO_WriteOnly | IO_Append) )
00607
return false;
00608
00609
00610
QTextStream strm( &logFile );
00611 strm <<
"- KNotify " <<
QDateTime::currentDateTime().toString() <<
": ";
00612 strm << text <<
endl;
00613
00614
00615 logFile.close();
00616
return true;
00617 }
00618
00619
bool KNotify::notifyByStderr(
const QString &text)
00620 {
00621
00622
if ( text.
isEmpty() )
00623
return true;
00624
00625
00626
QTextStream strm( stderr, IO_WriteOnly );
00627
00628
00629 strm <<
"KNotify " <<
QDateTime::currentDateTime().toString() <<
": ";
00630 strm << text <<
endl;
00631
00632
return true;
00633 }
00634
00635
bool KNotify::notifyByTaskbar( WId win )
00636 {
00637
if( win == 0 )
00638
return false;
00639
KWin::demandAttention( win );
00640
return true;
00641 }
00642
00643
bool KNotify::isGlobal(
const QString &eventname)
00644 {
00645
return d->globalEvents->hasGroup( eventname );
00646 }
00647
00648
void KNotify::setVolume(
int volume )
00649 {
00650
if ( volume<0 ) volume=0;
00651
if ( volume>=100 ) volume=100;
00652 d->volume = volume;
00653 }
00654
00655
void KNotify::playTimeout()
00656 {
00657
for (
QPtrListIterator< KDE::PlayObject > it(d->playObjects); *it;)
00658 {
00659
QPtrListIterator< KDE::PlayObject > current = it;
00660 ++it;
00661
if ( (*current)->state() != Arts::posPlaying )
00662 {
00663
QMap<KDE::PlayObject*,int>::Iterator eit = d->playObjectEventMap.find( *current );
00664
if ( eit != d->playObjectEventMap.end() )
00665 {
00666 soundFinished( *eit, PlayedOK );
00667 d->playObjectEventMap.remove( eit );
00668 }
00669 d->playObjects.remove( current );
00670 }
00671 }
00672
if ( !d->playObjects.count() )
00673 d->playTimer->stop();
00674 }
00675
00676
bool KNotify::isPlaying(
const QString& soundFile )
const
00677
{
00678
for (
QPtrListIterator< KDE::PlayObject > it(d->playObjects); *it; ++it)
00679 {
00680
if ( (*it)->mediaName() == soundFile )
00681
return true;
00682 }
00683
00684
return false;
00685 }
00686
00687
void KNotify::slotPlayerProcessExited(
KProcess *proc )
00688 {
00689 soundFinished( d->externalPlayerEventId,
00690 (proc->
normalExit() && proc->
exitStatus() == 0) ? PlayedOK : Unknown );
00691 }
00692
00693
void KNotify::abortFirstPlayObject()
00694 {
00695
QMap<KDE::PlayObject*,int>::Iterator it = d->playObjectEventMap.find( d->playObjects.getFirst() );
00696
if ( it != d->playObjectEventMap.end() )
00697 {
00698 soundFinished( it.data(), Aborted );
00699 d->playObjectEventMap.remove( it );
00700 }
00701 d->playObjects.removeFirst();
00702 }
00703
00704
void KNotify::soundFinished(
int eventId, PlayingFinishedStatus reason )
00705 {
00706
QByteArray data;
00707
QDataStream stream( data, IO_WriteOnly );
00708 stream << eventId << (
int) reason;
00709
00710 DCOPClient::mainClient()->emitDCOPSignal(
"KNotify",
"playingFinished(int,int)", data );
00711 }
00712
00713 WId KNotify::checkWinId(
const QString &appName, WId senderWinId )
00714 {
00715
if ( senderWinId == 0 )
00716 {
00717
QCString senderId = kapp->dcopClient()->senderId();
00718
QCString compare = (appName +
"-mainwindow").latin1();
00719
int len = compare.
length();
00720
00721
00722
QCStringList objs = kapp->dcopClient()->remoteObjects( senderId );
00723
for (QCStringList::ConstIterator it = objs.
begin(); it != objs.
end(); it++ ) {
00724
QCString obj( *it );
00725
if ( obj.left(len) == compare) {
00726
00727
QCString replyType;
00728
QByteArray data, replyData;
00729
00730
if ( kapp->dcopClient()->call(senderId, obj,
"getWinID()", data, replyType, replyData) ) {
00731
QDataStream answer(replyData, IO_ReadOnly);
00732
if (replyType ==
"int") {
00733 answer >> senderWinId;
00734
00735
00736 }
00737 }
00738 }
00739 }
00740 }
00741
return senderWinId;
00742 }
00743
00744
void KNotify::restartedArtsd()
00745 {
00746
delete d->audioManager;
00747 d->audioManager =
new KAudioManagerPlay( soundServer );
00748 d->audioManager->setTitle( i18n(
"KDE System Notifications" ) );
00749 d->audioManager->setAutoRestoreID(
"KNotify Aman Play" );
00750 }
00751
00752