Beginning Objective-C 2.0

I am new to software development and I would like to beginning programming in Cocoa.
I have downloaded Apple's Objective-C 2.0 Tutorial from the Developer Connection website, and I plan to read it before I begin reading a Cocoa tutorial written by Aaron Hillegass.
I currently only have knowledge of Java, and no prior experience with C. This means that I only have a background in object-oriented programming, as opposed to C, which is procedural.
Will I be able to comprehend Apple's tutorial? Should I obtain some knowledge on C before I begin reading the tutorial? Or should my knowledge of Java suffice?
Thank you!

The following links tell you about some of the improvements in ObjC 2.0 - I don't think that there is a lot to learn in addition to the "prior version" but some of the improvements are extremely nice to work with…
http://developer.apple.com/leopard/overview/objectivec2.html
http://theocacao.com/document.page/510
Andreas

Similar Messages

  • Varray of Objects "Bind variable not declared" error.. I don't want a bind variable.

    Hello.
    This program is supposed to pull values from a table using a loop, and in the loop, put the values in objects in a varray.  I'm new to objects and am stumped trying to get this program to run.  When I attempt to run it in SQL*Plus  I get the following feedback:
    Type created.
    Type body created
    SP2-0552: Bind variable "MY_VARRAY_EMP1" not declared.
    I don't think I even need a bind variable.  Any feedback would be appreciated.  Here's the program:
    -- Enable screen I/O
    SET SERVEROUTPUT ON SIZE 1000000
    SET VERIFY OFF
    -- begin object spec
    CREATE OR REPLACE TYPE employee3 AS OBJECT
      ename CHAR (20 char),
      empno NUMBER (4),
      sal NUMBER (10),
      MEMBER FUNCTION get_ename RETURN CHAR, MEMBER PROCEDURE set_ename (SELF IN OUT NOCOPY employee3),
      MEMBER FUNCTION get_empno RETURN NUMBER, MEMBER PROCEDURE set_empno (SELF IN OUT NOCOPY employee3),
      MEMBER FUNCTION get_sal RETURN NUMBER, MEMBER PROCEDURE set_sal (SELF IN OUT NOCOPY employee3)
    -- begin object body
    CREATE OR REPLACE TYPE BODY employee3 AS
      -- gets
      MEMBER FUNCTION get_ename RETURN CHAR IS
      BEGIN
      RETURN self.ename;
      END;
      MEMBER FUNCTION get_empno RETURN NUMBER IS
      BEGIN
      RETURN self.empno;
      END;
      MEMBER FUNCTION get_sal RETURN NUMBER IS
      BEGIN
      RETURN self.ename;
      END;
      -- sets
      MEMBER PROCEDURE set_ename(SELF IN OUT employee3) IS
      BEGIN
      self.ename := ename;
      END;
      MEMBER PROCEDURE set_empno(SELF IN OUT employee3) IS
      BEGIN
      self.empno := empno;
      END;
      MEMBER PROCEDURE set_sal(SELF IN OUT employee3) IS
      BEGIN
      self.sal := sal;
      END;
    END;
    DECLARE
      TYPE emp_varray IS VARRAY(10) OF EMPLOYEE3;
      my_varray_emp1 EMP_VARRAY;
      -- List of EMPNO's in order of appearance in EMP table (for cross-referencing, single-line retrieval)
      TYPE MYCREF_VARRAY IS VARRAY(10) OF NUMBER(4);
      varray_mycref MYCREF_VARRAY := MYCREF_VARRAY(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
      this_object EMPLOYEE3;
      -- make a variable to store one empno
      thisno NUMBER(4);
      -- make a counter
      counter INT;
      -- query variables for the set calls
      q_ename CHAR(20 CHAR);
      q_empno NUMBER(4);
      q_sal NUMBER(10);
      my_result INT;
    BEGIN
      --my_varray_emp1 := EMP_VARRAY(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
      -- Put the first 10 EMPNO's in my cref array
      SELECT empno BULK COLLECT INTO varray_mycref FROM emp WHERE ROWNUM < 11;
      -- Use a loop to retrieve the first 10 objects in the "emp" table and put them in the varray of objects
      q_ename := NULL;
      q_empno := NULL;
      q_sal := NULL;
      my_result := NULL;
      this_object := NULL;
      counter := 1;
      FOR counter IN 1..10 LOOP
      thisno := varray_mycref(counter);
      this_object := my_varray_emp1(counter);
      SELECT ename INTO q_ename FROM emp WHERE empno = thisno;
      my_result := this_object.set_ename(q_ename, NULL);
      SELECT empno INTO q_empno FROM emp WHERE empno = thisno;
      my_result := this_object.set_empno(q_empno, NULL);
      SELECT sal INTO q_sal FROM emp WHERE empno = thisno;
      my_result := this_object.set_sal(q_sal, NULL);
      END LOOP;
      -- Use another loop to display the information in the reverse order.
      FOR counter in REVERSE 1..10 LOOP
      this_object =: my_varray_emp1(counter);
      dbms_output.put_line((this_object.get_ename()) || CHR(9) || (this_object.get_empno()) || CHR(9) || (this_object.get_sal()));
      END LOOP;
    END;

    Cleaning up your code for errors and eliminating unnecessary complexity...
    Add a user-defined constructor which takes all attributes and calls the "setter" procedures in one trip:
    -- Enable screen I/O
    set SERVEROUTPUT on size 1000000
    set VERIFY off
    -- begin object spec
    create or replace type employee3 as object
      ename CHAR (20 char),
      empno NUMBER (4),
      sal NUMBER (10),
    constructor function employee3(
        self    in out nocopy    employee3,
        aEname    in        char,
        aEmpNo    in        integer,
        aSal    in        number
      return self as result,
      member function get_ename return CHAR, member procedure set_ename (SELF in out nocopy employee3, ename in char),
      member function get_empno return NUMBER, member procedure set_empno (SELF in out nocopy employee3, empno in integer),
      member function get_sal return NUMBER, member procedure set_sal (SELF in out nocopy employee3, sal in integer)
    -- begin object body
    create or replace type body employee3 as
      constructor function employee3(
        self    in out nocopy    employee3,
        aEname    in        char,
        aEmpNo    in        integer,
        aSal    in        number
      return self as result
      is
      begin
        self.set_ename(aEname);
        self.set_empno(aEmpNo);
        self.set_sal(aSal);
        return;
      end;
      -- gets
      member function get_ename return CHAR is
      begin
      return self.ename;
      end;
      member function get_empno return NUMBER is
      begin
      return self.empno;
      end;
      member function get_sal return NUMBER is
      begin
      return self.sal;
      end;
      -- sets
      member procedure set_ename(SELF in out employee3, ename in char) is
      begin
      self.ename := ename;
      end;
      member procedure set_empno(SELF in out employee3, empno in integer) is
      begin
      self.empno := empno;
      end;
      member procedure set_sal(SELF in out employee3, sal in integer) is
      begin
      self.sal := sal;
      end;
    end;
    (Since I don't have EMP handy at the moment, create a simple view instead)
    create or replace view emp
    as
    select    'EMP' || to_char(level) ename
    ,    level + 100 empno
    ,    DBMS_RANDOM.VALUE(25000,75000) sal
    from    DUAL
    connect by
        level <= 20
    Get rid of your loop and individual SELECTs, and replace it with a single SELECT BULK COLLECT INTO...
    declare
      type emp_varray is varray(10) of EMPLOYEE3;
      my_varray_emp1 EMP_VARRAY;
      this_object EMPLOYEE3;
    begin
      -- No need for a loop. Use SELECT BULK COLLECT INTO, together with a user-defined constructor call (since the
      -- user-defined constructor overrides the default constructor we need to call it using named-parameter notation):
      select    new employee3(
                aEname    => e.ename,
                aEmpNo    => e.empno,
                aSal    => e.sal
      bulk collect into
            my_varray_emp1
      from        emp e
      where        rownum <= 10;
      -- Use another loop to display the information in the reverse order.
      for counter in reverse 1..10 loop
      this_object := my_varray_emp1(counter);
      dbms_output.put_line((this_object.get_ename()) || chr(9) || to_char(this_object.get_empno()) || chr(9) || to_char(this_object.get_sal()));
      end loop;
    end;
    EMP10        
    110    60110
    EMP9         
    109    67485
    EMP8         
    108    58242
    EMP7         
    107    47597
    EMP6         
    106    58995
    EMP5         
    105    49098
    EMP4         
    104    47406
    EMP3         
    103    67574
    EMP2         
    102    59663
    EMP1         
    101    52929
    PL/SQL procedure successfully completed.
    Gerard

  • Moving object in JFrame

    Hello,
    I am starting to look into how to work with graphics in Java for the first time. So what I am trying to achieve is a simple circle moving across a frame.
    Here is the code that I thought would do the trick.
    package com.game.begin;
    import java.awt.Color;
    import java.awt.Graphics;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    public class Begin extends JPanel
         int x_pos = 10;          
         int y_pos = 100;     
         int radius = 20;
         JFrame f = new JFrame();
         public  static void main(String[] args){
              Begin b=new Begin();
            b.doRun();
         public void doRun(){
              f.setSize(600,600 + 20);
              f.setVisible(true);
              f.setTitle("Do Title");
              f.setContentPane(new Begin());
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   
    //        Graphics g=f.getGraphics();
              while (true){
                   x_pos ++;
                   System.out.println("x="+x_pos+" y="+y_pos);
                   repaint();
    //               paint(g);
                   try {
                        Thread.sleep (10);
                   } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
         public void paint (Graphics g)
              System.out.println("paint method of my thread..............");
              g.setColor  (Color.red);
              g.fillOval (x_pos - radius, y_pos - radius, 2 * radius, 2 * radius);
    }However all I get is a circle. It doesn't move across a screen. When I uncomment
    //        Graphics g=f.getGraphics();and
    //               paint(g);lines . I get a big red line moving across the screen. Basically I draw a new circle without erasing an old one. My understanding is that if I utilize repaint method Java will automatically erase old graphic and replace with the new one.
    I am not sure why in my case this doesn't happen. Can you explain what's going on and/or correct the above code?
    Thank you.

    import java.awt.*;
    import javax.swing.*;
    public class Begin extends JPanel
         int x_pos = 10;
         int y_pos = 100;
         int radius = 20;
         JFrame f = new JFrame();
         public  static void main(String[] args){
              Begin b=new Begin();
            b.doRun();
         public void doRun(){
              f.setSize(600,600 + 20);
              f.setVisible(true);
              f.setTitle("Do Title");
              // Why create a new Begin object?
              f.setContentPane(this);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            // Never do this!  Have the code render only when asked to do so.
    //        Graphics g=f.getGraphics();
              while (true){
                   x_pos ++;
                   System.out.println("x="+x_pos+" y="+y_pos);
                   repaint();
                   try {
                        // It is bad practice to block the EDT.  Invoke this loop from a Timer instead.
                        Thread.sleep (10);
                   } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
         // Call paint() for AWT.  Call paintComponent() for Swing.
         public void paintComponent (Graphics g)
              // Will erase the background!
              super.paintComponent(g);
              System.out.println("paint method of my thread..............");
              g.setColor  (Color.red);
              g.fillOval (x_pos - radius, y_pos - radius, 2 * radius, 2 * radius);
    }The more expert GUI developers could probably point you to the exact parts of the Java Tutorial that cover custom rendering and animation. But I could not be bothered googling them.

  • Updating Transient objects in Kodo 2.5.5

    I have a situation where I construct a JDO object in transient state in my
    code ( for batch processing of data from a file into the database) by
    calling the objects contructor and setting it's values. The row
    representing this object may or may not exist in the database.
    How do I make the object peristant ? If the row already exists, then I
    must be able to update the row with the new values ( non-primary keys ).
    If not, I should insert a new row.
    There are no multi table relationships involved in this case. A JDO object
    represents just one table.
    We want to avoid the scheme which involves retrieve the object first and
    then trying to update in a transaction.
    Adarsh

    Transaction t = kpm.currentTransaction();
    try {
    MyObject o = new MyObject(...)
    t.begin();
    Object id = ((PersistenceCapable)o).jdoNewObjectIdInstance();
    ((PersistenceCapable)o).jdoCopyKeyFieldsToObjectId(id);
    try{
    System.out.println(id);
    Object trio = pm.getObjectById(id,true);
    pm.deletePersistent(trio);
    }catch(ObjectNotFoundException oe){
    System.out.println("First time!");
    pm.makePersistent(o);
    t.commit();
    }catch(...){

  • Clone Objects

    Hi everybody,
    I have the next trouble, I need to clone an Object, but the method "clone()" in the Object class is protected.
    I am working with a DBMSOO that provide me the following classes: Database, Transaction. I want to have a generic command that retrieve Objects from a database Object-Oriented, and then to make a cast to a specific class.
    This is the code:
    public class Lookup
    private Object object;
    public Lookup
    Database db = new Database();
    db.open( "dbUrl->server", Database.OPEN_READ_ONLY );
    Transaction txn = new Transaction( db );
    txn.begin();
    object = db.lookup( "idObject" );
    txn.commit();
    db.close();
    public Object getObject() {
    return object;
    My trouble is that when the Transaction is finished with commit() method, the object reference is null. I thought to clone the Object, but is not posible.
    Could anyone help me, please?
    Sincerely,
    Alvaro
    PS: Sorry, for my english. I know it isn't very good.

    Hi DrClap,
    I understand you, but if I don't write the sentence:
    txn.commit()
    that close the Transaction, the reference "object" isn't null.
    What's the matter?
    Thanks a lot for your interesting.
    Alvaro

  • Objects of a tablespace

    Hi,
    1-how can I see the objects of a tablespace ?
    2-does TEMP tablespace contain any object ? How to see ?
    Thanks.

    Many thanks but :
    SP2-0734: unknown command beginning "'free spac..." - rest of line ignored.
    SP2-0734: unknown command beginning "' ' object..." - rest of line ignored.
    SP2-0734: unknown command beginning "file_id, /..." - rest of line ignored.
    SP2-0734: unknown command beginning "block_id, ..." - rest of line ignored.
    SP2-0044: For a list of known commands enter HELP
    and to leave enter EXIT.
    SP2-0734: unknown command beginning "CEIL(block..." - rest of line ignored.
    SP2-0734: unknown command beginning "from dba_f..." - rest of line ignored.
    SP2-0734: unknown command beginning "where tabl..." - rest of line ignored.
    SP2-0042: unknown command "union" - rest of line ignored.
    SP2-0044: For a list of known commands enter HELP
    and to leave enter EXIT.
    SP2-0734: unknown command beginning "substr(own..." - rest of line ignored.
    SP2-0734: unknown command beginning "substr(seg..." - rest of line ignored.
    SP2-0734: unknown command beginning "file_id, /..." - rest of line ignored.
    SP2-0734: unknown command beginning "block_id, ..." - rest of line ignored.
    SP2-0044: For a list of known commands enter HELP
    and to leave enter EXIT.
    SP2-0734: unknown command beginning "CEIL(block..." - rest of line ignored.
    SP2-0734: unknown command beginning "from dba_e..." - rest of line ignored.
    SP2-0734: unknown command beginning "where tabl..." - rest of line ignored.
    SP2-0734: unknown command beginning "order by 1..." - rest of line ignored.
    SP2-0044: For a list of known commands enter HELP
    and to leave enter EXIT.
    select tablespace_name,
    ERROR at line 1:
    ORA-00936: missing expression
    Usage: { EXIT | QUIT } [ SUCCESS | FAILURE | WARNING | n |
    <variable> | :<bindvariable> ] [ COMMIT | ROLLBACK ]
    Message was edited by:
    user522961

  • PHP MPD Class

    Most mpd.class.php's are old and produce a lot of errors which caused me much frustration in this thread.
    I was wrapping my head around why phpmpreloaded worked and the others never and it's because it uses an updated mpd.class.php. To save others the frustration and hassle I figured I'd post the new class here.
    Enjoy.
    <?php
    * Sven Ginka 03/2010
    * Version mpd.class.php-1.3
    * - take over from Hendrik Stoetter
    * - removed "split()" as this function is marked depracted
    * - added property "xfade" (used by IPodMp, phpMp+)
    * - added property "bitrate" (used by phpMp+)
    * - added define "MPD_SEARCH_FILENAME"
    * - included sorting algorithm "msort"
    * - added function validateFile() for guessing a title if no ID3 data is given
    * Hendrik Stoetter 03/2008
    * - this a lightly modified version of mod.class Version 1.2.
    * - fixed some bugs and added some new functions
    * - Changes:
    * GetDir($url) -> GetDir(url,$sort)
    * var $stats
    * Benjamin Carlisle 05/05/2004
    * mpd.class.php - PHP Object Interface to the MPD Music Player Daemon
    * Version 1.2, Released 05/05/2004
    * Copyright (C) 2003-2004 Benjamin Carlisle ([email protected])
    * http://mpd.24oz.com/ | http://www.musicpd.org/
    * This program is free software; you can redistribute it and/or modify
    * it under the terms of the GNU General Public License as published by
    * the Free Software Foundation; either version 2 of the License, or
    * (at your option) any later version.
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU General Public License for more details.
    * You should have received a copy of the GNU General Public License
    * along with this program; if not, write to the Free Software
    * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    // Create common command definitions for MPD to use
    define("MPD_CMD_STATUS", "status");
    define("MPD_CMD_STATISTICS", "stats");
    define("MPD_CMD_VOLUME", "volume");
    define("MPD_CMD_SETVOL", "setvol");
    define("MPD_CMD_PLAY", "play");
    define("MPD_CMD_STOP", "stop");
    define("MPD_CMD_PAUSE", "pause");
    define("MPD_CMD_NEXT", "next");
    define("MPD_CMD_PREV", "previous");
    define("MPD_CMD_PLLIST", "playlistinfo");
    define("MPD_CMD_PLADD", "add");
    define("MPD_CMD_PLREMOVE", "delete");
    define("MPD_CMD_PLCLEAR", "clear");
    define("MPD_CMD_PLSHUFFLE", "shuffle");
    define("MPD_CMD_PLLOAD", "load");
    define("MPD_CMD_PLSAVE", "save");
    define("MPD_CMD_KILL", "kill");
    define("MPD_CMD_REFRESH", "update");
    define("MPD_CMD_REPEAT", "repeat");
    define("MPD_CMD_LSDIR", "lsinfo");
    define("MPD_CMD_SEARCH", "search");
    define("MPD_CMD_START_BULK", "command_list_begin");
    define("MPD_CMD_END_BULK", "command_list_end");
    define("MPD_CMD_FIND", "find");
    define("MPD_CMD_RANDOM", "random");
    define("MPD_CMD_SEEK", "seek");
    define("MPD_CMD_PLSWAPTRACK", "swap");
    define("MPD_CMD_PLMOVETRACK", "move");
    define("MPD_CMD_PASSWORD", "password");
    define("MPD_CMD_TABLE", "list");
    define("MPD_CMD_PLMOVE", "move" );
    // Predefined MPD Response messages
    define("MPD_RESPONSE_ERR", "ACK");
    define("MPD_RESPONSE_OK", "OK");
    // MPD State Constants
    define("MPD_STATE_PLAYING", "play");
    define("MPD_STATE_STOPPED", "stop");
    define("MPD_STATE_PAUSED", "pause");
    // MPD Searching Constants
    define("MPD_SEARCH_ARTIST", "artist");
    define("MPD_SEARCH_TITLE", "title");
    define("MPD_SEARCH_ALBUM", "album");
    define("MPD_SEARCH_ANY", "any");
    define("MPD_SEARCH_FILENAME","filename");
    // MPD Cache Tables
    define("MPD_TBL_ARTIST","artist");
    define("MPD_TBL_ALBUM","album");
    $mpd_debug = 0;
    function addLog($text){
    global $mpd_debug;
    $style="background-color:lightgrey;border:thin solid grey;margin:5px;padding:5px";
    if ($mpd_debug) echo '<div style="'.$style.'">log:>'.$text.'</div>';
    function addErr($err){
    global $mpd_debug;
    if ($mpd_debug) echo 'error:>'.$err.'<br>';
    class mpd {
    // TCP/Connection variables
    var $host;
    var $port;
    var $password;
    var $mpd_sock = NULL;
    var $connected = FALSE;
    // MPD Status variables
    var $mpd_version = "(unknown)";
    var $state;
    var $current_track_position;
    var $current_track_length;
    var $current_track_id;
    var $volume;
    var $repeat;
    var $random;
    var $uptime;
    var $playtime;
    var $db_last_refreshed;
    var $num_songs_played;
    var $playlist_count;
    var $xfade;
    var $bitrate;
    var $num_artists;
    var $num_albums;
    var $num_songs;
    var $playlist = array();
    var $stats;
    // Misc Other Vars
    var $mpd_class_version = "1.2";
    var $debugging = FALSE; // Set to TRUE to turn extended debugging on.
    var $errStr = ""; // Used for maintaining information about the last error message
    var $command_queue; // The list of commands for bulk command sending
    // =================== BEGIN OBJECT METHODS ================
    /* mpd() : Constructor
    * Builds the MPD object, connects to the server, and refreshes all local object properties.
    function mpd($srv,$port,$pwd = NULL, $debug= FALSE ) {
    $this->host = $srv;
    $this->port = $port;
    $this->password = $pwd;
    $this->debugging = $debug;
    global $mpd_debug;
    $mpd_debug = $debug;
    $resp = $this->Connect();
    if ( is_null($resp) ) {
    addErr( "Could not connect" );
    return;
    } else {
    addLog( "connected");
    list ( $this->mpd_version ) = sscanf($resp, MPD_RESPONSE_OK . " MPD %s\n");
    if ( ! is_null($pwd) ) {
    if ( is_null($this->SendCommand(MPD_CMD_PASSWORD,$pwd)) ) {
    $this->connected = FALSE;
    addErr("bad password");
    return; // bad password or command
    if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!
    $this->connected = FALSE;
    addErr("Password supplied does not have read access");
    return;
    } else {
    if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!
    $this->connected = FALSE;
    addErr("Password required to access server");
    return;
    /* Connect()
    * Connects to the MPD server.
    * NOTE: This is called automatically upon object instantiation; you should not need to call this directly.
    function Connect() {
    addLog( "mpd->Connect() / host: ".$this->host.", port: ".$this->port."\n" );
    $this->mpd_sock = fsockopen($this->host,$this->port,$errNo,$errStr,10);
    if (!$this->mpd_sock) {
    addErr("Socket Error: $errStr ($errNo)");
    return NULL;
    } else {
    $counter=0;
    while(!feof($this->mpd_sock)) {
    $counter++;
    if ($counter > 10){
    addErr("no file end");
    return NULL;
    $response = fgets($this->mpd_sock,1024);
    addLog( $response );
    if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {
    $this->connected = TRUE;
    return $response;
    if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {
    // close socket
    fclose($this->mpd_sock);
    addErr("Server responded with: $response");
    return NULL;
    // close socket
    fclose($this->mpd_sock);
    // Generic response
    addErr("Connection not available");
    return NULL;
    /* SendCommand()
    * Sends a generic command to the MPD server. Several command constants are pre-defined for
    * use (see MPD_CMD_* constant definitions above).
    function SendCommand($cmdStr,$arg1 = "",$arg2 = "") {
    addLog("mpd->SendCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2 );
    // Clear out the error String
    $this->errStr = NULL;
    $respStr = "";
    if ( ! $this->connected ) {
    addErr( "mpd->SendCommand() / Error: Not connected");
    } else {
    // Check the command compatibility:
    if ( ! $this->_checkCompatibility($cmdStr) ) {
    return NULL;
    if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";
    if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";
    fputs($this->mpd_sock,"$cmdStr\n");
    while(!feof($this->mpd_sock)) {
    $response = fgets($this->mpd_sock,1024);
    //addLog($response);
    // An OK signals the end of transmission -- we'll ignore it
    if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {
    break;
    // An ERR signals the end of transmission with an error! Let's grab the single-line message.
    if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {
    list ( $junk, $errTmp ) = strtok(MPD_RESPONSE_ERR . " ",$response );
    addErr( strtok($errTmp,"\n") );
    return NULL;
    // Build the response string
    $respStr .= $response;
    addLog("mpd->SendCommand() / response: '".$respStr."'\n");
    return $respStr;
    /* QueueCommand()
    * Queues a generic command for later sending to the MPD server. The CommandQueue can hold
    * as many commands as needed, and are sent all at once, in the order they are queued, using
    * the SendCommandQueue() method. The syntax for queueing commands is identical to SendCommand().
    function QueueCommand($cmdStr,$arg1 = "",$arg2 = "") {
    if ( $this->debugging ) echo "mpd->QueueCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n";
    if ( ! $this->connected ) {
    echo "mpd->QueueCommand() / Error: Not connected\n";
    return NULL;
    } else {
    if ( strlen($this->command_queue) == 0 ) {
    $this->command_queue = MPD_CMD_START_BULK . "\n";
    if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";
    if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";
    $this->command_queue .= $cmdStr ."\n";
    if ( $this->debugging ) echo "mpd->QueueCommand() / return\n";
    return TRUE;
    /* SendCommandQueue()
    * Sends all commands in the Command Queue to the MPD server. See also QueueCommand().
    function SendCommandQueue() {
    if ( $this->debugging ) echo "mpd->SendCommandQueue()\n";
    if ( ! $this->connected ) {
    echo "mpd->SendCommandQueue() / Error: Not connected\n";
    return NULL;
    } else {
    $this->command_queue .= MPD_CMD_END_BULK . "\n";
    if ( is_null($respStr = $this->SendCommand($this->command_queue)) ) {
    return NULL;
    } else {
    $this->command_queue = NULL;
    if ( $this->debugging ) echo "mpd->SendCommandQueue() / response: '".$respStr."'\n";
    return $respStr;
    /* AdjustVolume()
    * Adjusts the mixer volume on the MPD by <modifier>, which can be a positive (volume increase),
    * or negative (volume decrease) value.
    function AdjustVolume($modifier) {
    if ( $this->debugging ) echo "mpd->AdjustVolume()\n";
    if ( ! is_numeric($modifier) ) {
    $this->errStr = "AdjustVolume() : argument 1 must be a numeric value";
    return NULL;
    $this->RefreshInfo();
    $newVol = $this->volume + $modifier;
    $ret = $this->SetVolume($newVol);
    if ( $this->debugging ) echo "mpd->AdjustVolume() / return\n";
    return $ret;
    /* SetVolume()
    * Sets the mixer volume to <newVol>, which should be between 1 - 100.
    function SetVolume($newVol) {
    if ( $this->debugging ) echo "mpd->SetVolume()\n";
    if ( ! is_numeric($newVol) ) {
    $this->errStr = "SetVolume() : argument 1 must be a numeric value";
    return NULL;
    // Forcibly prevent out of range errors
    if ( $newVol < 0 ) $newVol = 0;
    if ( $newVol > 100 ) $newVol = 100;
    // If we're not compatible with SETVOL, we'll try adjusting using VOLUME
    if ( $this->_checkCompatibility(MPD_CMD_SETVOL) ) {
    if ( ! is_null($ret = $this->SendCommand(MPD_CMD_SETVOL,$newVol))) $this->volume = $newVol;
    } else {
    $this->RefreshInfo(); // Get the latest volume
    if ( is_null($this->volume) ) {
    return NULL;
    } else {
    $modifier = ( $newVol - $this->volume );
    if ( ! is_null($ret = $this->SendCommand(MPD_CMD_VOLUME,$modifier))) $this->volume = $newVol;
    if ( $this->debugging ) echo "mpd->SetVolume() / return\n";
    return $ret;
    /* GetDir()
    * Retrieves a database directory listing of the <dir> directory and places the results into
    * a multidimensional array. If no directory is specified, the directory listing is at the
    * base of the MPD music path.
    function GetDir($dir = "",$sort = "") {
    addLog( "mpd->GetDir()" );
    $resp = $this->SendCommand(MPD_CMD_LSDIR,$dir);
    $listArray = $this->_parseFileListResponse($resp);
    if ($listArray==null){
    return null;
    // we have 3 differnt items: directory, playlist and file
    // we have to sort them individually and separate
    // playlist and directory by name
    // file by $sort
    // 1st: subarrays
    $array_directory = $listArray['directories'];
    $array_playlist = $listArray['playlists'];
    $array_file = $listArray['files'];
    // 2nd: sort them
    natcasesort($array_directory);
    natcasesort($array_playlist);
    usort($array_file,"msort");
    // 3rd: rebuild
    $array_return= array(
    "directories"=> $array_directory,
    "playlists"=> $array_playlist,
    "files"=> $array_file
    foreach ($array_directory as $value) {
    $array_return[]["directory"] = $value;
    foreach ($array_playlist as $value) {
    $array_return[]["playlist"] = $value;
    $array_return = array_merge($array_return,$array_file);
    addLog( "mpd->GetDir() / return ".print_r($array_return,true));
    return $array_return;
    /* GetDirTest() (Unoffical add) -- Returns readable dir contents
    * Retrieves a database directory listing of the <dir> directory and places the results into
    * a multidimensional array. If no directory is specified, the directory listing is at the
    * base of the MPD music path.
    function GetDirTest($dir = "") {
    if ( $this->debugging ) echo "mpd->GetDir()\n";
    $resp = $this->SendCommand(MPD_CMD_LSDIR,$dir);
    #$dirlist = $this->_parseFileListResponse($resp);
    $dirlist = $this->_parseFileListResponseHumanReadable($resp);
    if ( $this->debugging ) echo "mpd->GetDir() / return ".print_r($dirlist)."\n";
    return $dirlist;
    /* PLAdd()
    * Adds each track listed in a single-dimensional <trackArray>, which contains filenames
    * of tracks to add, to the end of the playlist. This is used to add many, many tracks to
    * the playlist in one swoop.
    function PLAddBulk($trackArray) {
    if ( $this->debugging ) echo "mpd->PLAddBulk()\n";
    $num_files = count($trackArray);
    for ( $i = 0; $i < $num_files; $i++ ) {
    $this->QueueCommand(MPD_CMD_PLADD,$trackArray[$i]);
    $resp = $this->SendCommandQueue();
    $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLAddBulk() / return\n";
    return $resp;
    /* PLAdd()
    * Adds the file <file> to the end of the playlist. <file> must be a track in the MPD database.
    function PLAdd($fileName) {
    if ( $this->debugging ) echo "mpd->PLAdd()\n";
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLADD,$fileName))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLAdd() / return\n";
    return $resp;
    /* PLMoveTrack()
    * Moves track number <origPos> to position <newPos> in the playlist. This is used to reorder
    * the songs in the playlist.
    function PLMoveTrack($origPos, $newPos) {
    if ( $this->debugging ) echo "mpd->PLMoveTrack()\n";
    if ( ! is_numeric($origPos) ) {
    $this->errStr = "PLMoveTrack(): argument 1 must be numeric";
    return NULL;
    if ( $origPos < 0 or $origPos > $this->playlist_count ) {
    $this->errStr = "PLMoveTrack(): argument 1 out of range";
    return NULL;
    if ( $newPos < 0 ) $newPos = 0;
    if ( $newPos > $this->playlist_count ) $newPos = $this->playlist_count;
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLMOVETRACK,$origPos,$newPos))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLMoveTrack() / return\n";
    return $resp;
    /* PLShuffle()
    * Randomly reorders the songs in the playlist.
    function PLShuffle() {
    if ( $this->debugging ) echo "mpd->PLShuffle()\n";
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLSHUFFLE))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLShuffle() / return\n";
    return $resp;
    /* PLLoad()
    * Retrieves the playlist from <file>.m3u and loads it into the current playlist.
    function PLLoad($file) {
    if ( $this->debugging ) echo "mpd->PLLoad()\n";
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLLOAD,$file))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLLoad() / return\n";
    return $resp;
    /* PLSave()
    * Saves the playlist to <file>.m3u for later retrieval. The file is saved in the MPD playlist
    * directory.
    function PLSave($file) {
    if ( $this->debugging ) echo "mpd->PLSave()\n";
    $resp = $this->SendCommand(MPD_CMD_PLSAVE,$file);
    if ( $this->debugging ) echo "mpd->PLSave() / return\n";
    return $resp;
    /* PLClear()
    * Empties the playlist.
    function PLClear() {
    if ( $this->debugging ) echo "mpd->PLClear()\n";
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLCLEAR))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLClear() / return\n";
    return $resp;
    /* PLRemove()
    * Removes track <id> from the playlist.
    function PLRemove($id) {
    if ( $this->debugging ) echo "mpd->PLRemove()\n";
    if ( ! is_numeric($id) ) {
    $this->errStr = "PLRemove() : argument 1 must be a numeric value";
    return NULL;
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLREMOVE,$id))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLRemove() / return\n";
    return $resp;
    /* SetRepeat()
    * Enables 'loop' mode -- tells MPD continually loop the playlist. The <repVal> parameter
    * is either 1 (on) or 0 (off).
    function SetRepeat($repVal) {
    if ( $this->debugging ) echo "mpd->SetRepeat()\n";
    $rpt = $this->SendCommand(MPD_CMD_REPEAT,$repVal);
    $this->repeat = $repVal;
    if ( $this->debugging ) echo "mpd->SetRepeat() / return\n";
    return $rpt;
    /* SetRandom()
    * Enables 'randomize' mode -- tells MPD to play songs in the playlist in random order. The
    * <rndVal> parameter is either 1 (on) or 0 (off).
    function SetRandom($rndVal) {
    if ( $this->debugging ) echo "mpd->SetRandom()\n";
    $resp = $this->SendCommand(MPD_CMD_RANDOM,$rndVal);
    $this->random = $rndVal;
    if ( $this->debugging ) echo "mpd->SetRandom() / return\n";
    return $resp;
    /* Shutdown()
    * Shuts down the MPD server (aka sends the KILL command). This closes the current connection,
    * and prevents future communication with the server.
    function Shutdown() {
    if ( $this->debugging ) echo "mpd->Shutdown()\n";
    $resp = $this->SendCommand(MPD_CMD_SHUTDOWN);
    $this->connected = FALSE;
    unset($this->mpd_version);
    unset($this->errStr);
    unset($this->mpd_sock);
    if ( $this->debugging ) echo "mpd->Shutdown() / return\n";
    return $resp;
    /* DBRefresh()
    * Tells MPD to rescan the music directory for new tracks, and to refresh the Database. Tracks
    * cannot be played unless they are in the MPD database.
    function DBRefresh() {
    if ( $this->debugging ) echo "mpd->DBRefresh()\n";
    $resp = $this->SendCommand(MPD_CMD_REFRESH);
    // Update local variables
    $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->DBRefresh() / return\n";
    return $resp;
    /* Play()
    * Begins playing the songs in the MPD playlist.
    function Play() {
    if ( $this->debugging ) echo "mpd->Play()\n";
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY) )) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->Play() / return\n";
    return $rpt;
    /* Stop()
    * Stops playing the MPD.
    function Stop() {
    if ( $this->debugging ) echo "mpd->Stop()\n";
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_STOP) )) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->Stop() / return\n";
    return $rpt;
    /* Pause()
    * Toggles pausing on the MPD. Calling it once will pause the player, calling it again
    * will unpause.
    function Pause() {
    if ( $this->debugging ) echo "mpd->Pause()\n";
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PAUSE) )) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->Pause() / return\n";
    return $rpt;
    /* SeekTo()
    * Skips directly to the <idx> song in the MPD playlist.
    function SkipTo($idx) {
    if ( $this->debugging ) echo "mpd->SkipTo()\n";
    if ( ! is_numeric($idx) ) {
    $this->errStr = "SkipTo() : argument 1 must be a numeric value";
    return NULL;
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY,$idx))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->SkipTo() / return\n";
    return $idx;
    /* SeekTo()
    * Skips directly to a given position within a track in the MPD playlist. The <pos> argument,
    * given in seconds, is the track position to locate. The <track> argument, if supplied is
    * the track number in the playlist. If <track> is not specified, the current track is assumed.
    function SeekTo($pos, $track = -1) {
    if ( $this->debugging ) echo "mpd->SeekTo()\n";
    if ( ! is_numeric($pos) ) {
    $this->errStr = "SeekTo() : argument 1 must be a numeric value";
    return NULL;
    if ( ! is_numeric($track) ) {
    $this->errStr = "SeekTo() : argument 2 must be a numeric value";
    return NULL;
    if ( $track == -1 ) {
    $track = $this->current_track_id;
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_SEEK,$track,$pos))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->SeekTo() / return\n";
    return $pos;
    /* Next()
    * Skips to the next song in the MPD playlist. If not playing, returns an error.
    function Next() {
    if ( $this->debugging ) echo "mpd->Next()\n";
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_NEXT))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->Next() / return\n";
    return $rpt;
    /* Previous()
    * Skips to the previous song in the MPD playlist. If not playing, returns an error.
    function Previous() {
    if ( $this->debugging ) echo "mpd->Previous()\n";
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PREV))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->Previous() / return\n";
    return $rpt;
    /* Search()
    * Searches the MPD database. The search <type> should be one of the following:
    * MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM
    * The search <string> is a case-insensitive locator string. Anything that contains
    * <string> will be returned in the results.
    function Search($type,$string) {
    addLog("mpd->Search()");
    if ( $type != MPD_SEARCH_ARTIST and
    $type != MPD_SEARCH_ALBUM and
    $type != MPD_SEARCH_ANY and
    $type != MPD_SEARCH_TITLE ) {
    addErr( "mpd->Search(): invalid search type" );
    return NULL;
    } else {
    if ( is_null($resp = $this->SendCommand(MPD_CMD_SEARCH,$type,$string))) return NULL;
    $searchlist = $this->_parseFileListResponse($resp);
    addLog( "mpd->Search() / return ".print_r($searchlist,true) );
    return $searchlist;
    /* Find()
    * Find() looks for exact matches in the MPD database. The find <type> should be one of
    * the following:
    * MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM
    * The find <string> is a case-insensitive locator string. Anything that exactly matches
    * <string> will be returned in the results.
    function Find($type,$string) {
    if ( $this->debugging ) echo "mpd->Find()\n";
    if ( $type != MPD_SEARCH_ARTIST and
    $type != MPD_SEARCH_ALBUM and
    $type != MPD_SEARCH_TITLE ) {
    $this->errStr = "mpd->Find(): invalid find type";
    return NULL;
    } else {
    if ( is_null($resp = $this->SendCommand(MPD_CMD_FIND,$type,$string))) return NULL;
    $searchlist = $this->_parseFileListResponse($resp);
    if ( $this->debugging ) echo "mpd->Find() / return ".print_r($searchlist)."\n";
    return $searchlist;
    /* Disconnect()
    * Closes the connection to the MPD server.
    function Disconnect() {
    if ( $this->debugging ) echo "mpd->Disconnect()\n";
    fclose($this->mpd_sock);
    $this->connected = FALSE;
    unset($this->mpd_version);
    unset($this->errStr);
    unset($this->mpd_sock);
    /* GetArtists()
    * Returns the list of artists in the database in an associative array.
    function GetArtists() {
    if ( $this->debugging ) echo "mpd->GetArtists()\n";
    if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ARTIST))) return NULL;
    $arArray = array();
    $arLine = strtok($resp,"\n");
    $arName = "";
    $arCounter = -1;
    while ( $arLine ) {
    list ( $element, $value ) = explode(": ",$arLine);
    if ( $element == "Artist" ) {
    $arCounter++;
    $arName = $value;
    $arArray[$arCounter] = $arName;
    $arLine = strtok("\n");
    if ( $this->debugging ) echo "mpd->GetArtists()\n";
    return $arArray;
    /* GetAlbums()
    * Returns the list of albums in the database in an associative array. Optional parameter
    * is an artist Name which will list all albums by a particular artist.
    function GetAlbums( $ar = NULL) {
    if ( $this->debugging ) echo "mpd->GetAlbums()\n";
    if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ALBUM, $ar ))) return NULL;
    $alArray = array();
    $alLine = strtok($resp,"\n");
    $alName = "";
    $alCounter = -1;
    while ( $alLine ) {
    list ( $element, $value ) = explode(": ",$alLine);
    if ( $element == "Album" ) {
    $alCounter++;
    $alName = $value;
    $alArray[$alCounter] = $alName;
    $alLine = strtok("\n");
    if ( $this->debugging ) echo "mpd->GetAlbums()\n";
    return $alArray;
    //***************************** INTERNAL FUNCTIONS ******************************//
    /* _computeVersionValue()
    * Computes a compatibility value from a version string
    private function _computeVersionValue($verStr) {
    list ($ver_maj, $ver_min, $ver_rel ) = explode(".",$verStr);
    return ( 100 * $ver_maj ) + ( 10 * $ver_min ) + ( $ver_rel );
    /* _checkCompatibility()
    * Check MPD command compatibility against our internal table. If there is no version
    * listed in the table, allow it by default.
    private function _checkCompatibility($cmd) {
    // Check minimum compatibility
    if (isset($this->COMPATIBILITY_MIN_TBL[$cmd])){
    $req_ver_low = $this->COMPATIBILITY_MIN_TBL[$cmd];
    } else {
    $req_ver_low = "0.9.1";
    // check max compatibility
    if (isset($this->COMPATIBILITY_MAX_TBL[$cmd])){
    $req_ver_hi = $this->COMPATIBILITY_MAX_TBL[$cmd];
    } else {
    $req_ver_hi = "0.20.0";
    $mpd_ver = $this->_computeVersionValue($this->mpd_version);
    if ( $req_ver_low ) {
    $req_ver = $this->_computeVersionValue($req_ver_low);
    if ( $mpd_ver < $req_ver ) {
    addErr("Command '$cmd' is not compatible with this version of MPD, version ".$req_ver_low." required");
    return FALSE;
    // Check maximum compatibility -- this will check for deprecations
    if ( $req_ver_hi ) {
    $req_ver = $this->_computeVersionValue($req_ver_hi);
    if ( $mpd_ver > $req_ver ) {
    addErr("Command '$cmd' has been deprecated in this version of MPD.");
    return FALSE;
    return TRUE;
    * checks the file entry and complete it if necesarry
    * checked fields are 'Artist', 'Genre' and 'Title'
    private function _validateFile( $fileItem ){
    $filename = $fileItem['file'];
    if (!isset($fileItem['Artist'])){ $fileItem['Artist']=null; }
    if (!isset($fileItem['Genre'])){ $fileItem['Genre']=null; }
    // special conversion for streams
    if (stripos($filename, 'http' )!==false){
    if (!isset($fileItem['Title'])) $title = ''; else $title=$fileItem['Title'];
    if (!isset($fileItem['Name'])) $name = ''; else $name=$fileItem['Name'];
    if (!isset($fileItem['Artist'])) $artist = ''; else $artist=$fileItem['Artist'];
    if (strlen($title.$name.$artist)==0){
    $fileItem['Title'] = $filename;
    } else {
    $fileItem['Title'] = 'stream://'.$title.' '.$name.' '.$artist;
    if (!isset($fileItem['Title'])){
    $file_parts = explode('/', $filename);
    $fileItem['Title'] = $filename;
    return $fileItem;
    * take the response of mpd and split it up into
    * items of types 'file', 'directory' and 'playlist'
    private function _extractItems( $resp ){
    if ( $resp == null ) {
    addLog('empty file list');
    return NULL;
    // strip unwanted chars
    $resp = trim($resp);
    // split up into lines
    $lineList = explode("\n", $resp );
    $array = array();
    $item=null;
    foreach ($lineList as $line ){
    list ( $element, $value ) = explode(": ",$line);
    // if one of the key words come up, store the item
    if (($element == "directory") or ($element=="playlist") or ($element=="file")){
    if ($item){
    $array[] = $item;
    $item = array();
    $item[$element] = $value;
    // check if there is a last item to store
    if (sizeof($item)>0){
    $array[] = $item;
    return $array;
    /* _parseFileListResponse()
    * Builds a multidimensional array with MPD response lists.
    * NOTE: This function is used internally within the class. It should not be used.
    private function _parseFileListResponse($resp) {
    $valuesArray = $this->_extractItems( $resp );
    if ($valuesArray == null ){
    return null;
    //1. create empty arrays
    $directoriesArray = array();
    $filesArray = array();
    $playlistsArray = array();
    //2. sort the items
    foreach ( $valuesArray as $item ) {
    if (isset($item['file'])){
    $filesArray[] = $this->_validateFile($item);
    } else if (isset($item['directory'])){
    $directoriesArray[] = $item['directory'];
    } else if (isset($item['playlist'])){
    $playlistsArray[] = $item['playlist'];
    } else {
    addErr('should not enter this');
    //3. create a combined list of items
    $returnArray = array(
    "directories"=>$directoriesArray,
    "playlists"=>$playlistsArray,
    "files"=>$filesArray
    addLog( print_r($valuesArray,true) );
    return $returnArray;
    /* RefreshInfo()
    * Updates all class properties with the values from the MPD server.
    * NOTE: This function is automatically called upon Connect() as of v1.1.
    function RefreshInfo() {
    // Get the Server Statistics
    $statStr = $this->SendCommand(MPD_CMD_STATISTICS);
    if ( !$statStr ) {
    return NULL;
    } else {
    $stats = array();
    $statStr=trim($statStr);
    $statLine = explode( "\n", $statStr );
    foreach ( $statLine as $line ) {
    list ( $element, $value ) = explode(": ",$line);
    $stats[$element] = $value;
    // Get the Server Status
    $statusStr = $this->SendCommand(MPD_CMD_STATUS);
    if ( ! $statusStr ) {
    return NULL;
    } else {
    $status = array();
    $statusStr=trim($statusStr);
    $statusLine = explode("\n", $statusStr );
    foreach ( $statusLine as $line ) {
    list ( $element, $value ) = explode(": ",$line);
    $status[$element] = $value;
    // Get the Playlist
    $plStr = $this->SendCommand(MPD_CMD_PLLIST);
    $array = $this->_parseFileListResponse($plStr);
    $playlist = $array['files'];
    $this->playlist_count = count($playlist);
    $this->playlist = array();
    if (sizeof($playlist)>0){
    foreach ($playlist as $item ){
    $this->playlist[$item['Pos']]=$item;
    // Set Misc Other Variables
    $this->state = $status['state'];
    if ( ($this->state == MPD_STATE_PLAYING) || ($this->state == MPD_STATE_PAUSED) ) {
    $this->current_track_id = $status['song'];
    list ($this->current_track_position, $this->current_track_length ) = explode(":",$status['time']);
    } else {
    $this->current_track_id = -1;
    $this->current_track_position = -1;
    $this->current_track_length = -1;
    $this->repeat = $status['repeat'];
    $this->random = $status['random'];
    $this->db_last_refreshed = $stats['db_update'];
    $this->volume = $status['volume'];
    $this->uptime = $stats['uptime'];
    $this->playtime = $stats['playtime'];
    $this->num_songs_played = $stats['songs'];
    $this->num_artists = $stats['artists'];
    $this->num_songs = $stats['songs'];
    $this->num_albums = $stats['albums'];
    $this->xfade = $status['xfade'];
    if(isset($status['bitrate'])) $this->bitrate = $status['bitrate'];
    else $this->bitrate = FALSE;
    return TRUE;
    /* ------------------ DEPRECATED METHODS -------------------*/
    /* GetStatistics()
    * Retrieves the 'statistics' variables from the server and tosses them into an array.
    * NOTE: This function really should not be used. Instead, use $this->[variable]. The function
    * will most likely be deprecated in future releases.
    function GetStatistics() {
    if ( $this->debugging ) echo "mpd->GetStatistics()\n";
    $stats = $this->SendCommand(MPD_CMD_STATISTICS);
    if ( !$stats ) {
    return NULL;
    } else {
    $statsArray = array();
    $statsLine = strtok($stats,"\n");
    while ( $statsLine ) {
    list ( $element, $value ) = explode(": ",$statsLine);
    $statsArray[$element] = $value;
    $statsLine = strtok("\n");
    if ( $this->debugging ) echo "mpd->GetStatistics() / return: " . print_r($statsArray) ."\n";
    return $statsArray;
    /* GetStatus()
    * Retrieves the 'status' variables from the server and tosses them into an array.
    * NOTE: This function really should not be used. Instead, use $this->[variable]. The function
    * will most likely be deprecated in future releases.
    function GetStatus() {
    if ( $this->debugging ) echo "mpd->GetStatus()\n";
    $status = $this->SendCommand(MPD_CMD_STATUS);
    if ( ! $status ) {
    return NULL;
    } else {
    $statusArray = array();
    $statusLine = strtok($status,"\n");
    while ( $statusLine ) {
    list ( $element, $value ) = explode(": ",$statusLine);
    $statusArray[$element] = $value;
    $statusLine = strtok("\n");
    if ( $this->debugging ) echo "mpd->GetStatus() / return: " . print_r($statusArray) ."\n";
    return $statusArray;
    /* GetVolume()
    * Retrieves the mixer volume from the server.
    * NOTE: This function really should not be used. Instead, use $this->volume. The function
    * will most likely be deprecated in future releases.
    function GetVolume() {
    if ( $this->debugging ) echo "mpd->GetVolume()\n";
    $volLine = $this->SendCommand(MPD_CMD_STATUS);
    if ( ! $volLine ) {
    return NULL;
    } else {
    list ($vol) = sscanf($volLine,"volume: %d");
    if ( $this->debugging ) echo "mpd->GetVolume() / return: $vol\n";
    return $vol;
    /* GetPlaylist()
    * Retrieves the playlist from the server and tosses it into a multidimensional array.
    * NOTE: This function really should not be used. Instead, use $this->playlist. The function
    * will most likely be deprecated in future releases.
    function GetPlaylist() {
    if ( $this->debugging ) echo "mpd->GetPlaylist()\n";
    $resp = $this->SendCommand(MPD_CMD_PLLIST);
    $playlist = $this->_parseFileListResponse($resp);
    if ( $this->debugging ) echo "mpd->GetPlaylist() / return ".print_r($playlist)."\n";
    return $playlist;
    /* ----------------- Command compatibility tables --------------------- */
    var $COMPATIBILITY_MIN_TBL = array(
    MPD_CMD_SEEK => "0.9.1" ,
    MPD_CMD_PLMOVE => "0.9.1" ,
    MPD_CMD_RANDOM => "0.9.1" ,
    MPD_CMD_PLSWAPTRACK => "0.9.1" ,
    MPD_CMD_PLMOVETRACK => "0.9.1" ,
    MPD_CMD_PASSWORD => "0.10.0" ,
    MPD_CMD_SETVOL => "0.10.0"
    var $COMPATIBILITY_MAX_TBL = array(
    MPD_CMD_VOLUME => "0.10.0"
    } // ---------------------------- end of class ------------------------------
    function msort($a,$b) {
    global $sort_array,$filenames_only;
    $i=0;
    $ret = 0;
    while($filenames_only!="yes" && $i<4 && $ret==0) {
    if(!isset($a[$sort_array[$i]])) {
    if(isset($b[$sort_array[$i]])) {
    $ret = -1;
    else if(!isset($b[$sort_array[$i]])) {
    $ret = 1;
    else if(strcmp($sort_array[$i],"Track")==0) {
    $ret = strnatcmp($a[$sort_array[$i]],$b[$sort_array[$i]]);
    else {
    $ret = strcasecmp($a[$sort_array[$i]],$b[$sort_array[$i]]);
    $i++;
    if($ret==0)
    $ret = strcasecmp($a["file"],$b["file"]);
    return $ret;
    function picksort($pick) {
    global $sort_array;
    if(0==strcmp($pick,$sort_array[0])) {
    return "$sort_array[0],$sort_array[1],$sort_array[2],$sort_array[3]";
    else if(0==strcmp($pick,$sort_array[1])) {
    return "$pick,$sort_array[0],$sort_array[2],$sort_array[3]";
    else if(0==strcmp($pick,$sort_array[2])) {
    return "$pick,$sort_array[0],$sort_array[1],$sort_array[3]";
    else if(0==strcmp($pick,$sort_array[3])) {
    return "$pick,$sort_array[0],$sort_array[1],$sort_array[2]";
    ?>

    BaconPie wrote:I used it to make a web based remote control for my phone. Glad it was of some help.
    regarding the phone client, ... there is one in the phpMpReloaded project called IPodMp :-)
    http://phpmpreloaded.sourceforge.net/sc … IPodMp.png
    cheers
    -tswaehn

  • Hyperion Planning business rules migrating to Calc Manager issue

    It was suggested I post this in calc manager as well, so I hope cross posting is allowed!
    We are trying to migrate from Hyperion Planning 11.1.1.3 to 11.1.2.2
    Our business rules were migrated to Calc Manager by our IT team. The rules run (for the most part).
    Our main complaint about this migration is that it excluded our comments inside the business rules and added it's own!
    When we first open the rule it is in graphical mode. But on the Script Tab I can see our orignal Business rule, but it's missing comments. Not all comments -- those at the top of the rule are intact, but after it starts getting into the meat of the rule, it loses many, but not all of the comments. When I chose to edit this rule in script mode, then calc manager adds tons if its own comments, making the code very junky to read.
    So, multiple questions -- how do we get the migration of business rules to calc manager to stop losing our important comments. Is it possible to get the newly migrated rules to initially open in script mode rather than graphical mode so that it doesn't add it's own comments. Or is there a way to turn off the added commenting?
    This is a snippet of our rule in 11.1.1.3:
    FIX ("D0P000 Pushdown")
    "Accrued Salaries and Wages Pushdown" = "BTL Accrued Sal & Wages Total"->"WBS_I19990_PLAN" * (D0P000->"Total Reg Labor" / "LMSS (LRP TEMPLATE LEVEL)"->"Total Reg Labor");
    ENDFIX
    /* FIX on account members that should be rolled up in the AGG statement below. */
    FIX (@DESCENDANTS( "Orders"),
    This is what it looks like when it comes up in graphical mode in Calc Mgr 11.1.2.2 (note that comment is already missing):
    FIX ("D0P000 Pushdown")
    "Accrued Salaries and Wages Pushdown" = "BTL Accrued Sal & Wages Total"->"WBS_I19990_PLAN" * (D0P000->"Total Reg Labor" / "LMSS (LRP TEMPLATE LEVEL)"->"Total Reg Labor");
    ENDFIX
    FIX (@DESCENDANTS( "Orders"),
    This is what it looks like when it switches from graphical to script (bonus comments are added):
    FIX ( /*DIM:Entities*/"D0P000 Pushdown")
    /*STARTCOMPONENT:FORMULA*/
    "Accrued Salaries and Wages Pushdown" = "BTL Accrued Sal & Wages Total"->"WBS_I19990_PLAN" * (D0P000->"Total Reg Labor" / "LMSS (LRP TEMPLATE LEVEL)"->"Total Reg Labor");
    /*ENDCOMPONENT*/ ENDFIX
    FIX ( /*DIM:Accounts*/@DESCENDANTS( "Orders"),
    Thanks for any help.
    Brenda

    You might learn to appreciate graphical mode in Calc Manager, we do. It is not like the old Business Rules in EAS. I am an old school calc script person, and have NO love for drag-and-drop coding ... I need control. ;-)
    Insert a blank script object and paste your code into the 'Script' tab for that object. Set up your prompts and use the {} notation in your code. All of the comments will stay put ... as long as you DON'T USE EDIT, SCRIPT! We make a fair number of generic, reusable pieces of code and save them as shared scripts. These can be dragged into Rules. Click on the Rule's Begin object and choose the Script tab ... you will see how the bits are assembled into complete calc script. We've even come up with a way to use LOOP ... ENDLOOP as though it were a procedural IF statement so we can control whether or not a chunk of code is active or not.
    Shared scripts are especially good for currency translation components since we occasionally add new currencies and want to make a change in one object that is used in dozens of business rules.
    Mike H.

  • Very confused beginner here...

    Hello everyone. I'm new to the board here. I am currently a junior meteorology major with a minor in computer science at Millersville University. To incorporate both my minor and major, I decided to make a computer program that scrolls weather watches and warnings across the bottom of a computer screen (much like they do on television). I am a beginner at Java, only using it for a few months. I really feel like I have bitten off more than I can chew with this program. However, I am dedicated in working through this problem. Below is a copy of the code I am using for this. I keep getting errors, however. I had it working perfectly, besides the fact that a) it never updated and b) it would never scroll more than one watch or warning, meaning it would just loop one over and over. I have also included the errors that I receive during this. Any help would be greatly appreciated. I am sorry if the code looks a bit trashy and disorganized. These are just some things, being a rookie, that I am going to have to learn how to clean up. Thanks
    import java.awt.*;
    import java.awt.event.*;
    import java.util.*;
    import javax.swing.Timer;
    import javax.swing.*;
    import java.applet.Applet;
    import java.applet.AudioClip;
    import java.net.*;
    import de.nava.informa.core.ChannelIF;
    import de.nava.informa.core.ItemIF;
    import de.nava.informa.impl.basic.ChannelBuilder;
    import de.nava.informa.parsers.FeedParser;
    public class WxScroll extends JFrame implements ActionListener {
         private static final long serialVersionUID = 1L;
         int count = 0;
         JLabel scrollLabel;
         String scroll, watwarstring, text;
         Label label;
         ItemIF item;
         Component newText;
         String watwar[];
         String newscroll, oldText;
         ChannelIF channel;
         Collection items;
         final TimerTask task;
         java.util.Timer timercheck;
         ChannelBuilder channelb;
         URL url;
         public WxScroll() {
              final Color red = new Color(255, 0, 0);
              final Color yellow = new Color(255, 255, 0);
              final Color orange = new Color(255, 165, 0);
              final Color darkred = new Color(205, 38, 38);
              final Color orangered = new Color(255, 69, 0);
              final Color darkmagenta = new Color(139, 0, 139);
              final Color blueviolet = new Color(138, 43, 226);
              final Color lime = new Color(50, 205, 50);
              final Color goldenrod = new Color(205, 155, 29);
              final Color deeppink = new Color(255, 20, 147);
              final Color lightsteelblue = new Color(176, 196, 222);
              final Color yellowgreen = new Color(154, 205, 50);
              final Color limegreen = new Color(34, 139, 34);
              final Color burlywood = new Color(222, 184, 135);
              final Color paleturquoise = new Color(102, 139, 139);
              final Color springgreen = new Color(0, 238, 118);
              final Color seagreen = new Color(46, 139, 87);
              final Color greenyellow = new Color(127, 255, 0);
              final Color steelblue = new Color(54, 100, 139);
              final Color royalblue = new Color(65, 105, 225);
              final Color hotpink = new Color(255, 105, 180);
              final Color tan = new Color(205, 133, 63);
              final Color skyblue = new Color(135, 206, 250);
              final Color palevioletred = new Color(219, 112, 147);
              final Color slateblue = new Color(0, 127, 255);
              final Color coral = new Color(255, 127, 0);
              final Color cornflower = new Color(100, 149, 237);
              final Color maroon = new Color(176, 48, 96);
              try {
                   URL url = new URL("file:misslebeep2.wav");
                   AudioClip ac = Applet.newAudioClip(url);
                   ac.play();
              } catch (Exception e) {
              timercheck = new java.util.Timer();
              task = new TimerTask() {
                   public void run() {
                        try {
                             channel = FeedParser
                                       .parse(
                                                 channelb = new ChannelBuilder(),
                                                 url = new URL(
                                                           "http://www.weather.gov/alerts/wwarssget.php?zone=COZ041"));
                        catch (Exception e) {
                             System.out.println("exception");
                        finally {
                             items = channel.getItems();
                             scrollLabel = new JLabel(newscroll);
                             for (Iterator i = items.iterator(); i.hasNext();) {
                                  count++;
                                  ItemIF item = (ItemIF) i.next();
                                  scroll = item.getDescription();
                                  newscroll += scroll
                                            .replaceAll("<br>", " ")
                                            .replaceAll(
                                                      "Issuing Weather Forecast Office Homepage",
                                            .replaceAll("</a>", " ")
                                            .replaceAll(
                                                      "<a href=http://www.nws.noaa.gov/er/ctp>",
                             if (newscroll.contains("There are no active"))
                                  scrollLabel.setVisible(false);
                             else {
                                  scrollLabel.setBackground(red);
                                  if (newscroll.contains("Tornado warning".toUpperCase()))
                                       scrollLabel.setBackground(red);
                                  if (newscroll.contains("Severe thunderstorm warning"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(orange);
                                  if (newscroll.contains("Flash Flood Warning"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(darkred);
                                  if (newscroll
                                            .contains("Blizzard Warning".toUpperCase()))
                                       scrollLabel.setBackground(orangered);
                                  if (newscroll.contains("ice storm warning"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(darkmagenta);
                                  if (newscroll.contains("short term".toUpperCase()))
                                       scrollLabel.setBackground(burlywood);
                                  if (newscroll.contains("heavy snow warning"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(blueviolet);
                                  if (newscroll.contains("heavy sleet warning"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(skyblue);
                                  if (newscroll.contains("flood warning".toUpperCase()))
                                       scrollLabel.setBackground(lime);
                                  if (newscroll.contains("high wind warning"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(goldenrod);
                                  if (newscroll
                                            .contains("red flag warning".toUpperCase()))
                                       scrollLabel.setBackground(deeppink);
                                  if (newscroll.contains("wind chill warning"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(lightsteelblue);
                                  if (newscroll.contains("freeze warning".toUpperCase()))
                                       scrollLabel.setBackground(Color.cyan);
                                  if (newscroll.contains("snow watch".toUpperCase()))
                                       scrollLabel.setBackground(Color.cyan);
                                  if (newscroll.contains("flood statement".toUpperCase()))
                                       scrollLabel.setBackground(yellowgreen);
                                  if (newscroll.contains("tornado watch".toUpperCase()))
                                       scrollLabel.setBackground(yellow);
                                  if (newscroll.contains("severe thunderstorm watch"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(palevioletred);
                                  if (newscroll.contains("flash flood watch"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(limegreen);
                                  if (newscroll.contains("freezing rain".toUpperCase()))
                                       scrollLabel.setBackground(slateblue);
                                  if (newscroll
                                            .contains("freezing drizzle".toUpperCase()))
                                       scrollLabel.setBackground(slateblue);
                                  if (newscroll.contains("sleet advisory".toUpperCase()))
                                       scrollLabel.setBackground(slateblue);
                                  if (newscroll.contains("winter weather advisory"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(burlywood);
                                  if (newscroll.contains("wind chill advisory"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(paleturquoise);
                                  if (newscroll.contains("heat advisory".toUpperCase()))
                                       scrollLabel.setBackground(coral);
                                  if (newscroll.contains("flood advisory".toUpperCase()))
                                       scrollLabel.setBackground(springgreen);
                                  if (newscroll.contains("snow advisory".toUpperCase()))
                                       scrollLabel.setBackground(paleturquoise);
                                  if (newscroll.contains("wind advisory".toUpperCase()))
                                       scrollLabel.setBackground(tan);
                                  if (newscroll.contains("frost advisory".toUpperCase()))
                                       scrollLabel.setBackground(cornflower);
                                  if (newscroll.contains("flood watch".toUpperCase()))
                                       scrollLabel.setBackground(seagreen);
                                  if (newscroll.contains("blizzard watch".toUpperCase()))
                                       scrollLabel.setBackground(greenyellow);
                                  if (newscroll.contains("winter storm watch"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(steelblue);
                                  if (newscroll.contains("winter storm warning"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(hotpink);
                                  if (newscroll.contains("high wind watch".toUpperCase()))
                                       scrollLabel.setBackground(goldenrod);
                                  if (newscroll.contains("excessive heat watch"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(maroon);
                                  if (newscroll.contains("freeze watch".toUpperCase()))
                                       scrollLabel.setBackground(royalblue);
                                  if (newscroll
                                            .contains("wind chill watch".toUpperCase()))
                                       scrollLabel.setBackground(royalblue);
                                  if (newscroll.contains("excessive heat watch"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(maroon);
                                  if (newscroll.contains("excessive heat watch"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(maroon);
                                  if (newscroll.contains("excessive heat watch"
                                            .toUpperCase()))
                                       scrollLabel.setBackground(maroon);
                                  scrollLabel.setFont(new Font("Arial", Font.BOLD, 40));
                                  getContentPane().add(scrollLabel, BorderLayout.SOUTH);
                                  scrollLabel.setOpaque(true);
                                  scrollLabel.setForeground(Color.white);
         // create 2nd timer. give time of 1000ms.
         // event.getsource...in action performed
         timercheck.scheduleAtFixedRate(task, 1000, 10000);
         Timer timer = new Timer(120,this);
         //javax.swing.Timer timer = new javax.swing.Timer(120, this);
         timer.start();
         public void actionPerformed(ActionEvent event) {
              oldText = scrollLabel.getText();
              StringBuffer newText = new StringBuffer(oldText.substring(1) + oldText.substring(0, 1));
              String text = newText.toString();
              scrollLabel = new JLabel (text);
              //scrollLabel.setText(newText.toString());
         public static void main(String[] args) {
              Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
              int y = (14 * screen.height) / 15;
              WxScroll frame = new WxScroll();
              JLabel title = new JLabel("WxScroll");
              JPanel titlePanel = new JPanel();
              titlePanel.setPreferredSize(new Dimension(0, 0));
              titlePanel.add(title);
              frame.setLocation(0, y);
              // paint component method, drawstring,
              frame.setUndecorated(true);
              frame.setAlwaysOnTop(true);
              frame.getContentPane().add(titlePanel);
              frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
              frame.pack();
              frame.setVisible(true);
    }The errors i receive are:
    Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
         at WxScroll.actionPerformed(WxScroll.java:289)
         at javax.swing.Timer.fireActionPerformed(Unknown Source)
         at javax.swing.Timer$DoPostEvent.run(Unknown Source)
         at java.awt.event.InvocationEvent.dispatch(Unknown Source)
         at java.awt.EventQueue.dispatchEvent(Unknown Source)
         at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
         at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
         at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
         at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
         at java.awt.EventDispatchThread.run(Unknown Source)

    I don't know. There are classes your code requires (e.g., everything in the de.nava.informa packages) that I don't have, so I can't really compile or run your code.
    I will say this: it's a confused mess. There's too much code and too little abstraction. This is typical of beginning object-oriented programmers.
    When you start seeing LOTS of repeated stuff like this:
                      if (newscroll.contains("Tornado warning".toUpperCase()))
                         scrollLabel.setBackground(red);
                      }alarm bells should start ringing in your head. It appears that a Map with a String as key and Color as value is wanted. I can make all that code collapse into something MUCH smaller. If I externalize all those awful Color declarations into a File that's read on startup (e.g., taking in the key message and the RGB values and initializing the Map), now I have something that I can change more easily. AND there's less code to manage.
    I see URLs, applet, TimerTask, HTML - the kitchen sink.
    I can't tell you what this class is about.
    Be lazier - write less code. That's what good programmers do.
    Try to think more abstractly.
    %

  • Refresh issues

    I wish to know if there are any refresh issues in the following scenario.
    Consider the same application running in 2 distinct VM, jvm1 and jvm2 in a
    simple
    configuration without L2 cache.
    In jvm1 I have:
    PersistenceManager pm = pmf.getPersistenceManager();
    pm.currentTransaction().begin();
    Object oid = xxx;
    Object o = pm.getObjectById(oid)
    System.err.println(o.xxxx);
    pm.currentTransaction().commit();
    pm.close():
    Then in jvm2:
    PersistenceManager pm = pmf.getPersistenceManager();
    pm.currentTransaction().begin();
    Object oid = xxx;
    Object o = pm.getObjectById(oid)
    o.setSomeAttribute(xxxx);
    pm.currentTransaction().commit();
    pm.close():
    Now if I execute in jvm1 the first code fragment, do I see the modification
    applied in
    jvm2 ?
    Thanks in advance,
    Guido Anzuoni.
    BTW, are you going to include oid (and hopefully, class) keyword in
    projection in kodo3 ?

    Guido,
    Yes, you will see the modification in the next PM. The only "stale data"
    issues you might see are when you get object ID X in JVM1, modify and
    commit object ID X in JVM2, and then continue to reference it in JVM1
    (without any closing or refreshing): you will continue to see the cached
    version of object ID X.
    When this situation is intolerable, you can use pessimistic
    transactions: that will guarantee up-to-date views of the object, at the
    cost of keeping database locks on the rows open.
    In article <[email protected]>, Guido Anzuoni wrote:
    No, no, just for confirmation. I have read some posts on this topic and I
    have only shown my tipical usage.
    Is this behaviour somehow dependent on optimistic settings ?
    What if the DB schema is a preexisting one and there is no column for
    optimistic locking check ?
    Thanks again,
    Guido.
    "Stephen Kim" <[email protected]> ha scritto nel messaggio
    news:[email protected]...
    Yes. Are you not seeing this behavior?
    As for oid and class keywords, I'm not sure if the feature has been
    resolved one way or another yet.
    Guido Anzuoni wrote:
    I wish to know if there are any refresh issues in the following
    scenario.
    Consider the same application running in 2 distinct VM, jvm1 and jvm2 ina
    simple
    configuration without L2 cache.
    In jvm1 I have:
    PersistenceManager pm = pmf.getPersistenceManager();
    pm.currentTransaction().begin();
    Object oid = xxx;
    Object o = pm.getObjectById(oid)
    System.err.println(o.xxxx);
    pm.currentTransaction().commit();
    pm.close():
    Then in jvm2:
    PersistenceManager pm = pmf.getPersistenceManager();
    pm.currentTransaction().begin();
    Object oid = xxx;
    Object o = pm.getObjectById(oid)
    o.setSomeAttribute(xxxx);
    pm.currentTransaction().commit();
    pm.close():
    Now if I execute in jvm1 the first code fragment, do I see themodification
    applied in
    jvm2 ?
    Thanks in advance,
    Guido Anzuoni.
    BTW, are you going to include oid (and hopefully, class) keyword in
    projection in kodo3 ?
    Stephen Kim
    [email protected]
    SolarMetric, Inc.
    http://www.solarmetric.com
    Marc Prud'hommeaux [email protected]
    SolarMetric Inc. http://www.solarmetric.com

  • Kodo.util.UserException with deletepersistent method

    Hi,
    When I want to delete an object, i have the following error :
    kodo.util.UserException: The given instance
    "operations.offres.produits.magazines.groupesetediteurs.GroupeDePresse@6dd60e"
    is not managed by this
    PersistenceManager.[operations.offres.produits.magazines.groupesetediteurs.GroupeDePresse@6dd60e]
    There are the persistence methods i've wrote :
    * Methode de classe pour r__cuperer un groupe de presse ou un Editeur
    * @param nom String
    * @return GroupesEtEditeurs
    public static GroupesEtEditeurs getGroupesEtEditeurs(String nom) {
    Persistance p = Persistance.getPersistance();
    KodoPersistenceManager pm = p.getKodoPersistenceManager();
    Query requete = pm.newQuery(GroupesEtEditeurs.class);
    requete.setFilter("nom == '" + nom + "'");
    requete.setUnique(true);
    pm.currentTransaction().begin();
    Object resultat = (Object) requete.execute();
    resultat = pm.detach(resultat);
    pm.currentTransaction().commit();
    requete.closeAll();
    pm.close();
    return (GroupesEtEditeurs) resultat;
    * Methode de classe pour sauvegarder et mettre __ jour un Groupe de
    presse ou un Editeur
    * @param groupesetediteurs GroupesEtEditeurs
    public static void savGroupesEtEditeurs(GroupesEtEditeurs
    groupesetediteurs) {
    Persistance p = Persistance.getPersistance();
    KodoPersistenceManager pm = p.getKodoPersistenceManager();
    pm.currentTransaction().begin();
    pm.attach(groupesetediteurs);
    pm.currentTransaction().commit();
    pm.close();
    * Methode de classe pour supprimer un Groupe de presse ou un Editeur
    * @param groupesetediteurs GroupesEtEditeurs
    public static void delGroupesEtEditeurs(GroupesEtEditeurs
    groupesetediteurs) {
    Persistance p = Persistance.getPersistance();
    KodoPersistenceManager pm = p.getKodoPersistenceManager();
    pm.currentTransaction().begin();
    pm.deletePersistent(groupesetediteurs);
    pm.currentTransaction().commit();
    pm.close();
    ... and in the main class :
    GroupeDePresse gp0 = GroupeDePresse.getGroupeDePresse("mongroupe gp3");
    GroupeDePresse.savGroupeDePresse(gp0);
    GroupeDePresse.delGroupeDePresse(gp0); <---- the error source !
    I've no problems for query, attach / detach or update ...
    Please help !
    thank you,
    Pascal

    Hi,
    When I want to delete an object, i have the following error :
    kodo.util.UserException: The given instance
    "operations.offres.produits.magazines.groupesetediteurs.GroupeDePresse@6dd60e"
    is not managed by this
    PersistenceManager.[operations.offres.produits.magazines.groupesetediteurs.GroupeDePresse@6dd60e]
    There are the persistence methods i've wrote :
    * Methode de classe pour r__cuperer un groupe de presse ou un Editeur
    * @param nom String
    * @return GroupesEtEditeurs
    public static GroupesEtEditeurs getGroupesEtEditeurs(String nom) {
    Persistance p = Persistance.getPersistance();
    KodoPersistenceManager pm = p.getKodoPersistenceManager();
    Query requete = pm.newQuery(GroupesEtEditeurs.class);
    requete.setFilter("nom == '" + nom + "'");
    requete.setUnique(true);
    pm.currentTransaction().begin();
    Object resultat = (Object) requete.execute();
    resultat = pm.detach(resultat);
    pm.currentTransaction().commit();
    requete.closeAll();
    pm.close();
    return (GroupesEtEditeurs) resultat;
    * Methode de classe pour sauvegarder et mettre __ jour un Groupe de
    presse ou un Editeur
    * @param groupesetediteurs GroupesEtEditeurs
    public static void savGroupesEtEditeurs(GroupesEtEditeurs
    groupesetediteurs) {
    Persistance p = Persistance.getPersistance();
    KodoPersistenceManager pm = p.getKodoPersistenceManager();
    pm.currentTransaction().begin();
    pm.attach(groupesetediteurs);
    pm.currentTransaction().commit();
    pm.close();
    * Methode de classe pour supprimer un Groupe de presse ou un Editeur
    * @param groupesetediteurs GroupesEtEditeurs
    public static void delGroupesEtEditeurs(GroupesEtEditeurs
    groupesetediteurs) {
    Persistance p = Persistance.getPersistance();
    KodoPersistenceManager pm = p.getKodoPersistenceManager();
    pm.currentTransaction().begin();
    pm.deletePersistent(groupesetediteurs);
    pm.currentTransaction().commit();
    pm.close();
    ... and in the main class :
    GroupeDePresse gp0 = GroupeDePresse.getGroupeDePresse("mongroupe gp3");
    GroupeDePresse.savGroupeDePresse(gp0);
    GroupeDePresse.delGroupeDePresse(gp0); <---- the error source !
    I've no problems for query, attach / detach or update ...
    Please help !
    thank you,
    Pascal

  • Getting ORA-0600 internal error code, arguments: [kdlx_logmnr_decompress

    Hi,
    We are getting this error for the capture process:
    ORA-00600: internal error code, arguments: [kdlx_logmnr_decompress : incorrect unit length passed], [16120], [6225], [0], [22044], [], [], [], [], [], [], []
    OPIRIP: Uncaught error 447. Error stack:
    ORA-00447: fatal error in background process
    That is aborting capture queue whenever we restart. I tried by re-installing Oracle but after sometime again this issue arises.
    I am new to replication thing, so don't have too much idea about this error. Following is trace file log of the error :
    *** 2013-02-06 17:04:07.311
    ORA-00600: internal error code, arguments: [kdlx_logmnr_decompress : incorrect unit length passed], [16120], [6225], [0], [22044], [], [], [], [], [], [], []
    *** 2013-02-06 17:04:51.995
    *** 2013-02-06 17:04:52.033
    Begin knlcDumpCapCtx:*******************************************
    Error 600 : ORA-00600: internal error code, arguments: [kdlx_logmnr_decompress : incorrect unit length passed], [16120], [6225], [0], [22044], [], [], [], [], [], [], []
    Capture Name: GENEVA1$CAP : Instantiation#: 2
    *** 2013-02-06 17:04:52.033
    ++++ Begin KNST dump for Sid: 1059 Serial#: 171
    Init Time: 01/31/2013 14:55:49
    ++++Begin KNSTCAP dump for : GENEVA1$CAP
    Capture#: 1 Logminer_Id: 1 State: CREATING LCR [ 02/06/2013 17:04:06]
    Capture_Message_Number: 0x0000.045b8dd0 [73108944]
    Capture_Message_Create_Time: 02/06/2013 17:04:05
    Enqueue_Message_Number: 0x0000.045b8dc8 [73108936]
    Enqueue_Message_Create_Time: 02/06/2013 17:04:05
    Total_Messages_Captured: 4544100
    Total_Messages_Created: 963971 [ 02/06/2013 17:04:06]
    Total_Messages_Enqueued: 987271 [ 02/06/2013 17:04:06]
    Total_Full_Evaluations: 10970
    Elapsed_Capture_Time: 52593362 Elapsed_Rule_Time: 59
    Elapsed_Enqueue_Time: 0 Elapsed_Lcr_Time: 1937
    Elapsed_Redo_Wait_Time: 0 Elapsed_Pause_Time: 0
    Apply_Name : APPLY$_GENEVA1_137
    Apply_DBLink : GENEVA2
    Apply_Messages_Sent: 0
    ++++End KNSTCAP dump
    ++++ End KNST DUMP
    +++ Begin DBA_CAPTURE dump for: GENEVA1$CAP
    Capture_Type: LOCAL
    Version: 11.2.0.1.0
    Source_Database: GENEVA1
    Use_Database_Link: NO
    Logminer_Id: 1 Logfile_Assignment: IMPLICIT
    Status: ENABLED
    First_Scn: 0x0000.041c5812 [68966418]
    Start_Scn: 0x0000.041c5812 [68966418]
    Captured_Scn: 0x0000.045b6bea [73100266]
    Applied_Scn: 0x0000.045b56cd [73094861]
    Last_Enqueued_Scn: 0x0000.045b8dc8 [73108936]
    Capture_User: STRMADMIN
    Queue: STRMADMIN.GENEVA1$CAPQ
    Rule_Set_Name[+]: "STRMADMIN"."RULESET$_13"
    Negative_Rule_Set_Name: "STRMADMIN"."RULESET$_38"
    Checkpoint_Retention_Time: 60
    +++ End DBA_CAPTURE dump
    +++ Begin DBA_CAPTURE_PARAMETERS dump for: GENEVA1$CAP
    PARALLELISM = 1 Set_by_User: NO
    STARTUP_SECONDS = 0 Set_by_User: NO
    TRACE_LEVEL = 0 Set_by_User: NO
    TIME_LIMIT = -1 Set_by_User: NO
    MESSAGE_LIMIT = -1 Set_by_User: NO
    MAXIMUM_SCN = 0xffff.ffffffff [281474976710655] Set_by_User: NO
    WRITE_ALERT_LOG = TRUE Set_by_User: NO
    DISABLE_ON_LIMIT = FALSE Set_by_User: NO
    DOWNSTREAM_REAL_TIME_MINE = TRUE Set_by_User: NO
    MESSAGE_TRACKING_FREQUENCY = 2000000 Set_by_User: NO
    SKIP_AUTOFILTERED_TABLE_DDL = TRUE Set_by_User: NO
    SPLIT_THRESHOLD = 1800 Set_by_User: NO
    MERGE_THRESHOLD = 60 Set_by_User: NO
    +++ End DBA_CAPTURE_PARAMETERS dump
    +++ Begin DBA_CAPTURE_EXTRA_ATTRIBUTES dump for: GENEVA1$CAP
    +++ End DBA_CAPTURE_EXTRA_ATTRIBUTES dump
    ++ LogMiner Session Dump Begin::
    SessionId: 1 SessionName: GENEVA1$CAP
    Start SCN: 0x0000.00000000 [0]
    End SCN: 0x0000.00000000 [0]
    Processed SCN: 0x0000.045b94b4 [73110708]
    Prepared SCN: 0x0000.045b94b4 [73110708]
    Read SCN: 0x0000.045b94b6 [73110710]
    Spill SCN: 0x0000.041c5812 [68966418]
    Resume SCN: 0x0000.00000000 [0]
    Branch SCN: 0x0000.00000000 [0]
    Branch Time: 01/01/1988 00:00:00
    ResetLog SCN: 0x0000.000e6c20 [945184]
    ResetLog Time: 01/31/2013 12:40:10
    DB ID: 1299957605 Global DB Name: GENEVA1
    krvxvtm: Enabled threads: 1
    Current Thread Id: 1, Thread State 0x01
    Current Log Seqn: 695, Current Thrd Scn: 0x0000.045b94b6 [73110710]
    Current Session State: 0x800, Current LM Compat: 0xb200000
    Flags: 0x3fa802d0, Real Time Apply is On
    +++ Additional Capture Information:
    Capture Flags: 266245
    Logminer Start SCN: 0x0000.041c5812 [68966418]
    Enqueue Filter SCN: 0x0000.041c5812 [68966418]
    Low SCN: 0x0000.045b8dd0 [73108944]
    Capture From Date: 01/01/1988 00:00:00
    Capture To Date: 01/01/1988 00:00:00
    Restart Capture Flag: NO
    Ping Pending: NO
    Buffered Txn Count: 0
    -- Xid Hash entry --
    Begin knlcDumpLobHash for XID: xid: 0x000e.007.00000453
    Lcr Count: 5 Flags: 82
    NO LCRs BUFFERED
    TAG is null
    End knlcDumpXidHash
    -- LOB Hash entry --
    Begin knlcDumpLobHash:
    Xid: Dumping Lob Hash Key-->
    xid: 0x000e.007.00000453 segcol:9 intcol:0 objn:76707 objv:1 thread:1
    rba: 0x0002b6.00005b29.0130 <--Done Dumping Lob Hash Key
    Offset: 32241 Sequence: 5 Long_Flag: FALSE
    gld2status: 213 lau boundary: FALSE
    Buffered LCR dump:
    Dumping lcr 0x7f415e15e0e8 : type 0
    Dumping internal row LCR
    (xid,scn,instnum,scnseq,flags,time,compat,compat_num)
    =(0x000e.007.00000453,0x0000.045b8dc7,0,0,0x0, 02/06/2013 17:04:05,9.2.0.0.0,0)
    header null flags = 0Xf7f0
    gdbnm=0x7f415e15db68, GENEVA1
    tag is null
    UBA = 0X3.c0056b.7.18.1.12bcf
    tde key id=0
    Message tracking: null
    Header extra: null
    child_xid (null)
    (lid_scn,lid_lid_scn_sqn,lcr_sqn,thread_id)=(0x0000.045b8dc7,3,1,1)
    parent_xid (null)
    Duration based allocation:DUR:10
    (obj#,ver,opnum)=(76707,1,9)
    offset = 0, size = 0, dml_id = 0, flags = 0x0
    knglrowx: flags=0x0, seq#=0, thread=0, userdata=0, RBA= rba: 0x000000.00000000.0000 knglrowx: srccsetid=0, flags2=0x0
    knglrowx: sys_part_nm (null)
    Old column count 0
    New column count 11
    segcol = 1, intcol = 1, flags 0, flags3 0 knglcolx: null
    allocsz=2 dtytyp=2 csetform=0 ptr=0x7f415e15d318
    (dty, kncdty, acl, csf, csi, ind)=(2,0,2,0,0,0)
    value = 10
    segcol = 2, intcol = 2, flags 0, flags3 0 knglcolx: null
    allocsz=51 dtytyp=1 csetform=0 ptr=0x7f415e15d2b8
    (dty, kncdty, acl, csf, csi, ind)=(1,0,51,0,0,0)
    value = putGetBytes8MBData_06_02_2013_17_04_619210585076288
    segcol = 3, intcol = 3, flags 0, flags3 0 knglcolx: null
    allocsz=2 dtytyp=2 csetform=0 ptr=0x7f415e15d288
    (dty, kncdty, acl, csf, csi, ind)=(2,0,2,0,0,0)
    value = 1
    segcol = 4, intcol = 4, flags 0, flags3 0 knglcolx: null
    allocsz=2 dtytyp=2 csetform=0 ptr=0x7f415e15d258
    (dty, kncdty, acl, csf, csi, ind)=(2,0,2,0,0,0)
    value = 56
    segcol = 5, intcol = 5, flags 0, flags3 0 knglcolx: null
    allocsz=2 dtytyp=2 csetform=0 ptr=0x7f415e15d228
    (dty, kncdty, acl, csf, csi, ind)=(2,0,2,0,0,0)
    value = 1
    segcol = 6, intcol = 6, flags 0, flags3 0 knglcolx: null
    allocsz=11 dtytyp=180 csetform=0 ptr=0x7f415e15d1f8
    (dty, kncdty, acl, csf, csi, ind)=(180,0,11,0,0,0)
    value = 2013-02-06 11:34:05.582000000
    segcol = 7, intcol = 7, flags 0, flags3 0 knglcolx: null
    allocsz=7 dtytyp=180 csetform=0 ptr=0x7f415e15d1c8
    (dty, kncdty, acl, csf, csi, ind)=(180,0,7,0,0,0)
    value = 1970-01-01 00:00:00
    segcol = 8, intcol = 8, flags 0, flags3 0 knglcolx: null
    allocsz=11 dtytyp=180 csetform=0 ptr=0x7f415e15d198
    (dty, kncdty, acl, csf, csi, ind)=(180,0,11,0,0,0)
    value = 2013-02-06 11:34:05.582000000
    segcol = 9, intcol = 9, flags 1, flags3 0 knglcolx: null
    allocsz=0 dtytyp=23 csetform=0 ptr=(nil)
    LOB DATA
    segcol = 10, intcol = 10, flags 0, flags3 0 knglcolx: null
    allocsz=0 dtytyp=23 csetform=0 ptr=(nil)
    value = NULL
    segcol = 11, intcol = 11, flags 0, flags3 0 knglcolx: null
    allocsz=2 dtytyp=2 csetform=0 ptr=0x7f415e15d168
    (dty, kncdty, acl, csf, csi, ind)=(2,0,2,0,0,0)
    value = 1
    End knlcDumpLobHash
    -- No TRIM LCR --
    Unsupported Reason: Unknown
    ++++++++++++ Dumping Current LogMiner Lcr: +++++++++++++++
    ++ LCR Dump Begin: 0x15b44d160 - lob_write
    op: 10, Original op: 10, baseobjn: 76707, objn: 76707, objv: 1
    DF: 0x00020803, DF2: 0x00002010, MF: 0x00040000, MF2: 0x00000040
    PF: 0x00000000, PF2: 0x00000000
    MergeFlag: 0x03, FilterFlag: 0x09
    Id: 0, iotPrimaryKeyCount: 0, numChgRec: 1
    NumCrSpilled: 0
    RedoThread#: 1, rba: 0x0002b6.00005ba1.017c
    scn: 0x0000.045b8dd0, (scn: 0x0000.045b8dd0, scn_sqn: 5, lcr_sqn: 1)xid: 0x000e.007.00000453, parentxid: 0x000e.007.00000453, proxyxid: 0x0000.000.00000000
    ncol: 11 newcount: 1, oldcount: 0
    LUBA: 0x3.c0056b.7.1b.12bcf
    GroupThreadId: 1, GroupRba: rba: 0x0002b6.00005b29.0130
    LOB info: length: 6225, LOB offset: 0, LOB CodePoint Offset: 0
    LOB ID: 0x0001000cc333
    Filter Flag: KEEP
    ++ KRVXOA Dump Begin:
    Object Number: 76707 BaseObjNum: 76707 BaseObjVersion: 1
    Object Name: GENEVA_OWNER1.GNV_AST_PLD_56 Type: 2
    User Cols: 11, Int Cols: 11, Kernel Cols: 11
    Tab Flag: 0x40000001, Trig Flags: 0x00, OBJ$ Flags: 0x00
    Property: 0x20040820, Attribute: 0x1c7f
    Unsupported Columns: 0x0
    End knlcDumpCapCtx:*********************************************
    Please help me out to get rid of this issue.
    Thanks,
    Heshang

    Hi,
    To further diagnose this issue, please open a service request with oracle support. As there are related issue but they are fixed in 12C.
    Thanks,
    Reena Chhabra

  • Can stream "capture process" skip an archivelog?

    DB: 10.2.0.5, on Windows 2003 SP2 32-bits
    A stream capture component in our database is stuck reading one the archive log file, and status in the v$streams_capture view is 'CREATING LCR' . It is not moving at all.
    I think, the archivelog is corrupted and will guess skipping from reading the log can help??
    Any idea?

    Find the transaction identifier in the trace file; for example in this trace the transaction is '0x000a.008.00019347'
    Convert it from hex to decimal; in this example '0x000a.008.00019347' will be '10.8.103239'.
    Example of trace file:
    ++++++++++++ Dumping Current LogMiner Lcr: +++++++++++++++
    ++ LCR Dump Begin: 0x000007FF3F75D8A0 - cannot_support
    op: 255, Original op: 255, baseobjn: 74480, objn: 74480, objv: 1
    DF: 0x00000003, DF2: 0x00000010, MF: 0x08240000, MF2: 0x00000000
    PF: 0x00000000, PF2: 0x00000000
    MergeFlag: 0x03, FilterFlag: 0x01
    Id: 1, iotPrimaryKeyCount: 0, numChgRec: 0
    NumCrSpilled: 0
    RedoThread#: 1, rba: 0x000604.00014fd2.014c
    scn: 0x0000.36a4b03c, (scn: 0x0000.36a4b03c, scn_sqn: 1, lcr_sqn: 0)xid: *0x000a.008.00019347*, parentxid: 0x000a.008.00019347, proxyxid: 0x0000.000.00000000, unsupportedReasonCode: 0,
    ncol: 5 newcount: 0, oldcount: 0
    LUBA: 0x3.c004eb.8.8.122f2
    Filter Flag: UNDECIDED
    ++ KRVXOA Dump Begin:
    Object Number: 74480 BaseObjNum: 74480 BaseObjVersion: 1
    Then stop the capture process and execute the following procedure:
    exec dbms_capture_adm.set_parameter('your_capture_process_name','_ignore_transaction','your_transaction_id_in_decimal_notation');
    Now you can restart the capture process and it will ignore the tx.

  • Importing mappings using OMBPLUS

    we just started using OWB, and in our environment we do not want to migrate mappings from DEV to TEST to PRODUCTION using GUI. i heard that importing and deploying can be done using OMB scripting ..
    can any please give some example scripts for importing mapping and deploying mappings on to a different box.
    Thanks

    Do you need to move the mapping definitions over to each box? Or just deploy them to different boxes?
    If you want a single design repository where you deploy from to multiple runtime areas, then this is acheived through creating multiple configurations and changing your project configuration prior to each deployment.
    If, on the other hand, you want to MOVE the current mapping definitions to each box where you will, in effect, be setting up a new design AND runtime repository, then there is added complexity.
    For example, scripting dropping old mappings prior to importing the new version of the project to avoid legacy objects hanging around becomes a potential issue. for that, you would need to script deployemnt plans of type DELETE for objects no longer wanted. This also helps script the new deployment as you don't have to code which mappings are being CREATEd, and which are being REPLACEd.
    I have an OMB+ script I am just testing right now to load a project MDL file and deploy it to a new repository. I have a partial script for unloading and old version of the project, but it is not ready yet. This one also assumes a clean install where I even have to go so far as to register my runtime user, and define and register all schemas to be used by the control center. We also do not deploy normal database objects via OWB. This script assumes that the proper database setup for tables, sequences, views, etc. has been done prior to deploying the OWB mappings and process flows. We use Designer as the repository of record for all non-OWB database objects.
    I don't claim to be an experienced TCL or OMB+ developer, but it might help you out as a starting point. Note that the config file and file of library functions used by this script (such as the exec_omb you will see that I use) are also appended to this post.
    File: owb_import.tcl
    #get db connection info
    source c:\\omb\\owb_config.tcl
    #get standard library
    source c:\\omb\\omb_library.tcl
    #  Connect to repos
    # Commit anything from previous work in this session, otherwise OMBDISCONNECT will fail out.
    exec_omb OMBCOMMIT
    # If already connected, disconnect first.
    set print [exec_omb OMBDISCONNECT]
      # Test if message is "OMB01001: Not connected to repository." or "Disconnected."
      # any other message is a showstopper!
    if [string match Disconn* $print ]  {
       log_msg LOG "Success Disconnecting from previous repository...."
    } else {
       # We expect an OMB01001 error for trying to disconnect when not connected
       if [string match OMB01001* $print ] {
          log_msg LOG "Disconnect unneccessary. Not currently connected...."
       } else {
          log_msg ERROR "Error Disconnecting from previous repository....Exiting process."
          log_msg ERROR "$print"
          #exit
    set print [exec_omb OMBCONNECT $OWB_DEG_USER/$OWB_DEG_PASS@$OWB_DEG_HOST:$OWB_DEG_PORT:$OWB_DEG_SRVC USE REPOSITORY '$OWB_DEG_REPOS']
    if [omb_error $print] {
        log_msg ERROR "Unable to connect to repository."
        log_msg ERROR "$print" "1"
        log_msg ERROR "Exiting Script.............."
        return
    } else {
        log_msg LOG "Connected to Repository"   
    # Connect to project
    set print [exec_omb OMBCC '$PROJECT_NAME']
    if [omb_error $print] {
       log_msg LOG "Project $PROJECT_NAME does not exist. Creating...."
       set print [exec_omb OMBCREATE PROJECT '$PROJECT_NAME']
       if [omb_error $print] {
          log_msg ERROR "Unable to create project '$PROJECT_NAME'"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       } else {
          log_msg LOG "Created Project '$PROJECT_NAME'"
          exec_omb OMBCOMMIT
          exec_omb OMBSAVE
          exec_omb OMBCC '$PROJECT_NAME'
    } else {
       log_msg LOG "Switched context to project $PROJECT_NAME"
    # Check Existance of Oracle Module
    set print [exec_omb OMBCC '$ORA_MODULE_NAME']
    if [omb_error $print] {
       log_msg LOG "Oracle Module $ORA_MODULE_NAME does not exist. Creating...."
       set print [exec_omb OMBCREATE ORACLE_MODULE '$ORA_MODULE_NAME']
       if [omb_error $print] {
          log_msg ERROR "Unable to create module '$ORA_MODULE_NAME'"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       } else {
          log_msg LOG "Created Oracle Module '$ORA_MODULE_NAME'"
          exec_omb OMBCOMMIT
          exec_omb OMBSAVE
          exec_omb OMBCC '$ORA_MODULE_NAME'
    } else {
       log_msg LOG "Switched context to module $ORA_MODULE_NAME"
    #switch back up to project level. You cannot attach locations to a module if you are in it.
    exec_omb OMBCC '..'
    log_msg LOG "Switched context back up to project $PROJECT_NAME"
    # Check Existance of OWB Registered USer
    set lst [OMBLIST USERS]
    if {[string match *$DATA_LOCATION_USER* $lst]} {
       log_msg LOG "Verify USer $DATA_LOCATION_USER Exists."
    } else {
       log_msg LOG "registering User $DATA_LOCATION_USER."
    #   set print [ exec_omb OMBREGISTER USER '$DATA_LOCATION_USER' SET PROPERTIES (DESCRIPTION, ISTARGETSCHEMA, TARGETSCHEMAPWD) VALUES ('$DATA_LOCATION_USER', 'true', '$DATA_LOCATION_PASS')]
       if [omb_error $print] {
          log_msg ERROR "Unable to register user '$DATA_LOCATION_USER'"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       exec_omb OMBCOMMIT
    # Import MDL File
    #switch back up to root level to ensure import succeeds.
    exec_omb OMBSAVE
    exec_omb OMBCC '..'
    log_msg LOG "Switched context back up to root level."
    set print [exec_omb OMBIMPORT MDL_FILE '$IMPORT_FILE_PATH/$IMPORT_FILE_NAME' USE UPDATE_MODE MATCH_BY NAMES OUTPUT LOG TO '$IMPORT_LOG_PATH/$IMPORT_LOG_NAME' ]
    if [omb_error $print] {
       #We expect to get warnings due to differences in Control center names etc,
       if {[string match OMB05105* $print]} {
          log_msg LOG "MDL File $IMPORT_FILE_NAME imported with warnings"
       } else {
           log_msg ERROR "Unable to import $IMPORT_FILE_PATH/$IMPORT_FILE_NAME. "
           log_msg ERROR "$print"
           log_msg ERROR "Exiting Script.............."
           exec_omb OMBROLLBACK
           return
    } else {
       log_msg LOG "MDL File $IMPORT_FILE_NAME imported with no warnings.............."
    exec_omb OMBCOMMIT
    exec_omb OMBCC '$PROJECT_NAME'
    log_msg LOG "Switched context back to project level."
    # Validate to Control Center
    set lst [OMBLIST CONTROL_CENTERS]
    if [string match *$CONTROL_CENTER_NAME* $lst] {
       log_msg LOG "Verify Control Center $CONTROL_CENTER_NAME Exists."
       log_msg LOG "Setting Passwords to enable import and deploy"
       set print [exec_omb OMBALTER LOCATION '$DATA_LOCATION_NAME' SET PROPERTIES (PASSWORD) VALUES ('$DATA_LOCATION_PASS')]
       if [omb_error $print] {
          log_msg ERROR "Unable to log onto location '$DATA_LOCATION_NAME' with password $DATA_LOCATION_PASS"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       exec_omb OMBCOMMIT
       set print [exec_omb OMBALTER LOCATION '$WFLOW_LOCATION_NAME' SET PROPERTIES (PASSWORD) VALUES ('$WFLOW_LOCATION_PASS')]
       if [omb_error $print] {
          log_msg ERROR "Unable to log onto workflow location '$WFLOW_LOCATION_NAME' with password $WFLOW_LOCATION_PASS"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       exec_omb OMBCOMMIT
       log_msg LOG "Connecting to Control Center $CONTROL_CENTER_NAME"
       set print [exec_omb OMBCONNECT CONTROL_CENTER USE '$DATA_LOCATION_PASS' ]
       if [omb_error $print] {
          log_msg ERROR "Unable to add Location $DATA_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       exec_omb OMBCOMMIT
       log_msg LOG "Connected.............."
    } else {
       log_msg LOG "Need to create Control Center $CONTROL_CENTER_NAME."
       log_msg LOG "Creating Code Location."
       # For Global_names = FALSE
       # set print [exec_omb OMBCREATE LOCATION '$DATA_LOCATION_NAME' SET PROPERTIES (TYPE, VERSION, DESCRIPTION, BUSINESS_NAME, HOST, PORT, SERVICE, CONNECT_AS_USER, PASSWORD, DATABASE_NAME) VALUES ('ORACLE_DATABASE','$DATA_LOCATION_VERS','ERS Datamart Code User','$DATA_LOCATION_NAME', '$DATA_LOCATION_HOST','$DATA_LOCATION_PORT','$DATA_LOCATION_SRVC', '$DATA_LOCATION_USER','$DATA_LOCATION_PASS','$DATA_LOCATION_SRVC' ) ] 
       set print [exec_omb OMBCREATE LOCATION '$DATA_LOCATION_NAME' SET PROPERTIES (TYPE, VERSION, DESCRIPTION, BUSINESS_NAME, HOST, PORT, SERVICE, CONNECT_AS_USER, PASSWORD) VALUES ('ORACLE_DATABASE','$DATA_LOCATION_VERS','ERS Datamart Code User','$DATA_LOCATION_NAME', '$DATA_LOCATION_HOST','$DATA_LOCATION_PORT','$DATA_LOCATION_SRVC', '$DATA_LOCATION_USER','$DATA_LOCATION_PASS') ] 
       if [omb_error $print] {
          log_msg ERROR "Unable to create location '$DATA_LOCATION_NAME'"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       exec_omb OMBCOMMIT
       log_msg LOG "Creating Workflow Location."
       set print [exec_omb OMBCREATE LOCATION '$WFLOW_LOCATION_NAME' SET PROPERTIES (TYPE, VERSION, DESCRIPTION, BUSINESS_NAME, HOST, PORT, SERVICE_NAME, PASSWORD, SCHEMA) VALUES ('ORACLE_WORKFLOW','$WFLOW_LOCATION_VERS','ERS Datamart Workflow User','$WFLOW_LOCATION_NAME', '$WFLOW_LOCATION_HOST','$WFLOW_LOCATION_PORT','$WFLOW_LOCATION_SRVC', '$WFLOW_LOCATION_PASS','$WFLOW_LOCATION_USER') ] 
       if [omb_error $print] {
          log_msg ERROR "Unable to create Workflow location '$WFLOW_LOCATION_NAME'"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          #return
       exec_omb OMBCOMMIT
       log_msg LOG "Creating Control Center"
       set print [exec_omb OMBCREATE CONTROL_CENTER '$CONTROL_CENTER_NAME' SET PROPERTIES (DESCRIPTION, BUSINESS_NAME, HOST, PORT, SERVICE_NAME, USER, SCHEMA, PASSWORD) VALUES ('ERS Datamart Control Center','$CONTROL_CENTER_NAME', '$DATA_LOCATION_HOST','$DATA_LOCATION_PORT','$DATA_LOCATION_SRVC', '$DATA_LOCATION_USER', '$CONTROL_CENTER_SCHEMA','$DATA_LOCATION_PASS') ]
       if [omb_error $print] {
          log_msg ERROR "Unable to create control center '$CONTROL_CENTER_NAME'"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       exec_omb OMBCOMMIT
       log_msg LOG "Adding Location $DATA_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
       set print [exec_omb OMBALTER CONTROL_CENTER '$CONTROL_CENTER_NAME' ADD REF LOCATION '$DATA_LOCATION_NAME' SET PROPERTIES (IS_TARGET, IS_SOURCE) VALUES ('true', 'true') ]
       if [omb_error $print] {
          log_msg ERROR "Unable to add Location $DATA_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       exec_omb OMBCOMMIT
       log_msg LOG "Adding Workflow Location $WFLOW_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
       set print [exec_omb OMBALTER CONTROL_CENTER '$CONTROL_CENTER_NAME' ADD REF LOCATION '$WFLOW_LOCATION_NAME' SET PROPERTIES (IS_TARGET, IS_SOURCE) VALUES ('true', 'true') ]
       if [omb_error $print] {
          log_msg ERROR "Unable to add Location $DATA_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          #return
       exec_omb OMBCOMMIT
       log_msg LOG "Setting Control Center as default control center for project"
       exec_omb OMBCC 'DEFAULT_CONFIGURATION'
       set print [exec_omb OMBALTER DEPLOYMENT 'DEFAULT_DEPLOYMENT' SET REF CONTROL_CENTER '$CONTROL_CENTER_NAME' ]
       if [omb_error $print] {
          log_msg ERROR "Unable to set Control Center $CONTROL_CENTER_NAME in default configuration"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       exec_omb OMBCOMMIT
       exec_omb OMBCC '..'
       log_msg LOG "Connecting to Control Center $CONTROL_CENTER_NAME"
       set print [exec_omb OMBCONNECT CONTROL_CENTER USE '$DATA_LOCATION_PASS' ]
       if [omb_error $print] {
          log_msg ERROR "Unable to add Location $DATA_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       exec_omb OMBCOMMIT
       log_msg LOG "Registering Code Location."
       set print [exec_omb OMBALTER LOCATION '$DATA_LOCATION_NAME' SET PROPERTIES (PASSWORD) VALUES ('$DATA_LOCATION_PASS')]
       exec_omb OMBCOMMIT
       set print [exec_omb OMBREGISTER LOCATION '$DATA_LOCATION_NAME']
       if [omb_error $print] {
          log_msg ERROR "Unable to register Location $DATA_LOCATION_NAME"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       exec_omb OMBCOMMIT
       log_msg LOG "Registering Workflow Location."
       set print [exec_omb OMBALTER LOCATION '$WFLOW_LOCATION_NAME' SET PROPERTIES (PASSWORD) VALUES ('$WFLOW_LOCATION_PASS')]
       exec_omb OMBCOMMIT
       set print [exec_omb OMBREGISTER LOCATION '$WFLOW_LOCATION_NAME']
       if [omb_error $print] {
          log_msg ERROR "Unable to register Workflow Location $WFLOW_LOCATION_NAME"
          log_msg ERROR "$print"
          log_msg ERROR "Exiting Script.............."
          exec_omb OMBROLLBACK
          return
       exec_omb OMBCOMMIT
    # Assign location to Oracle Module
    log_msg LOG "Assigning Code Location to Oracle Module."
    set print [ exec_omb OMBALTER ORACLE_MODULE '$ORA_MODULE_NAME' ADD REFERENCE LOCATION '$DATA_LOCATION_NAME' SET AS DEFAULT ]
    if [omb_error $print] {
       log_msg ERROR "Unable to add reference location '$DATA_LOCATION_NAME' to module '$ORA_MODULE_NAME' "
       log_msg ERROR "$print"
       log_msg ERROR "Exiting Script.............."
       exec_omb OMBROLLBACK
       return
    set print [ exec_omb OMBALTER ORACLE_MODULE '$ORA_MODULE_NAME' SET REFERENCE METADATA_LOCATION '$DATA_LOCATION_NAME' ]
    if [omb_error $print] {
       log_msg ERROR "Unable to set metadata location '$DATA_LOCATION_NAME' on module '$ORA_MODULE_NAME' "
       log_msg ERROR "$print"
       log_msg ERROR "Exiting Script.............."
       exec_omb OMBROLLBACK
       return
    set print [ exec_omb OMBALTER ORACLE_MODULE '$ORA_MODULE_NAME' SET PROPERTIES (DB_LOCATION) VALUES ('$DATA_LOCATION_NAME') ]
    if [omb_error $print] {
       log_msg ERROR "Unable to add db_location '$DATA_LOCATION_NAME' to module '$ORA_MODULE_NAME' "
       log_msg ERROR "$print"
       log_msg ERROR "Exiting Script.............."
       exec_omb OMBROLLBACK
       return
    exec_omb OMBCOMMIT
    # Assign location to Workflow Module
    log_msg LOG "Assigning Location to Workflow Module."
    set print [ exec_omb OMBALTER ORACLE_MODULE '$ORA_MODULE_NAME' ADD REFERENCE LOCATION '$DATA_LOCATION_NAME' SET AS DEFAULT ]
    if [omb_error $print] {
       log_msg ERROR "Unable to add reference location '$DATA_LOCATION_NAME' to module '$ORA_MODULE_NAME' "
       log_msg ERROR "$print"
       log_msg ERROR "Exiting Script.............."
       exec_omb OMBROLLBACK
       return
    # Begin Object Deployment
    log_msg LOG "*********** Deploying: Mappings ****************"
    exec_omb OMBCC '$ORA_MODULE_NAME'
    set mapList [ OMBLIST MAPPINGS ]
    foreach mapName $mapList {
         log_msg LOG "Deploying: $mapName"
         set print [ exec_omb OMBCREATE TRANSIENT DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ADD ACTION 'MAPPING_DEPLOY' SET PROPERTIES (OPERATION) VALUES ('CREATE') SET REFERENCE MAPPING '$mapName' ]
         if [omb_error $print] {
            log_msg ERROR "Unable to create Deployment plan for '$mapName'"
            log_msg ERROR "$print"
           return
         set print [ exec_omb OMBDEPLOY DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ]
         if [omb_error $print] {
            log_msg ERROR "Error on execute of Deployment plan for '$mapName'"
            log_msg ERROR "$print"
            exec_omb OMBDROP DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN'
            exec_omb OMBCOMMIT
           return
         exec_omb OMBDROP DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN'
         exec_omb OMBCOMMIT
    log_msg LOG "*********** Deploying: Process Flows **************"
    exec_omb OMBCC '..'
    exec_omb OMBCC '..'
    set all_Owfs [OMBLIST PROCESS_FLOW_PACKAGES]
    if {$all_Owfs!="" } {
         foreach one_Owf $all_Owfs {
              set print [ exec_omb OMBCREATE TRANSIENT DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ]
              if [omb_error $print] {
                log_msg ERROR "Unable to create Deployment plan for '$one_Owf'"
                log_msg ERROR "$print"
                return
              set print [ exec_omb OMBALTER DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ADD ACTION 'OWFDEP$one_Owf' SET PROPERTIES (OPERATION) VALUES ('CREATE') SET REFERENCE PROCESS_FLOW_PACKAGE '$one_Owf' ]
              if [omb_error $print] {
                log_msg ERROR "Unable to alter Deployment plan for '$one_Owf'"
                log_msg ERROR "$print"
                exec_omb OMBDROP DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN'
                return
              log_msg LOG "OWF LOCATION: $Process_Flow_Module - OWF: $one_Owf Deployment...";
              set print [ exec_omb OMBDEPLOY DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ]
              if [omb_error $print] {
                log_msg ERROR "Unable to execute Deployment plan for '$one_Owf'"
                log_msg ERROR "$print"
                exec_omb OMBDROP DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN'
                return
              set print [ exec_omb OMBDROP DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ]
              log_msg LOG "OWF LOCATION: $Process_Flow_Module - OWF: $one_Owf Deployed";
         log_msg LOG "OWF LOCATION: $Process_Flow_Module - All Workflows Deployed...";
    #OMBDISCONNECTWhich depends on the following two files:
    OMB_LIBRARY.TCL
    # Default logging function.
    #  Accepts inputs: LOGMSG - a text string to output
    #                  FORCELOG - if "1" then output regardless of VERBOSE_LOG setting
    proc log_msg {LOGTYPE LOGMSG {FORCELOG "0"}} {
       global VERBOSE_LOG
       if { $VERBOSE_LOG == "1"} {
         puts "$LOGTYPE:-> $LOGMSG"
       } else {
           if { $FORCELOG == "1"} {
              puts "$LOGTYPE:-> $LOGMSG"
    proc exec_omb { args } {
       log_msg OMBCMD "$args"
       # the point of this is simply to return errorMsg or return string, whichever is applicable,
       # to simplify error checking using omb_error{}
       if [catch { set retstr [eval $args] } errmsg] {
          return $errmsg
       } else {
          return $retstr
    proc omb_error { retstr } {
       # OMB and Oracle errors may have caused a failure.
       if [string match OMB0* $retstr] {
          return 1
       } elseif [string match ORA-* $retstr] {
          return 1
       } else {
          return 0
    }and a config file where all config/passowrd info is put.
    # GLOBAL VARIABLE DECLARATION SECTION
    #DESIGN REPOSITORY  CONNECTION INFORMATION
    # Login info for the main design repository owner
    set OWB_DEG_USER    owb_user
    set OWB_DEG_PASS    password
    set OWB_DEG_HOST    host01
    set OWB_DEG_PORT    5555
    set OWB_DEG_SRVC    orcl_srvc
    set OWB_DEG_REPOS   owb_user
    # CONTROL CENTER AND LOCATION DECLARATION SECTION
    set CONTROL_CENTER_NAME          ERS_DM_CTLCNTR
    set CONTROL_CENTER_SCHEMA      owb_user
    #Connection info to ers_etl_app schema for deployment
    set DATA_LOCATION_NAME         ERS_DM_DATA
    set DATA_LOCATION_VERS         9.2
    set DATA_LOCATION_USER         ERS_ETL_APP
    set DATA_LOCATION_PASS         ers_etl_app
    set DATA_LOCATION_HOST         newserver
    set DATA_LOCATION_PORT         1555
    set DATA_LOCATION_SRVC         orcl_new
    #Connection info to workflow schema for deployment
    set WFLOW_LOCATION_NAME        ERS_DM_WFLOW
    set WFLOW_LOCATION_VERS        2.6.2
    set WFLOW_LOCATION_USER        OWF_MGR
    set WFLOW_LOCATION_PASS        owf_mgr
    set WFLOW_LOCATION_HOST        newserver
    set WFLOW_LOCATION_PORT        1555
    set WFLOW_LOCATION_SRVC        orcl_new
    # PROJECT,MUDULE AND DIRECTORY DECLARATION SECTION
    set PROJECT_NAME      ERS_DM
    set ORA_MODULE_NAME    ERS_ETL_APP
    set PFLOW_MODULE_NAME  LD_DMRT
    set PFLOW_PACKAGE_NAME LD_DMRT
    # Directory DECLARATION SECTION
    set IMPORT_FILE_NAME "ers_dply_tst_rc01.mdl"
    set IMPORT_FILE_PATH "C:/OMB/import/db_imports"
    set IMPORT_LOG_NAME  "ers_dply_tst_rc01_imp.log"
    set IMPORT_LOG_PATH  "C:/OMB/import/logs"
    # Logging Option
    global VERBOSE_LOG
    set VERBOSE_LOG "1"Hope that this helps you out!
    Message was edited by: zeppo
    Edited to: Try and correct formatting tags.

  • PHP arrow operator problem

    I'm half way through writing a web interface for mpd. I needed a way to interact with it so I searched around and found this. It's a php class that interfaces with mpd.
    I downloaded it and it comes with an example php file for using it. The only problem is that when I use the example page it just prints out anything after the arrow operator. As far as I'm aware the arrow operator is for accessing class methods and variables but I've never actually done any OOP with PHP.
    Anyway here is the example file:
    <?
    * mpd-class-example.php - Example interface using mpd.class.php
    * Version 1.2, released 05/05/2004
    * Copyright (C) 2003-2004 Benjamin Carlisle ([email protected])
    * http://mpd.24oz.com/ | http://www.musicpd.org/
    * This program illustrates the basic commands and usage of the MPD class.
    * *** PLEASE NOTE *** My intention in including this file is not to provide you with an
    * out-of-the-box MPD jukebox, but instead to provide a general understanding of how I saw
    * the class as being utilized. If you'd like to see more examples, please let me know. But
    * this should provide you with a good starting point for your own program development.
    * This program is free software; you can redistribute it and/or modify
    * it under the terms of the GNU General Public License as published by
    * the Free Software Foundation; either version 2 of the License, or
    * (at your option) any later version.
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU General Public License for more details.
    * You should have received a copy of the GNU General Public License
    * along with this program; if not, write to the Free Software
    * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    ?>
    <HTML>
    <style type="text/css"><!-- .defaultText { font-family: Arial, Helvetica, sans-serif; font-size: 9pt; font-style: normal; font-weight: normal; color: #111111} .err { color: #DD3333 } --></style>
    <BODY class="defaultText">
    <?
    include('mpd.class.php');
    $myMpd = new mpd('localhost',2100);
    if ( $myMpd->connected == FALSE ) {
    echo "Error Connecting: " . $myMpd->errStr;
    } else {
    switch ($_REQUEST[m]) {
    case "add":
    if ( is_null($myMpd->PLAdd($_REQUEST[filename])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    case "rem":
    if ( is_null($myMpd->PLRemove($_REQUEST[id])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    case "setvol":
    if ( is_null($myMpd->SetVolume($_REQUEST[vol])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    case "play":
    if ( is_null($myMpd->Play()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    case "stop":
    if ( is_null($myMpd->Stop()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    case "pause":
    if ( is_null($myMpd->Pause()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    default:
    break;
    ?>
    <DIV ALIGN=CENTER>[ <A HREF="<? echo $_SERVER[PHP_SELF] ?>">Refresh Page</A> ]</DIV>
    <HR>
    <B>Connected to MPD Version <? echo $myMpd->mpd_version ?> at <? echo $myMpd->host ?>:<? echo $myMpd->port ?></B><BR>
    State:
    <?
    switch ($myMpd->state) {
    case MPD_STATE_PLAYING: echo "MPD is Playing [<A HREF='".$_SERVER[PHP_SELF]."?m=pause'>Pause</A>] [<A HREF='".$_SERVER[PHP_SELF]."?m=stop'>Stop</A>]"; break;
    case MPD_STATE_PAUSED: echo "MPD is Paused [<A HREF='".$_SERVER[PHP_SELF]."?m=pause'>Unpause</A>]"; break;
    case MPD_STATE_STOPPED: echo "MPD is Stopped [<A HREF='".$_SERVER[PHP_SELF]."?m=play'>Play</A>]"; break;
    default: echo "(Unknown State!)"; break;
    ?>
    <BR>
    Volume: <? echo $myMpd->volume ?> [ <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=0'>0</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=25'>25</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=75'>75</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=100'>100</A> ]<BR>
    Uptime: <? echo secToTimeStr($myMpd->uptime) ?><BR>
    Playtime: <? echo secToTimeStr($myMpd->playtime) ?><BR>
    <? if ( $myMpd->state == MPD_STATE_PLAYING or $myMpd->state == MPD_STATE_PAUSED ) { ?>
    Currently Playing: <? echo $myMpd->playlist[$myMpd->current_track_id]['Artist']." - ".$myMpd->playlist[$myMpd->current_track_id]['Title'] ?><BR>
    Track Position: <? echo $myMpd->current_track_position."/".$myMpd->current_track_length." (".(round(($myMpd->current_track_position/$myMpd->current_track_length),2)*100)."%)" ?><BR>
    Playlist Position: <? echo ($myMpd->current_track_id+1)."/".$myMpd->playlist_count." (".(round((($myMpd->current_track_id+1)/$myMpd->playlist_count),2)*100)."%)" ?><BR>
    <? } ?>
    <HR>
    <B>Playlist - Total: <? echo $myMpd->playlist_count ?> tracks (Click to Remove)</B><BR>
    <?
    if ( is_null($myMpd->playlist) ) echo "ERROR: " .$myMpd->errStr."\n";
    else {
    foreach ($myMpd->playlist as $id => $entry) {
    echo ( $id == $myMpd->current_track_id ? "<B>" : "" ) . ($id+1) . ". <A HREF='".$_SERVER[PHP_SELF]."?m=rem&id=".$id."'>".$entry['Artist']." - ".$entry['Title']."</A>".( $id == $myMpd->current_track_id ? "</B>" : "" )."<BR>\n";
    ?>
    <HR>
    <B>Sample Search for the String 'U2' (Click to Add to Playlist)</B><BR>
    <?
    $sl = $myMpd->Search(MPD_SEARCH_ARTIST,'U2');
    if ( is_null($sl) ) echo "ERROR: " .$myMpd->errStr."\n";
    else {
    foreach ($sl as $id => $entry) {
    echo ($id+1) . ": <A HREF='".$_SERVER[PHP_SELF]."?m=add&filename=".urlencode($entry['file'])."'>".$entry['Artist']." - ".$entry['Title']."</A><BR>\n";
    if ( count($sl) == 0 ) echo "<I>No results returned from search.</I>";
    // Example of how you would use Bulk Add features of MPD
    // $myarray = array();
    // $myarray[0] = "ACDC - Thunderstruck.mp3";
    // $myarray[1] = "ACDC - Back In Black.mp3";
    // $myarray[2] = "ACDC - Hells Bells.mp3";
    // if ( is_null($myMpd->PLAddBulk($myarray)) ) echo "ERROR: ".$myMpd->errStr."\n";
    ?>
    <HR>
    <B>Artist List</B><BR>
    <?
    if ( is_null($ar = $myMpd->GetArtists()) ) echo "ERROR: " .$myMpd->errStr."\n";
    else {
    while(list($key, $value) = each($ar) ) {
    echo ($key+1) . ". " . $value . "<BR>";
    $myMpd->Disconnect();
    // Used to make number of seconds perty.
    function secToTimeStr($secs) {
    $days = ($secs%604800)/86400;
    $hours = (($secs%604800)%86400)/3600;
    $minutes = ((($secs%604800)%86400)%3600)/60;
    $seconds = (((($secs%604800)%86400)%3600)%60);
    if (round($days)) $timestring .= round($days)."d ";
    if (round($hours)) $timestring .= round($hours)."h ";
    if (round($minutes)) $timestring .= round($minutes)."m";
    if (!round($minutes)&&!round($hours)&&!round($days)) $timestring.=" ".round($seconds)."s";
    return $timestring;
    ?>
    </BODY></HTML>
    The class file:
    <?php
    * mpd.class.php - PHP Object Interface to the MPD Music Player Daemon
    * Version 1.2, Released 05/05/2004
    * Copyright (C) 2003-2004 Benjamin Carlisle ([email protected])
    * http://mpd.24oz.com/ | http://www.musicpd.org/
    * This program is free software; you can redistribute it and/or modify
    * it under the terms of the GNU General Public License as published by
    * the Free Software Foundation; either version 2 of the License, or
    * (at your option) any later version.
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU General Public License for more details.
    * You should have received a copy of the GNU General Public License
    * along with this program; if not, write to the Free Software
    * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    // Create common command definitions for MPD to use
    define("MPD_CMD_STATUS", "status");
    define("MPD_CMD_STATISTICS", "stats");
    define("MPD_CMD_VOLUME", "volume");
    define("MPD_CMD_SETVOL", "setvol");
    define("MPD_CMD_PLAY", "play");
    define("MPD_CMD_STOP", "stop");
    define("MPD_CMD_PAUSE", "pause");
    define("MPD_CMD_NEXT", "next");
    define("MPD_CMD_PREV", "previous");
    define("MPD_CMD_PLLIST", "playlistinfo");
    define("MPD_CMD_PLADD", "add");
    define("MPD_CMD_PLREMOVE", "delete");
    define("MPD_CMD_PLCLEAR", "clear");
    define("MPD_CMD_PLSHUFFLE", "shuffle");
    define("MPD_CMD_PLLOAD", "load");
    define("MPD_CMD_PLSAVE", "save");
    define("MPD_CMD_KILL", "kill");
    define("MPD_CMD_REFRESH", "update");
    define("MPD_CMD_REPEAT", "repeat");
    define("MPD_CMD_LSDIR", "lsinfo");
    define("MPD_CMD_SEARCH", "search");
    define("MPD_CMD_START_BULK", "command_list_begin");
    define("MPD_CMD_END_BULK", "command_list_end");
    define("MPD_CMD_FIND", "find");
    define("MPD_CMD_RANDOM", "random");
    define("MPD_CMD_SEEK", "seek");
    define("MPD_CMD_PLSWAPTRACK", "swap");
    define("MPD_CMD_PLMOVETRACK", "move");
    define("MPD_CMD_PASSWORD", "password");
    define("MPD_CMD_TABLE", "list");
    // Predefined MPD Response messages
    define("MPD_RESPONSE_ERR", "ACK");
    define("MPD_RESPONSE_OK", "OK");
    // MPD State Constants
    define("MPD_STATE_PLAYING", "play");
    define("MPD_STATE_STOPPED", "stop");
    define("MPD_STATE_PAUSED", "pause");
    // MPD Searching Constants
    define("MPD_SEARCH_ARTIST", "artist");
    define("MPD_SEARCH_TITLE", "title");
    define("MPD_SEARCH_ALBUM", "album");
    // MPD Cache Tables
    define("MPD_TBL_ARTIST","artist");
    define("MPD_TBL_ALBUM","album");
    class mpd {
    // TCP/Connection variables
    var $host;
    var $port;
    var $password;
    var $mpd_sock = NULL;
    var $connected = FALSE;
    // MPD Status variables
    var $mpd_version = "(unknown)";
    var $state;
    var $current_track_position;
    var $current_track_length;
    var $current_track_id;
    var $volume;
    var $repeat;
    var $random;
    var $uptime;
    var $playtime;
    var $db_last_refreshed;
    var $num_songs_played;
    var $playlist_count;
    var $num_artists;
    var $num_albums;
    var $num_songs;
    var $playlist = array();
    // Misc Other Vars
    var $mpd_class_version = "1.2";
    var $debugging = FALSE; // Set to TRUE to turn extended debugging on.
    var $errStr = ""; // Used for maintaining information about the last error message
    var $command_queue; // The list of commands for bulk command sending
    // =================== BEGIN OBJECT METHODS ================
    /* mpd() : Constructor
    * Builds the MPD object, connects to the server, and refreshes all local object properties.
    function mpd($srv,$port,$pwd = NULL) {
    $this->host = $srv;
    $this->port = $port;
    $this->password = $pwd;
    $resp = $this->Connect();
    if ( is_null($resp) ) {
    $this->errStr = "Could not connect";
    return;
    } else {
    list ( $this->mpd_version ) = sscanf($resp, MPD_RESPONSE_OK . " MPD %s\n");
    if ( ! is_null($pwd) ) {
    if ( is_null($this->SendCommand(MPD_CMD_PASSWORD,$pwd)) ) {
    $this->connected = FALSE;
    return; // bad password or command
    if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!
    $this->connected = FALSE;
    $this->errStr = "Password supplied does not have read access";
    return;
    } else {
    if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!
    $this->connected = FALSE;
    $this->errStr = "Password required to access server";
    return;
    /* Connect()
    * Connects to the MPD server.
    * NOTE: This is called automatically upon object instantiation; you should not need to call this directly.
    function Connect() {
    if ( $this->debugging ) echo "mpd->Connect() / host: ".$this->host.", port: ".$this->port."\n";
    $this->mpd_sock = fsockopen($this->host,$this->port,$errNo,$errStr,10);
    if (!$this->mpd_sock) {
    $this->errStr = "Socket Error: $errStr ($errNo)";
    return NULL;
    } else {
    while(!feof($this->mpd_sock)) {
    $response = fgets($this->mpd_sock,1024);
    if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {
    $this->connected = TRUE;
    return $response;
    break;
    if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {
    $this->errStr = "Server responded with: $response";
    return NULL;
    // Generic response
    $this->errStr = "Connection not available";
    return NULL;
    /* SendCommand()
    * Sends a generic command to the MPD server. Several command constants are pre-defined for
    * use (see MPD_CMD_* constant definitions above).
    function SendCommand($cmdStr,$arg1 = "",$arg2 = "") {
    if ( $this->debugging ) echo "mpd->SendCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n";
    if ( ! $this->connected ) {
    echo "mpd->SendCommand() / Error: Not connected\n";
    } else {
    // Clear out the error String
    $this->errStr = "";
    $respStr = "";
    // Check the command compatibility:
    if ( ! $this->_checkCompatibility($cmdStr) ) {
    return NULL;
    if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";
    if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";
    fputs($this->mpd_sock,"$cmdStr\n");
    while(!feof($this->mpd_sock)) {
    $response = fgets($this->mpd_sock,1024);
    // An OK signals the end of transmission -- we'll ignore it
    if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {
    break;
    // An ERR signals the end of transmission with an error! Let's grab the single-line message.
    if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {
    list ( $junk, $errTmp ) = split(MPD_RESPONSE_ERR . " ",$response );
    $this->errStr = strtok($errTmp,"\n");
    if ( strlen($this->errStr) > 0 ) {
    return NULL;
    // Build the response string
    $respStr .= $response;
    if ( $this->debugging ) echo "mpd->SendCommand() / response: '".$respStr."'\n";
    return $respStr;
    /* QueueCommand()
    * Queues a generic command for later sending to the MPD server. The CommandQueue can hold
    * as many commands as needed, and are sent all at once, in the order they are queued, using
    * the SendCommandQueue() method. The syntax for queueing commands is identical to SendCommand().
    function QueueCommand($cmdStr,$arg1 = "",$arg2 = "") {
    if ( $this->debugging ) echo "mpd->QueueCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n";
    if ( ! $this->connected ) {
    echo "mpd->QueueCommand() / Error: Not connected\n";
    return NULL;
    } else {
    if ( strlen($this->command_queue) == 0 ) {
    $this->command_queue = MPD_CMD_START_BULK . "\n";
    if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";
    if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";
    $this->command_queue .= $cmdStr ."\n";
    if ( $this->debugging ) echo "mpd->QueueCommand() / return\n";
    return TRUE;
    /* SendCommandQueue()
    * Sends all commands in the Command Queue to the MPD server. See also QueueCommand().
    function SendCommandQueue() {
    if ( $this->debugging ) echo "mpd->SendCommandQueue()\n";
    if ( ! $this->connected ) {
    echo "mpd->SendCommandQueue() / Error: Not connected\n";
    return NULL;
    } else {
    $this->command_queue .= MPD_CMD_END_BULK . "\n";
    if ( is_null($respStr = $this->SendCommand($this->command_queue)) ) {
    return NULL;
    } else {
    $this->command_queue = NULL;
    if ( $this->debugging ) echo "mpd->SendCommandQueue() / response: '".$respStr."'\n";
    return $respStr;
    /* AdjustVolume()
    * Adjusts the mixer volume on the MPD by <modifier>, which can be a positive (volume increase),
    * or negative (volume decrease) value.
    function AdjustVolume($modifier) {
    if ( $this->debugging ) echo "mpd->AdjustVolume()\n";
    if ( ! is_numeric($modifier) ) {
    $this->errStr = "AdjustVolume() : argument 1 must be a numeric value";
    return NULL;
    $this->RefreshInfo();
    $newVol = $this->volume + $modifier;
    $ret = $this->SetVolume($newVol);
    if ( $this->debugging ) echo "mpd->AdjustVolume() / return\n";
    return $ret;
    /* SetVolume()
    * Sets the mixer volume to <newVol>, which should be between 1 - 100.
    function SetVolume($newVol) {
    if ( $this->debugging ) echo "mpd->SetVolume()\n";
    if ( ! is_numeric($newVol) ) {
    $this->errStr = "SetVolume() : argument 1 must be a numeric value";
    return NULL;
    // Forcibly prevent out of range errors
    if ( $newVol < 0 ) $newVol = 0;
    if ( $newVol > 100 ) $newVol = 100;
    // If we're not compatible with SETVOL, we'll try adjusting using VOLUME
    if ( $this->_checkCompatibility(MPD_CMD_SETVOL) ) {
    if ( ! is_null($ret = $this->SendCommand(MPD_CMD_SETVOL,$newVol))) $this->volume = $newVol;
    } else {
    $this->RefreshInfo(); // Get the latest volume
    if ( is_null($this->volume) ) {
    return NULL;
    } else {
    $modifier = ( $newVol - $this->volume );
    if ( ! is_null($ret = $this->SendCommand(MPD_CMD_VOLUME,$modifier))) $this->volume = $newVol;
    if ( $this->debugging ) echo "mpd->SetVolume() / return\n";
    return $ret;
    /* GetDir()
    * Retrieves a database directory listing of the <dir> directory and places the results into
    * a multidimensional array. If no directory is specified, the directory listing is at the
    * base of the MPD music path.
    function GetDir($dir = "") {
    if ( $this->debugging ) echo "mpd->GetDir()\n";
    $resp = $this->SendCommand(MPD_CMD_LSDIR,$dir);
    $dirlist = $this->_parseFileListResponse($resp);
    if ( $this->debugging ) echo "mpd->GetDir() / return ".print_r($dirlist)."\n";
    return $dirlist;
    /* PLAdd()
    * Adds each track listed in a single-dimensional <trackArray>, which contains filenames
    * of tracks to add, to the end of the playlist. This is used to add many, many tracks to
    * the playlist in one swoop.
    function PLAddBulk($trackArray) {
    if ( $this->debugging ) echo "mpd->PLAddBulk()\n";
    $num_files = count($trackArray);
    for ( $i = 0; $i < $num_files; $i++ ) {
    $this->QueueCommand(MPD_CMD_PLADD,$trackArray[$i]);
    $resp = $this->SendCommandQueue();
    $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLAddBulk() / return\n";
    return $resp;
    /* PLAdd()
    * Adds the file <file> to the end of the playlist. <file> must be a track in the MPD database.
    function PLAdd($fileName) {
    if ( $this->debugging ) echo "mpd->PLAdd()\n";
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLADD,$fileName))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLAdd() / return\n";
    return $resp;
    /* PLMoveTrack()
    * Moves track number <origPos> to position <newPos> in the playlist. This is used to reorder
    * the songs in the playlist.
    function PLMoveTrack($origPos, $newPos) {
    if ( $this->debugging ) echo "mpd->PLMoveTrack()\n";
    if ( ! is_numeric($origPos) ) {
    $this->errStr = "PLMoveTrack(): argument 1 must be numeric";
    return NULL;
    if ( $origPos < 0 or $origPos > $this->playlist_count ) {
    $this->errStr = "PLMoveTrack(): argument 1 out of range";
    return NULL;
    if ( $newPos < 0 ) $newPos = 0;
    if ( $newPos > $this->playlist_count ) $newPos = $this->playlist_count;
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLMOVETRACK,$origPos,$newPos))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLMoveTrack() / return\n";
    return $resp;
    /* PLShuffle()
    * Randomly reorders the songs in the playlist.
    function PLShuffle() {
    if ( $this->debugging ) echo "mpd->PLShuffle()\n";
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLSHUFFLE))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLShuffle() / return\n";
    return $resp;
    /* PLLoad()
    * Retrieves the playlist from <file>.m3u and loads it into the current playlist.
    function PLLoad($file) {
    if ( $this->debugging ) echo "mpd->PLLoad()\n";
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLLOAD,$file))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLLoad() / return\n";
    return $resp;
    /* PLSave()
    * Saves the playlist to <file>.m3u for later retrieval. The file is saved in the MPD playlist
    * directory.
    function PLSave($file) {
    if ( $this->debugging ) echo "mpd->PLSave()\n";
    $resp = $this->SendCommand(MPD_CMD_PLSAVE,$file);
    if ( $this->debugging ) echo "mpd->PLSave() / return\n";
    return $resp;
    /* PLClear()
    * Empties the playlist.
    function PLClear() {
    if ( $this->debugging ) echo "mpd->PLClear()\n";
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLCLEAR))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLClear() / return\n";
    return $resp;
    /* PLRemove()
    * Removes track <id> from the playlist.
    function PLRemove($id) {
    if ( $this->debugging ) echo "mpd->PLRemove()\n";
    if ( ! is_numeric($id) ) {
    $this->errStr = "PLRemove() : argument 1 must be a numeric value";
    return NULL;
    if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLREMOVE,$id))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->PLRemove() / return\n";
    return $resp;
    /* SetRepeat()
    * Enables 'loop' mode -- tells MPD continually loop the playlist. The <repVal> parameter
    * is either 1 (on) or 0 (off).
    function SetRepeat($repVal) {
    if ( $this->debugging ) echo "mpd->SetRepeat()\n";
    $rpt = $this->SendCommand(MPD_CMD_REPEAT,$repVal);
    $this->repeat = $repVal;
    if ( $this->debugging ) echo "mpd->SetRepeat() / return\n";
    return $rpt;
    /* SetRandom()
    * Enables 'randomize' mode -- tells MPD to play songs in the playlist in random order. The
    * <rndVal> parameter is either 1 (on) or 0 (off).
    function SetRandom($rndVal) {
    if ( $this->debugging ) echo "mpd->SetRandom()\n";
    $resp = $this->SendCommand(MPD_CMD_RANDOM,$rndVal);
    $this->random = $rndVal;
    if ( $this->debugging ) echo "mpd->SetRandom() / return\n";
    return $resp;
    /* Shutdown()
    * Shuts down the MPD server (aka sends the KILL command). This closes the current connection,
    * and prevents future communication with the server.
    function Shutdown() {
    if ( $this->debugging ) echo "mpd->Shutdown()\n";
    $resp = $this->SendCommand(MPD_CMD_SHUTDOWN);
    $this->connected = FALSE;
    unset($this->mpd_version);
    unset($this->errStr);
    unset($this->mpd_sock);
    if ( $this->debugging ) echo "mpd->Shutdown() / return\n";
    return $resp;
    /* DBRefresh()
    * Tells MPD to rescan the music directory for new tracks, and to refresh the Database. Tracks
    * cannot be played unless they are in the MPD database.
    function DBRefresh() {
    if ( $this->debugging ) echo "mpd->DBRefresh()\n";
    $resp = $this->SendCommand(MPD_CMD_REFRESH);
    // Update local variables
    $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->DBRefresh() / return\n";
    return $resp;
    /* Play()
    * Begins playing the songs in the MPD playlist.
    function Play() {
    if ( $this->debugging ) echo "mpd->Play()\n";
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY) )) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->Play() / return\n";
    return $rpt;
    /* Stop()
    * Stops playing the MPD.
    function Stop() {
    if ( $this->debugging ) echo "mpd->Stop()\n";
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_STOP) )) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->Stop() / return\n";
    return $rpt;
    /* Pause()
    * Toggles pausing on the MPD. Calling it once will pause the player, calling it again
    * will unpause.
    function Pause() {
    if ( $this->debugging ) echo "mpd->Pause()\n";
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PAUSE) )) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->Pause() / return\n";
    return $rpt;
    /* SeekTo()
    * Skips directly to the <idx> song in the MPD playlist.
    function SkipTo($idx) {
    if ( $this->debugging ) echo "mpd->SkipTo()\n";
    if ( ! is_numeric($idx) ) {
    $this->errStr = "SkipTo() : argument 1 must be a numeric value";
    return NULL;
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY,$idx))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->SkipTo() / return\n";
    return $idx;
    /* SeekTo()
    * Skips directly to a given position within a track in the MPD playlist. The <pos> argument,
    * given in seconds, is the track position to locate. The <track> argument, if supplied is
    * the track number in the playlist. If <track> is not specified, the current track is assumed.
    function SeekTo($pos, $track = -1) {
    if ( $this->debugging ) echo "mpd->SeekTo()\n";
    if ( ! is_numeric($pos) ) {
    $this->errStr = "SeekTo() : argument 1 must be a numeric value";
    return NULL;
    if ( ! is_numeric($track) ) {
    $this->errStr = "SeekTo() : argument 2 must be a numeric value";
    return NULL;
    if ( $track == -1 ) {
    $track = $this->current_track_id;
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_SEEK,$track,$pos))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->SeekTo() / return\n";
    return $pos;
    /* Next()
    * Skips to the next song in the MPD playlist. If not playing, returns an error.
    function Next() {
    if ( $this->debugging ) echo "mpd->Next()\n";
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_NEXT))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->Next() / return\n";
    return $rpt;
    /* Previous()
    * Skips to the previous song in the MPD playlist. If not playing, returns an error.
    function Previous() {
    if ( $this->debugging ) echo "mpd->Previous()\n";
    if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PREV))) $this->RefreshInfo();
    if ( $this->debugging ) echo "mpd->Previous() / return\n";
    return $rpt;
    /* Search()
    * Searches the MPD database. The search <type> should be one of the following:
    * MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM
    * The search <string> is a case-insensitive locator string. Anything that contains
    * <string> will be returned in the results.
    function Search($type,$string) {
    if ( $this->debugging ) echo "mpd->Search()\n";
    if ( $type != MPD_SEARCH_ARTIST and
    $type != MPD_SEARCH_ALBUM and
    $type != MPD_SEARCH_TITLE ) {
    $this->errStr = "mpd->Search(): invalid search type";
    return NULL;
    } else {
    if ( is_null($resp = $this->SendCommand(MPD_CMD_SEARCH,$type,$string))) return NULL;
    $searchlist = $this->_parseFileListResponse($resp);
    if ( $this->debugging ) echo "mpd->Search() / return ".print_r($searchlist)."\n";
    return $searchlist;
    /* Find()
    * Find() looks for exact matches in the MPD database. The find <type> should be one of
    * the following:
    * MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM
    * The find <string> is a case-insensitive locator string. Anything that exactly matches
    * <string> will be returned in the results.
    function Find($type,$string) {
    if ( $this->debugging ) echo "mpd->Find()\n";
    if ( $type != MPD_SEARCH_ARTIST and
    $type != MPD_SEARCH_ALBUM and
    $type != MPD_SEARCH_TITLE ) {
    $this->errStr = "mpd->Find(): invalid find type";
    return NULL;
    } else {
    if ( is_null($resp = $this->SendCommand(MPD_CMD_FIND,$type,$string))) return NULL;
    $searchlist = $this->_parseFileListResponse($resp);
    if ( $this->debugging ) echo "mpd->Find() / return ".print_r($searchlist)."\n";
    return $searchlist;
    /* Disconnect()
    * Closes the connection to the MPD server.
    function Disconnect() {
    if ( $this->debugging ) echo "mpd->Disconnect()\n";
    fclose($this->mpd_sock);
    $this->connected = FALSE;
    unset($this->mpd_version);
    unset($this->errStr);
    unset($this->mpd_sock);
    /* GetArtists()
    * Returns the list of artists in the database in an associative array.
    function GetArtists() {
    if ( $this->debugging ) echo "mpd->GetArtists()\n";
    if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ARTIST))) return NULL;
    $arArray = array();
    $arLine = strtok($resp,"\n");
    $arName = "";
    $arCounter = -1;
    while ( $arLine ) {
    list ( $element, $value ) = split(": ",$arLine);
    if ( $element == "Artist" ) {
    $arCounter++;
    $arName = $value;
    $arArray[$arCounter] = $arName;
    $arLine = strtok("\n");
    if ( $this->debugging ) echo "mpd->GetArtists()\n";
    return $arArray;
    /* GetAlbums()
    * Returns the list of albums in the database in an associative array. Optional parameter
    * is an artist Name which will list all albums by a particular artist.
    function GetAlbums( $ar = NULL) {
    if ( $this->debugging ) echo "mpd->GetAlbums()\n";
    if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ALBUM, $ar ))) return NULL;
    $alArray = array();
    $alLine = strtok($resp,"\n");
    $alName = "";
    $alCounter = -1;
    while ( $alLine ) {
    list ( $element, $value ) = split(": ",$alLine);
    if ( $element == "Album" ) {
    $alCounter++;
    $alName = $value;
    $alArray[$alCounter] = $alName;
    $alLine = strtok("\n");
    if ( $this->debugging ) echo "mpd->GetAlbums()\n";
    return $alArray;
    //***************************** INTERNAL FUNCTIONS ******************************//
    /* _computeVersionValue()
    * Computes a compatibility value from a version string
    function _computeVersionValue($verStr) {
    list ($ver_maj, $ver_min, $ver_rel ) = split("\.",$verStr);
    return ( 100 * $ver_maj ) + ( 10 * $ver_min ) + ( $ver_rel );
    /* _checkCompatibility()
    * Check MPD command compatibility against our internal table. If there is no version
    * listed in the table, allow it by default.
    function _checkCompatibility($cmd) {
    // Check minimum compatibility
    $req_ver_low = $this->COMPATIBILITY_MIN_TBL[$cmd];
    $req_ver_hi = $this->COMPATIBILITY_MAX_TBL[$cmd];
    $mpd_ver = $this->_computeVersionValue($this->mpd_version);
    if ( $req_ver_low ) {
    $req_ver = $this->_computeVersionValue($req_ver_low);
    if ( $mpd_ver < $req_ver ) {
    $this->errStr = "Command '$cmd' is not compatible with this version of MPD, version ".$req_ver_low." required";
    return FALSE;
    // Check maxmum compatibility -- this will check for deprecations
    if ( $req_ver_hi ) {
    $req_ver = $this->_computeVersionValue($req_ver_hi);
    if ( $mpd_ver > $req_ver ) {
    $this->errStr = "Command '$cmd' has been deprecated in this version of MPD.";
    return FALSE;
    return TRUE;
    /* _parseFileListResponse()
    * Builds a multidimensional array with MPD response lists.
    * NOTE: This function is used internally within the class. It should not be used.
    function _parseFileListResponse($resp) {
    if ( is_null($resp) ) {
    return NULL;
    } else {
    $plistArray = array();
    $plistLine = strtok($resp,"\n");
    $plistFile = "";
    $plCounter = -1;
    while ( $plistLine ) {
    list ( $element, $value ) = split(": ",$plistLine);
    if ( $element == "file" ) {
    $plCounter++;
    $plistFile = $value;
    $plistArray[$plCounter]["file"] = $plistFile;
    } else {
    $plistArray[$plCounter][$element] = $value;
    $plistLine = strtok("\n");
    return $plistArray;
    /* RefreshInfo()
    * Updates all class properties with the values from the MPD server.
    * NOTE: This function is automatically called upon Connect() as of v1.1.
    function RefreshInfo() {
    // Get the Server Statistics
    $statStr = $this->SendCommand(MPD_CMD_STATISTICS);
    if ( !$statStr ) {
    return NULL;
    } else {
    $stats = array();
    $statLine = strtok($statStr,"\n");
    while ( $statLine ) {
    list ( $element, $value ) = split(": ",$statLine);
    $stats[$element] = $value;
    $statLine = strtok("\n");
    // Get the Server Status
    $statusStr = $this->SendCommand(MPD_CMD_STATUS);
    if ( ! $statusStr ) {
    return NULL;
    } else {
    $status = array();
    $statusLine = strtok($statusStr,"\n");
    while ( $statusLine ) {
    list ( $element, $value ) = split(": ",$statusLine);
    $status[$element] = $value;
    $statusLine = strtok("\n");
    // Get the Playlist
    $plStr = $this->SendCommand(MPD_CMD_PLLIST);
    $this->playlist = $this->_parseFileListResponse($plStr);
    $this->playlist_count = count($this->playlist);
    // Set Misc Other Variables
    $this->state = $status['state'];
    if ( ($this->state == MPD_STATE_PLAYING) || ($this->state == MPD_STATE_PAUSED) ) {
    $this->current_track_id = $status['song'];
    list ($this->current_track_position, $this->current_track_length ) = split(":",$status['time']);
    } else {
    $this->current_track_id = -1;
    $this->current_track_position = -1;
    $this->current_track_length = -1;
    $this->repeat = $status['repeat'];
    $this->random = $status['random'];
    $this->db_last_refreshed = $stats['db_update'];
    $this->volume = $status['volume'];
    $this->uptime = $stats['uptime'];
    $this->playtime = $stats['playtime'];
    $this->num_songs_played = $stats['songs_played'];
    $this->num_artists = $stats['num_artists'];
    $this->num_songs = $stats['num_songs'];
    $this->num_albums = $stats['num_albums'];
    return TRUE;
    /* ------------------ DEPRECATED METHODS -------------------*/
    /* GetStatistics()
    * Retrieves the 'statistics' variables from the server and tosses them into an array.
    * NOTE: This function really should not be used. Instead, use $this->[variable]. The function
    * will most likely be deprecated in future releases.
    function GetStatistics() {
    if ( $this->debugging ) echo "mpd->GetStatistics()\n";
    $stats = $this->SendCommand(MPD_CMD_STATISTICS);
    if ( !$stats ) {
    return NULL;
    } else {
    $statsArray = array();
    $statsLine = strtok($stats,"\n");
    while ( $statsLine ) {
    list ( $element, $value ) = split(": ",$statsLine);
    $statsArray[$element] = $value;
    $statsLine = strtok("\n");
    if ( $this->debugging ) echo "mpd->GetStatistics() / return: " . print_r($statsArray) ."\n";
    return $statsArray;
    /* GetStatus()
    * Retrieves the 'status' variables from the server and tosses them into an array.
    * NOTE: This function really should not be used. Instead, use $this->[variable]. The function
    * will most likely be deprecated in future releases.
    function GetStatus() {
    if ( $this->debugging ) echo "mpd->GetStatus()\n";
    $status = $this->SendCommand(MPD_CMD_STATUS);
    if ( ! $status ) {
    return NULL;
    } else {
    $statusArray = array();
    $statusLine = strtok($status,"\n");
    while ( $statusLine ) {
    list ( $element, $value ) = split(": ",$statusLine);
    $statusArray[$element] = $value;
    $statusLine = strtok("\n");
    if ( $this->debugging ) echo "mpd->GetStatus() / return: " . print_r($statusArray) ."\n";
    return $statusArray;
    /* GetVolume()
    * Retrieves the mixer volume from the server.
    * NOTE: This function really should not be used. Instead, use $this->volume. The function
    * will most likely be deprecated in future releases.
    function GetVolume() {
    if ( $this->debugging ) echo "mpd->GetVolume()\n";
    $volLine = $this->SendCommand(MPD_CMD_STATUS);
    if ( ! $volLine ) {
    return NULL;
    } else {
    list ($vol) = sscanf($volLine,"volume: %d");
    if ( $this->debugging ) echo "mpd->GetVolume() / return: $vol\n";
    return $vol;
    /* GetPlaylist()
    * Retrieves the playlist from the server and tosses it into a multidimensional array.
    * NOTE: This function really should not be used. Instead, use $this->playlist. The function
    * will most likely be deprecated in future releases.
    function GetPlaylist() {
    if ( $this->debugging ) echo "mpd->GetPlaylist()\n";
    $resp = $this->SendCommand(MPD_CMD_PLLIST);
    $playlist = $this->_parseFileListResponse($resp);
    if ( $this->debugging ) echo "mpd->GetPlaylist() / return ".print_r($playlist)."\n";
    return $playlist;
    /* ----------------- Command compatibility tables --------------------- */
    var $COMPATIBILITY_MIN_TBL = array(
    MPD_CMD_SEEK => "0.9.1" ,
    MPD_CMD_PLMOVE => "0.9.1" ,
    MPD_CMD_RANDOM => "0.9.1" ,
    MPD_CMD_PLSWAPTRACK => "0.9.1" ,
    MPD_CMD_PLMOVETRACK => "0.9.1" ,
    MPD_CMD_PASSWORD => "0.10.0" ,
    MPD_CMD_SETVOL => "0.10.0"
    var $COMPATIBILITY_MAX_TBL = array(
    MPD_CMD_VOLUME => "0.10.0"
    } // ---------------------------- end of class ------------------------------
    ?>
    and the HTML output:
    <HTML>
    <style type="text/css"><!-- .defaultText { font-family: Arial, Helvetica, sans-serif; font-size: 9pt; font-style: normal; font-weight: normal; color: #111111} .err { color: #DD3333 } --></style>
    <BODY class="defaultText">
    connected == FALSE ) {
    echo "Error Connecting: " . $myMpd->errStr;
    } else {
    switch ($_REQUEST[m]) {
    case "add":
    if ( is_null($myMpd->PLAdd($_REQUEST[filename])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    case "rem":
    if ( is_null($myMpd->PLRemove($_REQUEST[id])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    case "setvol":
    if ( is_null($myMpd->SetVolume($_REQUEST[vol])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    case "play":
    if ( is_null($myMpd->Play()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    case "stop":
    if ( is_null($myMpd->Stop()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    case "pause":
    if ( is_null($myMpd->Pause()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
    break;
    default:
    break;
    ?>
    <DIV ALIGN=CENTER>[ <A HREF="<? echo $_SERVER[PHP_SELF] ?>">Refresh Page</A> ]</DIV>
    <HR>
    <B>Connected to MPD Version mpd_version ?> at host ?>:port ?></B><BR>
    State:
    state) {
    case MPD_STATE_PLAYING: echo "MPD is Playing [<A HREF='".$_SERVER[PHP_SELF]."?m=pause'>Pause</A>] [<A HREF='".$_SERVER[PHP_SELF]."?m=stop'>Stop</A>]"; break;
    case MPD_STATE_PAUSED: echo "MPD is Paused [<A HREF='".$_SERVER[PHP_SELF]."?m=pause'>Unpause</A>]"; break;
    case MPD_STATE_STOPPED: echo "MPD is Stopped [<A HREF='".$_SERVER[PHP_SELF]."?m=play'>Play</A>]"; break;
    default: echo "(Unknown State!)"; break;
    ?>
    <BR>
    Volume: volume ?> [ <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=0'>0</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=25'>25</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=75'>75</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=100'>100</A> ]<BR>
    Uptime: uptime) ?><BR>
    Playtime: playtime) ?><BR>
    state == MPD_STATE_PLAYING or $myMpd->state == MPD_STATE_PAUSED ) { ?>
    Currently Playing: playlist[$myMpd->current_track_id]['Artist']." - ".$myMpd->playlist[$myMpd->current_track_id]['Title'] ?><BR>
    Track Position: current_track_position."/".$myMpd->current_track_length." (".(round(($myMpd->current_track_position/$myMpd->current_track_length),2)*100)."%)" ?><BR>
    Playlist Position: current_track_id+1)."/".$myMpd->playlist_count." (".(round((($myMpd->current_track_id+1)/$myMpd->playlist_count),2)*100)."%)" ?><BR>
    <HR>
    <B>Playlist - Total: playlist_count ?> tracks (Click to Remove)</B><BR>
    playlist) ) echo "ERROR: " .$myMpd->errStr."\n";
    else {
    foreach ($myMpd->playlist as $id => $entry) {
    echo ( $id == $myMpd->current_track_id ? "<B>" : "" ) . ($id+1) . ". <A HREF='".$_SERVER[PHP_SELF]."?m=rem&id=".$id."'>".$entry['Artist']." - ".$entry['Title']."</A>".( $id == $myMpd->current_track_id ? "</B>" : "" )."<BR>\n";
    ?>
    <HR>
    <B>Sample Search for the String 'U2' (Click to Add to Playlist)</B><BR>
    Search(MPD_SEARCH_ARTIST,'U2');
    if ( is_null($sl) ) echo "ERROR: " .$myMpd->errStr."\n";
    else {
    foreach ($sl as $id => $entry) {
    echo ($id+1) . ": <A HREF='".$_SERVER[PHP_SELF]."?m=add&filename=".urlencode($entry['file'])."'>".$entry['Artist']." - ".$entry['Title']."</A><BR>\n";
    if ( count($sl) == 0 ) echo "<I>No results returned from search.</I>";
    // Example of how you would use Bulk Add features of MPD
    // $myarray = array();
    // $myarray[0] = "ACDC - Thunderstruck.mp3";
    // $myarray[1] = "ACDC - Back In Black.mp3";
    // $myarray[2] = "ACDC - Hells Bells.mp3";
    // if ( is_null($myMpd->PLAddBulk($myarray)) ) echo "ERROR: ".$myMpd->errStr."\n";
    ?>
    <HR>
    <B>Artist List</B><BR>
    GetArtists()) ) echo "ERROR: " .$myMpd->errStr."\n";
    else {
    while(list($key, $value) = each($ar) ) {
    echo ($key+1) . ". " . $value . "<BR>";
    $myMpd->Disconnect();
    // Used to make number of seconds perty.
    function secToTimeStr($secs) {
    $days = ($secs%604800)/86400;
    $hours = (($secs%604800)%86400)/3600;
    $minutes = ((($secs%604800)%86400)%3600)/60;
    $seconds = (((($secs%604800)%86400)%3600)%60);
    if (round($days)) $timestring .= round($days)."d ";
    if (round($hours)) $timestring .= round($hours)."h ";
    if (round($minutes)) $timestring .= round($minutes)."m";
    if (!round($minutes)&&!round($hours)&&!round($days)) $timestring.=" ".round($seconds)."s";
    return $timestring;
    ?>
    </BODY></HTML>
    As you can see it doesn't seem to understand the pointer operator. Do I have to enable anything in the PHP config files or something?

    It's set up correctly. Also, it does parse PHP, just not after the arrow.
    Here is my php.ini:
    ; With mbstring support this will automatically be converted into the encoding
    ; given by corresponding encode setting. When empty mbstring.internal_encoding
    ; is used. For the decode settings you can distinguish between motorola and
    ; intel byte order. A decode setting cannot be empty.
    ; http://php.net/exif.encode-unicode
    ;exif.encode_unicode = ISO-8859-15
    ; http://php.net/exif.decode-unicode-motorola
    ;exif.decode_unicode_motorola = UCS-2BE
    ; http://php.net/exif.decode-unicode-intel
    ;exif.decode_unicode_intel = UCS-2LE
    ; http://php.net/exif.encode-jis
    ;exif.encode_jis =
    ; http://php.net/exif.decode-jis-motorola
    ;exif.decode_jis_motorola = JIS
    ; http://php.net/exif.decode-jis-intel
    ;exif.decode_jis_intel = JIS
    [Tidy]
    ; The path to a default tidy configuration file to use when using tidy
    ; http://php.net/tidy.default-config
    ;tidy.default_config = /usr/local/lib/php/default.tcfg
    ; Should tidy clean and repair output automatically?
    ; WARNING: Do not use this option if you are generating non-html content
    ; such as dynamic images
    ; http://php.net/tidy.clean-output
    tidy.clean_output = Off
    [soap]
    ; Enables or disables WSDL caching feature.
    ; http://php.net/soap.wsdl-cache-enabled
    soap.wsdl_cache_enabled=1
    ; Sets the directory name where SOAP extension will put cache files.
    ; http://php.net/soap.wsdl-cache-dir
    soap.wsdl_cache_dir="/tmp"
    ; (time to live) Sets the number of second while cached file will be used
    ; instead of original one.
    ; http://php.net/soap.wsdl-cache-ttl
    soap.wsdl_cache_ttl=86400
    ; Sets the size of the cache limit. (Max. number of WSDL files to cache)
    soap.wsdl_cache_limit = 5
    [sysvshm]
    ; A default size of the shared memory segment
    ;sysvshm.init_mem = 10000
    [ldap]
    ; Sets the maximum number of open links or -1 for unlimited.
    ldap.max_links = -1
    [mcrypt]
    ; For more information about mcrypt settings see http://php.net/mcrypt-module-open
    ; Directory where to load mcrypt algorithms
    ; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt)
    ;mcrypt.algorithms_dir=
    ; Directory where to load mcrypt modes
    ; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt)
    ;mcrypt.modes_dir=
    [dba]
    ;dba.default_handler=
    ; Local Variables:
    ; tab-width: 4
    ; End:
    Last edited by BaconPie (2010-11-04 20:11:33)

Maybe you are looking for