示例#1
0
void         TrainModelNN   (_String* model, _String* matrix)
{
    _String         errMsg;

    long            modelIdx = modelNames.Find(model);

    _Parameter      verbI;

    checkParameter (VerbosityLevelString, verbI, 0.0);

    char            buffer [128];

    if (modelIdx < 0) {
        errMsg = *model & " did not refer to an existring model";
    } else {
        _Variable*    boundsMatrix              =   FetchVar  (LocateVarByName (*matrix));

        if (boundsMatrix && (boundsMatrix->ObjectClass() == MATRIX)) {
            _Matrix  *    bmatrix               =   (_Matrix*)      boundsMatrix->GetValue ();

            if (bmatrix->IsAStringMatrix() && (bmatrix->GetVDim () == 3)) {
                _Variable*    modelMatrix           =   LocateVar       (modelMatrixIndices.lData[modelIdx]);
                _SimpleList   modelVariableList;
                {
                    _AVLList mvla (&modelVariableList);
                    modelMatrix->ScanForVariables       (mvla, true);
                    mvla.ReorderList();
                }

                if (bmatrix->GetHDim () == modelVariableList.lLength) {
                    // now map model variables to bounds matrix
                    _SimpleList          variableMap;
                    _String             *myName;

                    for (long k = 0; k < modelVariableList.lLength; k++) {
                        myName = ((_FString*)bmatrix->GetFormula(k,0)->Compute())->theString;
                        long      vID    = LocateVarByName (*myName);

                        if (vID < 0) {
                            break;
                        }

                        vID = variableNames.GetXtra (vID);
                        vID = modelVariableList.Find(vID);

                        if (vID < 0) {
                            break;
                        }

                        variableMap << vID;
                    }

                    if (variableMap.lLength == modelVariableList.lLength) {
                        _Matrix     vBounds (variableMap.lLength,2, false, true);

                        long        k2 = 0;

                        for (; k2 < variableMap.lLength; k2++) {
                            _Parameter lb = ((_FString*)bmatrix->GetFormula(k2,1)->Compute())->theString->toNum(),
                                       ub = ((_FString*)bmatrix->GetFormula(k2,2)->Compute())->theString->toNum();

                            if ( ub>lb || k2) {
                                vBounds.Store (k2,0,lb);
                                vBounds.Store (k2,1,ub);
                                if (ub<=lb && vBounds (k2-1,0) <= vBounds (k2-1,1) && (!CheckEqual(vBounds (k2-1,0),0.0) || !CheckEqual(vBounds (k2-1,1),1.0))) {
                                    break;
                                }
                            }

                        }
                        if (k2 == modelVariableList.lLength) {
                            // set up the sampling now
                            _String             fName       = ProcessLiteralArgument (&ModelNNFile,nil);
                            FILE*               nnFile      = doFileOpen (fName.getStr(), "w");
                            if (nnFile) {
                                _Matrix*            modelMatrix = (_Matrix*) LocateVar(modelMatrixIndices.lData[modelIdx])->GetValue();

                                _Parameter          mainSteps,
                                                    checkSteps,
                                                    errorTerm,
                                                    loopMax,
                                                    hiddenNodes,
                                                    absError,
                                                    nn1,
                                                    nn2;

                                long                fullDimension = modelMatrix->GetHDim() * modelMatrix->GetVDim();


                                checkParameter      (ModelNNTrainingSteps,      mainSteps,      10000.0);
                                checkParameter      (ModelNNVerificationSample, checkSteps,     500.0);
                                checkParameter      (ModelNNPrecision,          errorTerm,      0.01);
                                checkParameter      (ModelNNTrainingSteps,      loopMax,        10);
                                checkParameter      (ModelNNHiddenNodes,        hiddenNodes,    5);
                                checkParameter      (ModelNNLearningRate,       nn1,            .3);
                                checkParameter      (ModelNNPersistenceRate,    nn2,            .1);

                                Net**               matrixNet = new Net* [fullDimension] ;

                                for (long i = 0; i < fullDimension; i++) {
                                    checkPointer (matrixNet [i] = new Net (variableMap.lLength,(long)hiddenNodes,1,errorTerm,nn1,nn2,100,200,true));
                                    //matrixNet[i]->verbose = true;
                                }

                                checkPointer        (matrixNet);

                                _List               tIn,
                                                    tOut;

                                FILE*               varSamples = doFileOpen ("variableSamples.out", "w");

                                fprintf (varSamples, "%s" ,LocateVar(modelVariableList.lData[0])->GetName()->getStr());
                                for (long vc = 1; vc < modelVariableList.lLength; vc++) {
                                    fprintf (varSamples, ",%s" ,LocateVar(modelVariableList.lData[variableMap.lData[vc]])->GetName()->getStr());
                                }

                                fprintf (varSamples, "\n");

                                for (long itCount = 0; itCount < loopMax; itCount ++) {
                                    if (verbI > 5) {
                                        snprintf (buffer, sizeof(buffer), "\nNeural Network Pass %ld. Building a training set...\n", itCount);
                                        BufferToConsole (buffer);
                                    }

                                    while   (tIn.countitems() < mainSteps) {
                                        NNMatrixSampler     (0, vBounds, modelVariableList, variableMap, modelMatrix, tIn, tOut);
                                    }

                                    _Matrix             inData (mainSteps, variableMap.lLength, false, true);
                                    _Parameter          *md = inData.theData;

                                    for (long matrixC = 0; matrixC < mainSteps; matrixC++) {
                                        _Parameter  *   ed = ((_Matrix*)tIn (matrixC))->theData;
                                        fprintf (varSamples, "\n%g",*ed);
                                        *md = *ed;
                                        ed++;
                                        md++;
                                        for (long entryC = 1; entryC < variableMap.lLength; entryC++, ed++, md++) {
                                            *md = *ed;
                                            fprintf (varSamples, ",%g", *md);
                                        }
                                    }

                                    tIn.Clear();

                                    if (verbI > 5) {
                                        BufferToConsole ( "Done Building Training Set. Training...\n");
                                    }

                                    long lastDone = 0;

                                    for (long cellCount = 0; cellCount < fullDimension; cellCount++) {
                                        Net* thisCell = matrixNet[cellCount];
                                        _Matrix outVector (mainSteps, 1, false, true);

                                        for (long oc = 0; oc < mainSteps; oc++) {
                                            outVector.theData[oc] = ((_Matrix*)tOut(oc))->theData[cellCount];
                                        }

                                        thisCell->studyAll (inData.theData, outVector.theData, mainSteps);

                                        long    nowDone = (cellCount+1)*100./fullDimension;
                                        if (nowDone > lastDone) {
                                            snprintf (buffer, sizeof(buffer),"%ld%% done\n", lastDone = nowDone);
                                            BufferToConsole (buffer);
                                        }
                                    }
                                    tOut.Clear();

                                    if (verbI > 5) {
                                        BufferToConsole ( "Done Training. Resampling...\n");
                                    }

                                    _PMathObj  tObj = _Constant(0).Time();
                                    _Parameter time1 = tObj->Value(),
                                               time2;

                                    while   (tIn.countitems() < checkSteps) {
                                        NNMatrixSampler     (0, vBounds, modelVariableList, variableMap, modelMatrix, tIn, tOut);
                                    }

                                    absError = 0.0;

                                    DeleteObject (tObj);
                                    tObj = _Constant(0).Time();
                                    time2 = tObj->Value();

                                    if (verbI > 5) {
                                        snprintf (buffer, sizeof(buffer),"Done Resampling in %g seconds. Computing Error...\n", time2-time1);
                                        BufferToConsole (buffer);
                                    }

                                    _Parameter  maxValT,
                                                maxValE;

                                    for (long verCount = 0; verCount < checkSteps; verCount++) {
                                        _Parameter*  inData     = ((_Matrix*)tIn(verCount))->theData,
                                                     *  outData  = ((_Matrix*)tOut(verCount))->theData;

                                        for (long cellCount = 0; cellCount < fullDimension; cellCount++) {
                                            Net         *thisCell = matrixNet[cellCount];

                                            _Parameter estVal     = thisCell->eval(inData)[0],
                                                       trueVal      = outData[cellCount],
                                                       localError;

                                            localError = estVal-trueVal;

                                            if (localError < 0) {
                                                localError = -localError;
                                            }

                                            if (absError < localError) {
                                                maxValT  = trueVal;
                                                maxValE  = estVal;
                                                absError = localError;
                                            }
                                        }
                                    }

                                    DeleteObject (tObj);
                                    tObj = _Constant(0).Time();
                                    time1 = tObj->Value();
                                    DeleteObject (tObj);


                                    if (verbI > 5) {
                                        snprintf (buffer, sizeof(buffer), "Done Error Checking in %g seconds. Got max abs error %g on the pair %g %g\n", time1-time2, absError, maxValT, maxValE);
                                        BufferToConsole (buffer);
                                    }
                                    if (absError <= errorTerm) {
                                        break;
                                    }
                                }

                                if (absError > errorTerm) {
                                    ReportWarning (_String("Couldn't achive desired precision in TrainModelNN. Achieved error of ") & absError);
                                }
                                fclose  (varSamples);
                                fprintf (nnFile,"{{\n\"%s\"", LocateVar(modelVariableList.lData[0])->GetName()->getStr());
                                _Matrix newBounds (modelVariableList.lLength, 2, false, true);
                                if (vBounds(0,0)>vBounds(0,1)) {
                                    newBounds.Store (variableMap.lData[0],0,0.);
                                    newBounds.Store (variableMap.lData[0],1,1.);
                                } else {
                                    newBounds.Store (variableMap.lData[0],0,vBounds(0,0));
                                    newBounds.Store (variableMap.lData[0],1,vBounds(0,1));
                                }
                                for (long varCounter = 1; varCounter < modelVariableList.lLength; varCounter ++) {
                                    fprintf (nnFile,",\n\"%s\"", LocateVar(modelVariableList.lData[varCounter])->GetName()->getStr());
                                    if (vBounds(varCounter,0)>vBounds(varCounter,1)) {
                                        newBounds.Store (variableMap.lData[varCounter],0,0.);
                                        newBounds.Store (variableMap.lData[varCounter],1,1.);
                                    } else {
                                        newBounds.Store (variableMap.lData[varCounter],0,vBounds(varCounter,0));
                                        newBounds.Store (variableMap.lData[varCounter],1,vBounds(varCounter,1));
                                    }
                                }

                                fprintf (nnFile,"\n}}\n");
                                newBounds.toFileStr (nnFile);


                                for (long i2 = 0; i2 < fullDimension; i2++) {
                                    matrixNet[i2]->save(nnFile);
                                    delete matrixNet [i2];
                                }

                                fclose (nnFile);
                                delete              matrixNet;
                            } else {
                                errMsg = _String ("Failed to open ") & fName & " for writing";
                            }
                        } else {
                            errMsg = _String ("Invalid variable bounds in row ") & (k2+1) & " of the bounds matrix";
                        }
                    } else {
                        errMsg = *myName & " was not one of the model parameters";
                    }

                } else {
                    errMsg = *matrix & " must be a have the same number of rows as the number of model parameters";
                }

            } else {
                errMsg = *matrix & " must be a string matrix with 3 columns";
            }
        } else {
            errMsg = *matrix & " was not the identifier of a valid matrix variable";
        }



    }

    if (errMsg.sLength) {
        errMsg = errMsg & _String(" in call to TrainModelNN.");
        WarnError (errMsg);
    }
}
示例#2
0
bool XProcess::startXSession(){
  //Returns true if the session can continue, or false if it needs to be closed down

  //Check that the necessary info to start the session is available
  if( xuser.isEmpty() || xcmd.isEmpty() || xhome.isEmpty() || xde.isEmpty() ){
    emit InvalidLogin();  //Make sure the GUI knows that it was a failure
    return true;
  }
  //Backend::log("Starting up Desktop environment ("+xcmd+") as user ("+xuser+")");
  
  //Check for PAM username/password validity
  if( !pam_checkPW() ){ emit InvalidLogin(); pam_shutdown(); return true; }

  //If this has a special device password, mount the personacrypt device
  if( !xanonlogin && !xdevpass.isEmpty() && Backend::getAvailablePersonaCryptUsers().contains(xuser) ){
    if( !Backend::MountPersonaCryptUser(xuser, xdevpass) ){ 
      //Could not mount the personacrypt device (invalid password?)
      xdevpass.clear(); //clear the invalid password
      emit InvalidLogin(); pam_shutdown(); return true; 
    }else{
      //overwrite the password in memory, but leave it flagged (not empty)
      if(DEBUG){ qDebug() << "Mounted PersonaCrypt Device"; }
      xdevpass.clear();
      xdevpass = "******"; 
    }
  }

  //Save the current user/desktop as the last login
  Backend::saveLoginInfo(xuser,xde);

  // Get the users uid/gid information
  struct passwd *pw;
  int uid;
  char *ok;

  if (!(pw = getpwnam(xuser.toLatin1()))) {
      uid = strtol(xuser.toLatin1(), &ok, 10);
      if (!(pw = getpwuid(uid))) {
          return false;
      }
  }

  //Emit the last couple logs before dropping privileges
  Backend::log("Starting session:");
  Backend::log(" - Session Log: ~/.pcdm-startup.log");
  //For sanity's sake, ensure that the ZFS mountpoint are all available first
  if(QFile::exists("/sbin/zfs")){
    QProcess::execute("zfs mount -a"); //just to ensure the user's home dir is actually mounted
  }
  //Check/create the user's home-dir before dropping privs
  if(!QFile::exists(xhome)){
    qDebug() << "No Home dir found - populating...";
    QString hmcmd = "pw usermod "+xuser+" -m";
    QProcess::execute(hmcmd);
  }
  //If this is an anonymous login, create the blank home-dir on top
  if(xanonlogin){
    if(DEBUG){ qDebug() << " - Stealth Session selected"; }
    QProcess::execute("personacrypt tempinit "+xuser+" 10G"); //always use 10GB blank dir
  }
  
  // Get the environment before we drop priv
  this->setProcessEnvironment( QProcessEnvironment::systemEnvironment() ); //current environment

  //Now allow this user access to the Xserver
  QString xhostcmd = "xhost si:localuser:"******"/usr/local/bin/dbus-launch")){
    cmd.append("dbus-launch --exit-with-session "+xcmd);
  }
  //Need to run a couple commands in sequence: so put them in a script file
  tOut << "#!/bin/sh\n\n";
  tOut << "if [ -e '"+xhome+"/.xprofile' ] ; then\n";
  tOut << "  chmod 755 "+xhome+"/.xprofile\n";
  tOut << "  . "+xhome+"/.xprofile\n";
  tOut << "fi\n";
  tOut << cmd + "\n"; //+ " >" + xhome+ "/.pcdm-startup.log" + " 2>" + xhome + "/.pcdm-startup.log\n";
  tOut << "exit $?"; //Make sure we return the DE return value

  QString tUid, tGid, logFile;
  tUid.setNum(pw->pw_uid);
  tGid.setNum(pw->pw_gid);
  logFile=xhome + "/.pcdm-startup.log";
  cmd = "/usr/local/share/PCDM/pcdm-session "+xuser+" "+tUid+" "+tGid+" "+tFile->fileName()+" "+logFile;
  connect( this, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotCleanup()) );
  tFile->setPermissions(QFile::ReadOwner | QFile::WriteOwner |QFile::ReadGroup | QFile::ReadUser | QFile::ReadOther);
  tFile->close();

  if(DEBUG){ Backend::log("Starting session with:\n" + cmd ); }
  this->start(cmd);
  return true;
}
示例#3
0
bool XProcess::startXSession(){
  //Returns true if the session can continue, or false if it needs to be closed down
  qDebug() << "Starting X Session:" << xuser << xcmd << xhome << xde << VT;
  //Check that the necessary info to start the session is available
  if( xuser.isEmpty() || xcmd.isEmpty() || xhome.isEmpty() || xde.isEmpty() ){
    emit InvalidLogin();  //Make sure the GUI knows that it was a failure
    return true;
  }
  //Backend::log("Starting up Desktop environment ("+xcmd+") as user ("+xuser+")");

  //Check for PAM username/password validity
  if( !pam_checkPW() ){ emit InvalidLogin(); pam_shutdown(); return true; }

  //Make sure the user is added to any required groups
  QStringList cgroups = Backend::runShellCommand("id -nG "+xuser).join("").split(" "); //current groups
  if(!cgroups.contains("video")){ Backend::runShellCommand("pw group mod video -m "+xuser); } //add user to video group (required for GPU access)

  //If this has a special device password, mount the personacrypt device
  if( !xanonlogin && !xdevpass.isEmpty() ){ //&& Backend::getAvailablePersonaCryptUsers().contains(xuser) ){
    Backend::log(" - PersonaCrypt Login Detected");
    if( !Backend::MountPersonaCryptUser(xuser, xdevpass) ){
      //Could not mount the personacrypt device (invalid password?)
      xdevpass.clear(); //clear the invalid password
      emit InvalidLogin(); pam_shutdown(); return true;
    }else{
      //overwrite the password in memory, but leave it flagged (not empty)
      if(DEBUG){ qDebug() << "Mounted PersonaCrypt Device"; }
      xdevpass.clear();
      xdevpass = "******";
    }
  }

  //Save the current user/desktop as the last login
  Backend::saveLoginInfo(xuser, xhome, xde);

  // Get the users uid/gid information
  struct passwd *pw;
  int uid;
  char *ok;

  if (!(pw = getpwnam(xuser.toLatin1()))) {
      uid = strtol(xuser.toLatin1(), &ok, 10);
      if (!(pw = getpwuid(uid))) {
          return false;
      }
  }

  //Emit the last couple logs before dropping privileges
  Backend::log("Starting session:");
  Backend::log(" - Session Log: ~/.pcdm-startup.log");
  QProcess::execute("killall compton");
  //For sanity's sake, ensure that the ZFS mountpoint are all available first
  if(QFile::exists("/sbin/zfs")){
    QProcess::execute("zfs mount -a"); //just to ensure the user's home dir is actually mounted
  }
  //Check/create the user's home-dir before dropping privs
  if(!QFile::exists(xhome)){
    qDebug() << "No Home dir found - populating...";
    QString hmcmd = "pw usermod "+xuser+" -m";
    QProcess::execute(hmcmd);
  }
  //If this is an anonymous login, create the blank home-dir on top
  if(xanonlogin){
    if(DEBUG){ qDebug() << " - Stealth Session selected"; }
    QProcess::execute("personacrypt tempinit "+xuser+" 10G"); //always use 10GB blank dir
  }

  // Get the environment before we drop priv
  this->setProcessEnvironment( QProcessEnvironment::systemEnvironment() ); //current environment

  //Now allow this user access to the Xserver
  QString xhostcmd = "xhost si:localuser:"******"/tmp/pcdm-session."+VT+".XXXXXX");
  if ( ! tFile->open() )
     return false;

  QTextStream tOut(tFile);

  // Configure the DE startup command
  if(QFile::exists("/usr/local/bin/dbus-launch") && !xcmd.contains("lumina-desktop") ){
    cmd.append("dbus-launch --exit-with-session "+xcmd);
  }else{
    cmd.append(xcmd);
  }

  QString tUid, tGid, logFile;
  tUid.setNum(pw->pw_uid);
  tGid.setNum(pw->pw_gid);
  logFile=xhome + "/.pcdm-startup.log";

  // Locate the auth file
  QString authfile = qgetenv("XAUTHORITY");
  if ( authfile.isEmpty() )
    authfile = xhome + "/.Xauthority";

  //Need to run a couple commands in sequence: so put them in a script file
  tOut << "#!/bin/sh\n\n";

  QString PICOCLIENT = qgetenv("PICO_CLIENT_LOGIN");
  QString PICOHOME = qgetenv("PICO_CLIENT_HOME");
  if ( ! PICOCLIENT.isEmpty() && ! PICOHOME.isEmpty() ) {
    // Change ownership on the Xauthority file for PICO usage
    tOut << "rm "+authfile+"\n";
    tOut << "ln -fs "+PICOHOME+"/.Xauthority "+authfile+"\n";
    QString PICOPULSE = qgetenv("PICO_PULSE_COOKIE");
    // Check if PULSE is enabled
    if ( ! PICOPULSE.isEmpty() ) {
      tOut << "mkdir -p "+xhome+"/.config/pulse 2>/dev/null\n";
      tOut << "cp "+PICOPULSE+" "+xhome+"/.config/pulse/cookie\n";
      tOut << "chown "+tUid+":"+tGid+" " +xhome+"/.config/pulse/cookie\n";
    }
    QProcess::execute("chown "+tUid+" "+PICOHOME+"/.Xauthority"); // Change ownership on the pico login
  } else {
    // Change ownership on the Xauthority file
    QProcess::execute("chown "+tUid+":"+tGid+" "+authfile);
  }

  tOut << Backend::resetKbdCmd() + "\n"; //do this before sourcing .xprofile - in case there is a user-override set there
  tOut << "if [ -e '"+xhome+"/.xprofile' ] ; then\n";
  tOut << "  chmod 755 "+xhome+"/.xprofile\n";
  tOut << "  . "+xhome+"/.xprofile\n";
  tOut << "fi\n";
  tOut << cmd + "\n"; //+ " >" + xhome+ "/.pcdm-startup.log" + " 2>" + xhome + "/.pcdm-startup.log\n";
  tOut << "exit $?"; //Make sure we return the DE return value

  cmd = "/usr/local/share/PCDM/pcdm-session"; //+xuser+" "+tUid+" "+tGid+" "+tFile->fileName()+" "+logFile;
  QStringList cmdArgs; cmdArgs << xuser << tUid << tGid << tFile->fileName() << logFile;
  connect( this, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotCleanup()) );
  tFile->setPermissions(QFile::ReadOwner | QFile::WriteOwner |QFile::ReadGroup | QFile::ReadUser | QFile::ReadOther);
  tFile->close();

  if(DEBUG){ Backend::log("Starting session with:\n" + cmd ); }
  this->start(cmd, cmdArgs);
  return true;
}
示例#4
0
int main(int argc, char *argv[]) {
	long lastVolume = 0;
	long actVolume  = 0;
	long pTime, dTime;
	char buff[255];
	char *sndCard = NULL;
	char *playerName = NULL;
	int  aName;

	#define LINE_NUM 4
	tagtypes_t layout[LINE_NUM][3] = {
		{COMPOSER,    ARTIST,       MAXTAG_TYPES},
		{ALBUM,       MAXTAG_TYPES, MAXTAG_TYPES},
		{TITLE,       MAXTAG_TYPES, MAXTAG_TYPES},
		{ALBUMARTIST, CONDUCTOR,    MAXTAG_TYPES},
	};

	opterr = 0;
	while ((aName = getopt (argc, argv, "o:n:tvh")) != -1) {
		switch (aName) {
			case 't':
				enableTOut();
				break;

			case 'v':
				incVerbose();
				break;

			case 'o':
				sndCard = optarg;
				break;

			case 'n':
				playerName = optarg;
				break;

			case 'h':
				printf("LMSMonitor Ver. 0.2\nUsage [options] -n Player name\noptions:\n -o Soundcard (eg. hw:CARD=IQaudIODAC)\n -t enable print info to stdout\n -v increment verbose level\n\n");
				exit(1);
				break;
		}
	}

	if((tags = initSliminfo(playerName)) == NULL)	{ exit(1); }

	// init ALSA mixer monitor
	startMimo(sndCard, NULL);

#ifdef __arm__
	// init OLED display
	if (initDisplay() == EXIT_FAILURE) {
		exit(EXIT_FAILURE);
	}
#endif

	while (true) {

		actVolume = getActVolume();
		if (actVolume != lastVolume) {
			sprintf(buff, "Vol:             %3ld%%", actVolume);
#ifdef __arm__
			putText(0, 0, buff);
			drawHorizontalBargraph(24, 2, 75, 4, actVolume);
			refreshDisplay();
#endif
			tOut(buff);
			lastVolume = actVolume;
		}

		if (isRefreshed()) {
			tOut("_____________________\n");

			for (int line = 0; line < LINE_NUM; line++) {
#ifdef __arm__
				int filled = false;
#endif
				for (tagtypes_t *t = layout[line]; *t != MAXTAG_TYPES; t++) {
					if (tags[*t].valid) {
#ifdef __arm__
						filled = true;
#endif
						if (tags[*t].changed) {
								strncpy(buff, tags[*t].tagData, maxCharacter());
#ifdef __arm__
								putTextToCenter((line + 1) * 10, buff);
#endif
						}
						sprintf(stbl, "%s\n", tags[*t].tagData);
						tOut(stbl);
						break;
					}
				}
#ifdef __arm__
				if(!filled) {
					clearLine((line + 1) * 10);
				}
#endif
			}

			pTime = tags[TIME].valid     ? strtol(tags[TIME].tagData,     NULL, 10) : 0;
			dTime = tags[DURATION].valid ? strtol(tags[DURATION].tagData, NULL, 10) : 0;

#ifdef __arm__
			sprintf(buff, "%ld:%02ld", pTime/60, pTime%60);
			int tlen = strlen(buff);
			clearLine(56);
			putText(0, 56, buff);

			sprintf(buff, "%ld:%02ld", dTime/60, dTime%60);
			int dlen = strlen(buff);
			putText(maxXPixel() - (dlen * CHAR_WIDTH), 56, buff);

			sprintf(buff, "%s", tags[MODE].valid ? tags[MODE].tagData : "");
			int mlen = strlen(buff);
			putText(((maxXPixel() - ((tlen + mlen + dlen) * CHAR_WIDTH)) / 2) + (tlen * CHAR_WIDTH), 56, buff);

			drawHorizontalBargraph(-1, 51, 0, 4, (pTime*100) / (dTime == 0 ? 1 : dTime));
#else
			sprintf(buff, "%3ld:%02ld  %5s  %3ld:%02ld", pTime/60, pTime%60, tags[MODE].valid ? tags[MODE].tagData : "",  dTime/60, dTime%60);
			sprintf(stbl, "%s\n\n", buff);
			tOut(stbl);
#endif
			for(int i = 0; i < MAXTAG_TYPES; i++) {
				tags[i].changed = false;
			}

#ifdef __arm__
			refreshDisplay();
#endif
			askRefresh();
		}

		usleep(SLEEP_TIME);
    }

#ifdef __arm__
	closeDisplay();
#endif
	closeSliminfo();
	return 0;
}