Source for file User.php

Documentation is available at User.php

  1. <?
  2.  
  3. /** Represents a user and provides different methods to query user information.
  4.  *
  5.  * @package    php-lastfm-api
  6.  * @author  Felix Bruns <felixbruns@web.de>
  7.  * @version    1.0
  8.  */
  9. class User extends Media {
  10.     /** The users language.
  11.      *
  12.      * @var string 
  13.      * @access    private
  14.      */
  15.     private $language;
  16.  
  17.     /** The users country.
  18.      *
  19.      * @var string 
  20.      * @access    private
  21.      */
  22.     private $country;
  23.  
  24.     /** The users age.
  25.      *
  26.      * @var integer 
  27.      * @access    private
  28.      */
  29.     private $age;
  30.  
  31.     /** The users gender.
  32.      *
  33.      * @var string 
  34.      * @access    private
  35.      */
  36.     private $gender;
  37.  
  38.     /** Indicates if the user is a subscriber.
  39.      *
  40.      * @var boolean 
  41.      * @access    private
  42.      */
  43.     private $subscriber;
  44.  
  45.     /** The number of playlist of this user.
  46.      *
  47.      * @var integer 
  48.      * @access    private
  49.      */
  50.     private $playlists;
  51.  
  52.     /** The last track the user played.
  53.      *
  54.      * @var Track 
  55.      * @access    private
  56.      */
  57.     private $lastTrack;
  58.  
  59.     /** Similarity match.
  60.      *
  61.      * @var float 
  62.      * @access    private
  63.      */
  64.     private $match;
  65.  
  66.     /** I have no idea. Haha. TODO.
  67.      *
  68.      * @var integer 
  69.      * @access    private
  70.      */
  71.     private $weight;
  72.  
  73.     /** Possible time periods.
  74.      *
  75.      * @var integer 
  76.      * @access    public
  77.      */
  78.     const PERIOD_OVERALL  = 'overall';
  79.     const PERIOD_3MONTHS  = '3month';
  80.     const PERIOD_6MONTHS  = '6month';
  81.     const PERIOD_12MONTHS = '12month';
  82.  
  83.     /** Create an Artist object.
  84.      *
  85.      * @param string    $name        Username.
  86.      * @param string    $url        Last.fm URL of this user.
  87.      * @param string    $language    Language of this user.
  88.      * @param string    $country    Country of this user.
  89.      * @param integer    $age        Age of this user.
  90.      * @param string    $gender        Gender of this user.
  91.      * @param boolean    $subscriber    Subscriber status of this user.
  92.      * @param integer    $playCount    Track play count of this user.
  93.      * @param string    $playlists    Number of playlist of this user.
  94.      * @param array        $images        An array of cover art images of different sizes.
  95.      * @param Track        $lastTrack    Last track the user played.
  96.      * @param float        $match        Similarity value.
  97.      * @param integer    $weight        Still no idea.
  98.      *
  99.      * @access    public
  100.      */
  101.     public function __construct($name$url$language$country$age$gender,
  102.                                 $subscriber$playCount$playlists,
  103.                                 array $images$lastTrack$match$weight){
  104.         parent::__construct($name''$url$images0$playCount);
  105.  
  106.         $this->language   $language;
  107.         $this->country    $country;
  108.         $this->age        $age;
  109.         $this->gender     $gender;
  110.         $this->subscriber $subscriber;
  111.         $this->playlists  $playlists;
  112.         $this->lastTrack  $lastTrack;
  113.         $this->match      $match;
  114.         $this->weight     $weight;
  115.     }
  116.  
  117.     /** Returns the users language.
  118.      *
  119.      * @return    string    The users language.
  120.      * @access    public
  121.      */
  122.     public function getLanguage(){
  123.         return $this->language;
  124.     }
  125.  
  126.     /** Returns the users country.
  127.      *
  128.      * @return    string    The users country.
  129.      * @access    public
  130.      */
  131.     public function getCountry(){
  132.         return $this->country;
  133.     }
  134.  
  135.     /** Returns the users age.
  136.      *
  137.      * @return    integer    The users age.
  138.      * @access    public
  139.      */
  140.     public function getAge(){
  141.         return $this->age;
  142.     }
  143.  
  144.     /** Returns the users gender.
  145.      *
  146.      * @return    string    The users gender.
  147.      * @access    public
  148.      */
  149.     public function getGender(){
  150.         return $this->gender;
  151.     }
  152.  
  153.     /** Returns if the user is a subscriber.
  154.      *
  155.      * @return    boolean    The users subscription status (true or false).
  156.      * @access    public
  157.      */
  158.     public function isSubscriber(){
  159.         return $this->subscriber;
  160.     }
  161.  
  162.     /** Returns the number of playlists of this user.
  163.      *
  164.      * @return    integer    Number of playlists.
  165.      * @access    public
  166.      */
  167.     public function getPlaylistCount(){
  168.         return $this->playlists;
  169.     }
  170.  
  171.     /** Returns the last played track of this user.
  172.      *
  173.      * @return    Track    A Track object.
  174.      * @access    public
  175.      */
  176.     public function getLastTrack(){
  177.         return $this->lastTrack;
  178.     }
  179.  
  180.     /** Returns the similarity match of this user.
  181.      *
  182.      * @return    float    A floating-point number.
  183.      * @access    public
  184.      */
  185.     public function getMatch(){
  186.         return $this->match;
  187.     }
  188.  
  189.     /** Returns whatever.
  190.      *
  191.      * @return    integer    I don't even know if it's an integer right now.
  192.      * @access    public
  193.      */
  194.     public function getWeight(){
  195.         return $this->weight;
  196.     }
  197.  
  198.     /** Get a list of upcoming events that this user is attending. Easily integratable into calendars, using the iCal standard.
  199.      *
  200.      * @param    string    $user    The user to fetch the events for. (Required)
  201.      * @return    array            An array of Event objects.
  202.      *
  203.      * @static
  204.      * @access    public
  205.      * @throws    Error
  206.      */
  207.     public static function getEvents($user){
  208.         $xml CallerFactory::getDefaultCaller()->call('user.getEvents'array(
  209.             'user' => $user
  210.         ));
  211.  
  212.         $events array();
  213.  
  214.         foreach($xml->children(as $event){
  215.             $events[Event::fromSimpleXMLElement($event);
  216.         }
  217.  
  218.         return $events;
  219.     }
  220.  
  221.     /** Get a list of the user's friends on last.fm.
  222.      *
  223.      * @param    string    $user            The last.fm username to fetch the friends of. (Required)
  224.      * @param    boolean    $recentTracks    Whether or not to include information about friends' recent listening in the response. (Optional)
  225.      * @param    integer    $limit            An integer used to limit the number of friends returned. (Optional)
  226.      * @return    array                    An array of User objects.
  227.      *
  228.      * @static
  229.      * @access    public
  230.      * @throws    Error
  231.      */
  232.     public static function getFriends($user$recentTracks null$limit null){
  233.         $xml CallerFactory::getDefaultCaller()->call('user.getFriends'array(
  234.             'user'         => $user,
  235.             'recenttracks' => $recenttracks,
  236.             'limit'        => $limit
  237.         ));
  238.  
  239.         $friends array();
  240.  
  241.         foreach($xml->children(as $friend){
  242.             $friends[User::fromSimpleXMLElement($friend);
  243.         }
  244.  
  245.         return $friends;
  246.     }
  247.  
  248.     /** Get information about a user profile.
  249.      *
  250.      * @param    Session    $session    A session obtained by {@link de.felixbruns.lastfm.Auth#getSession Auth::getSession} or {@link de.felixbruns.lastfm.Auth#getMobileSession Auth::getMobileSession}. (Required)
  251.      * @return    User                A User object.
  252.      *
  253.      * @static
  254.      * @access    public
  255.      * @throws    Error
  256.      */
  257.     public static function getInfo($session){
  258.         $xml CallerFactory::getDefaultCaller()->signedCall('user.getInfo'array(
  259.             'user'         => $user,
  260.             'recenttracks' => $recenttracks,
  261.             'limit'        => $limit
  262.         )$session);
  263.  
  264.         return User::fromSimpleXMLElement($xml);
  265.     }
  266.  
  267.     /** Get the last 50 tracks loved by a user.
  268.      *
  269.      * @param    string    $user    The user name to fetch the loved tracks for. (Required)
  270.      * @return    array            An array of Track objects.
  271.      *
  272.      * @static
  273.      * @access    public
  274.      * @throws    Error
  275.      */
  276.     public static function getLovedTracks($user){
  277.         $xml CallerFactory::getDefaultCaller()->call('user.getLovedTracks'array(
  278.             'user' => $user
  279.         ));
  280.  
  281.         $tracks array();
  282.  
  283.         foreach($xml->children(as $track){
  284.             $tracks[Track::fromSimpleXMLElement($track);
  285.         }
  286.  
  287.         return $tracks;
  288.     }
  289.  
  290.     /** Get a list of a user's neighbours on last.fm.
  291.      *
  292.      * @param    string    $user    The last.fm username to fetch the neighbours of. (Required)
  293.      * @param    integer    $limit    An integer used to limit the number of neighbours returned. (Optional)
  294.      * @return    array            An array of Track objects.
  295.      *
  296.      * @static
  297.      * @access    public
  298.      * @throws    Error
  299.      */
  300.     public static function getNeighbours($user$limit null){
  301.         $xml CallerFactory::getDefaultCaller()->call('user.getNeighbours'array(
  302.             'user'  => $user,
  303.             'limit' => $limit
  304.         ));
  305.  
  306.         $neighbours array();
  307.  
  308.         foreach($xml->children(as $neighbour){
  309.             $neighbours[User::fromSimpleXMLElement($neighbour);
  310.         }
  311.  
  312.         return $neighbours;
  313.     }
  314.  
  315.     /** Get a paginated list of all events a user has attended in the past.
  316.      *
  317.      * @param    string    $user    The username to fetch the events for. (Required)
  318.      * @param    integer    $limit    The number of events to return per page. (Optional)
  319.      * @param    integer    $page    The page number to scan to. (Optional)
  320.      * @return    PaginatedResult    A PaginatedResult object.
  321.      * @see        PaginatedResult
  322.      *
  323.      * @static
  324.      * @access    public
  325.      * @throws    Error
  326.      */
  327.     public static function getPastEvents($user$limit null$page null){
  328.         $xml CallerFactory::getDefaultCaller()->call('user.getPastEvents'array(
  329.             'user'  => $user,
  330.             'limit' => $limit,
  331.             'page'  => $page
  332.         ));
  333.  
  334.         $events array();
  335.  
  336.         foreach($xml->children(as $event){
  337.             $events[Event::fromSimpleXMLElement($event);
  338.         }
  339.  
  340.         $perPage Util::toInteger($xml['perPage']);
  341.  
  342.         return new PaginatedResult(
  343.             Util::toInteger($xml['total']),
  344.             (Util::toInteger($xml['page']1$perPage,
  345.             $perPage,
  346.             $events
  347.         );
  348.     }
  349.  
  350.     /** Get a list of a user's playlists on last.fm.
  351.      *
  352.      * @param    string    $user    The last.fm username to fetch the playlists of. (Required)
  353.      * @return    array            An array of Playlist objects.
  354.      *
  355.      * @static
  356.      * @access    public
  357.      * @throws    Error
  358.      */
  359.     public static function getPlaylists($user){
  360.         $xml CallerFactory::getDefaultCaller()->call('user.getPlaylists'array(
  361.             'user' => $user
  362.         ));
  363.  
  364.         $playlists array();
  365.  
  366.         foreach($xml->children(as $playlist){
  367.             $playlists[Playlist::fromSimpleXMLElement($playlist);
  368.         }
  369.  
  370.         return $playlist;
  371.     }
  372.  
  373.     /** Get a list of the recent tracks listened to by this user. Indicates now playing track if the user is currently listening.
  374.      *
  375.      * @param    string    $user    The last.fm username to fetch the recent tracks of. (Required)
  376.      * @param    integer    $limit    An integer used to limit the number of tracks returned. (Optional)
  377.      * @return    array            An array of Playlist objects.
  378.      *
  379.      * @static
  380.      * @access    public
  381.      * @throws    Error
  382.      */
  383.     public static function getRecentTracks($user$limit null){
  384.         $xml CallerFactory::getDefaultCaller()->call('user.getRecentTracks'array(
  385.             'user'  => $user,
  386.             'limit' => $limit
  387.         ));
  388.  
  389.         $tracks array();
  390.  
  391.         foreach($xml->children(as $track){
  392.             $tracks[Track::fromSimpleXMLElement($track);
  393.         }
  394.  
  395.         return $tracks;
  396.     }
  397.  
  398.     /** Get Last.fm artist recommendations for a user.
  399.      *
  400.      * @param    integer    $limit    The number of events to return per page. (Optional)
  401.      * @param    integer    $page    The page number to scan to. (Optional)
  402.      * @return    PaginatedResult    A PaginatedResult object.
  403.      *
  404.      * @static
  405.      * @access    public
  406.      * @throws    Error
  407.      */
  408.     public static function getRecommendedArtists($limit null$page null$session){
  409.         $xml CallerFactory::getDefaultCaller()->signedCall('user.getRecommendedArtists'array(
  410.             'limit' => $limit,
  411.             'page'  => $page
  412.         )$session);
  413.  
  414.         $artists array();
  415.  
  416.         foreach($xml->children(as $artist){
  417.             $artists[Artist::fromSimpleXMLElement($artist);
  418.         }
  419.  
  420.         $perPage Util::toInteger($xml['perPage']);
  421.  
  422.         return new PaginatedResult(
  423.             Util::toInteger($xml['total']),
  424.             (Util::toInteger($xml['page']1$perPage,
  425.             $perPage,
  426.             $artists
  427.         );
  428.     }
  429.  
  430.     /** Get a paginated list of all events recommended to a user by last.fm, based on their listening profile.
  431.      *
  432.      * @param    integer    $limit    The number of events to return per page. (Optional)
  433.      * @param    integer    $page    The page number to scan to. (Optional)
  434.      * @return    PaginatedResult    A PaginatedResult object.
  435.      *
  436.      * @static
  437.      * @access    public
  438.      * @throws    Error
  439.      */
  440.     public static function getRecommendedEvents($limit null$page null$session){
  441.         $xml CallerFactory::getDefaultCaller()->signedCall('user.getRecommendedEvents'array(
  442.             'limit' => $limit,
  443.             'page'  => $page
  444.         )$session);
  445.  
  446.         $events array();
  447.  
  448.         foreach($xml->children(as $event){
  449.             $events[Event::fromSimpleXMLElement($event);
  450.         }
  451.  
  452.         $perPage Util::toInteger($xml['perPage']);
  453.  
  454.         return new PaginatedResult(
  455.             Util::toInteger($xml['total']),
  456.             (Util::toInteger($xml['page']1$perPage,
  457.             $perPage,
  458.             $events
  459.         );
  460.     }
  461.  
  462.     /** Get shouts for this user.
  463.      *
  464.      * @param    string    $user    The username to fetch shouts for. (Required)
  465.      * @return    array            An array of Shout objects.
  466.      *
  467.      * @static
  468.      * @access    public
  469.      * @throws    Error
  470.      */
  471.     public static function getShouts($user){
  472.         $xml CallerFactory::getDefaultCaller()->call('user.getShouts'array(
  473.             'user' => $user
  474.         ));
  475.  
  476.         $shouts array();
  477.  
  478.         foreach($xml->children(as $shout){
  479.             $shouts[Shout::fromSimpleXMLElement($shout);
  480.         }
  481.  
  482.         return $shouts;
  483.     }
  484.  
  485.     /** Get the top albums listened to by a user. You can stipulate a time period. Sends the overall chart by default.
  486.      *
  487.      * @param    string    $user    The user name to fetch top albums for. (Required)
  488.      * @param    integer    $period    The time period over which to retrieve top albums for. (Optional)
  489.      * @return    array            An array of Album objects.
  490.      *
  491.      * @static
  492.      * @access    public
  493.      * @throws    Error
  494.      */
  495.     public static function getTopAlbums($user$period null){
  496.         $xml CallerFactory::getDefaultCaller()->call('user.getTopAlbums'array(
  497.             'user'   => $user,
  498.             'period' => $period
  499.         ));
  500.  
  501.         $albums array();
  502.  
  503.         foreach($xml->children(as $album){
  504.             $albums[Album::fromSimpleXMLElement($album);
  505.         }
  506.  
  507.         return $albums;
  508.     }
  509.  
  510.     /** Get the top artists listened to by a user. You can stipulate a time period. Sends the overall chart by default.
  511.      *
  512.      * @param    string    $user    The user name to fetch top artists for. (Required)
  513.      * @param    integer    $period    The time period over which to retrieve top artists for. (Optional)
  514.      * @return    array            An array of Artist objects.
  515.      *
  516.      * @static
  517.      * @access    public
  518.      * @throws    Error
  519.      */
  520.     public static function getTopArtists($user$period null){
  521.         $xml CallerFactory::getDefaultCaller()->call('user.getTopArtists'array(
  522.             'user'   => $user,
  523.             'period' => $period
  524.         ));
  525.  
  526.         $artists array();
  527.  
  528.         foreach($xml->children(as $artist){
  529.             $artists[Artist::fromSimpleXMLElement($artist);
  530.         }
  531.  
  532.         return $artists;
  533.     }
  534.  
  535.     /** Get the top tags used by this user.
  536.      *
  537.      * @param    string    $user    The user name to fetch top tags for. (Required)
  538.      * @param    integer    $limit    Limit the number of tags returned. (Optional)
  539.      * @return    array            An array of Tag objects.
  540.      *
  541.      * @static
  542.      * @access    public
  543.      * @throws    Error
  544.      */
  545.     public static function getTopTags($user$limit null){
  546.         $xml CallerFactory::getDefaultCaller()->call('user.getTopTags'array(
  547.             'user'  => $user,
  548.             'limit' => $limit
  549.         ));
  550.  
  551.         $tags array();
  552.  
  553.         foreach($xml->children(as $tag){
  554.             $tags[Tag::fromSimpleXMLElement($tag);
  555.         }
  556.  
  557.         return $tags;
  558.     }
  559.  
  560.     /** Get the top tracks listened to by a user. You can stipulate a time period. Sends the overall chart by default.
  561.      *
  562.      * @param    string    $user    The user name to fetch top tracks for. (Required)
  563.      * @param    integer    $period    The time period over which to retrieve top tracks for. (Optional)
  564.      * @return    array            An array of Track objects.
  565.      *
  566.      * @static
  567.      * @access    public
  568.      * @throws    Error
  569.      */
  570.     public static function getTopTracks($user$period null){
  571.         $xml CallerFactory::getDefaultCaller()->call('user.getTopTracks'array(
  572.             'user'   => $user,
  573.             'period' => $period
  574.         ));
  575.  
  576.         $tracks array();
  577.  
  578.         foreach($xml->children(as $track){
  579.             $tracks[Track::fromSimpleXMLElement($track);
  580.         }
  581.  
  582.         return $tracks;
  583.     }
  584.  
  585.     /** Get an album chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent album chart for this user.
  586.      *
  587.      * @param    string    $user    The last.fm username to fetch the charts of. (Required)
  588.       * @param    string    $from    The date at which the chart should start from. See {@link de.felixbruns.lastfm.User#getWeeklyChartList User::getWeeklyChartList} for more. (Optional)
  589.      * @param    string    $to        The date at which the chart should end on. See {@link de.felixbruns.lastfm.User#getWeeklyChartList User::getWeeklyChartList} for more. (Optional)
  590.      * @return    array            An array of Album objects.
  591.      *
  592.      * @static
  593.      * @access    public
  594.      * @throws    Error
  595.      */
  596.     public static function getWeeklyAlbumChart($user$from null$to null){
  597.         $xml CallerFactory::getDefaultCaller()->call('user.getWeeklyAlbumChart'array(
  598.             'user' => $user,
  599.             'from' => $from,
  600.             'to'   => $to
  601.         ));
  602.  
  603.         $albums array();
  604.  
  605.         foreach($xml->children(as $album){
  606.             $albums[Album::fromSimpleXMLElement($album);
  607.         }
  608.  
  609.         return $albums;
  610.     }
  611.  
  612.     /** Get an artist chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent artist chart for this user.
  613.      *
  614.      * @param    string    $user    The last.fm username to fetch the charts of. (Required)
  615.       * @param    string    $from    The date at which the chart should start from. See {@link de.felixbruns.lastfm.User#getWeeklyChartList User::getWeeklyChartList} for more. (Optional)
  616.      * @param    string    $to        The date at which the chart should end on. See {@link de.felixbruns.lastfm.User#getWeeklyChartList User::getWeeklyChartList} for more. (Optional)
  617.      * @return    array            An array of Artist objects.
  618.      *
  619.      * @static
  620.      * @access    public
  621.      * @throws    Error
  622.      */
  623.     public static function getWeeklyArtistChart($user$from null$to null){
  624.         $xml CallerFactory::getDefaultCaller()->call('user.getWeeklyArtistChart'array(
  625.             'user' => $user,
  626.             'from' => $from,
  627.             'to'   => $to
  628.         ));
  629.  
  630.         $artists array();
  631.  
  632.         foreach($xml->children(as $artist){
  633.             $artists[Artist::fromSimpleXMLElement($artist);
  634.         }
  635.  
  636.         return $artists;
  637.     }
  638.  
  639.     /** Get a list of available charts for this user, expressed as date ranges which can be sent to the chart services.
  640.      *
  641.      * @param    string    $user    The last.fm username to fetch the charts list for. (Required)
  642.      * @return    array            An array of from/to unix timestamp pairs.
  643.      *
  644.      * @static
  645.      * @access    public
  646.      * @throws    Error
  647.      */
  648.     public static function getWeeklyChartList($user$from null$to null){
  649.         $xml CallerFactory::getDefaultCaller()->call('user.getWeeklyChartList'array(
  650.             'user' => $user
  651.         ));
  652.  
  653.         $chartList array();
  654.  
  655.         foreach($xml->children(as $chart){
  656.             $chartList[array(
  657.                 'from' => Util::toInteger($chart['from']),
  658.                 'to'   => Util::toInteger($chart['to']),
  659.             );
  660.         }
  661.  
  662.         return $chartList;
  663.     }
  664.  
  665.     /** Get a track chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent track chart for this user.
  666.      *
  667.      * @param    string    $user    The last.fm username to fetch the charts of. (Required)
  668.       * @param    string    $from    The date at which the chart should start from. See {@link de.felixbruns.lastfm.User#getWeeklyChartList User::getWeeklyChartList} for more. (Optional)
  669.      * @param    string    $to        The date at which the chart should end on. See {@link de.felixbruns.lastfm.User#getWeeklyChartList User::getWeeklyChartList} for more. (Optional)
  670.      * @return    array            An array of Track objects.
  671.      *
  672.      * @static
  673.      * @access    public
  674.      * @throws    Error
  675.      */
  676.     public static function getWeeklyTrackChart($user$from null$to null){
  677.         $xml CallerFactory::getDefaultCaller()->call('user.getWeeklyTrackChart'array(
  678.             'user' => $user,
  679.             'from' => $from,
  680.             'to'   => $to
  681.         ));
  682.  
  683.         $tracks array();
  684.  
  685.         foreach($xml->children(as $track){
  686.             $tracks[Track::fromSimpleXMLElement($track);
  687.         }
  688.  
  689.         return $tracks;
  690.     }
  691.  
  692.     /** Create a User object from a SimpleXMLElement.
  693.      *
  694.      * @param    SimpleXMLElement    $xml    A SimpleXMLElement.
  695.      * @return    User                        A User object.
  696.      *
  697.      * @static
  698.      * @access    public
  699.      * @internal
  700.      */
  701.     public static function fromSimpleXMLElement(SimpleXMLElement $xml){
  702.         $images array();
  703.  
  704.         foreach($xml->image as $image){
  705.             $images[Util::toImageType($image['size'])Util::toString($image);
  706.         }
  707.  
  708.         return new User(
  709.             Util::toString($xml->name),
  710.             Util::toString($xml->url),
  711.             Util::toString($xml->lang),
  712.             Util::toString($xml->country),
  713.             Util::toInteger($xml->age),
  714.             Util::toString($xml->gender),
  715.             Util::toInteger($xml->subscriber),
  716.             Util::toInteger($xml->playcount),
  717.             Util::toInteger($xml->playlists),
  718.             $images,
  719.             ($xml->recenttrack)?
  720.                 Track::fromSimpleXMLElement($xml->recenttrack):null,
  721.             Util::toFloat($xml->match),
  722.             Util::toInteger($xml->weight)
  723.         );
  724.     }
  725. }
  726.  
  727. ?>

Documentation generated on Mon, 22 Dec 2008 16:57:51 +0100 by phpDocumentor 1.4.1