Index: /extensions/flickr2piwigo/admin.php
===================================================================
--- /extensions/flickr2piwigo/admin.php	(revision 16063)
+++ /extensions/flickr2piwigo/admin.php	(revision 16063)
@@ -0,0 +1,35 @@
+<?php
+if (!defined('FLICKR_PATH')) die('Hacking attempt!');
+
+global $template, $page, $conf;
+
+$conf['flickr2piwigo'] = unserialize($conf['flickr2piwigo']);
+load_language('plugin.lang', FLICKR_PATH);
+
+if (!file_exists(FLICKR_FS_CACHE))
+{
+  mdir(FLICKR_FS_CACHE, 0755);
+}
+
+// tabsheet
+include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+$page['tab'] = (isset($_GET['tab'])) ? $_GET['tab'] : $page['tab'] = 'import';
+  
+$tabsheet = new tabsheet();
+$tabsheet->add('import', l10n('Import'), FLICKR_ADMIN . '-import');
+$tabsheet->add('config', l10n('Configuration'), FLICKR_ADMIN . '-config');
+$tabsheet->select($page['tab']);
+$tabsheet->assign();
+
+// include page
+include(FLICKR_PATH . 'admin/' . $page['tab'] . '.php');
+
+// template
+$template->assign(array(
+  'FLICKR_PATH'=> FLICKR_PATH,
+  'FLICKR_ABS_PATH'=> dirname(__FILE__).'/',
+  'FLICKR_ADMIN' => FLICKR_ADMIN,
+  ));
+$template->assign_var_from_handle('ADMIN_CONTENT', 'flickr2piwigo');
+
+?>
Index: /extensions/flickr2piwigo/admin/config.php
===================================================================
--- /extensions/flickr2piwigo/admin/config.php	(revision 16063)
+++ /extensions/flickr2piwigo/admin/config.php	(revision 16063)
@@ -0,0 +1,27 @@
+<?php
+if (!defined('FLICKR_PATH')) die('Hacking attempt!');
+
+if (isset($_POST['save_config']))
+{
+  $conf['flickr2piwigo'] = array(
+    'api_key' => trim($_POST['api_key']),
+    'secret_key' => trim($_POST['secret_key']),
+    'username' => trim($_POST['username']),
+    );
+  unset($_SESSION['phpFlickr_auth_token']);
+  conf_update_param('flickr2piwigo', serialize($conf['flickr2piwigo']));
+}
+
+
+$template->assign('flickr2piwigo', $conf['flickr2piwigo']);
+
+$template->assign(array(
+  'FLICKR_HELP_CONTENT' => load_language('help_api_key.html', FLICKR_PATH, array('return'=>true)),
+  'FLICKR_CALLBACK' => get_absolute_root_url().FLICKR_ADMIN.'-import',
+  ));
+
+
+$template->set_filename('flickr2piwigo', dirname(__FILE__).'/template/config.tpl');
+
+
+?>
Index: /extensions/flickr2piwigo/admin/import.php
===================================================================
--- /extensions/flickr2piwigo/admin/import.php	(revision 16063)
+++ /extensions/flickr2piwigo/admin/import.php	(revision 16063)
@@ -0,0 +1,288 @@
+<?php
+if (!defined('FLICKR_PATH')) die('Hacking attempt!');
+
+// check API parameters and connect to flickr
+if (empty($conf['flickr2piwigo']['api_key']) or empty($conf['flickr2piwigo']['secret_key']) or empty($conf['flickr2piwigo']['username']))
+{
+  array_push($page['warnings'], l10n('Please fill your API keys on the configuration tab'));
+  $_GET['action'] = 'error';
+}
+else
+{
+  // init flickr API
+  include_once(FLICKR_PATH . 'include/phpFlickr/phpFlickr.php');
+  $flickr = new phpFlickr($conf['flickr2piwigo']['api_key'], $conf['flickr2piwigo']['secret_key']);
+  $flickr->enableCache('fs', FLICKR_FS_CACHE);
+  
+  // must authenticate
+  if (empty($_SESSION['phpFlickr_auth_token']) and @$_GET['action']!='login')
+  {
+    $_GET['action'] = 'init_login';
+  }
+  else
+  {
+    // get user id
+    $u = $flickr->people_findByUsername($conf['flickr2piwigo']['username']);
+    if ($u === false)
+    {
+      array_push($page['errors'], l10n('Unknown username, please verify your configuration'));
+      $_GET['action'] = 'error';
+    }
+  }
+  
+  
+  // generate token after authentication
+  if (!empty($_GET['frob']))
+  {
+    $flickr->auth_getToken($_GET['frob']);
+    $_GET['action'] = 'logued';
+  }
+}
+
+if (!isset($_GET['action'])) $_GET['action'] = 'choice';
+
+
+switch ($_GET['action'])
+{
+  // button to login page
+  case 'init_login':
+  {
+    $template->assign('flickr_login', FLICKR_ADMIN.'-import&amp;action=login');
+    break;
+  }
+  
+  // call flickr login procedure
+  case 'login':
+  {
+    $flickr->auth('read', false);
+    break;
+  }
+  
+  // message after login
+  case 'logued':
+  {
+    $_SESSION['page_infos'][] = l10n('Successfully logued to you Flickr account');
+    redirect(FLICKR_ADMIN.'-import');
+    break;
+  }
+  
+  // main menu
+  case 'choice':
+  {
+    $template->assign('list_albums_url', FLICKR_ADMIN.'-import&amp;action=list_albums');
+    $template->assign('import_all_url', FLICKR_ADMIN.'-import&amp;action=list_all');
+    break;
+  }
+  
+  // list user albums
+  case 'list_albums':
+  {
+    // all albums
+    $albums = $flickr->photosets_getList($u['id']);
+    $total_albums = $albums['total'];
+    $albums = $albums['photoset'];
+    
+    foreach ($albums as &$album)
+    {
+      //$album['U_IMPORT_ALL'] = FLICKR_ADMIN.'-import&amp;action=import_album&amp;album='.$album['id'];
+      $album['U_LIST'] = FLICKR_ADMIN.'-import&amp;action=list_photos&amp;album='.$album['id'];
+    }
+    unset($album);
+    
+    // not classed
+    $wo_albums = $flickr->photos_getNotInSet(NULL, NULL, NULL, NULL, 'photos', NULL, NULL, 1);
+    if ($wo_albums['photos']['total'] > 0)
+    {
+      array_push($albums, array(
+        'id' => 'not_in_set',
+        'title' => l10n('Pictures without album'),
+        'description' => null,
+        'photos' => $wo_albums['photos']['total'],
+        //'U_IMPORT_ALL' => FLICKR_ADMIN.'-import&amp;action=import_album&amp;album='.$album['id'],
+        'U_LIST' => FLICKR_ADMIN.'-import&amp;action=list_photos&amp;album=not_in_set',
+        ));
+    }
+    
+    $template->assign(array(
+      'total_albums' => $total_albums,
+      'albums' => $albums,
+      ));
+    break;
+  }
+  
+  // list photos of an album
+  case 'list_photos':
+  {
+    if (isset($_GET['start']))   $page['start'] = intval($_GET['start']);
+    else                         $page['start'] = 0;
+    if (isset($_GET['display'])) $page['display'] = $_GET['display']=='all' ? 500 : intval($_GET['display']);
+    else                         $page['display'] = 20;
+    
+    $self_url = FLICKR_ADMIN.'-import&amp;action=list_photos&amp;album='.$_GET['album'];
+    $flickr_prefix = 'flickr-'.$conf['flickr2piwigo']['username'].'-';
+    $flickr_root_url = $flickr->urls_getUserPhotos($u['id']);
+    
+    // get existing photos
+    $query = '
+SELECT id, file
+  FROM '.IMAGES_TABLE.'
+  WHERE file LIKE "'.$flickr_prefix.'%"
+;';
+    $existing_photos = simple_hash_from_query($query, 'id', 'file');
+    $existing_photos = array_map(create_function('$p', '$p=preg_replace("#^'.$flickr_prefix.'([0-9]+)\.([a-z]{3,4})$#i", "$1", $p); return $p;'), $existing_photos);
+    
+    // get photos
+    if ($_GET['album'] == 'not_in_set')
+    {
+      $all_photos = $flickr->photos_getNotInSet(NULL, NULL, NULL, NULL, 'photos', NULL, NULL, 500);
+      $all_photos = $all_photos['photos']['photo'];
+    }
+    else
+    {
+      $all_photos = $flickr->photosets_getPhotos($_GET['album'], NULL, NULL, 500, NULL, 'photos');
+      $all_photos = $all_photos['photoset']['photo'];
+    }
+    
+    // remove existing
+    $duplicates = 0;
+    foreach ($all_photos as $i => $photo)
+    {
+      if (in_array($photo['id'], $existing_photos))
+      {
+        unset($all_photos[$i]);
+        $duplicates++;
+      }
+    }
+    if ($duplicates>0)
+    {
+      array_push($page['infos'], l10n_dec('One picture is not displayed because already existing in the database.', '%d pictures are not displayed because already existing in the database.', $duplicates));
+    }
+    
+    // displayed photos
+    $page_photos = array_slice($all_photos, $page['start'], $page['display']);
+    $all_elements = array_map(create_function('$p', 'return  \'"\'.$p["id"].\'"\';'), $all_photos);
+    
+    foreach ($page_photos as &$photo)
+    {
+      $photo['thumb'] = $flickr->buildPhotoURL($photo, "thumbnail");
+      $photo['src'] = $flickr->get_biggest_size($photo['id'], "medium_800");
+      $photo['url'] = $flickr_root_url.$photo['id'];
+    }
+    unset($photo);
+    
+    $template->assign(array(
+      'nb_thumbs_set' => count($all_photos),
+      'nb_thumbs_page' => count($page_photos),
+      'thumbnails' => $page_photos,
+      'all_elements' => $all_elements,
+      'album' => $_GET['album'],
+      'F_ACTION' => FLICKR_ADMIN.'-import&amp;action=import_set',
+      'U_DISPLAY' => $self_url,
+      ));
+      
+    // get piwigo categories
+    $query = '
+SELECT id, name, uppercats, global_rank
+  FROM '.CATEGORIES_TABLE.'
+;';
+    display_select_cat_wrapper($query, array(), 'associate_options', true);
+    display_select_cat_wrapper($query, array(), 'category_parent_options');
+    
+    // get navbar
+    $nav_bar = create_navigation_bar(
+      $self_url,
+      count($all_elements),
+      $page['start'],
+      $page['display']
+      );
+    $template->assign('navbar', $nav_bar);
+    break;
+  }
+    
+  case 'list_all':
+  {
+    $flickr_prefix = 'flickr-'.$conf['flickr2piwigo']['username'].'-';
+    
+    // get all photos in all albums
+    $all_albums = $flickr->photosets_getList($u['id']);
+    $all_albums = $all_albums['photoset'];
+    
+    $all_photos = array();
+    foreach ($all_albums as &$album)
+    {
+      $album_photos = $flickr->photosets_getPhotos($album['id'], NULL, NULL, 500, NULL, 'photos');
+      $album_photos = $album_photos['photoset']['photo'];
+      
+      foreach ($album_photos as &$photo)
+      {
+        $all_photos[ $photo['id'] ][] = $album['title'];
+      }
+      unset($photo);
+    }
+    unset($album);
+    
+    // get existing photos
+    $query = '
+SELECT id, file
+  FROM '.IMAGES_TABLE.'
+  WHERE file LIKE "'.$flickr_prefix.'%"
+;';
+    $existing_photos = simple_hash_from_query($query, 'id', 'file');
+    $existing_photos = array_map(create_function('$p', '$p=preg_replace("#^'.$flickr_prefix.'([0-9]+)\.([a-z]{3,4})$#i", "$1", $p); return $p;'), $existing_photos);
+    
+    // remove duplicates
+    $duplicates = 0;
+    foreach ($all_photos as $id => &$photo)
+    {
+      if (in_array($id, $existing_photos))
+      {
+        unset($all_photos[$id]);
+        $duplicates++;
+      }
+      else
+      {
+        $photo = array(
+          'id' => $id,
+          'albums' => implode(',', $photo),
+          );
+      }
+    }
+    unset($photo);
+    if ($duplicates>0)
+    {
+      array_push($page['infos'], l10n_dec('%d picture is not displayed because already existing in the database.', '%d pictures are not displayed because already existing in the database.', $duplicates));
+    }
+    $all_photos = array_values($all_photos);
+    
+    $template->assign(array(
+      'nb_elements' => count($all_photos),
+      'all_elements' => json_encode($all_photos),
+      'F_ACTION' => FLICKR_ADMIN.'-import&amp;action=import_set',
+      ));
+      
+    // get piwigo categories
+    $query = '
+SELECT id, name, uppercats, global_rank
+  FROM '.CATEGORIES_TABLE.'
+;';
+    display_select_cat_wrapper($query, array(), 'associate_options', true);
+    display_select_cat_wrapper($query, array(), 'category_parent_options');
+    break;
+  }
+  
+  // success message after import
+  case 'import_set':
+  {
+    if (isset($_POST['done']))
+    {
+      $_SESSION['page_infos'][] = sprintf(l10n('%d pictures imported'), $_POST['done']);
+    }
+    redirect(FLICKR_ADMIN.'-import');
+  }
+}
+
+$template->assign('ACTION', $_GET['action']);
+
+$template->set_filename('flickr2piwigo', dirname(__FILE__).'/template/import.tpl');
+
+?>
Index: /extensions/flickr2piwigo/admin/index.php
===================================================================
--- /extensions/flickr2piwigo/admin/index.php	(revision 16063)
+++ /extensions/flickr2piwigo/admin/index.php	(revision 16063)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | 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                                          |
+// |                                                                       |
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/flickr2piwigo/admin/template/config.tpl
===================================================================
--- /extensions/flickr2piwigo/admin/template/config.tpl	(revision 16063)
+++ /extensions/flickr2piwigo/admin/template/config.tpl	(revision 16063)
@@ -0,0 +1,44 @@
+{combine_css path=$FLICKR_PATH|@cat:"admin/template/style.css"}
+
+<div class="titrePage">
+	<h2>Flickr2Piwigo</h2>
+</div>
+
+<form method="post" action="" class="properties">
+<fieldset>
+  <legend>{'Flickr logins'|@translate}</legend>
+  
+  <ul>
+    <li>
+      <label>
+        <span class="property">{'API key'|@translate}</span>
+        <input type="text" name="api_key" value="{$flickr2piwigo.api_key}" size="40">
+      </label>
+    </li>
+
+    <li>
+      <label>
+        <span class="property">{'API secret'|@translate}</span>
+        <input type="text" name="secret_key" value="{$flickr2piwigo.secret_key}" size="20">
+      </label>
+    </li>
+
+    <li>
+      <label>
+        <span class="property">{'Username'|@translate}</span>
+        <input type="text" name="username" value="{$flickr2piwigo.username}" size="20"></label>
+      </label>
+    </li>
+  </ul>
+</fieldset>
+
+<p><input type="submit" name="save_config" value="{'Save Settings'|@translate}"></p>
+
+<fieldset>
+  <legend>{'How do I get my Flickr API key?'|@translate}</legend>
+  
+  <p><b>{'Callback URL'|@translate} :</b> <span style="font-family:monospace;font-size:14px;">{$FLICKR_CALLBACK}</span></p>
+  {$FLICKR_HELP_CONTENT}
+</fieldset>
+  
+</form>
Index: /extensions/flickr2piwigo/admin/template/import.list_all.tpl
===================================================================
--- /extensions/flickr2piwigo/admin/template/import.list_all.tpl	(revision 16063)
+++ /extensions/flickr2piwigo/admin/template/import.list_all.tpl	(revision 16063)
@@ -0,0 +1,136 @@
+{include file='include/colorbox.inc.tpl'}
+{include file='include/add_album.inc.tpl'}
+{combine_script id='jquery.ajaxmanager' load='footer' path='themes/default/js/plugins/jquery.ajaxmanager.js'}
+{combine_script id='jquery.jgrowl' load='footer' require='jquery' path='themes/default/js/plugins/jquery.jgrowl_minimized.js'}
+{combine_css path="admin/themes/default/uploadify.jGrowl.css"}
+
+{footer_script require='jquery.ajaxmanager,jquery.jgrowl'}
+/* global vars */
+var errorHead   = '{'ERROR'|@translate|@escape:'javascript'}';
+var errorMsg    = '{'an error happened'|@translate|@escape:'javascript'}';
+var successHead = '{'Success'|@translate|@escape:'javascript'}';
+
+var import_done = 0;
+var import_selected = {$nb_elements};
+var queuedManager = jQuery.manageAjax.create('queued', {ldelim}
+  queue: true,  
+  maxRequests: 1
+});
+
+{literal}
+/* import queue */
+function performImport(photo, album, fills) {
+  queuedManager.add({
+    type: 'GET',
+    dataType: 'json',
+    url: 'ws.php',
+    data: { method: 'pwg.images.addFlickr', id: photo, category: album, fills: fills, format: 'json' },
+    success: function(data) {
+      if (data['stat'] == 'ok') {
+        jQuery.jGrowl(data['result'], { theme: 'success', header: successHead, life: 4000, sticky: false });
+        jQuery("#photo-"+photo.id).fadeOut(function(){ $(this).remove(); });
+      } else {
+        jQuery.jGrowl(data['result'], { theme: 'error', header: errorHead, sticky: true });
+      }
+      
+      import_done++;
+      $("#progress").html(import_done +"/"+ import_selected);
+      
+      if (import_done == import_selected) {
+        $("#import_form").append('<input type="hidden" name="done" value="' + import_done + '">');
+        $("#import_form").submit();
+      }
+    },
+    error: function(data) {
+      jQuery.jGrowl(errorMsg, { theme: 'error', header: errorHead, sticky: true });
+    }
+  });
+}
+
+
+$(document).ready(function() {
+  //var all_elements = jQuery.parseJSON('{/literal}{$all_elements}{literal}');
+  var all_elements = {/literal}{$all_elements}{literal};
+  
+  /* begin import */
+  jQuery('#beginImport').click(function() {
+    $("#loader_import").fadeIn();
+    
+    if ($("input[name='album_mode']").val() == 'identical') {
+      var album = 0;
+    } else {
+      var album = $("#albumSelect option:selected").val();
+    }
+    
+    var fills = '';
+    $("input[name^='fill_']:checked").each(function() {
+      fills+= $(this).attr("name") +',';
+    }); 
+    
+    import_selected = all_elements.length;
+    $("#progress").html("0/"+ import_selected);
+    
+    for (var i in all_elements) {
+      if (album == 0) this_album = all_elements[i]['albums'];
+      else            this_album = album;
+      
+      performImport(all_elements[i]['id'], this_album, fills);
+    }
+    
+    return false;
+  });
+  
+  /* album mode */
+  $("input[name='album_mode']").change(function() {
+    if ($(this).val() == 'one_album') {
+      $("#albumSelectWrapper").slideDown();
+    } else {
+      $("#albumSelectWrapper").slideUp();
+    }
+  });
+});
+{/literal}
+{/footer_script}
+
+<form action="{$F_ACTION}" method="post" id="import_form">
+
+  <fieldset>
+    <legend>{'Selection'|@translate}</legend>
+
+  {if $nb_elements}
+    {'%d elements ready for importation'|@translate|@sprintf:$nb_elements}
+  {else}
+    <div>{'No photo in the current set.'|@translate}</div>
+  {/if}
+  </fieldset>
+  
+  <fieldset>
+    <legend>{'Import options'|@translate}</legend>
+    
+    <p>
+      <label><input type="radio" name="album_mode" value="identical" checked="checked"> {'Reproduce flickr albums'|@translate}</label><br>
+      <label><input type="radio" name="album_mode" value="one_album"> {'Import all photos in this album'|@translate} :</label>
+    </p>
+
+    <p id="albumSelectWrapper" style="display:none;">
+      <select style="width:400px" name="associate" id="albumSelect" size="1">
+        {html_options options=$associate_options}
+      </select>
+      {'... or '|@translate}<a href="#" class="addAlbumOpen" title="{'create a new album'|@translate}">{'create a new album'|@translate}</a>
+    </p>
+    
+    <p>
+      {'Fill these fields from Flickr datas'|@translate} :
+      <label><input type="checkbox" name="fill_name" checked="checked"> {'Photo name'|@translate}</label>
+      <label><input type="checkbox" name="fill_author" checked="checked"> {'Author'|@translate}</label>
+      <label><input type="checkbox" name="fill_tags" checked="checked"> {'Tags'|@translate}</label>
+      <label><input type="checkbox" name="fill_taken" checked="checked"> {'Creation date'|@translate}</label>
+      <label><input type="checkbox" name="fill_posted"> {'Post date'|@translate}</label>
+    </p>
+    
+    <p>
+      <input type="submit" name="import_set" id="beginImport" value="{'Begin transfert'|@translate}" {if not $nb_elements}style="display:none;"{/if}>
+      <span id="loader_import" style="display:none;"><img src="admin/themes/default/images/ajax-loader.gif"> <i>{'Processing...'|@translate}</i> <span id="progress"></span></span>
+    </p>
+  </fieldset>
+</form>
Index: /extensions/flickr2piwigo/admin/template/import.list_photos.tpl
===================================================================
--- /extensions/flickr2piwigo/admin/template/import.list_photos.tpl	(revision 16063)
+++ /extensions/flickr2piwigo/admin/template/import.list_photos.tpl	(revision 16063)
@@ -0,0 +1,428 @@
+{include file='include/colorbox.inc.tpl'}
+{include file='include/add_album.inc.tpl'}
+{combine_script id='jquery.ajaxmanager' load='footer' path='themes/default/js/plugins/jquery.ajaxmanager.js'}
+{combine_script id='jquery.jgrowl' load='footer' require='jquery' path='themes/default/js/plugins/jquery.jgrowl_minimized.js'}
+{combine_css path="admin/themes/default/uploadify.jGrowl.css"}
+
+{footer_script require='jquery.ajaxmanager,jquery.jgrowl'}
+/* global vars */
+var nb_thumbs_page = {$nb_thumbs_page};
+var nb_thumbs_set = {$nb_thumbs_set};
+var all_elements = [{if !empty($all_elements)}{','|@implode:$all_elements}{/if}];
+
+var errorHead   = '{'ERROR'|@translate|@escape:'javascript'}';
+var errorMsg    = '{'an error happened'|@translate|@escape:'javascript'}';
+var successHead = '{'Success'|@translate|@escape:'javascript'}';
+var selectedMessage_pattern = "{'%d of %d photos selected'|@translate}";
+var selectedMessage_none = "{'No photo selected, %d photos in current set'|@translate}";
+var selectedMessage_all = "{'All %d photos are selected'|@translate}";
+var applyOnDetails_pattern = "{'on the %d selected photos'|@translate}";
+
+var import_done = 0;
+var import_selected = 0;
+var queuedManager = jQuery.manageAjax.create('queued', {ldelim}
+  queue: true,  
+  maxRequests: 1
+});
+
+{literal}
+/* Shift-click: select all photos between the click and the shift+click */
+jQuery(document).ready(function() {
+  var last_clicked=0;
+  var last_clickedstatus=true;
+  jQuery.fn.enableShiftClick = function() {
+    var inputs = [];
+    var count=0;
+    var This=$(this);
+    this.find('input[type=checkbox]').each(function() {
+      var pos=count;
+      inputs[count++]=this;
+      $(this).bind("shclick", function (dummy,event) {
+        if (event.shiftKey) {
+          var first = last_clicked;
+          var last = pos;
+          if (first > last) {
+            first=pos;
+            last=last_clicked;
+          }
+
+          for (var i=first; i<=last;i++) {
+            input = $(inputs[i]);
+            $(input).attr('checked', last_clickedstatus);
+            if (last_clickedstatus)
+            {
+              $(input).siblings("span.wrap2").addClass("thumbSelected");
+            }
+            else
+            {
+              $(input).siblings("span.wrap2").removeClass("thumbSelected");
+            }
+          }
+        }
+        else {
+          last_clicked = pos;
+          last_clickedstatus = this.checked;
+        }
+        return true;
+      });
+      $(this).click(function(event) {console.log(event.shiftKey);$(this).triggerHandler("shclick",event)});
+    });
+  }
+});
+
+/* sprintf */
+function str_repeat(i, m) {
+    for (var o = []; m > 0; o[--m] = i);
+    return o.join('');
+}
+
+function sprintf() {
+  var i = 0, a, f = arguments[i++], o = [], m, p, c, x, s = '';
+  while (f) {
+    if (m = /^[^\x25]+/.exec(f)) {
+      o.push(m[0]);
+    }
+    else if (m = /^\x25{2}/.exec(f)) {
+      o.push('%');
+    }
+    else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) {
+      if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) {
+        throw('Too few arguments.');
+      }
+      if (/[^s]/.test(m[7]) && (typeof(a) != 'number')) {
+        throw('Expecting number but found ' + typeof(a));
+      }
+      switch (m[7]) {
+        case 'b': a = a.toString(2); break;
+        case 'c': a = String.fromCharCode(a); break;
+        case 'd': a = parseInt(a); break;
+        case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break;
+        case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break;
+        case 'o': a = a.toString(8); break;
+        case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break;
+        case 'u': a = Math.abs(a); break;
+        case 'x': a = a.toString(16); break;
+        case 'X': a = a.toString(16).toUpperCase(); break;
+      }
+      a = (/[def]/.test(m[7]) && m[2] && a >= 0 ? '+'+ a : a);
+      c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' ';
+      x = m[5] - String(a).length - s.length;
+      p = m[5] ? str_repeat(c, x) : '';
+      o.push(s + (m[4] ? a + p : p + a));
+    }
+    else {
+      throw('Huh ?!');
+    }
+    f = f.substring(m[0].length);
+  }
+  return o.join('');
+}
+
+/* update displaying */
+function checkPermitAction() {
+  var nbSelected = 0;
+  if ($("input[name=setSelected]").is(':checked')) {
+    nbSelected = nb_thumbs_set;
+  } else {
+    $(".thumbnails input[type=checkbox]").each(function() {
+      if ($(this).is(':checked')) nbSelected++;
+    });
+  }
+
+  if (nbSelected == 0) {
+    $("#beginImport").hide();
+  } else {
+    $("#beginImport").show();
+  }
+
+  $("#applyOnDetails").text(
+    sprintf(
+      applyOnDetails_pattern,
+      nbSelected
+    )
+  );
+
+  // display the number of currently selected photos in the "Selection" fieldset
+  if (nbSelected == 0) {
+    $("#selectedMessage").text(
+      sprintf(
+        selectedMessage_none,
+        nb_thumbs_set
+      )
+    );
+  } else if (nbSelected == nb_thumbs_set) {
+    $("#selectedMessage").text(
+      sprintf(
+        selectedMessage_all,
+        nb_thumbs_set
+      )
+    );
+  } else {
+    $("#selectedMessage").text(
+      sprintf(
+        selectedMessage_pattern,
+        nbSelected,
+        nb_thumbs_set
+      )
+    );
+  }
+}
+
+/* import queue */
+function performImport(photo, album, fills) {
+  queuedManager.add({
+    type: 'GET',
+    dataType: 'json',
+    url: 'ws.php',
+    data: { method: 'pwg.images.addFlickr', id: photo, category: album, fills: fills, format: 'json' },
+    success: function(data) {
+      if (data['stat'] == 'ok') {
+        jQuery.jGrowl(data['result'], { theme: 'success', header: successHead, life: 4000, sticky: false });
+        jQuery("#photo-"+photo).fadeOut(function(){ $(this).remove(); });
+      } else {
+        jQuery.jGrowl(data['result'], { theme: 'error', header: errorHead, sticky: true });
+      }
+      
+      import_done++;
+      $("#progress").html(import_done +"/"+ import_selected);
+      
+      if (import_done == import_selected) {
+        $("#import_form").append('<input type="hidden" name="done" value="' + import_done + '">');
+        $("#import_form").submit();
+      }
+    },
+    error: function(data) {
+      jQuery.jGrowl(errorMsg, { theme: 'error', header: errorHead, sticky: true });
+    }
+  });
+}
+
+
+$(document).ready(function() {
+  checkPermitAction();
+  $("a.preview-box").colorbox();
+  $('ul.thumbnails').enableShiftClick();
+
+  /* tiptip */
+  $('img.thumbnail').tipTip({
+    'delay' : 0,
+    'fadeIn' : 200,
+    'fadeOut' : 200
+  });
+
+  /* thumbnail click */
+  $(".wrap1 label").click(function (event) {
+    $("input[name=setSelected]").attr('checked', false);
+
+    var wrap2 = $(this).children(".wrap2");
+    var checkbox = $(this).children("input[type=checkbox]");
+
+    checkbox.triggerHandler("shclick",event);
+
+    if ($(checkbox).is(':checked')) {
+      $(wrap2).addClass("thumbSelected"); 
+    }
+    else {
+      $(wrap2).removeClass('thumbSelected'); 
+    }
+
+    checkPermitAction();
+  });
+
+  /* select all */
+  $("#selectAll").click(function () {
+    $("input[name=setSelected]").attr('checked', false);
+    
+    $(".thumbnails label").each(function() {
+      var wrap2 = $(this).children(".wrap2");
+      var checkbox = $(this).children("input[type=checkbox]");
+
+      $(checkbox).attr('checked', true);
+      $(wrap2).addClass("thumbSelected"); 
+    });
+    
+    checkPermitAction();
+    return false;
+  });
+
+  /* select none */
+  $("#selectNone").click(function () {
+    $("input[name=setSelected]").attr('checked', false);
+    
+    $(".thumbnails label").each(function() {
+      var wrap2 = $(this).children(".wrap2");
+      var checkbox = $(this).children("input[type=checkbox]");
+
+      $(checkbox).attr('checked', false);
+      $(wrap2).removeClass("thumbSelected"); 
+    });
+    
+    checkPermitAction();
+    return false;
+  });
+
+  /* select invert */
+  $("#selectInvert").click(function () {
+    $("input[name=setSelected]").attr('checked', false);
+    
+    $(".thumbnails label").each(function() {
+      var wrap2 = $(this).children(".wrap2");
+      var checkbox = $(this).children("input[type=checkbox]");
+
+      $(checkbox).attr('checked', !$(checkbox).is(':checked'));
+
+      if ($(checkbox).is(':checked')) {
+        $(wrap2).addClass("thumbSelected"); 
+      } else {
+        $(wrap2).removeClass('thumbSelected'); 
+      }
+    });
+    
+    checkPermitAction();
+    return false;
+  }); 
+  
+  /* select set */
+  $("#selectSet").click(function () {
+    $("input[name=setSelected]").attr('checked', true);
+    
+    $(".thumbnails label").each(function() {
+      var wrap2 = $(this).children(".wrap2");
+      var checkbox = $(this).children("input[type=checkbox]");
+
+      $(checkbox).attr('checked', true);
+      $(wrap2).addClass("thumbSelected"); 
+    });
+    
+    checkPermitAction();
+    return false;
+  });
+ 
+  /* begin import */
+  jQuery('#beginImport').click(function() {
+    $("#loader_import").fadeIn();
+    var album = $("#albumSelect option:selected").val();
+    
+    var fills = '';
+    $("input[name^='fill_']:checked").each(function() {
+      fills+= $(this).attr("name") +',';
+    }); 
+    
+    if (jQuery('input[name="setSelected"]').attr('checked')) {
+      import_selected = all_elements.length;
+      $("#progress").html("0/"+ import_selected);
+      
+      for (var i in all_elements) {
+        performImport(all_elements[i], album, fills);
+      }
+		} else {
+      import_selected = $("input[name='selection[]']:checked").length;
+      $("#progress").html("0/"+ import_selected);
+      
+			jQuery("input[name='selection[]']:checked").each(function() {
+        performImport(jQuery(this).attr('value'), album, fills);
+      });
+    }
+    
+    return false;
+  });
+  
+  /* pagination loader */
+  jQuery('#navigation a').click(function() {
+    $("#loader_display").fadeIn()
+  });
+});
+{/literal}
+{/footer_script}
+
+<div id="batchManagerGlobal">
+<form action="{$F_ACTION}" method="post" id="import_form">
+
+  <fieldset>
+    <legend>{'Selection'|@translate}</legend>
+
+  {if !empty($thumbnails)}
+    <p id="checkActions">
+      {'Select:'|@translate}
+    {if $nb_thumbs_set > $nb_thumbs_page}
+      <a href="#" id="selectAll">{'The whole page'|@translate}</a>,
+      <a href="#" id="selectSet">{'The whole set'|@translate}</a>,
+    {else}
+      <a href="#" id="selectAll">{'All'|@translate}</a>,
+    {/if}
+      <a href="#" id="selectNone">{'None'|@translate}</a>,
+      <a href="#" id="selectInvert">{'Invert'|@translate}</a>
+
+      <span id="selectedMessage"></span>
+      <input type="checkbox" name="setSelected" style="display:none">
+      <span id="loader_display" style="display:none;"><img src="admin/themes/default/images/ajax-loader.gif"> <i>{'Processing...'|@translate}</i></span>
+    </p>
+
+    <ul class="thumbnails">
+      {foreach from=$thumbnails item=thumbnail}
+			<li id="photo-{$thumbnail.id}">
+				<span class="wrap1">
+					<label>
+						<span class="wrap2">
+						<div class="actions"><a href="{$thumbnail.src}" class="preview-box">{'Zoom'|@translate}</a> &middot; <a href="{$thumbnail.url}" target="_blank" title="{'Open Flickr page in a new tab'|@translate}">Flickr</a></div>
+							<span>
+								<img src="{$thumbnail.thumb}" alt="{$thumbnail.title}" title="{$thumbnail.title|@escape:'html'}" class="thumbnail">
+							</span>
+						</span>
+						<input type="checkbox" name="selection[]" value="{$thumbnail.id}">
+					</label>
+				</span>
+			</li>
+      {/foreach}
+    </ul>
+    
+    
+    <div style="clear:both;" id="navigation">
+    {if !empty($navbar) }
+      <div style="float:left">
+      {include file='navigation_bar.tpl'|@get_extent:'navbar'}
+      </div>
+    {/if}
+    
+      <div style="float:right;margin-top:10px;">{'display'|@translate}
+        <a href="{$U_DISPLAY}&amp;display=20">20</a>
+        &middot; <a href="{$U_DISPLAY}&amp;display=50">50</a>
+        &middot; <a href="{$U_DISPLAY}&amp;display=100">100</a>
+        &middot; <a href="{$U_DISPLAY}&amp;display=all">{'all'|@translate}</a>
+        {'photos per page'|@translate}
+      </div>
+    </div>
+
+  {else}
+    <div>{'No photo in the current set.'|@translate}</div>
+  {/if}
+  </fieldset>
+  
+  <fieldset>
+    <legend>{'Import options'|@translate}</legend>
+
+    <p>
+      <label for="albumSelect">{'Album'|@translate} :</label>
+      <select style="width:400px" name="associate" id="albumSelect" size="1">
+        {html_options options=$associate_options}
+      </select>
+      {'... or '|@translate}<a href="#" class="addAlbumOpen" title="{'create a new album'|@translate}">{'create a new album'|@translate}</a>
+    </p>
+    
+    <p>
+      {'Fill these fields from Flickr datas'|@translate} :
+      <label><input type="checkbox" name="fill_name" checked="checked"> {'Photo name'|@translate}</label>
+      <label><input type="checkbox" name="fill_author" checked="checked"> {'Author'|@translate}</label>
+      <label><input type="checkbox" name="fill_tags" checked="checked"> {'Tags'|@translate}</label>
+      <label><input type="checkbox" name="fill_taken" checked="checked"> {'Creation date'|@translate}</label>
+      <label><input type="checkbox" name="fill_posted"> {'Post date'|@translate}</label>
+    </p>
+
+    <p>
+      <input type="hidden" name="album" value="{$album}">
+      <input type="submit" name="import_set" id="beginImport" value="{'Begin transfert'|@translate}" style="display:none;">
+      <span id="loader_import" style="display:none;"><img src="admin/themes/default/images/ajax-loader.gif"> <i>{'Processing...'|@translate}</i> <span id="progress"></span></span>
+    </p>
+  </fieldset>
+</form>
+</div>
Index: /extensions/flickr2piwigo/admin/template/import.tpl
===================================================================
--- /extensions/flickr2piwigo/admin/template/import.tpl	(revision 16063)
+++ /extensions/flickr2piwigo/admin/template/import.tpl	(revision 16063)
@@ -0,0 +1,34 @@
+{combine_css path=$FLICKR_PATH|@cat:"admin/template/style.css"}
+
+<div class="titrePage">
+	<h2>Flickr2Piwigo</h2>
+</div>
+
+{if $ACTION == 'init_login'}
+<p><a href="{$flickr_login}">{'Login'|@translate}</a></p>
+
+{elseif $ACTION == 'choice'}
+<p>
+  <a href="{$list_albums_url}">{'List my albums'|@translate}</a> -
+  <a href="{$import_all_url}">{'Import all my pictures'|@translate}</a>
+</p>
+
+{elseif $ACTION == 'list_albums'}
+<h3>{'%d albums'|@translate}|@sprintf:$total_albums}</h3>
+<ul>
+{foreach from=$albums item=album}
+  <li>
+    <b><a href="{$album.U_LIST}">{$album.title}</a></b> <i>{'(%d photos)'|@translate|@sprintf:$album.photos}</i> 
+    {*- <a href="{$album.U_IMPORT_ALL}">{'Import all pictures of this album'|@translate}</a>*}
+    {*<p>{$album.description}</p>*}
+  </li>
+{/foreach}
+</ul>
+
+{elseif $ACTION == 'list_photos'}
+{include file=$FLICKR_ABS_PATH|@cat:'admin/template/import.list_photos.tpl'}
+
+{elseif $ACTION == 'list_all'}
+{include file=$FLICKR_ABS_PATH|@cat:'admin/template/import.list_all.tpl'}
+
+{/if}
Index: /extensions/flickr2piwigo/admin/template/index.php
===================================================================
--- /extensions/flickr2piwigo/admin/template/index.php	(revision 16063)
+++ /extensions/flickr2piwigo/admin/template/index.php	(revision 16063)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | 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                                          |
+// |                                                                       |
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/flickr2piwigo/include/index.php
===================================================================
--- /extensions/flickr2piwigo/include/index.php	(revision 16063)
+++ /extensions/flickr2piwigo/include/index.php	(revision 16063)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | 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                                          |
+// |                                                                       |
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/flickr2piwigo/include/phpFlickr/README.txt
===================================================================
--- /extensions/flickr2piwigo/include/phpFlickr/README.txt	(revision 16063)
+++ /extensions/flickr2piwigo/include/phpFlickr/README.txt	(revision 16063)
@@ -0,0 +1,215 @@
+phpFlickr Class 3.0
+Written by Dan Coulter (dancoulter@users.sourceforge.net)
+Project Homepage: http://www.phpflickr.com/
+Google Code Project Page: http://code.google.com/p/phpflickr/
+Released under GNU Lesser General Public License (http://www.gnu.org/copyleft/lgpl.html)
+For more information about the class and upcoming tools and applications using it,
+visit http://www.phpflickr.com/ or http://code.google.com/p/phpflickr/
+
+If you are interested in hiring me for a project (involving phpFlickr
+or not), feel free to email me.
+
+Installation instructions:
+1.  Copy the files from the installation package into a folder on your
+    server.  They need to be readible by your web server.  You can put 
+    them into an include folder defined in your php.ini file, if you 
+    like, though it's not required. 
+    
+2.  All you have to do now is include the file in your PHP scripts and 
+    create an instance.  For example:
+    $f = new phpFlickr();
+
+    The constructor has three arguments:
+    A.  $api_key - This is the API key given to you by flickr.com. This 
+        argument is required and you can get an API Key at:
+        http://www.flickr.com/services/api/key.gne
+        
+    B.  $secret - The "secret" is optional because is not required to 
+        make unauthenticated calls, but is absolutely required for the 
+        new authentication API (see Authentication section below).  You 
+        will get one assigned alongside your api key.
+    
+    C.  $die_on_error - This takes a boolean value and determines 
+        whether the class will die (aka cease operation) if the API 
+        returns an error statement.  It defaults to false.  Every method 
+        will return false if the API returns an error.  You can access 
+        error messages using the getErrorCode() and getErrorMsg() 
+        methods.
+        
+3.  All of the API methods have been implemented in my class.  You can 
+    see a full list and documentation here: 
+        http://www.flickr.com/services/api/
+    To call a method, remove the "flickr." part of the name and replace 
+    any periods with underscores. For example, instead of 
+    flickr.photos.search, you would call $f->photos_search() or instead 
+    of flickr.photos.licenses.getInfo, you would call 
+    $f->photos_licenses_getInfo() (yes, it is case sensitive).
+    
+    All functions have their arguments implemented in the list order on 
+    their documentation page (a link to which is included with each 
+    method in the phpFlickr clasS). The only exceptions to this are 
+    photos_search(), photos_getWithoutGeodata() and 
+    photos_getWithoutGeodata() which have so many optional arguments
+    that it's easier for everyone if you just have to pass an 
+    associative array of arguments.  See the comment in the 
+    photos_search() definition in phpFlickr.php for more information.
+    
+
+    
+Authentication:
+    As of this release of the phpFlickr class there is only one authentication method
+    available to the API.  This method is somewhat complex, but is far more secure and
+    allows your users to feel a little safer authenticating to your application.  You'll
+    no longer have to ask for their username and password.
+    
+    Authentication API - http://www.flickr.com/services/api/auth.spec.html
+        
+        I know how complicated this API looks at first glance, so I've tried to
+        make this as transparent to the coding process.  I'll go through the steps
+        you'll need to use this.  Both the auth.php and getToken.php file will
+        need your API Key and Secret entered before you can use them.
+        
+        To have end users authenticate their accounts:
+            First, setup a callback script.  I've included a callback script that 
+            is pretty flexible.  You'll find it in the package entitled "auth.php".  
+            You'll need to go to flickr and point your api key to this file as the 
+            callback script.  Once you've done this, on any page that you want to 
+            require the end user end user to authenticate their flickr account to 
+            your app, just call the phpFlickr::auth() function with whatever 
+            permission you need to use.
+            For example:
+                $f->auth("write");
+            The three permissions are "read", "write" and "delete".  The function
+            defaults to "read", if you leave it blank.  
+            
+            Calling this function will send the user's browser to Flickr's page to 
+            authenticate to your app.  Once they have logged in, it will bounce
+            them back to your callback script which will redirect back to the
+            original page that you called the auth() function from after setting
+            a session variable to save their authentication token.  If that session
+            variable exists, calling the auth() function will return the permissions
+            that the user granted your app on the Flickr page instead of redirecting
+            to an external page.
+        
+        To authenticate the app to your account to show your private pictures (for example)
+            This method will allow you to have the app authenticate to one specific
+            account, no matter who views your website.  This is useful to display
+            private photos or photosets (among other things).
+            
+            *Note*: The method below is a little hard to understand, so I've setup a tool
+            to help you through this: http://www.phpflickr.com/tools/auth/.
+                        
+            First, you'll have to setup a callback script with Flickr.  Once you've
+            done that, edit line 12 of the included getToken.php file to reflect 
+            which permissions you'll need for the app.  Then browse to the page.
+            Once you've authorized the app with Flickr, it'll send you back to that
+            page which will give you a token which will look something like this:
+                1234-567890abcdef1234
+            Go to the file where you are creating an instance of phpFlickr (I suggest
+            an include file) and after you've created it set the token to use:
+                $f->setToken("<token string>");
+            This token never expires, so you don't have to worry about having to
+            login periodically.
+            
+
+Using Caching:
+    Caching can be very important to a project.  Just a few calls to the Flickr API
+    can take long enough to bore your average web user (depending on the calls you
+    are making).  I've built in caching that will access either a database or files
+    in your filesystem.  To enable caching, use the phpFlickr::enableCache() function.
+    This function requires at least two arguments. The first will be the type of
+    cache you're using (either "db" or "fs")
+    
+    1.  If you're using database caching, you'll need to supply a PEAR::DB connection
+        string. For example: 
+        $flickr->enableCache("db", "mysql://user:password@server/database");
+        The third (optional) argument is expiration of the cache in seconds (defaults 
+        to 600).  The fourth (optional) argument is the table where you want to store
+        the cache.  This defaults to flickr_cache and will attempt to create the table
+        if it does not already exist.
+    
+    2.  If you're using filesystem caching, you'll need to supply a folder where the
+        web server has write access. For example: 
+        $flickr->enableCache("fs", "/var/www/phpFlickrCache");
+        The third (optional) argument is, the same as in the Database caching, an
+        expiration in seconds for the cache.
+        Note: filesystem caching will probably be slower than database caching. I
+        haven't done any tests of this, but if you get large amounts of calls, the
+        process of cleaning out old calls may get hard on your server.
+        
+        You may not want to allow the world to view the files that are created during
+        caching.  If you want to hide this information, either make sure that your
+        permissions are set correctly, or disable the webserver from displaying 
+        *.cache files.  In Apache, you can specify this in the configuration files
+        or in a .htaccess file with the following directives:
+        
+        <FilesMatch "\.cache$">
+            Deny from all
+        </FilesMatch>
+        
+        Alternatively, you can specify a directory that is outside of the web server's
+        document root.
+        
+Uploading
+    Uploading is pretty simple. Aside from being authenticated (see Authentication 
+    section) the very minimum that you'll have to pass is a path to an image file on 
+    your php server. You can do either synchronous or asynchronous uploading as follows:
+        synchronous:    sync_upload("photo.jpg");
+        asynchronous:   async_upload("photo.jpg");
+    
+    The basic difference is that synchronous uploading waits around until Flickr
+    processes the photo and returns a PhotoID.  Asynchronous just uploads the
+    picture and gets a "ticketid" that you can use to check on the status of your 
+    upload. Asynchronous is much faster, though the photoid won't be instantly
+    available for you. You can read more about asynchronous uploading here:
+        http://www.flickr.com/services/api/upload.async.html
+        
+    Both of the functions take the same arguments which are:
+        Photo: The path of the file to upload.
+        Title: The title of the photo.
+        Description: A description of the photo. May contain some limited HTML.
+        Tags: A space-separated list of tags to apply to the photo.
+        is_public: Set to 0 for no, 1 for yes.
+        is_friend: Set to 0 for no, 1 for yes.
+        is_family: Set to 0 for no, 1 for yes.
+        
+Replacing Photos
+    Flickr has released API support for uploading a replacement photo.  To use this
+    new method, just use the "replace" function in phpFlickr.  You'll be required
+    to pass the file name and Flickr's photo ID.  You need to authenticate your script
+    with "write" permissions before you can replace a photo.  The arguments are:
+        Photo: The path of the file to upload.
+        Photo ID: The numeric Flickr ID of the photo you want to replace.
+        Async (optional): Set to 0 for a synchronous call, 1 for asynchronous.
+    If you use the asynchronous call, it will return a ticketid instead
+    of photoid.
+
+Other Notes:
+    1.  Many of the methods have optional arguments.  For these, I have implemented 
+        them in the same order that the Flickr API documentation lists them. PHP
+        allows for optional arguments in function calls, but if you want to use the
+        third optional argument, you have to fill in the others to the left first.
+        You can use the "NULL" value (without quotes) in the place of an actual
+        argument.  For example:
+        $f->groups_pools_getPhotos($group_id, NULL, NULL, 10);
+        This will get the first ten photos from a specific group's pool.  If you look
+        at the documentation, you will see that there is another argument, "page". I've
+        left it off because it appears after "per_page".
+    2.  Some people will need to ues phpFlickr from behind a proxy server.  I've
+        implemented a method that will allow you to use an HTTP proxy for all of your
+        traffic.  Let's say that you have a proxy server on your local server running
+        at port 8181.  This is the code you would use:
+            $f = new phpFlickr("[api key]");
+            $f->setProxy("localhost", "8181");
+        After that, all of your calls will be automatically made through your proxy server.
+            
+
+That's it! Enjoy the class.  Check out the project page (listed above) for updates
+and news.  I plan to implement file uploads and functions to aggregate data from
+several different methods for easier use in a web application.  Thanks for your
+interest in this project!
+
+    Please email me if you have any questions or problems. You'll find my email
+	at the top of this file.
+
+ 
Index: /extensions/flickr2piwigo/include/phpFlickr/getToken.php
===================================================================
--- /extensions/flickr2piwigo/include/phpFlickr/getToken.php	(revision 16063)
+++ /extensions/flickr2piwigo/include/phpFlickr/getToken.php	(revision 16063)
@@ -0,0 +1,19 @@
+<?php
+    /* Last updated with phpFlickr 1.4
+     *
+     * If you need your app to always login with the same user (to see your private
+     * photos or photosets, for example), you can use this file to login and get a
+     * token assigned so that you can hard code the token to be used.  To use this
+     * use the phpFlickr::setToken() function whenever you create an instance of 
+     * the class.
+     */
+
+    require_once("phpFlickr.php");
+    $f = new phpFlickr("<api key>", "<secret>");
+    
+    //change this to the permissions you will need
+    $f->auth("read");
+    
+    echo "Copy this token into your code: " . $_SESSION['phpFlickr_auth_token'];
+    
+?>
Index: /extensions/flickr2piwigo/include/phpFlickr/phpFlickr.php
===================================================================
--- /extensions/flickr2piwigo/include/phpFlickr/phpFlickr.php	(revision 16063)
+++ /extensions/flickr2piwigo/include/phpFlickr/phpFlickr.php	(revision 16063)
@@ -0,0 +1,1855 @@
+<?php
+/* phpFlickr Class 3.1
+ * Written by Dan Coulter (dan@dancoulter.com)
+ * Project Home Page: http://phpflickr.com/
+ * Released under GNU Lesser General Public License (http://www.gnu.org/copyleft/lgpl.html)
+ * For more information about the class and upcoming tools and toys using it,
+ * visit http://www.phpflickr.com/
+ *
+ *	 For installation instructions, open the README.txt file packaged with this
+ *	 class. If you don't have a copy, you can see it at:
+ *	 http://www.phpflickr.com/README.txt
+ *
+ *	 Please submit all problems or questions to the Help Forum on my Google Code project page:
+ *		 http://code.google.com/p/phpflickr/issues/list
+ *
+ * Modified on June 25th 2012 by Mistic (http://www.strangeplanet.fr) :
+ *    - add get_biggest_size() method
+ *    - update buildPhotoURL() methos with all available sizes
+ *
+ */ 
+if ( !class_exists('phpFlickr') ) {
+	if (session_id() == "") {
+		@session_start();
+	}
+
+	class phpFlickr {
+		var $api_key;
+		var $secret;
+		
+		var $rest_endpoint = 'http://api.flickr.com/services/rest/';
+		var $upload_endpoint = 'http://api.flickr.com/services/upload/';
+		var $replace_endpoint = 'http://api.flickr.com/services/replace/';
+		var $req;
+		var $response;
+		var $parsed_response;
+		var $cache = false;
+		var $cache_db = null;
+		var $cache_table = null;
+		var $cache_dir = null;
+		var $cache_expire = null;
+		var $cache_key = null;
+		var $last_request = null;
+		var $die_on_error;
+		var $error_code;
+		Var $error_msg;
+		var $token;
+		var $php_version;
+		var $custom_post = null, $custom_cache_get = null, $custom_cache_set = null;
+
+		/*
+		 * When your database cache table hits this many rows, a cleanup
+		 * will occur to get rid of all of the old rows and cleanup the
+		 * garbage in the table.  For most personal apps, 1000 rows should
+		 * be more than enough.  If your site gets hit by a lot of traffic
+		 * or you have a lot of disk space to spare, bump this number up.
+		 * You should try to set it high enough that the cleanup only
+		 * happens every once in a while, so this will depend on the growth
+		 * of your table.
+		 */
+		var $max_cache_rows = 1000;
+
+		function phpFlickr ($api_key, $secret = NULL, $die_on_error = false) {
+			//The API Key must be set before any calls can be made.  You can
+			//get your own at http://www.flickr.com/services/api/misc.api_keys.html
+			$this->api_key = $api_key;
+			$this->secret = $secret;
+			$this->die_on_error = $die_on_error;
+			$this->service = "flickr";
+
+			//Find the PHP version and store it for future reference
+			$this->php_version = explode("-", phpversion());
+			$this->php_version = explode(".", $this->php_version[0]);
+		}
+
+		function enableCache ($type, $connection, $cache_expire = 600, $table = 'flickr_cache') {
+			// Turns on caching.  $type must be either "db" (for database caching) or "fs" (for filesystem).
+			// When using db, $connection must be a PEAR::DB connection string. Example:
+			//	  "mysql://user:password@server/database"
+			// If the $table, doesn't exist, it will attempt to create it.
+			// When using file system, caching, the $connection is the folder that the web server has write
+			// access to. Use absolute paths for best results.  Relative paths may have unexpected behavior
+			// when you include this.  They'll usually work, you'll just want to test them.
+			if ($type == 'db') {
+				if ( preg_match('|mysql://([^:]*):([^@]*)@([^/]*)/(.*)|', $connection, $matches) ) {
+					//Array ( [0] => mysql://user:password@server/database [1] => user [2] => password [3] => server [4] => database ) 
+					$db = mysql_connect($matches[3], $matches[1], $matches[2]);
+					mysql_select_db($matches[4], $db);
+					
+					/*
+					 * If high performance is crucial, you can easily comment
+					 * out this query once you've created your database table.
+					 */
+					mysql_query("
+						CREATE TABLE IF NOT EXISTS `$table` (
+							`request` CHAR( 35 ) NOT NULL ,
+							`response` MEDIUMTEXT NOT NULL ,
+							`expiration` DATETIME NOT NULL ,
+							INDEX ( `request` )
+						) TYPE = MYISAM
+					", $db);
+					
+					$result = mysql_query("SELECT COUNT(*) FROM $table", $db);
+					$result = mysql_fetch_row($result);
+					if ( $result[0] > $this->max_cache_rows ) {
+						mysql_query("DELETE FROM $table WHERE expiration < DATE_SUB(NOW(), INTERVAL $cache_expire second)", $db);
+						mysql_query('OPTIMIZE TABLE ' . $this->cache_table, $db);
+					}
+					$this->cache = 'db';
+					$this->cache_db = $db;
+					$this->cache_table = $table;
+				}
+			} elseif ($type == 'fs') {
+				$this->cache = 'fs';
+				$connection = realpath($connection);
+				$this->cache_dir = $connection;
+				if ($dir = opendir($this->cache_dir)) {
+					while ($file = readdir($dir)) {
+						if (substr($file, -6) == '.cache' && ((filemtime($this->cache_dir . '/' . $file) + $cache_expire) < time()) ) {
+							unlink($this->cache_dir . '/' . $file);
+						}
+					}
+				}
+			} elseif ( $type == 'custom' ) {
+				$this->cache = "custom";
+				$this->custom_cache_get = $connection[0];
+				$this->custom_cache_set = $connection[1];
+			}
+			$this->cache_expire = $cache_expire;
+		}
+
+		function getCached ($request)
+		{
+			//Checks the database or filesystem for a cached result to the request.
+			//If there is no cache result, it returns a value of false. If it finds one,
+			//it returns the unparsed XML.
+			foreach ( $request as $key => $value ) {
+				if ( empty($value) ) unset($request[$key]);
+				else $request[$key] = (string) $request[$key];
+			}
+			//if ( is_user_logged_in() ) print_r($request);
+			$reqhash = md5(serialize($request));
+			$this->cache_key = $reqhash;
+			$this->cache_request = $request;
+			if ($this->cache == 'db') {
+				$result = mysql_query("SELECT response FROM " . $this->cache_table . " WHERE request = '" . $reqhash . "' AND DATE_SUB(NOW(), INTERVAL " . (int) $this->cache_expire . " SECOND) < expiration", $this->cache_db);
+				if ( mysql_num_rows($result) ) {
+					$result = mysql_fetch_assoc($result);
+					return $result['response'];
+				} else {
+					return false;
+				}
+			} elseif ($this->cache == 'fs') {
+				$file = $this->cache_dir . '/' . $reqhash . '.cache';
+				if (file_exists($file)) {
+					if ($this->php_version[0] > 4 || ($this->php_version[0] == 4 && $this->php_version[1] >= 3)) {
+						return file_get_contents($file);
+					} else {
+						return implode('', file($file));
+					}
+				}
+			} elseif ( $this->cache == 'custom' ) {
+				return call_user_func_array($this->custom_cache_get, array($reqhash));
+			}
+			return false;
+		}
+
+		function cache ($request, $response)
+		{
+			//Caches the unparsed response of a request.
+			unset($request['api_sig']);
+			foreach ( $request as $key => $value ) {
+				if ( empty($value) ) unset($request[$key]);
+				else $request[$key] = (string) $request[$key];
+			}
+			$reqhash = md5(serialize($request));
+			if ($this->cache == 'db') {
+				//$this->cache_db->query("DELETE FROM $this->cache_table WHERE request = '$reqhash'");
+				$result = mysql_query("SELECT COUNT(*) FROM " . $this->cache_table . " WHERE request = '" . $reqhash . "'", $this->cache_db);
+				$result = mysql_fetch_row($result);
+				if ( $result[0] ) {
+					$sql = "UPDATE " . $this->cache_table . " SET response = '" . str_replace("'", "''", $response) . "', expiration = '" . strftime("%Y-%m-%d %H:%M:%S") . "' WHERE request = '" . $reqhash . "'";
+					mysql_query($sql, $this->cache_db);
+				} else {
+					$sql = "INSERT INTO " . $this->cache_table . " (request, response, expiration) VALUES ('$reqhash', '" . str_replace("'", "''", $response) . "', '" . strftime("%Y-%m-%d %H:%M:%S") . "')";
+					mysql_query($sql, $this->cache_db);
+				}
+			} elseif ($this->cache == "fs") {
+				$file = $this->cache_dir . "/" . $reqhash . ".cache";
+				$fstream = fopen($file, "w");
+				$result = fwrite($fstream,$response);
+				fclose($fstream);
+				return $result;
+			} elseif ( $this->cache == "custom" ) {
+				return call_user_func_array($this->custom_cache_set, array($reqhash, $response, $this->cache_expire));
+			}
+			return false;
+		}
+		
+		function setCustomPost ( $function ) {
+			$this->custom_post = $function;
+		}
+		
+		function post ($data, $type = null) {
+			if ( is_null($type) ) {
+				$url = $this->rest_endpoint;
+			}
+			
+			if ( !is_null($this->custom_post) ) {
+				return call_user_func($this->custom_post, $url, $data);
+			}
+			
+			if ( !preg_match("|http://(.*?)(/.*)|", $url, $matches) ) {
+				die('There was some problem figuring out your endpoint');
+			}
+			
+			if ( function_exists('curl_init') ) {
+				// Has curl. Use it!
+				$curl = curl_init($this->rest_endpoint);
+				curl_setopt($curl, CURLOPT_POST, true);
+				curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
+				curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+				$response = curl_exec($curl);
+				curl_close($curl);
+			} else {
+				// Use sockets.
+				foreach ( $data as $key => $value ) {
+					$data[$key] = $key . '=' . urlencode($value);
+				}
+				$data = implode('&', $data);
+			
+				$fp = @pfsockopen($matches[1], 80);
+				if (!$fp) {
+					die('Could not connect to the web service');
+				}
+				fputs ($fp,'POST ' . $matches[2] . " HTTP/1.1\n");
+				fputs ($fp,'Host: ' . $matches[1] . "\n");
+				fputs ($fp,"Content-type: application/x-www-form-urlencoded\n");
+				fputs ($fp,"Content-length: ".strlen($data)."\n");
+				fputs ($fp,"Connection: close\r\n\r\n");
+				fputs ($fp,$data . "\n\n");
+				$response = "";
+				while(!feof($fp)) {
+					$response .= fgets($fp, 1024);
+				}
+				fclose ($fp);
+				$chunked = false;
+				$http_status = trim(substr($response, 0, strpos($response, "\n")));
+				if ( $http_status != 'HTTP/1.1 200 OK' ) {
+					die('The web service endpoint returned a "' . $http_status . '" response');
+				}
+				if ( strpos($response, 'Transfer-Encoding: chunked') !== false ) {
+					$temp = trim(strstr($response, "\r\n\r\n"));
+					$response = '';
+					$length = trim(substr($temp, 0, strpos($temp, "\r")));
+					while ( trim($temp) != "0" && ($length = trim(substr($temp, 0, strpos($temp, "\r")))) != "0" ) {
+						$response .= trim(substr($temp, strlen($length)+2, hexdec($length)));
+						$temp = trim(substr($temp, strlen($length) + 2 + hexdec($length)));
+					}
+				} elseif ( strpos($response, 'HTTP/1.1 200 OK') !== false ) {
+					$response = trim(strstr($response, "\r\n\r\n"));
+				}
+			}
+			return $response;
+		}
+		
+		function request ($command, $args = array(), $nocache = false)
+		{
+			//Sends a request to Flickr's REST endpoint via POST.
+			if (substr($command,0,7) != "flickr.") {
+				$command = "flickr." . $command;
+			}
+
+			//Process arguments, including method and login data.
+			$args = array_merge(array("method" => $command, "format" => "php_serial", "api_key" => $this->api_key), $args);
+			if (!empty($this->token)) {
+				$args = array_merge($args, array("auth_token" => $this->token));
+			} elseif (!empty($_SESSION['phpFlickr_auth_token'])) {
+				$args = array_merge($args, array("auth_token" => $_SESSION['phpFlickr_auth_token']));
+			}
+			ksort($args);
+			$auth_sig = "";
+			$this->last_request = $args;
+			if (!($this->response = $this->getCached($args)) || $nocache) {
+				foreach ($args as $key => $data) {
+					if ( is_null($data) ) {
+						unset($args[$key]);
+						continue;
+					}
+					$auth_sig .= $key . $data;
+				}
+				if (!empty($this->secret)) {
+					$api_sig = md5($this->secret . $auth_sig);
+					$args['api_sig'] = $api_sig;
+				}
+				$this->response = $this->post($args);
+				$this->cache($args, $this->response);
+			}
+			
+			/*
+			 * Uncomment this line (and comment out the next one) if you're doing large queries
+			 * and you're concerned about time.  This will, however, change the structure of
+			 * the result, so be sure that you look at the results.
+			 */
+			//$this->parsed_response = unserialize($this->response);
+			$this->parsed_response = $this->clean_text_nodes(unserialize($this->response));
+			if ($this->parsed_response['stat'] == 'fail') {
+				if ($this->die_on_error) die("The Flickr API returned the following error: #{$this->parsed_response['code']} - {$this->parsed_response['message']}");
+				else {
+					$this->error_code = $this->parsed_response['code'];
+					$this->error_msg = $this->parsed_response['message'];
+					$this->parsed_response = false;
+				}
+			} else {
+				$this->error_code = false;
+				$this->error_msg = false;
+			}
+			return $this->response;
+		}
+
+		function clean_text_nodes ($arr) {
+			if (!is_array($arr)) {
+				return $arr;
+			} elseif (count($arr) == 0) {
+				return $arr;
+			} elseif (count($arr) == 1 && array_key_exists('_content', $arr)) {
+				return $arr['_content'];
+			} else {
+				foreach ($arr as $key => $element) {
+					$arr[$key] = $this->clean_text_nodes($element);
+				}
+				return($arr);
+			}
+		}
+
+		function setToken ($token) {
+			// Sets an authentication token to use instead of the session variable
+			$this->token = $token;
+		}
+
+		function setProxy ($server, $port) {
+			// Sets the proxy for all phpFlickr calls.
+			$this->req->setProxy($server, $port);
+		}
+
+		function getErrorCode () {
+			// Returns the error code of the last call.  If the last call did not
+			// return an error. This will return a false boolean.
+			return $this->error_code;
+		}
+
+		function getErrorMsg () {
+			// Returns the error message of the last call.  If the last call did not
+			// return an error. This will return a false boolean.
+			return $this->error_msg;
+		}
+
+		/* These functions are front ends for the flickr calls */
+    function get_biggest_size($image_id, $limit='original')
+    {
+      $sizes = array(
+        "square"     => "Square",
+        "square_75"  => "Square",
+        "square_150" => "Large Square",
+        "thumbnail"  => "Thumbnail",
+        "small"      => "Small",
+        "small_240"  => "Small",
+        "small_320"  => "Small 320",
+        "medium"     => "Medium",
+        "medium_500" => "Medium",
+        "medium_640" => "Medium 640",
+        "medium_800" => "Medium 800",
+        "large"      => "Large",
+        "large_1024" => "Large",
+        "large_1600" => "Large 1600",
+        "large_2048" => "Large 2048",
+        "original"   => "Original",
+        );
+        
+      if (!array_key_exists($limit, $sizes)) $limit = 'medium';
+      $limit = array_search($limit, array_keys($sizes));
+      
+      $img_sizes = $this->photos_getSizes($image_id);
+      $img_sizes = array_reverse($img_sizes);
+      
+      foreach ($img_sizes as $size)
+      {
+        if ($limit >= array_search($size['label'], array_values($sizes)))
+        {
+          return $size['source'];
+        }
+      }
+      
+      return null;
+    }
+
+		function buildPhotoURL ($photo, $size = "Medium") {
+			//receives an array (can use the individual photo data returned
+			//from an API call) and returns a URL (doesn't mean that the
+			//file size exists)
+			$sizes = array(
+        "square" => "_s",
+        "square_75" => "_s",
+        "square_150" => "_q",
+        "thumbnail" => "_t",
+        "small" => "_m",
+        "small_240" => "_m",
+        "small_320" => "_n",
+        "medium" => "",
+        "medium_500" => "",
+        "medium_640" => "_z",
+        "medium_800" => "_c",
+        "large" => "_b",
+        "large_1024" => "_b",
+        "large_1600" => "_h",
+        "large_2048" => "_k",
+        "original" => "_o",
+			);
+			
+			$size = strtolower($size);
+			if (!array_key_exists($size, $sizes)) {
+				$size = "medium";
+			}
+			
+			if ($size == "original") {
+				$url = "http://farm" . $photo['farm'] . ".static.flickr.com/" . $photo['server'] . "/" . $photo['id'] . "_" . $photo['originalsecret'] . "_o" . "." . $photo['originalformat'];
+			} else {
+				$url = "http://farm" . $photo['farm'] . ".static.flickr.com/" . $photo['server'] . "/" . $photo['id'] . "_" . $photo['secret'] . $sizes[$size] . ".jpg";
+			}
+			return $url;
+		}
+
+		function getFriendlyGeodata ($lat, $lon) {
+			/* I've added this method to get the friendly geodata (i.e. 'in New York, NY') that the
+			 * website provides, but isn't available in the API. I'm providing this service as long
+			 * as it doesn't flood my server with requests and crash it all the time.
+			 */
+			return unserialize(file_get_contents('http://phpflickr.com/geodata/?format=php&lat=' . $lat . '&lon=' . $lon));
+		}
+
+		function sync_upload ($photo, $title = null, $description = null, $tags = null, $is_public = null, $is_friend = null, $is_family = null) {
+			if ( function_exists('curl_init') ) {
+				// Has curl. Use it!
+
+				//Process arguments, including method and login data.
+				$args = array("api_key" => $this->api_key, "title" => $title, "description" => $description, "tags" => $tags, "is_public" => $is_public, "is_friend" => $is_friend, "is_family" => $is_family);
+				if (!empty($this->token)) {
+					$args = array_merge($args, array("auth_token" => $this->token));
+				} elseif (!empty($_SESSION['phpFlickr_auth_token'])) {
+					$args = array_merge($args, array("auth_token" => $_SESSION['phpFlickr_auth_token']));
+				}
+
+				ksort($args);
+				$auth_sig = "";
+				foreach ($args as $key => $data) {
+					if ( is_null($data) ) {
+						unset($args[$key]);
+					} else {
+						$auth_sig .= $key . $data;
+					}
+				}
+				if (!empty($this->secret)) {
+					$api_sig = md5($this->secret . $auth_sig);
+					$args["api_sig"] = $api_sig;
+				}
+
+				$photo = realpath($photo);
+				$args['photo'] = '@' . $photo;
+				
+
+				$curl = curl_init($this->upload_endpoint);
+				curl_setopt($curl, CURLOPT_POST, true);
+				curl_setopt($curl, CURLOPT_POSTFIELDS, $args);
+				curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+				$response = curl_exec($curl);
+				$this->response = $response;
+				curl_close($curl);
+				
+				$rsp = explode("\n", $response);
+				foreach ($rsp as $line) {
+					if (preg_match('|<err code="([0-9]+)" msg="(.*)"|', $line, $match)) {
+						if ($this->die_on_error)
+							die("The Flickr API returned the following error: #{$match[1]} - {$match[2]}");
+						else {
+							$this->error_code = $match[1];
+							$this->error_msg = $match[2];
+							$this->parsed_response = false;
+							return false;
+						}
+					} elseif (preg_match("|<photoid>(.*)</photoid>|", $line, $match)) {
+						$this->error_code = false;
+						$this->error_msg = false;
+						return $match[1];
+					}
+				}
+
+			} else {
+				die("Sorry, your server must support CURL in order to upload files");
+			}
+
+		}
+
+		function async_upload ($photo, $title = null, $description = null, $tags = null, $is_public = null, $is_friend = null, $is_family = null) {
+			if ( function_exists('curl_init') ) {
+				// Has curl. Use it!
+
+				//Process arguments, including method and login data.
+				$args = array("async" => 1, "api_key" => $this->api_key, "title" => $title, "description" => $description, "tags" => $tags, "is_public" => $is_public, "is_friend" => $is_friend, "is_family" => $is_family);
+				if (!empty($this->token)) {
+					$args = array_merge($args, array("auth_token" => $this->token));
+				} elseif (!empty($_SESSION['phpFlickr_auth_token'])) {
+					$args = array_merge($args, array("auth_token" => $_SESSION['phpFlickr_auth_token']));
+				}
+
+				ksort($args);
+				$auth_sig = "";
+				foreach ($args as $key => $data) {
+					if ( is_null($data) ) {
+						unset($args[$key]);
+					} else {
+						$auth_sig .= $key . $data;
+					}
+				}
+				if (!empty($this->secret)) {
+					$api_sig = md5($this->secret . $auth_sig);
+					$args["api_sig"] = $api_sig;
+				}
+
+				$photo = realpath($photo);
+				$args['photo'] = '@' . $photo;
+				
+
+				$curl = curl_init($this->upload_endpoint);
+				curl_setopt($curl, CURLOPT_POST, true);
+				curl_setopt($curl, CURLOPT_POSTFIELDS, $args);
+				curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+				$response = curl_exec($curl);
+				$this->response = $response;
+				curl_close($curl);
+				
+				$rsp = explode("\n", $response);
+				foreach ($rsp as $line) {
+					if (ereg('<err code="([0-9]+)" msg="(.*)"', $line, $match)) {
+						if ($this->die_on_error)
+							die("The Flickr API returned the following error: #{$match[1]} - {$match[2]}");
+						else {
+							$this->error_code = $match[1];
+							$this->error_msg = $match[2];
+							$this->parsed_response = false;
+							return false;
+						}
+					} elseif (ereg("<ticketid>(.*)</", $line, $match)) {
+						$this->error_code = false;
+						$this->error_msg = false;
+						return $match[1];
+					}
+				}
+			} else {
+				die("Sorry, your server must support CURL in order to upload files");
+			}
+		}
+
+		// Interface for new replace API method.
+		function replace ($photo, $photo_id, $async = null) {
+			if ( function_exists('curl_init') ) {
+				// Has curl. Use it!
+
+				//Process arguments, including method and login data.
+				$args = array("api_key" => $this->api_key, "photo_id" => $photo_id, "async" => $async);
+				if (!empty($this->token)) {
+					$args = array_merge($args, array("auth_token" => $this->token));
+				} elseif (!empty($_SESSION['phpFlickr_auth_token'])) {
+					$args = array_merge($args, array("auth_token" => $_SESSION['phpFlickr_auth_token']));
+				}
+
+				ksort($args);
+				$auth_sig = "";
+				foreach ($args as $key => $data) {
+					if ( is_null($data) ) {
+						unset($args[$key]);
+					} else {
+						$auth_sig .= $key . $data;
+					}
+				}
+				if (!empty($this->secret)) {
+					$api_sig = md5($this->secret . $auth_sig);
+					$args["api_sig"] = $api_sig;
+				}
+
+				$photo = realpath($photo);
+				$args['photo'] = '@' . $photo;
+				
+
+				$curl = curl_init($this->replace_endpoint);
+				curl_setopt($curl, CURLOPT_POST, true);
+				curl_setopt($curl, CURLOPT_POSTFIELDS, $args);
+				curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+				$response = curl_exec($curl);
+				$this->response = $response;
+				curl_close($curl);
+				
+				if ($async == 1)
+					$find = 'ticketid';
+				 else
+					$find = 'photoid';
+
+				$rsp = explode("\n", $response);
+				foreach ($rsp as $line) {
+					if (preg_match('|<err code="([0-9]+)" msg="(.*)"|', $line, $match)) {
+						if ($this->die_on_error)
+							die("The Flickr API returned the following error: #{$match[1]} - {$match[2]}");
+						else {
+							$this->error_code = $match[1];
+							$this->error_msg = $match[2];
+							$this->parsed_response = false;
+							return false;
+						}
+					} elseif (preg_match("|<" . $find . ">(.*)</|", $line, $match)) {
+						$this->error_code = false;
+						$this->error_msg = false;
+						return $match[1];
+					}
+				}
+			} else {
+				die("Sorry, your server must support CURL in order to upload files");
+			}
+		}
+
+		function auth ($perms = "read", $remember_uri = true) {
+			// Redirects to Flickr's authentication piece if there is no valid token.
+			// If remember_uri is set to false, the callback script (included) will
+			// redirect to its default page.
+
+			if (empty($_SESSION['phpFlickr_auth_token']) && empty($this->token)) {
+				if ( $remember_uri === true ) {
+					$_SESSION['phpFlickr_auth_redirect'] = $_SERVER['REQUEST_URI'];
+				} elseif ( $remember_uri !== false ) {
+					$_SESSION['phpFlickr_auth_redirect'] = $remember_uri;
+				}
+				$api_sig = md5($this->secret . "api_key" . $this->api_key . "perms" . $perms);
+				
+				if ($this->service == "23") {
+					header("Location: http://www.23hq.com/services/auth/?api_key=" . $this->api_key . "&perms=" . $perms . "&api_sig=". $api_sig);
+				} else {
+					header("Location: http://www.flickr.com/services/auth/?api_key=" . $this->api_key . "&perms=" . $perms . "&api_sig=". $api_sig);
+				}
+				exit;
+			} else {
+				$tmp = $this->die_on_error;
+				$this->die_on_error = false;
+				$rsp = $this->auth_checkToken();
+				if ($this->error_code !== false) {
+          // file_put_contents('et2.txt', $this->error_msg);
+					unset($_SESSION['phpFlickr_auth_token']);
+					$this->auth($perms, $remember_uri);
+				}
+				$this->die_on_error = $tmp;
+				return $rsp['perms'];
+			}
+		}
+
+		/*******************************
+
+		To use the phpFlickr::call method, pass a string containing the API method you want
+		to use and an associative array of arguments.  For example:
+			$result = $f->call("flickr.photos.comments.getList", array("photo_id"=>'34952612'));
+		This method will allow you to make calls to arbitrary methods that haven't been
+		implemented in phpFlickr yet.
+
+		*******************************/
+
+		function call ($method, $arguments) {
+			foreach ( $arguments as $key => $value ) {
+				if ( is_null($value) ) unset($arguments[$key]);
+			}
+			$this->request($method, $arguments);
+			return $this->parsed_response ? $this->parsed_response : false;
+		}
+
+		/*
+			These functions are the direct implementations of flickr calls.
+			For method documentation, including arguments, visit the address
+			included in a comment in the function.
+		*/
+
+		/* Activity methods */
+		function activity_userComments ($per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.activity.userComments.html */
+			$this->request('flickr.activity.userComments', array("per_page" => $per_page, "page" => $page));
+			return $this->parsed_response ? $this->parsed_response['items']['item'] : false;
+		}
+
+		function activity_userPhotos ($timeframe = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.activity.userPhotos.html */
+			$this->request('flickr.activity.userPhotos', array("timeframe" => $timeframe, "per_page" => $per_page, "page" => $page));
+			return $this->parsed_response ? $this->parsed_response['items']['item'] : false;
+		}
+
+		/* Authentication methods */
+		function auth_checkToken () {
+			/* http://www.flickr.com/services/api/flickr.auth.checkToken.html */
+			$this->request('flickr.auth.checkToken');
+			return $this->parsed_response ? $this->parsed_response['auth'] : false;
+		}
+
+		function auth_getFrob () {
+			/* http://www.flickr.com/services/api/flickr.auth.getFrob.html */
+			$this->request('flickr.auth.getFrob');
+			return $this->parsed_response ? $this->parsed_response['frob'] : false;
+		}
+
+		function auth_getFullToken ($mini_token) {
+			/* http://www.flickr.com/services/api/flickr.auth.getFullToken.html */
+			$this->request('flickr.auth.getFullToken', array('mini_token'=>$mini_token));
+			return $this->parsed_response ? $this->parsed_response['auth'] : false;
+		}
+
+		function auth_getToken ($frob) {
+			/* http://www.flickr.com/services/api/flickr.auth.getToken.html */
+			$this->request('flickr.auth.getToken', array('frob'=>$frob));
+			$_SESSION['phpFlickr_auth_token'] = $this->parsed_response['auth']['token'];
+			return $this->parsed_response ? $this->parsed_response['auth'] : false;
+		}
+
+		/* Blogs methods */
+		function blogs_getList ($service = NULL) {
+			/* http://www.flickr.com/services/api/flickr.blogs.getList.html */
+			$rsp = $this->call('flickr.blogs.getList', array('service' => $service));
+			return $rsp['blogs']['blog'];
+		}
+		
+		function blogs_getServices () {
+			/* http://www.flickr.com/services/api/flickr.blogs.getServices.html */
+			return $this->call('flickr.blogs.getServices', array());
+		}
+
+		function blogs_postPhoto ($blog_id = NULL, $photo_id, $title, $description, $blog_password = NULL, $service = NULL) {
+			/* http://www.flickr.com/services/api/flickr.blogs.postPhoto.html */
+			return $this->call('flickr.blogs.postPhoto', array('blog_id' => $blog_id, 'photo_id' => $photo_id, 'title' => $title, 'description' => $description, 'blog_password' => $blog_password, 'service' => $service));
+		}
+
+		/* Collections Methods */
+		function collections_getInfo ($collection_id) {
+			/* http://www.flickr.com/services/api/flickr.collections.getInfo.html */
+			return $this->call('flickr.collections.getInfo', array('collection_id' => $collection_id));
+		}
+
+		function collections_getTree ($collection_id = NULL, $user_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.collections.getTree.html */
+			return $this->call('flickr.collections.getTree', array('collection_id' => $collection_id, 'user_id' => $user_id));
+		}
+		
+		/* Commons Methods */
+		function commons_getInstitutions () {
+			/* http://www.flickr.com/services/api/flickr.commons.getInstitutions.html */
+			return $this->call('flickr.commons.getInstitutions', array());
+		}
+		
+		/* Contacts Methods */
+		function contacts_getList ($filter = NULL, $page = NULL, $per_page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.contacts.getList.html */
+			$this->request('flickr.contacts.getList', array('filter'=>$filter, 'page'=>$page, 'per_page'=>$per_page));
+			return $this->parsed_response ? $this->parsed_response['contacts'] : false;
+		}
+
+		function contacts_getPublicList ($user_id, $page = NULL, $per_page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.contacts.getPublicList.html */
+			$this->request('flickr.contacts.getPublicList', array('user_id'=>$user_id, 'page'=>$page, 'per_page'=>$per_page));
+			return $this->parsed_response ? $this->parsed_response['contacts'] : false;
+		}
+		
+		function contacts_getListRecentlyUploaded ($date_lastupload = NULL, $filter = NULL) {
+			/* http://www.flickr.com/services/api/flickr.contacts.getListRecentlyUploaded.html */
+			return $this->call('flickr.contacts.getListRecentlyUploaded', array('date_lastupload' => $date_lastupload, 'filter' => $filter));
+		}
+
+		/* Favorites Methods */
+		function favorites_add ($photo_id) {
+			/* http://www.flickr.com/services/api/flickr.favorites.add.html */
+			$this->request('flickr.favorites.add', array('photo_id'=>$photo_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function favorites_getList ($user_id = NULL, $jump_to = NULL, $min_fave_date = NULL, $max_fave_date = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.favorites.getList.html */
+			return $this->call('flickr.favorites.getList', array('user_id' => $user_id, 'jump_to' => $jump_to, 'min_fave_date' => $min_fave_date, 'max_fave_date' => $max_fave_date, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+		
+		function favorites_getPublicList ($user_id, $jump_to = NULL, $min_fave_date = NULL, $max_fave_date = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.favorites.getPublicList.html */
+			return $this->call('flickr.favorites.getPublicList', array('user_id' => $user_id, 'jump_to' => $jump_to, 'min_fave_date' => $min_fave_date, 'max_fave_date' => $max_fave_date, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+		
+		function favorites_remove ($photo_id, $user_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.favorites.remove.html */
+			$this->request("flickr.favorites.remove", array('photo_id' => $photo_id, 'user_id' => $user_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		/* Galleries Methods */
+		function galleries_addPhoto ($gallery_id, $photo_id, $comment = NULL) {
+			/* http://www.flickr.com/services/api/flickr.galleries.addPhoto.html */
+			return $this->call('flickr.galleries.addPhoto', array('gallery_id' => $gallery_id, 'photo_id' => $photo_id, 'comment' => $comment));
+		}
+		
+		function galleries_create ($title, $description, $primary_photo_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.galleries.create.html */
+			return $this->call('flickr.galleries.create', array('title' => $title, 'description' => $description, 'primary_photo_id' => $primary_photo_id));
+		}
+
+		function galleries_editMeta ($gallery_id, $title, $description = NULL) {
+			/* http://www.flickr.com/services/api/flickr.galleries.editMeta.html */
+			return $this->call('flickr.galleries.editMeta', array('gallery_id' => $gallery_id, 'title' => $title, 'description' => $description));
+		}
+
+		function galleries_editPhoto ($gallery_id, $photo_id, $comment) {
+			/* http://www.flickr.com/services/api/flickr.galleries.editPhoto.html */
+			return $this->call('flickr.galleries.editPhoto', array('gallery_id' => $gallery_id, 'photo_id' => $photo_id, 'comment' => $comment));
+		}
+
+		function galleries_editPhotos ($gallery_id, $primary_photo_id, $photo_ids) {
+			/* http://www.flickr.com/services/api/flickr.galleries.editPhotos.html */
+			return $this->call('flickr.galleries.editPhotos', array('gallery_id' => $gallery_id, 'primary_photo_id' => $primary_photo_id, 'photo_ids' => $photo_ids));
+		}
+
+		function galleries_getInfo ($gallery_id) {
+			/* http://www.flickr.com/services/api/flickr.galleries.getInfo.html */
+			return $this->call('flickr.galleries.getInfo', array('gallery_id' => $gallery_id));
+		}
+
+		function galleries_getList ($user_id, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.galleries.getList.html */
+			return $this->call('flickr.galleries.getList', array('user_id' => $user_id, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function galleries_getListForPhoto ($photo_id, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.galleries.getListForPhoto.html */
+			return $this->call('flickr.galleries.getListForPhoto', array('photo_id' => $photo_id, 'per_page' => $per_page, 'page' => $page));
+		}
+			
+		function galleries_getPhotos ($gallery_id, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.galleries.getPhotos.html */
+			return $this->call('flickr.galleries.getPhotos', array('gallery_id' => $gallery_id, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		/* Groups Methods */
+		function groups_browse ($cat_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.groups.browse.html */
+			$this->request("flickr.groups.browse", array("cat_id"=>$cat_id));
+			return $this->parsed_response ? $this->parsed_response['category'] : false;
+		}
+
+		function groups_getInfo ($group_id, $lang = NULL) {
+			/* http://www.flickr.com/services/api/flickr.groups.getInfo.html */
+			return $this->call('flickr.groups.getInfo', array('group_id' => $group_id, 'lang' => $lang));
+		}
+
+		function groups_search ($text, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.groups.search.html */
+			$this->request("flickr.groups.search", array("text"=>$text,"per_page"=>$per_page,"page"=>$page));
+			return $this->parsed_response ? $this->parsed_response['groups'] : false;
+		}
+
+		/* Groups Members Methods */
+		function groups_members_getList ($group_id, $membertypes = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.groups.members.getList.html */
+			return $this->call('flickr.groups.members.getList', array('group_id' => $group_id, 'membertypes' => $membertypes, 'per_page' => $per_page, 'page' => $page));
+		}
+		
+		/* Groups Pools Methods */
+		function groups_pools_add ($photo_id, $group_id) {
+			/* http://www.flickr.com/services/api/flickr.groups.pools.add.html */
+			$this->request("flickr.groups.pools.add", array("photo_id"=>$photo_id, "group_id"=>$group_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function groups_pools_getContext ($photo_id, $group_id, $num_prev = NULL, $num_next = NULL) {
+			/* http://www.flickr.com/services/api/flickr.groups.pools.getContext.html */
+			return $this->call('flickr.groups.pools.getContext', array('photo_id' => $photo_id, 'group_id' => $group_id, 'num_prev' => $num_prev, 'num_next' => $num_next));
+		}
+		
+		function groups_pools_getGroups ($page = NULL, $per_page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.groups.pools.getGroups.html */
+			$this->request("flickr.groups.pools.getGroups", array('page'=>$page, 'per_page'=>$per_page));
+			return $this->parsed_response ? $this->parsed_response['groups'] : false;
+		}
+
+		function groups_pools_getPhotos ($group_id, $tags = NULL, $user_id = NULL, $jump_to = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.groups.pools.getPhotos.html */
+			if (is_array($extras)) {
+				$extras = implode(",", $extras);
+			}
+			return $this->call('flickr.groups.pools.getPhotos', array('group_id' => $group_id, 'tags' => $tags, 'user_id' => $user_id, 'jump_to' => $jump_to, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function groups_pools_remove ($photo_id, $group_id) {
+			/* http://www.flickr.com/services/api/flickr.groups.pools.remove.html */
+			$this->request("flickr.groups.pools.remove", array("photo_id"=>$photo_id, "group_id"=>$group_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		/* Interestingness methods */
+		function interestingness_getList ($date = NULL, $use_panda = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.interestingness.getList.html */
+			if (is_array($extras)) {
+				$extras = implode(",", $extras);
+			}
+
+			return $this->call('flickr.interestingness.getList', array('date' => $date, 'use_panda' => $use_panda, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		/* Machine Tag methods */
+		function machinetags_getNamespaces ($predicate = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.machinetags.getNamespaces.html */
+			return $this->call('flickr.machinetags.getNamespaces', array('predicate' => $predicate, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function machinetags_getPairs ($namespace = NULL, $predicate = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.machinetags.getPairs.html */
+			return $this->call('flickr.machinetags.getPairs', array('namespace' => $namespace, 'predicate' => $predicate, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function machinetags_getPredicates ($namespace = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.machinetags.getPredicates.html */
+			return $this->call('flickr.machinetags.getPredicates', array('namespace' => $namespace, 'per_page' => $per_page, 'page' => $page));
+		}
+		
+		function machinetags_getRecentValues ($namespace = NULL, $predicate = NULL, $added_since = NULL) {
+			/* http://www.flickr.com/services/api/flickr.machinetags.getRecentValues.html */
+			return $this->call('flickr.machinetags.getRecentValues', array('namespace' => $namespace, 'predicate' => $predicate, 'added_since' => $added_since));
+		}
+
+		function machinetags_getValues ($namespace, $predicate, $per_page = NULL, $page = NULL, $usage = NULL) {
+			/* http://www.flickr.com/services/api/flickr.machinetags.getValues.html */
+			return $this->call('flickr.machinetags.getValues', array('namespace' => $namespace, 'predicate' => $predicate, 'per_page' => $per_page, 'page' => $page, 'usage' => $usage));
+		}
+		
+		/* Panda methods */
+		function panda_getList () {
+			/* http://www.flickr.com/services/api/flickr.panda.getList.html */
+			return $this->call('flickr.panda.getList', array());
+		}
+
+		function panda_getPhotos ($panda_name, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.panda.getPhotos.html */
+			return $this->call('flickr.panda.getPhotos', array('panda_name' => $panda_name, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		/* People methods */
+		function people_findByEmail ($find_email) {
+			/* http://www.flickr.com/services/api/flickr.people.findByEmail.html */
+			$this->request("flickr.people.findByEmail", array("find_email"=>$find_email));
+			return $this->parsed_response ? $this->parsed_response['user'] : false;
+		}
+
+		function people_findByUsername ($username) {
+			/* http://www.flickr.com/services/api/flickr.people.findByUsername.html */
+			$this->request("flickr.people.findByUsername", array("username"=>$username));
+			return $this->parsed_response ? $this->parsed_response['user'] : false;
+		}
+
+		function people_getInfo ($user_id) {
+			/* http://www.flickr.com/services/api/flickr.people.getInfo.html */
+			$this->request("flickr.people.getInfo", array("user_id"=>$user_id));
+			return $this->parsed_response ? $this->parsed_response['person'] : false;
+		}
+
+		function people_getPhotos ($user_id, $args = array()) {
+			/* This function strays from the method of arguments that I've
+			 * used in the other functions for the fact that there are just
+			 * so many arguments to this API method. What you'll need to do
+			 * is pass an associative array to the function containing the
+			 * arguments you want to pass to the API.  For example:
+			 *   $photos = $f->photos_search(array("tags"=>"brown,cow", "tag_mode"=>"any"));
+			 * This will return photos tagged with either "brown" or "cow"
+			 * or both. See the API documentation (link below) for a full
+			 * list of arguments.
+			 */
+
+			 /* http://www.flickr.com/services/api/flickr.people.getPhotos.html */
+			return $this->call('flickr.people.getPhotos', array_merge(array('user_id' => $user_id), $args));
+		}
+
+		function people_getPhotosOf ($user_id, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.people.getPhotosOf.html */
+			return $this->call('flickr.people.getPhotosOf', array('user_id' => $user_id, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+		
+		function people_getPublicGroups ($user_id) {
+			/* http://www.flickr.com/services/api/flickr.people.getPublicGroups.html */
+			$this->request("flickr.people.getPublicGroups", array("user_id"=>$user_id));
+			return $this->parsed_response ? $this->parsed_response['groups']['group'] : false;
+		}
+
+		function people_getPublicPhotos ($user_id, $safe_search = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.people.getPublicPhotos.html */
+			return $this->call('flickr.people.getPublicPhotos', array('user_id' => $user_id, 'safe_search' => $safe_search, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function people_getUploadStatus () {
+			/* http://www.flickr.com/services/api/flickr.people.getUploadStatus.html */
+			/* Requires Authentication */
+			$this->request("flickr.people.getUploadStatus");
+			return $this->parsed_response ? $this->parsed_response['user'] : false;
+		}
+
+
+		/* Photos Methods */
+		function photos_addTags ($photo_id, $tags) {
+			/* http://www.flickr.com/services/api/flickr.photos.addTags.html */
+			$this->request("flickr.photos.addTags", array("photo_id"=>$photo_id, "tags"=>$tags), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photos_delete ($photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.delete.html */
+			$this->request("flickr.photos.delete", array("photo_id"=>$photo_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photos_getAllContexts ($photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.getAllContexts.html */
+			$this->request("flickr.photos.getAllContexts", array("photo_id"=>$photo_id));
+			return $this->parsed_response ? $this->parsed_response : false;
+		}
+
+		function photos_getContactsPhotos ($count = NULL, $just_friends = NULL, $single_photo = NULL, $include_self = NULL, $extras = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.getContactsPhotos.html */
+			$this->request("flickr.photos.getContactsPhotos", array("count"=>$count, "just_friends"=>$just_friends, "single_photo"=>$single_photo, "include_self"=>$include_self, "extras"=>$extras));
+			return $this->parsed_response ? $this->parsed_response['photos']['photo'] : false;
+		}
+
+		function photos_getContactsPublicPhotos ($user_id, $count = NULL, $just_friends = NULL, $single_photo = NULL, $include_self = NULL, $extras = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.getContactsPublicPhotos.html */
+			$this->request("flickr.photos.getContactsPublicPhotos", array("user_id"=>$user_id, "count"=>$count, "just_friends"=>$just_friends, "single_photo"=>$single_photo, "include_self"=>$include_self, "extras"=>$extras));
+			return $this->parsed_response ? $this->parsed_response['photos']['photo'] : false;
+		}
+
+		function photos_getContext ($photo_id, $num_prev = NULL, $num_next = NULL, $extras = NULL, $order_by = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.getContext.html */
+			return $this->call('flickr.photos.getContext', array('photo_id' => $photo_id, 'num_prev' => $num_prev, 'num_next' => $num_next, 'extras' => $extras, 'order_by' => $order_by));
+		}
+
+		function photos_getCounts ($dates = NULL, $taken_dates = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.getCounts.html */
+			$this->request("flickr.photos.getCounts", array("dates"=>$dates, "taken_dates"=>$taken_dates));
+			return $this->parsed_response ? $this->parsed_response['photocounts']['photocount'] : false;
+		}
+
+		function photos_getExif ($photo_id, $secret = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.getExif.html */
+			$this->request("flickr.photos.getExif", array("photo_id"=>$photo_id, "secret"=>$secret));
+			return $this->parsed_response ? $this->parsed_response['photo'] : false;
+		}
+		
+		function photos_getFavorites ($photo_id, $page = NULL, $per_page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.getFavorites.html */
+			$this->request("flickr.photos.getFavorites", array("photo_id"=>$photo_id, "page"=>$page, "per_page"=>$per_page));
+			return $this->parsed_response ? $this->parsed_response['photo'] : false;
+		}
+
+		function photos_getInfo ($photo_id, $secret = NULL, $humandates = NULL, $privacy_filter = NULL, $get_contexts = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.getInfo.html */
+			return $this->call('flickr.photos.getInfo', array('photo_id' => $photo_id, 'secret' => $secret, 'humandates' => $humandates, 'privacy_filter' => $privacy_filter, 'get_contexts' => $get_contexts));
+		}
+		
+		function photos_getNotInSet ($max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL, $privacy_filter = NULL, $media = NULL, $min_upload_date = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.getNotInSet.html */
+			return $this->call('flickr.photos.getNotInSet', array('max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date, 'privacy_filter' => $privacy_filter, 'media' => $media, 'min_upload_date' => $min_upload_date, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+		
+		function photos_getPerms ($photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.getPerms.html */
+			$this->request("flickr.photos.getPerms", array("photo_id"=>$photo_id));
+			return $this->parsed_response ? $this->parsed_response['perms'] : false;
+		}
+
+		function photos_getRecent ($jump_to = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.getRecent.html */
+			if (is_array($extras)) {
+				$extras = implode(",", $extras);
+			}
+			return $this->call('flickr.photos.getRecent', array('jump_to' => $jump_to, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function photos_getSizes ($photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.getSizes.html */
+			$this->request("flickr.photos.getSizes", array("photo_id"=>$photo_id));
+			return $this->parsed_response ? $this->parsed_response['sizes']['size'] : false;
+		}
+
+		function photos_getUntagged ($min_upload_date = NULL, $max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL, $privacy_filter = NULL, $media = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.getUntagged.html */
+			return $this->call('flickr.photos.getUntagged', array('min_upload_date' => $min_upload_date, 'max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date, 'privacy_filter' => $privacy_filter, 'media' => $media, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function photos_getWithGeoData ($args = array()) {
+			/* See the documentation included with the photos_search() function.
+			 * I'm using the same style of arguments for this function. The only
+			 * difference here is that this doesn't require any arguments. The
+			 * flickr.photos.search method requires at least one search parameter.
+			 */
+			/* http://www.flickr.com/services/api/flickr.photos.getWithGeoData.html */
+			$this->request("flickr.photos.getWithGeoData", $args);
+			return $this->parsed_response ? $this->parsed_response['photos'] : false;
+		}
+
+		function photos_getWithoutGeoData ($args = array()) {
+			/* See the documentation included with the photos_search() function.
+			 * I'm using the same style of arguments for this function. The only
+			 * difference here is that this doesn't require any arguments. The
+			 * flickr.photos.search method requires at least one search parameter.
+			 */
+			/* http://www.flickr.com/services/api/flickr.photos.getWithoutGeoData.html */
+			$this->request("flickr.photos.getWithoutGeoData", $args);
+			return $this->parsed_response ? $this->parsed_response['photos'] : false;
+		}
+
+		function photos_recentlyUpdated ($min_date, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.recentlyUpdated.html */
+			return $this->call('flickr.photos.recentlyUpdated', array('min_date' => $min_date, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function photos_removeTag ($tag_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.removeTag.html */
+			$this->request("flickr.photos.removeTag", array("tag_id"=>$tag_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photos_search ($args = array()) {
+			/* This function strays from the method of arguments that I've
+			 * used in the other functions for the fact that there are just
+			 * so many arguments to this API method. What you'll need to do
+			 * is pass an associative array to the function containing the
+			 * arguments you want to pass to the API.  For example:
+			 *   $photos = $f->photos_search(array("tags"=>"brown,cow", "tag_mode"=>"any"));
+			 * This will return photos tagged with either "brown" or "cow"
+			 * or both. See the API documentation (link below) for a full
+			 * list of arguments.
+			 */
+
+			/* http://www.flickr.com/services/api/flickr.photos.search.html */
+			$this->request("flickr.photos.search", $args);
+			return $this->parsed_response ? $this->parsed_response['photos'] : false;
+		}
+
+		function photos_setContentType ($photo_id, $content_type) {
+			/* http://www.flickr.com/services/api/flickr.photos.setContentType.html */
+			return $this->call('flickr.photos.setContentType', array('photo_id' => $photo_id, 'content_type' => $content_type));
+		}
+		
+		function photos_setDates ($photo_id, $date_posted = NULL, $date_taken = NULL, $date_taken_granularity = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.setDates.html */
+			$this->request("flickr.photos.setDates", array("photo_id"=>$photo_id, "date_posted"=>$date_posted, "date_taken"=>$date_taken, "date_taken_granularity"=>$date_taken_granularity), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photos_setMeta ($photo_id, $title, $description) {
+			/* http://www.flickr.com/services/api/flickr.photos.setMeta.html */
+			$this->request("flickr.photos.setMeta", array("photo_id"=>$photo_id, "title"=>$title, "description"=>$description), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photos_setPerms ($photo_id, $is_public, $is_friend, $is_family, $perm_comment, $perm_addmeta) {
+			/* http://www.flickr.com/services/api/flickr.photos.setPerms.html */
+			$this->request("flickr.photos.setPerms", array("photo_id"=>$photo_id, "is_public"=>$is_public, "is_friend"=>$is_friend, "is_family"=>$is_family, "perm_comment"=>$perm_comment, "perm_addmeta"=>$perm_addmeta), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photos_setSafetyLevel ($photo_id, $safety_level = NULL, $hidden = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.setSafetyLevel.html */
+			return $this->call('flickr.photos.setSafetyLevel', array('photo_id' => $photo_id, 'safety_level' => $safety_level, 'hidden' => $hidden));
+		}
+		
+		function photos_setTags ($photo_id, $tags) {
+			/* http://www.flickr.com/services/api/flickr.photos.setTags.html */
+			$this->request("flickr.photos.setTags", array("photo_id"=>$photo_id, "tags"=>$tags), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		/* Photos - Comments Methods */
+		function photos_comments_addComment ($photo_id, $comment_text) {
+			/* http://www.flickr.com/services/api/flickr.photos.comments.addComment.html */
+			$this->request("flickr.photos.comments.addComment", array("photo_id" => $photo_id, "comment_text"=>$comment_text), TRUE);
+			return $this->parsed_response ? $this->parsed_response['comment'] : false;
+		}
+
+		function photos_comments_deleteComment ($comment_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.comments.deleteComment.html */
+			$this->request("flickr.photos.comments.deleteComment", array("comment_id" => $comment_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photos_comments_editComment ($comment_id, $comment_text) {
+			/* http://www.flickr.com/services/api/flickr.photos.comments.editComment.html */
+			$this->request("flickr.photos.comments.editComment", array("comment_id" => $comment_id, "comment_text"=>$comment_text), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photos_comments_getList ($photo_id, $min_comment_date = NULL, $max_comment_date = NULL, $page = NULL, $per_page = NULL, $include_faves = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.comments.getList.html */
+			return $this->call('flickr.photos.comments.getList', array('photo_id' => $photo_id, 'min_comment_date' => $min_comment_date, 'max_comment_date' => $max_comment_date, 'page' => $page, 'per_page' => $per_page, 'include_faves' => $include_faves));
+		}
+		
+		function photos_comments_getRecentForContacts ($date_lastcomment = NULL, $contacts_filter = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.comments.getRecentForContacts.html */
+			return $this->call('flickr.photos.comments.getRecentForContacts', array('date_lastcomment' => $date_lastcomment, 'contacts_filter' => $contacts_filter, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		/* Photos - Geo Methods */
+		function photos_geo_batchCorrectLocation ($lat, $lon, $accuracy, $place_id = NULL, $woe_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.geo.batchCorrectLocation.html */
+			return $this->call('flickr.photos.geo.batchCorrectLocation', array('lat' => $lat, 'lon' => $lon, 'accuracy' => $accuracy, 'place_id' => $place_id, 'woe_id' => $woe_id));
+		}
+
+		function photos_geo_correctLocation ($photo_id, $place_id = NULL, $woe_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.geo.correctLocation.html */
+			return $this->call('flickr.photos.geo.correctLocation', array('photo_id' => $photo_id, 'place_id' => $place_id, 'woe_id' => $woe_id));
+		}
+
+		function photos_geo_getLocation ($photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.geo.getLocation.html */
+			$this->request("flickr.photos.geo.getLocation", array("photo_id"=>$photo_id));
+			return $this->parsed_response ? $this->parsed_response['photo'] : false;
+		}
+
+		function photos_geo_getPerms ($photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.geo.getPerms.html */
+			$this->request("flickr.photos.geo.getPerms", array("photo_id"=>$photo_id));
+			return $this->parsed_response ? $this->parsed_response['perms'] : false;
+		}
+		
+		function photos_geo_photosForLocation ($lat, $lon, $accuracy = NULL, $extras = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.geo.photosForLocation.html */
+			return $this->call('flickr.photos.geo.photosForLocation', array('lat' => $lat, 'lon' => $lon, 'accuracy' => $accuracy, 'extras' => $extras, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function photos_geo_removeLocation ($photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.geo.removeLocation.html */
+			$this->request("flickr.photos.geo.removeLocation", array("photo_id"=>$photo_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photos_geo_setContext ($photo_id, $context) {
+			/* http://www.flickr.com/services/api/flickr.photos.geo.setContext.html */
+			return $this->call('flickr.photos.geo.setContext', array('photo_id' => $photo_id, 'context' => $context));
+		}
+
+		function photos_geo_setLocation ($photo_id, $lat, $lon, $accuracy = NULL, $context = NULL, $bookmark_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.geo.setLocation.html */
+			return $this->call('flickr.photos.geo.setLocation', array('photo_id' => $photo_id, 'lat' => $lat, 'lon' => $lon, 'accuracy' => $accuracy, 'context' => $context, 'bookmark_id' => $bookmark_id));
+		}
+		
+		function photos_geo_setPerms ($is_public, $is_contact, $is_friend, $is_family, $photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.geo.setPerms.html */
+			return $this->call('flickr.photos.geo.setPerms', array('is_public' => $is_public, 'is_contact' => $is_contact, 'is_friend' => $is_friend, 'is_family' => $is_family, 'photo_id' => $photo_id));
+		}
+
+		/* Photos - Licenses Methods */
+		function photos_licenses_getInfo () {
+			/* http://www.flickr.com/services/api/flickr.photos.licenses.getInfo.html */
+			$this->request("flickr.photos.licenses.getInfo");
+			return $this->parsed_response ? $this->parsed_response['licenses']['license'] : false;
+		}
+
+		function photos_licenses_setLicense ($photo_id, $license_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.licenses.setLicense.html */
+			/* Requires Authentication */
+			$this->request("flickr.photos.licenses.setLicense", array("photo_id"=>$photo_id, "license_id"=>$license_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		/* Photos - Notes Methods */
+		function photos_notes_add ($photo_id, $note_x, $note_y, $note_w, $note_h, $note_text) {
+			/* http://www.flickr.com/services/api/flickr.photos.notes.add.html */
+			$this->request("flickr.photos.notes.add", array("photo_id" => $photo_id, "note_x" => $note_x, "note_y" => $note_y, "note_w" => $note_w, "note_h" => $note_h, "note_text" => $note_text), TRUE);
+			return $this->parsed_response ? $this->parsed_response['note'] : false;
+		}
+
+		function photos_notes_delete ($note_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.notes.delete.html */
+			$this->request("flickr.photos.notes.delete", array("note_id" => $note_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photos_notes_edit ($note_id, $note_x, $note_y, $note_w, $note_h, $note_text) {
+			/* http://www.flickr.com/services/api/flickr.photos.notes.edit.html */
+			$this->request("flickr.photos.notes.edit", array("note_id" => $note_id, "note_x" => $note_x, "note_y" => $note_y, "note_w" => $note_w, "note_h" => $note_h, "note_text" => $note_text), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		/* Photos - Transform Methods */
+		function photos_transform_rotate ($photo_id, $degrees) {
+			/* http://www.flickr.com/services/api/flickr.photos.transform.rotate.html */
+			$this->request("flickr.photos.transform.rotate", array("photo_id" => $photo_id, "degrees" => $degrees), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		/* Photos - People Methods */
+		function photos_people_add ($photo_id, $user_id, $person_x = NULL, $person_y = NULL, $person_w = NULL, $person_h = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.people.add.html */
+			return $this->call('flickr.photos.people.add', array('photo_id' => $photo_id, 'user_id' => $user_id, 'person_x' => $person_x, 'person_y' => $person_y, 'person_w' => $person_w, 'person_h' => $person_h));
+		}
+
+		function photos_people_delete ($photo_id, $user_id, $email = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.people.delete.html */
+			return $this->call('flickr.photos.people.delete', array('photo_id' => $photo_id, 'user_id' => $user_id, 'email' => $email));
+		}
+		
+		function photos_people_deleteCoords ($photo_id, $user_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.people.deleteCoords.html */
+			return $this->call('flickr.photos.people.deleteCoords', array('photo_id' => $photo_id, 'user_id' => $user_id));
+		}
+
+		function photos_people_editCoords ($photo_id, $user_id, $person_x, $person_y, $person_w, $person_h, $email = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photos.people.editCoords.html */
+			return $this->call('flickr.photos.people.editCoords', array('photo_id' => $photo_id, 'user_id' => $user_id, 'person_x' => $person_x, 'person_y' => $person_y, 'person_w' => $person_w, 'person_h' => $person_h, 'email' => $email));
+		}
+		
+		function photos_people_getList ($photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photos.people.getList.html */
+			return $this->call('flickr.photos.people.getList', array('photo_id' => $photo_id));
+		}
+		
+		/* Photos - Upload Methods */
+		function photos_upload_checkTickets ($tickets) {
+			/* http://www.flickr.com/services/api/flickr.photos.upload.checkTickets.html */
+			if (is_array($tickets)) {
+				$tickets = implode(",", $tickets);
+			}
+			$this->request("flickr.photos.upload.checkTickets", array("tickets" => $tickets), TRUE);
+			return $this->parsed_response ? $this->parsed_response['uploader']['ticket'] : false;
+		}
+
+		/* Photosets Methods */
+		function photosets_addPhoto ($photoset_id, $photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photosets.addPhoto.html */
+			$this->request("flickr.photosets.addPhoto", array("photoset_id" => $photoset_id, "photo_id" => $photo_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photosets_create ($title, $description, $primary_photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photosets.create.html */
+			$this->request("flickr.photosets.create", array("title" => $title, "primary_photo_id" => $primary_photo_id, "description" => $description), TRUE);
+			return $this->parsed_response ? $this->parsed_response['photoset'] : false;
+		}
+
+		function photosets_delete ($photoset_id) {
+			/* http://www.flickr.com/services/api/flickr.photosets.delete.html */
+			$this->request("flickr.photosets.delete", array("photoset_id" => $photoset_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photosets_editMeta ($photoset_id, $title, $description = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photosets.editMeta.html */
+			$this->request("flickr.photosets.editMeta", array("photoset_id" => $photoset_id, "title" => $title, "description" => $description), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photosets_editPhotos ($photoset_id, $primary_photo_id, $photo_ids) {
+			/* http://www.flickr.com/services/api/flickr.photosets.editPhotos.html */
+			$this->request("flickr.photosets.editPhotos", array("photoset_id" => $photoset_id, "primary_photo_id" => $primary_photo_id, "photo_ids" => $photo_ids), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photosets_getContext ($photo_id, $photoset_id, $num_prev = NULL, $num_next = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photosets.getContext.html */
+			return $this->call('flickr.photosets.getContext', array('photo_id' => $photo_id, 'photoset_id' => $photoset_id, 'num_prev' => $num_prev, 'num_next' => $num_next));
+		}
+		
+		function photosets_getInfo ($photoset_id) {
+			/* http://www.flickr.com/services/api/flickr.photosets.getInfo.html */
+			$this->request("flickr.photosets.getInfo", array("photoset_id" => $photoset_id));
+			return $this->parsed_response ? $this->parsed_response['photoset'] : false;
+		}
+
+		function photosets_getList ($user_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photosets.getList.html */
+			$this->request("flickr.photosets.getList", array("user_id" => $user_id));
+			return $this->parsed_response ? $this->parsed_response['photosets'] : false;
+		}
+
+		function photosets_getPhotos ($photoset_id, $extras = NULL, $privacy_filter = NULL, $per_page = NULL, $page = NULL, $media = NULL) {
+			/* http://www.flickr.com/services/api/flickr.photosets.getPhotos.html */
+			return $this->call('flickr.photosets.getPhotos', array('photoset_id' => $photoset_id, 'extras' => $extras, 'privacy_filter' => $privacy_filter, 'per_page' => $per_page, 'page' => $page, 'media' => $media));
+		}
+
+		function photosets_orderSets ($photoset_ids) {
+			/* http://www.flickr.com/services/api/flickr.photosets.orderSets.html */
+			if (is_array($photoset_ids)) {
+				$photoset_ids = implode(",", $photoset_ids);
+			}
+			$this->request("flickr.photosets.orderSets", array("photoset_ids" => $photoset_ids), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photosets_removePhoto ($photoset_id, $photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photosets.removePhoto.html */
+			$this->request("flickr.photosets.removePhoto", array("photoset_id" => $photoset_id, "photo_id" => $photo_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+		
+		function photosets_removePhotos ($photoset_id, $photo_ids) {
+			/* http://www.flickr.com/services/api/flickr.photosets.removePhotos.html */
+			return $this->call('flickr.photosets.removePhotos', array('photoset_id' => $photoset_id, 'photo_ids' => $photo_ids));
+		}
+		
+		function photosets_reorderPhotos ($photoset_id, $photo_ids) {
+			/* http://www.flickr.com/services/api/flickr.photosets.reorderPhotos.html */
+			return $this->call('flickr.photosets.reorderPhotos', array('photoset_id' => $photoset_id, 'photo_ids' => $photo_ids));
+		}
+		
+		function photosets_setPrimaryPhoto ($photoset_id, $photo_id) {
+			/* http://www.flickr.com/services/api/flickr.photosets.setPrimaryPhoto.html */
+			return $this->call('flickr.photosets.setPrimaryPhoto', array('photoset_id' => $photoset_id, 'photo_id' => $photo_id));
+		}
+
+		/* Photosets Comments Methods */
+		function photosets_comments_addComment ($photoset_id, $comment_text) {
+			/* http://www.flickr.com/services/api/flickr.photosets.comments.addComment.html */
+			$this->request("flickr.photosets.comments.addComment", array("photoset_id" => $photoset_id, "comment_text"=>$comment_text), TRUE);
+			return $this->parsed_response ? $this->parsed_response['comment'] : false;
+		}
+
+		function photosets_comments_deleteComment ($comment_id) {
+			/* http://www.flickr.com/services/api/flickr.photosets.comments.deleteComment.html */
+			$this->request("flickr.photosets.comments.deleteComment", array("comment_id" => $comment_id), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photosets_comments_editComment ($comment_id, $comment_text) {
+			/* http://www.flickr.com/services/api/flickr.photosets.comments.editComment.html */
+			$this->request("flickr.photosets.comments.editComment", array("comment_id" => $comment_id, "comment_text"=>$comment_text), TRUE);
+			return $this->parsed_response ? true : false;
+		}
+
+		function photosets_comments_getList ($photoset_id) {
+			/* http://www.flickr.com/services/api/flickr.photosets.comments.getList.html */
+			$this->request("flickr.photosets.comments.getList", array("photoset_id"=>$photoset_id));
+			return $this->parsed_response ? $this->parsed_response['comments'] : false;
+		}
+		
+		/* Places Methods */
+		function places_find ($query) {
+			/* http://www.flickr.com/services/api/flickr.places.find.html */
+			return $this->call('flickr.places.find', array('query' => $query));
+		}
+
+		function places_findByLatLon ($lat, $lon, $accuracy = NULL) {
+			/* http://www.flickr.com/services/api/flickr.places.findByLatLon.html */
+			return $this->call('flickr.places.findByLatLon', array('lat' => $lat, 'lon' => $lon, 'accuracy' => $accuracy));
+		}
+
+		function places_getChildrenWithPhotosPublic ($place_id = NULL, $woe_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.places.getChildrenWithPhotosPublic.html */
+			return $this->call('flickr.places.getChildrenWithPhotosPublic', array('place_id' => $place_id, 'woe_id' => $woe_id));
+		}
+
+		function places_getInfo ($place_id = NULL, $woe_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.places.getInfo.html */
+			return $this->call('flickr.places.getInfo', array('place_id' => $place_id, 'woe_id' => $woe_id));
+		}
+
+		function places_getInfoByUrl ($url) {
+			/* http://www.flickr.com/services/api/flickr.places.getInfoByUrl.html */
+			return $this->call('flickr.places.getInfoByUrl', array('url' => $url));
+		}
+		
+		function places_getPlaceTypes () {
+			/* http://www.flickr.com/services/api/flickr.places.getPlaceTypes.html */
+			return $this->call('flickr.places.getPlaceTypes', array());
+		}
+		
+		function places_getShapeHistory ($place_id = NULL, $woe_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.places.getShapeHistory.html */
+			return $this->call('flickr.places.getShapeHistory', array('place_id' => $place_id, 'woe_id' => $woe_id));
+		}
+
+		function places_getTopPlacesList ($place_type_id, $date = NULL, $woe_id = NULL, $place_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.places.getTopPlacesList.html */
+			return $this->call('flickr.places.getTopPlacesList', array('place_type_id' => $place_type_id, 'date' => $date, 'woe_id' => $woe_id, 'place_id' => $place_id));
+		}
+		
+		function places_placesForBoundingBox ($bbox, $place_type = NULL, $place_type_id = NULL, $recursive = NULL) {
+			/* http://www.flickr.com/services/api/flickr.places.placesForBoundingBox.html */
+			return $this->call('flickr.places.placesForBoundingBox', array('bbox' => $bbox, 'place_type' => $place_type, 'place_type_id' => $place_type_id, 'recursive' => $recursive));
+		}
+
+		function places_placesForContacts ($place_type = NULL, $place_type_id = NULL, $woe_id = NULL, $place_id = NULL, $threshold = NULL, $contacts = NULL, $min_upload_date = NULL, $max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL) {
+			/* http://www.flickr.com/services/api/flickr.places.placesForContacts.html */
+			return $this->call('flickr.places.placesForContacts', array('place_type' => $place_type, 'place_type_id' => $place_type_id, 'woe_id' => $woe_id, 'place_id' => $place_id, 'threshold' => $threshold, 'contacts' => $contacts, 'min_upload_date' => $min_upload_date, 'max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date));
+		}
+
+		function places_placesForTags ($place_type_id, $woe_id = NULL, $place_id = NULL, $threshold = NULL, $tags = NULL, $tag_mode = NULL, $machine_tags = NULL, $machine_tag_mode = NULL, $min_upload_date = NULL, $max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL) {
+			/* http://www.flickr.com/services/api/flickr.places.placesForTags.html */
+			return $this->call('flickr.places.placesForTags', array('place_type_id' => $place_type_id, 'woe_id' => $woe_id, 'place_id' => $place_id, 'threshold' => $threshold, 'tags' => $tags, 'tag_mode' => $tag_mode, 'machine_tags' => $machine_tags, 'machine_tag_mode' => $machine_tag_mode, 'min_upload_date' => $min_upload_date, 'max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date));
+		}
+
+		function places_placesForUser ($place_type_id = NULL, $place_type = NULL, $woe_id = NULL, $place_id = NULL, $threshold = NULL, $min_upload_date = NULL, $max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL) {
+			/* http://www.flickr.com/services/api/flickr.places.placesForUser.html */
+			return $this->call('flickr.places.placesForUser', array('place_type_id' => $place_type_id, 'place_type' => $place_type, 'woe_id' => $woe_id, 'place_id' => $place_id, 'threshold' => $threshold, 'min_upload_date' => $min_upload_date, 'max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date));
+		}
+		
+		function places_resolvePlaceId ($place_id) {
+			/* http://www.flickr.com/services/api/flickr.places.resolvePlaceId.html */
+			$rsp = $this->call('flickr.places.resolvePlaceId', array('place_id' => $place_id));
+			return $rsp ? $rsp['location'] : $rsp;
+		}
+		
+		function places_resolvePlaceURL ($url) {
+			/* http://www.flickr.com/services/api/flickr.places.resolvePlaceURL.html */
+			$rsp = $this->call('flickr.places.resolvePlaceURL', array('url' => $url));
+			return $rsp ? $rsp['location'] : $rsp;
+		}
+		
+		function places_tagsForPlace ($woe_id = NULL, $place_id = NULL, $min_upload_date = NULL, $max_upload_date = NULL, $min_taken_date = NULL, $max_taken_date = NULL) {
+			/* http://www.flickr.com/services/api/flickr.places.tagsForPlace.html */
+			return $this->call('flickr.places.tagsForPlace', array('woe_id' => $woe_id, 'place_id' => $place_id, 'min_upload_date' => $min_upload_date, 'max_upload_date' => $max_upload_date, 'min_taken_date' => $min_taken_date, 'max_taken_date' => $max_taken_date));
+		}
+
+		/* Prefs Methods */
+		function prefs_getContentType () {
+			/* http://www.flickr.com/services/api/flickr.prefs.getContentType.html */
+			$rsp = $this->call('flickr.prefs.getContentType', array());
+			return $rsp ? $rsp['person'] : $rsp;
+		}
+		
+		function prefs_getGeoPerms () {
+			/* http://www.flickr.com/services/api/flickr.prefs.getGeoPerms.html */
+			return $this->call('flickr.prefs.getGeoPerms', array());
+		}
+		
+		function prefs_getHidden () {
+			/* http://www.flickr.com/services/api/flickr.prefs.getHidden.html */
+			$rsp = $this->call('flickr.prefs.getHidden', array());
+			return $rsp ? $rsp['person'] : $rsp;
+		}
+		
+		function prefs_getPrivacy () {
+			/* http://www.flickr.com/services/api/flickr.prefs.getPrivacy.html */
+			$rsp = $this->call('flickr.prefs.getPrivacy', array());
+			return $rsp ? $rsp['person'] : $rsp;
+		}
+		
+		function prefs_getSafetyLevel () {
+			/* http://www.flickr.com/services/api/flickr.prefs.getSafetyLevel.html */
+			$rsp = $this->call('flickr.prefs.getSafetyLevel', array());
+			return $rsp ? $rsp['person'] : $rsp;
+		}
+
+		/* Reflection Methods */
+		function reflection_getMethodInfo ($method_name) {
+			/* http://www.flickr.com/services/api/flickr.reflection.getMethodInfo.html */
+			$this->request("flickr.reflection.getMethodInfo", array("method_name" => $method_name));
+			return $this->parsed_response ? $this->parsed_response : false;
+		}
+
+		function reflection_getMethods () {
+			/* http://www.flickr.com/services/api/flickr.reflection.getMethods.html */
+			$this->request("flickr.reflection.getMethods");
+			return $this->parsed_response ? $this->parsed_response['methods']['method'] : false;
+		}
+
+		/* Stats Methods */
+		function stats_getCollectionDomains ($date, $collection_id = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.stats.getCollectionDomains.html */
+			return $this->call('flickr.stats.getCollectionDomains', array('date' => $date, 'collection_id' => $collection_id, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function stats_getCollectionReferrers ($date, $domain, $collection_id = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.stats.getCollectionReferrers.html */
+			return $this->call('flickr.stats.getCollectionReferrers', array('date' => $date, 'domain' => $domain, 'collection_id' => $collection_id, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function stats_getCollectionStats ($date, $collection_id) {
+			/* http://www.flickr.com/services/api/flickr.stats.getCollectionStats.html */
+			return $this->call('flickr.stats.getCollectionStats', array('date' => $date, 'collection_id' => $collection_id));
+		}
+		
+		function stats_getCSVFiles () {
+			/* http://www.flickr.com/services/api/flickr.stats.getCSVFiles.html */
+			return $this->call('flickr.stats.getCSVFiles', array());
+		}
+
+		function stats_getPhotoDomains ($date, $photo_id = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.stats.getPhotoDomains.html */
+			return $this->call('flickr.stats.getPhotoDomains', array('date' => $date, 'photo_id' => $photo_id, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function stats_getPhotoReferrers ($date, $domain, $photo_id = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.stats.getPhotoReferrers.html */
+			return $this->call('flickr.stats.getPhotoReferrers', array('date' => $date, 'domain' => $domain, 'photo_id' => $photo_id, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function stats_getPhotosetDomains ($date, $photoset_id = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.stats.getPhotosetDomains.html */
+			return $this->call('flickr.stats.getPhotosetDomains', array('date' => $date, 'photoset_id' => $photoset_id, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function stats_getPhotosetReferrers ($date, $domain, $photoset_id = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.stats.getPhotosetReferrers.html */
+			return $this->call('flickr.stats.getPhotosetReferrers', array('date' => $date, 'domain' => $domain, 'photoset_id' => $photoset_id, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function stats_getPhotosetStats ($date, $photoset_id) {
+			/* http://www.flickr.com/services/api/flickr.stats.getPhotosetStats.html */
+			return $this->call('flickr.stats.getPhotosetStats', array('date' => $date, 'photoset_id' => $photoset_id));
+		}
+
+		function stats_getPhotoStats ($date, $photo_id) {
+			/* http://www.flickr.com/services/api/flickr.stats.getPhotoStats.html */
+			return $this->call('flickr.stats.getPhotoStats', array('date' => $date, 'photo_id' => $photo_id));
+		}
+
+		function stats_getPhotostreamDomains ($date, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.stats.getPhotostreamDomains.html */
+			return $this->call('flickr.stats.getPhotostreamDomains', array('date' => $date, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function stats_getPhotostreamReferrers ($date, $domain, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.stats.getPhotostreamReferrers.html */
+			return $this->call('flickr.stats.getPhotostreamReferrers', array('date' => $date, 'domain' => $domain, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function stats_getPhotostreamStats ($date) {
+			/* http://www.flickr.com/services/api/flickr.stats.getPhotostreamStats.html */
+			return $this->call('flickr.stats.getPhotostreamStats', array('date' => $date));
+		}
+
+		function stats_getPopularPhotos ($date = NULL, $sort = NULL, $per_page = NULL, $page = NULL) {
+			/* http://www.flickr.com/services/api/flickr.stats.getPopularPhotos.html */
+			return $this->call('flickr.stats.getPopularPhotos', array('date' => $date, 'sort' => $sort, 'per_page' => $per_page, 'page' => $page));
+		}
+
+		function stats_getTotalViews ($date = NULL) {
+			/* http://www.flickr.com/services/api/flickr.stats.getTotalViews.html */
+			return $this->call('flickr.stats.getTotalViews', array('date' => $date));
+		}
+		
+		/* Tags Methods */
+		function tags_getClusterPhotos ($tag, $cluster_id) {
+			/* http://www.flickr.com/services/api/flickr.tags.getClusterPhotos.html */
+			return $this->call('flickr.tags.getClusterPhotos', array('tag' => $tag, 'cluster_id' => $cluster_id));
+		}
+
+		function tags_getClusters ($tag) {
+			/* http://www.flickr.com/services/api/flickr.tags.getClusters.html */
+			return $this->call('flickr.tags.getClusters', array('tag' => $tag));
+		}
+
+		function tags_getHotList ($period = NULL, $count = NULL) {
+			/* http://www.flickr.com/services/api/flickr.tags.getHotList.html */
+			$this->request("flickr.tags.getHotList", array("period" => $period, "count" => $count));
+			return $this->parsed_response ? $this->parsed_response['hottags'] : false;
+		}
+
+		function tags_getListPhoto ($photo_id) {
+			/* http://www.flickr.com/services/api/flickr.tags.getListPhoto.html */
+			$this->request("flickr.tags.getListPhoto", array("photo_id" => $photo_id));
+			return $this->parsed_response ? $this->parsed_response['photo']['tags']['tag'] : false;
+		}
+
+		function tags_getListUser ($user_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.tags.getListUser.html */
+			$this->request("flickr.tags.getListUser", array("user_id" => $user_id));
+			return $this->parsed_response ? $this->parsed_response['who']['tags']['tag'] : false;
+		}
+
+		function tags_getListUserPopular ($user_id = NULL, $count = NULL) {
+			/* http://www.flickr.com/services/api/flickr.tags.getListUserPopular.html */
+			$this->request("flickr.tags.getListUserPopular", array("user_id" => $user_id, "count" => $count));
+			return $this->parsed_response ? $this->parsed_response['who']['tags']['tag'] : false;
+		}
+
+		function tags_getListUserRaw ($tag = NULL) {
+			/* http://www.flickr.com/services/api/flickr.tags.getListUserRaw.html */
+			return $this->call('flickr.tags.getListUserRaw', array('tag' => $tag));
+		}
+		
+		function tags_getRelated ($tag) {
+			/* http://www.flickr.com/services/api/flickr.tags.getRelated.html */
+			$this->request("flickr.tags.getRelated", array("tag" => $tag));
+			return $this->parsed_response ? $this->parsed_response['tags'] : false;
+		}
+
+		function test_echo ($args = array()) {
+			/* http://www.flickr.com/services/api/flickr.test.echo.html */
+			$this->request("flickr.test.echo", $args);
+			return $this->parsed_response ? $this->parsed_response : false;
+		}
+
+		function test_login () {
+			/* http://www.flickr.com/services/api/flickr.test.login.html */
+			$this->request("flickr.test.login");
+			return $this->parsed_response ? $this->parsed_response['user'] : false;
+		}
+
+		function urls_getGroup ($group_id) {
+			/* http://www.flickr.com/services/api/flickr.urls.getGroup.html */
+			$this->request("flickr.urls.getGroup", array("group_id"=>$group_id));
+			return $this->parsed_response ? $this->parsed_response['group']['url'] : false;
+		}
+
+		function urls_getUserPhotos ($user_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.urls.getUserPhotos.html */
+			$this->request("flickr.urls.getUserPhotos", array("user_id"=>$user_id));
+			return $this->parsed_response ? $this->parsed_response['user']['url'] : false;
+		}
+
+		function urls_getUserProfile ($user_id = NULL) {
+			/* http://www.flickr.com/services/api/flickr.urls.getUserProfile.html */
+			$this->request("flickr.urls.getUserProfile", array("user_id"=>$user_id));
+			return $this->parsed_response ? $this->parsed_response['user']['url'] : false;
+		}
+		
+		function urls_lookupGallery ($url) {
+			/* http://www.flickr.com/services/api/flickr.urls.lookupGallery.html */
+			return $this->call('flickr.urls.lookupGallery', array('url' => $url));
+		}
+
+		function urls_lookupGroup ($url) {
+			/* http://www.flickr.com/services/api/flickr.urls.lookupGroup.html */
+			$this->request("flickr.urls.lookupGroup", array("url"=>$url));
+			return $this->parsed_response ? $this->parsed_response['group'] : false;
+		}
+
+		function urls_lookupUser ($url) {
+			/* http://www.flickr.com/services/api/flickr.photos.notes.edit.html */
+			$this->request("flickr.urls.lookupUser", array("url"=>$url));
+			return $this->parsed_response ? $this->parsed_response['user'] : false;
+		}
+	}
+}
+
+if ( !class_exists('phpFlickr_pager') ) {
+	class phpFlickr_pager {
+		var $phpFlickr, $per_page, $method, $args, $results, $global_phpFlickr;
+		var $total = null, $page = 0, $pages = null, $photos, $_extra = null;
+		
+		
+		function phpFlickr_pager($phpFlickr, $method = null, $args = null, $per_page = 30) {
+			$this->per_page = $per_page;
+			$this->method = $method;
+			$this->args = $args;
+			$this->set_phpFlickr($phpFlickr);
+		}
+		
+		function set_phpFlickr($phpFlickr) {
+			if ( is_a($phpFlickr, 'phpFlickr') ) {
+				$this->phpFlickr = $phpFlickr;
+				if ( $this->phpFlickr->cache ) {
+					$this->args['per_page'] = 500;
+				} else {
+					$this->args['per_page'] = (int) $this->per_page;
+				}
+			}
+		}
+		
+		function __sleep() {
+			return array(
+				'method',
+				'args',
+				'per_page',
+				'page',
+				'_extra',
+			);
+		}
+		
+		function load($page) {
+			$allowed_methods = array(
+				'flickr.photos.search' => 'photos',
+				'flickr.photosets.getPhotos' => 'photoset',
+			);
+			if ( !in_array($this->method, array_keys($allowed_methods)) ) return false;
+			
+			if ( $this->phpFlickr->cache ) {
+				$min = ($page - 1) * $this->per_page;
+				$max = $page * $this->per_page - 1;
+				if ( floor($min/500) == floor($max/500) ) {
+					$this->args['page'] = floor($min/500) + 1;
+					$this->results = $this->phpFlickr->call($this->method, $this->args);
+					if ( $this->results ) {
+						$this->results = $this->results[$allowed_methods[$this->method]];
+						$this->photos = array_slice($this->results['photo'], $min % 500, $this->per_page);
+						$this->total = $this->results['total'];
+						$this->pages = ceil($this->results['total'] / $this->per_page);
+						return true;
+					} else {
+						return false;
+					}
+				} else {
+					$this->args['page'] = floor($min/500) + 1;
+					$this->results = $this->phpFlickr->call($this->method, $this->args);
+					if ( $this->results ) {
+						$this->results = $this->results[$allowed_methods[$this->method]];
+
+						$this->photos = array_slice($this->results['photo'], $min % 500);
+						$this->total = $this->results['total'];
+						$this->pages = ceil($this->results['total'] / $this->per_page);
+						
+						$this->args['page'] = floor($min/500) + 2;
+						$this->results = $this->phpFlickr->call($this->method, $this->args);
+						if ( $this->results ) {
+							$this->results = $this->results[$allowed_methods[$this->method]];
+							$this->photos = array_merge($this->photos, array_slice($this->results['photo'], 0, $max % 500 + 1));
+						}
+						return true;
+					} else {
+						return false;
+					}
+
+				}
+			} else {
+				$this->args['page'] = $page;
+				$this->results = $this->phpFlickr->call($this->method, $this->args);
+				if ( $this->results ) {
+					$this->results = $this->results[$allowed_methods[$this->method]];
+					
+					$this->photos = $this->results['photo'];
+					$this->total = $this->results['total'];
+					$this->pages = $this->results['pages'];
+					return true;
+				} else {
+					return false;
+				}
+			}
+		}
+		
+		function get($page = null) {
+			if ( is_null($page) ) {
+				$page = $this->page;
+			} else {
+				$this->page = $page;
+			}
+			if ( $this->load($page) ) {
+				return $this->photos;
+			}
+			$this->total = 0;
+			$this->pages = 0;
+			return array();
+		}
+		
+		function next() {
+			$this->page++;
+			if ( $this->load($this->page) ) {
+				return $this->photos;
+			}
+			$this->total = 0;
+			$this->pages = 0;
+			return array();
+		}
+		
+	}
+}
+
+?>
Index: /extensions/flickr2piwigo/index.php
===================================================================
--- /extensions/flickr2piwigo/index.php	(revision 16063)
+++ /extensions/flickr2piwigo/index.php	(revision 16063)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | 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                                          |
+// |                                                                       |
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/flickr2piwigo/language/en_UK/description.txt
===================================================================
--- /extensions/flickr2piwigo/language/en_UK/description.txt	(revision 16063)
+++ /extensions/flickr2piwigo/language/en_UK/description.txt	(revision 16063)
@@ -0,0 +1,1 @@
+Extension for importing pictures from your Flickr account
Index: /extensions/flickr2piwigo/language/en_UK/help_api_key.html
===================================================================
--- /extensions/flickr2piwigo/language/en_UK/help_api_key.html	(revision 16063)
+++ /extensions/flickr2piwigo/language/en_UK/help_api_key.html	(revision 16063)
@@ -0,0 +1,12 @@
+<ol>
+  <li>Go to <a href="http://www.flickr.com">Flickr website</a> and connect to your account</li>
+  <li>Go to the <a href="http://www.flickr.com/services/api/keys">API keys page</a></li>
+  <li>Click <b>Get another key</b></li>
+  <li>Choose <b>Apply for a non-commercial key</b></li>
+  <li>Enter a name and a description and check the two checkboxes before submit</li>
+  <li>Now copy the <b>Key</b> and the <b>Secret</b> to Flickr2Piwigo configuration</li>
+  <li>Click <b>Edit auth flow for this app</b></li>
+  <li>Enter a desciption again, past in <b>Callback URL</b> the above URL and click <b>Save changes</b></li>
+  <li>Don't forget to write your exact username in Flickr2Piwigo configuration</li>
+  <li>You're done!</li>
+</ol>
Index: /extensions/flickr2piwigo/language/en_UK/index.php
===================================================================
--- /extensions/flickr2piwigo/language/en_UK/index.php	(revision 16063)
+++ /extensions/flickr2piwigo/language/en_UK/index.php	(revision 16063)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | 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                                          |
+// |                                                                       |
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/flickr2piwigo/language/en_UK/plugin.lang.php
===================================================================
--- /extensions/flickr2piwigo/language/en_UK/plugin.lang.php	(revision 16063)
+++ /extensions/flickr2piwigo/language/en_UK/plugin.lang.php	(revision 16063)
@@ -0,0 +1,32 @@
+<?php
+
+$lang['Please fill your API keys on the configuration tab'] = 'Please fill your API keys on the configuration tab';
+$lang['Unknown username, please verify your configuration'] = 'Unknown username, please verify your configuration';
+$lang['Successfully logued to you Flickr account'] = 'Successfully logued to you Flickr account';
+$lang['Pictures without album'] = 'Pictures without album';
+$lang['One picture is not displayed because already existing in the database.'] = 'One picture is not displayed because already existing in the database.';
+$lang['%d pictures are not displayed because already existing in the database.'] = '%d pictures are not displayed because already existing in the database.';
+$lang['%d pictures imported'] = '%d pictures imported';
+$lang['Import'] = 'Import';
+$lang['API not authenticated'] = 'API not authenticated';
+$lang['%s imported'] = '%s imported';
+$lang['Flickr logins'] = 'Flickr logins';
+$lang['API key'] = 'API key';
+$lang['API secret'] = 'API secret';
+$lang['How do I get my Flickr API key?'] = 'How do I get my Flickr API key?';
+$lang['Callback URL'] = 'Callback URL';
+$lang['Import options'] = 'Import options';
+$lang['Reproduce flickr albums'] = 'Reproduce flickr albums';
+$lang['Import all photos in this album'] = 'Import all photos in this album';
+$lang['Fill these fields from Flickr datas'] = 'Fill these fields from Flickr datas';
+$lang['Processing...'] = 'Processing...';
+$lang['List my albums'] = 'List my albums';
+$lang['Import all my pictures'] = 'Import all my pictures';
+$lang['(%d photos)'] = '(%d photos)';
+$lang['%d albums'] = '%d albums';
+//$lang['Import all pictures of this album'] = 'Import all pictures of this album';
+$lang['List pictures of this album'] = 'List pictures of this album';
+$lang['Begin transfert'] = 'Begin transfert';
+$lang['Open Flickr page in a new tab'] = 'Open Flickr page in a new tab';
+
+?>
Index: /extensions/flickr2piwigo/language/fr_FR/description.txt
===================================================================
--- /extensions/flickr2piwigo/language/fr_FR/description.txt	(revision 16063)
+++ /extensions/flickr2piwigo/language/fr_FR/description.txt	(revision 16063)
@@ -0,0 +1,1 @@
+Extension permettant d'importer des photos depuis votre compte Flickr.
Index: /extensions/flickr2piwigo/language/fr_FR/help_api_key.html
===================================================================
--- /extensions/flickr2piwigo/language/fr_FR/help_api_key.html	(revision 16063)
+++ /extensions/flickr2piwigo/language/fr_FR/help_api_key.html	(revision 16063)
@@ -0,0 +1,12 @@
+<ol>
+  <li>Allez sur <a href="http://www.flickr.com">le site Flickr</a> et connectez vous à votre compte</li>
+  <li>Rendez-vous à la <a href="http://www.flickr.com/services/api/keys">page des clefs API</a></li>
+  <li>Cliquez sur <b>Obtenir une autre clé</b></li>
+  <li>Choisissez <b>Demander une clé non commerciale</b></li>
+  <li>Entrez un nom et une description et cochez les cases avant de valider</li>
+  <li>Maintanant copiez la <b>Clé</b> et le <b>Secret</b> dans la configuration de Flickr2Piwigo</li>
+  <li>Cliquez sur <b>Modifier le flux d'authentification</b></li>
+  <li>Entrer à nouveau une description, collez dans <b>URL de rappel</b> l'URL ci-dessus et cliquez sur <b>Save changes</b></li>
+  <li>N'oubliez pas de renseigner votre nom d'utilisateur exact dans la configuration de Flickr2Piwigo</li>
+  <li>Terminé!</li>
+</ol>
Index: /extensions/flickr2piwigo/language/fr_FR/index.php
===================================================================
--- /extensions/flickr2piwigo/language/fr_FR/index.php	(revision 16063)
+++ /extensions/flickr2piwigo/language/fr_FR/index.php	(revision 16063)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | 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                                          |
+// |                                                                       |
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/flickr2piwigo/language/fr_FR/plugin.lang.php
===================================================================
--- /extensions/flickr2piwigo/language/fr_FR/plugin.lang.php	(revision 16063)
+++ /extensions/flickr2piwigo/language/fr_FR/plugin.lang.php	(revision 16063)
@@ -0,0 +1,32 @@
+<?php
+
+$lang['Please fill your API keys on the configuration tab'] = 'Veuillez renseigner votre clé d\'API sur l\'écran de configuration';
+$lang['Unknown username, please verify your configuration'] = 'Nom d\'utilisateur inconnu, veuillez vérifier la configuration';
+$lang['Successfully logued to you Flickr account'] = 'Connecté à votre compte Flickr';
+$lang['Pictures without album'] = 'Photos sans album';
+$lang['One picture is not displayed because already existing in the database.'] = 'Une photo n\'est pas affichée car elle existe déjà sur la galerie';
+$lang['%d pictures are not displayed because already existing in the database.'] = '%d photo ne sont pas affichées car elles existent déjà sur la galerie';
+$lang['%d pictures imported'] = '%d photos importées';
+$lang['Import'] = 'Importation';
+$lang['API not authenticated'] = 'API non authentifiée';
+$lang['%s imported'] = '%s importé';
+$lang['Flickr logins'] = 'Identifiants Flickr';
+$lang['API key'] = 'Clé API';
+$lang['API secret'] = 'Secret API';
+$lang['How do I get my Flickr API key?'] = 'Comment obtenir ma clé d\'API ?';
+$lang['Callback URL'] = 'URL de rappel';
+$lang['Import options'] = 'Options d\'importation';
+$lang['Reproduce flickr albums'] = 'Reproduire les albums Flickr';
+$lang['Import all photos in this album'] = 'Ajouter toutes les photos à cet album';
+$lang['Fill these fields from Flickr datas'] = 'Remplir ces champs à partir des données de Flickr';
+$lang['Processing...'] = 'En cours...';
+$lang['List my albums'] = 'Lister mes albums';
+$lang['Import all my pictures'] = 'Importer toutes mes photos';
+$lang['(%d photos)'] = '(%d photos)';
+$lang['%d albums'] = '%d albums';
+//$lang['Import all pictures of this album'] = 'Importer toutes les photos de cet album';
+$lang['List pictures of this album'] = 'Lister les photos de cet album';
+$lang['Begin transfert'] = 'Commencer les transfert';
+$lang['Open Flickr page in a new tab'] = 'Ouvrir la page Flickr dans un nouvel onglet';
+
+?>
Index: /extensions/flickr2piwigo/language/index.php
===================================================================
--- /extensions/flickr2piwigo/language/index.php	(revision 16063)
+++ /extensions/flickr2piwigo/language/index.php	(revision 16063)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | 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                                          |
+// |                                                                       |
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/flickr2piwigo/main.inc.php
===================================================================
--- /extensions/flickr2piwigo/main.inc.php	(revision 16063)
+++ /extensions/flickr2piwigo/main.inc.php	(revision 16063)
@@ -0,0 +1,158 @@
+<?php 
+/*
+Plugin Name: Flickr2Piwigo
+Version: auto
+Description: Extension for importing pictures from your Flickr account
+Plugin URI: http://piwigo.org/ext/extension_view.php?eid=
+Author: Mistic
+Author URI: http://www.strangeplanet.fr
+*/
+
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+global $conf;
+
+define('FLICKR_PATH', PHPWG_PLUGINS_PATH . basename(dirname(__FILE__)) . '/');
+define('FLICKR_ADMIN', get_root_url() . 'admin.php?page=plugin-' . basename(dirname(__FILE__)));
+define('FLICKR_FS_CACHE', $conf['data_location'].'flickr_cache/');
+
+add_event_handler('get_admin_plugin_menu_links', 'flickr2_admin_menu');
+
+function flickr2_admin_menu($menu) 
+{
+  array_push($menu, array(
+    'NAME' => 'Flickr2Piwigo',
+    'URL' => FLICKR_ADMIN,
+  ));
+  return $menu;
+}
+
+add_event_handler('ws_add_methods', 'flickr2_add_ws_method');
+
+function flickr2_add_ws_method($arr)
+{
+  $service = &$arr[0];
+  
+  $service->addMethod(
+    'pwg.images.addFlickr',
+    'ws_images_addFlickr',
+    array(
+      'category' => array('default' => null),   
+      'id' => array('default' => null),
+      'fills' => array('default' =>null),
+      ),
+    'Used by Flickr2Piwigo, fills  (fill_name,fill_posted,fill_taken,fill_author,fill_tags)'
+    );
+}
+
+function ws_images_addFlickr($photo, &$service)
+{
+  global $conf;
+  
+  if (!is_admin())
+  {
+    return new PwgError(403, 'Forbidden');
+  }
+  
+  $conf['flickr2piwigo'] = unserialize($conf['flickr2piwigo']);
+  
+  if (empty($conf['flickr2piwigo']['api_key']) or empty($conf['flickr2piwigo']['secret_key']) or empty($conf['flickr2piwigo']['username']))
+  {
+    return new PwgError(500, l10n('Please fill your API keys on the configuration tab'));
+  }
+  
+  if (empty($_SESSION['phpFlickr_auth_token']))
+  {
+    return new PwgError(403, l10n('API not authenticated'));
+  }
+  
+  // category
+  if (!preg_match('#^[0-9]+$#', $photo['category']))
+  {
+    $categories_names = explode(',', $photo['category']);
+    
+    $photo['category'] = array();
+    foreach ($categories_names as $category_name)
+    {
+      $query = '
+SELECT id FROM '.CATEGORIES_TABLE.'
+  WHERE LOWER(name) = "'.strtolower($category_name).'"
+;';
+      $result = pwg_query($query);
+      
+      if (pwg_db_num_rows($result))
+      {
+        list($cat_id) = pwg_db_fetch_row($result);
+        array_push($photo['category'], $cat_id);
+      }
+      else
+      {
+        include_once(PHPWG_ROOT_PATH . 'admin/include/functions.php');
+        $cat = create_virtual_category($category_name);
+        array_push($photo['category'], $cat_id['id']);
+      }
+    }
+  }
+  else
+  {
+    $photo['category'] = array($photo['category']);
+  }
+  
+  // init flickr API
+  include_once(FLICKR_PATH . 'include/phpFlickr/phpFlickr.php');
+  $flickr = new phpFlickr($conf['flickr2piwigo']['api_key'], $conf['flickr2piwigo']['secret_key']);
+  $flickr->enableCache('fs', FLICKR_FS_CACHE);
+  
+  // photos infos
+  $photo_f = $flickr->photos_getInfo($photo['id']);
+  $photo = array_merge($photo, $photo_f['photo']);
+  $photo['url'] = $flickr->get_biggest_size($photo['id'], 'original');
+  $photo['path'] = FLICKR_FS_CACHE . 'flickr-'.$conf['flickr2piwigo']['username'].'-'.$photo['id'].'.'.get_extension($photo['url']);
+  
+  // copy file
+  $file = fopen($photo['url'], "rb");
+  $newf = fopen($photo['path'], "wb");
+  while (!feof($file))
+  {
+    fwrite($newf, fread($file, 1024 * 8 ), 1024 * 8 );
+  }
+  fclose($file);
+  fclose($newf);
+  
+  // add to database
+  include_once(PHPWG_ROOT_PATH . 'admin/include/functions_upload.inc.php');
+  $photo['image_id'] = add_uploaded_file($photo['path'], basename($photo['path']), $photo['category']);
+  
+  // do some updates
+  if (!empty($photo['fills']))
+  {
+    $photo['fills'] = rtrim($photo['fills'], ',');
+    $photo['fills'] = explode(',', $photo['fills']);
+  
+    $updates = array();
+    if (in_array('fill_name', $photo['fills']))   $updates['name'] = $photo['title']; 
+    if (in_array('fill_posted', $photo['fills'])) $updates['date_available'] = date('Y-d-m H:i:s', $photo['dates']['posted']);
+    if (in_array('fill_taken', $photo['fills']))  $updates['date_creation'] = $photo['dates']['taken'];
+    if (in_array('fill_author', $photo['fills'])) $updates['author'] = $conf['flickr2piwigo']['username'];
+    
+    if (count($updates))
+    {
+      single_update(
+        IMAGES_TABLE,
+        $updates,
+        array('id' => $photo['image_id'])
+        );
+    }
+    
+    if ( !empty($photo['tags']['tag']) and in_array('fill_tags', $photo['fills']) )
+    {
+      $raw_tags = array_map(create_function('$t', 'return $t["_content"];'), $photo['tags']['tag']);
+      $raw_tags = implode(',', $raw_tags);
+      set_tags(get_tag_ids($raw_tags), $photo['image_id']);
+    }
+  }
+  
+  return sprintf(l10n('%s imported'), $photo['title']);
+}
+
+?>
Index: /extensions/flickr2piwigo/maintain.inc.php
===================================================================
--- /extensions/flickr2piwigo/maintain.inc.php	(revision 16063)
+++ /extensions/flickr2piwigo/maintain.inc.php	(revision 16063)
@@ -0,0 +1,41 @@
+<?php
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+define(
+  'flickr2piwigo_default_config', 
+  serialize(array(
+    'api_key' => null,
+    'secret_key' => null,
+    'username' => null,
+    ))
+  );
+  
+
+function plugin_install() 
+{
+  global $conf;
+  conf_update_param('flickr2piwigo', flickr2piwigo_default_config);
+  mdir($conf['data_location'].'flickr_cache/', 0755);
+}
+
+function plugin_activate()
+{
+  global $conf;
+
+  if (empty($conf['flickr2piwigo']))
+  {
+    conf_update_param('flickr2piwigo', flickr2piwigo_default_config);
+  }
+  
+  if (!file_exists($conf['data_location'].'flickr_cache/'))
+  {
+    mdir($conf['data_location'].'flickr_cache/', 0755);
+  }
+}
+
+function plugin_uninstall() 
+{
+  pwg_query('DELETE FROM `'. CONFIG_TABLE .'` WHERE param = "flickr2piwigo" LIMIT 1;');
+}
+
+?>
