#4674 Add support for external medias: oembed, ogp, etc
	
		
	
				
					
				
			
							parent
							
								
									0433b28f7f
								
							
						
					
					
						commit
						7b2e9fbbd7
					
				@ -0,0 +1 @@ | 
				
			||||
Used to extract metadata from external resources : youtube, dailymotion, etc | 
				
			||||
@ -0,0 +1,56 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Process all renderers attached in order. | 
				
			||||
 *  | 
				
			||||
 * If a renderer returns an key value that has not already been set add it | 
				
			||||
 * to the result. Otherwise let the previous value unchanged. | 
				
			||||
 * | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetAggregatedRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    protected $renderers = array(); | 
				
			||||
 | 
				
			||||
    public function __construct($renderers) | 
				
			||||
    { | 
				
			||||
        $this->renderers = $renderers; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @return array | 
				
			||||
     */ | 
				
			||||
    public function renderers() | 
				
			||||
    { | 
				
			||||
        return $this->renderers; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset | 
				
			||||
     * @return array | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        $result = array(); | 
				
			||||
        $plugins = self::plugins(); | 
				
			||||
        foreach ($this->renderers as $renderer) | 
				
			||||
        { | 
				
			||||
            $data = $renderer->render($asset); | 
				
			||||
            $data = $data ? $data : array(); | 
				
			||||
            foreach ($data as $key => $value) | 
				
			||||
            { | 
				
			||||
                if (!isset($result[$key]) && !empty($value)) | 
				
			||||
                { | 
				
			||||
                    $result[$key] = $value; | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,107 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
require_once dirname(__FILE__) . '/http_resource.class.php'; | 
				
			||||
require_once dirname(__FILE__) . '/asset_aggregated_renderer.class.php'; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Renderer for an http resource.  | 
				
			||||
 * Extract meta data and snippet html view from an given url/resource. | 
				
			||||
 *  | 
				
			||||
 * Base class. Other renderers must inherit from it. | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    const THUMBNAIL = 'thumbnail'; | 
				
			||||
    const EMBED_SNIPPET = 'embed_snippet'; | 
				
			||||
    const EMBED_TYPE = 'embed_type'; | 
				
			||||
    const EMBED_URL = 'embed_url'; | 
				
			||||
    const WIDTH = 'width'; | 
				
			||||
    const HEIGHT = 'height'; | 
				
			||||
    const LANGUAGE = 'language'; | 
				
			||||
    const URL = 'url'; | 
				
			||||
    const TAGS = 'tags'; | 
				
			||||
    const TITLE = 'title'; | 
				
			||||
    const CREATED_TIME = 'created_time'; | 
				
			||||
    const DURATION = 'duration'; | 
				
			||||
    const DESCRIPTION = 'description'; | 
				
			||||
    const ICON = 'icon'; | 
				
			||||
 | 
				
			||||
    static function get($url, $config = array()) | 
				
			||||
    { | 
				
			||||
        if (strpos('url', 'javascript:') !== false) | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
        $result = array(); | 
				
			||||
        $url = trim($url); | 
				
			||||
        if (empty($url)) | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
        $asset = new HttpResource($url, $config); | 
				
			||||
        $renderer = new AssetAggregatedRenderer(self::plugins()); | 
				
			||||
        $result = $renderer->render($asset); | 
				
			||||
        $result['url'] = $url; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    static function plugins() | 
				
			||||
    { | 
				
			||||
        static $result = array(); | 
				
			||||
        if (!empty($result)) | 
				
			||||
        { | 
				
			||||
            return $result; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        /* | 
				
			||||
         * We make sure we load them from most specialized to less specialized. | 
				
			||||
         * The first that provides a value for a field wins. | 
				
			||||
         */ | 
				
			||||
        $protocols = array( | 
				
			||||
            'oembed', | 
				
			||||
            'og', | 
				
			||||
            'image', | 
				
			||||
            'media', | 
				
			||||
            'rss', | 
				
			||||
            'google_map', | 
				
			||||
            'google_document', | 
				
			||||
            'google_document_viewer', | 
				
			||||
            'google_widget', | 
				
			||||
            'mediaserver', | 
				
			||||
            'scratch', | 
				
			||||
            'page'); | 
				
			||||
 | 
				
			||||
        foreach ($protocols as $protocol) | 
				
			||||
        { | 
				
			||||
            $file = "asset_{$protocol}_renderer.class.php"; | 
				
			||||
            require_once dirname(__FILE__) . '/protocol/' . $file; | 
				
			||||
             | 
				
			||||
            $class = "asset_{$protocol}_renderer"; | 
				
			||||
            $class = explode('_', $class); | 
				
			||||
            $class = array_map('ucfirst', $class); | 
				
			||||
            $class = implode($class); | 
				
			||||
             | 
				
			||||
            $result[] = new $class(); | 
				
			||||
        } | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Renderer function. Take a http asset as input and return an array containing | 
				
			||||
     * various properties: metadata, html snippet, etc. | 
				
			||||
     *  | 
				
			||||
     * @param HttpResource $asset | 
				
			||||
     * @return array | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        $result = array(); | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,662 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * An HTTP resource. In most cases an HTML document. | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class HttpResource | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Fetch the content and metadata of an url.  | 
				
			||||
     *  | 
				
			||||
     * If the content type is not parsable, i.e. it is not made of text,  | 
				
			||||
     * only fetch the metadata and not the content. This is mostly done to  | 
				
			||||
     * avoid downloading big files - videos, images, etc - which is unnecessary. | 
				
			||||
     *  | 
				
			||||
     * @param string $url   the url to fetch | 
				
			||||
     * @return array        array containing the content and various info | 
				
			||||
     */ | 
				
			||||
    static function fetch($url, $fetch_content = null) | 
				
			||||
    { | 
				
			||||
        static $cache = array(); | 
				
			||||
        if (isset($cache[$url])) | 
				
			||||
        { | 
				
			||||
            return $cache; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        if (is_null($fetch_content) || $fetch_content === false) | 
				
			||||
        { | 
				
			||||
            // create a new cURL resource | 
				
			||||
            $ch = curl_init(); | 
				
			||||
 | 
				
			||||
            // set URL and other appropriate options | 
				
			||||
            curl_setopt($ch, CURLOPT_URL, $url); | 
				
			||||
            curl_setopt($ch, CURLOPT_HEADER, false); | 
				
			||||
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | 
				
			||||
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); | 
				
			||||
            curl_setopt($ch, CURLOPT_NOBODY, true); | 
				
			||||
 | 
				
			||||
            $content = curl_exec($ch); | 
				
			||||
            $error = curl_error($ch); | 
				
			||||
            $info = curl_getinfo($ch); | 
				
			||||
 | 
				
			||||
            // close cURL resource, and free up system resources | 
				
			||||
            curl_close($ch); | 
				
			||||
            $info['content'] = $content; | 
				
			||||
            $info['error'] = $error; | 
				
			||||
 | 
				
			||||
            if ($fetch_content === false) | 
				
			||||
            { | 
				
			||||
                return $cache[$url] = $info; | 
				
			||||
            } | 
				
			||||
 | 
				
			||||
            if (isset($info['content_type']) && strpos($info['content_type'], 'text') === false) | 
				
			||||
            { | 
				
			||||
                return $cache[$url] = $info; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        // create a new cURL resource | 
				
			||||
        $ch = curl_init(); | 
				
			||||
 | 
				
			||||
        // set URL and other appropriate options | 
				
			||||
        curl_setopt($ch, CURLOPT_URL, $url); | 
				
			||||
        curl_setopt($ch, CURLOPT_HEADER, false); | 
				
			||||
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | 
				
			||||
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); | 
				
			||||
 | 
				
			||||
        //curl_setopt($ch, CURLOPT_VERBOSE, true); | 
				
			||||
 | 
				
			||||
        $content = curl_exec($ch); | 
				
			||||
        $error = curl_error($ch); | 
				
			||||
        $info = curl_getinfo($ch); | 
				
			||||
 | 
				
			||||
        // close cURL resource, and free up system resources | 
				
			||||
        curl_close($ch); | 
				
			||||
        $info['content'] = $content; | 
				
			||||
        $info['error'] = $error; | 
				
			||||
 | 
				
			||||
        return $cache[$url] = $info; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    static function fetch_json($url) | 
				
			||||
    { | 
				
			||||
        $content = self::fetch($url, true); | 
				
			||||
        $content = $content['content']; | 
				
			||||
        if ($content) | 
				
			||||
        { | 
				
			||||
            $result = (array) json_decode($content); | 
				
			||||
        } | 
				
			||||
        else | 
				
			||||
        { | 
				
			||||
            $result = array(); | 
				
			||||
        } | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected $url; | 
				
			||||
    protected $url_params = null; | 
				
			||||
    protected $info = null; | 
				
			||||
    protected $source = null; | 
				
			||||
    protected $metadata = null; | 
				
			||||
    protected $links = null; | 
				
			||||
    protected $title = null; | 
				
			||||
    protected $mime = null; | 
				
			||||
    protected $doc = null; | 
				
			||||
    protected $config = array(); | 
				
			||||
 | 
				
			||||
    public function __construct($url, $config = array()) | 
				
			||||
    { | 
				
			||||
        $this->url = $url; | 
				
			||||
        $this->config = $config; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function config($key = '', $default = null) | 
				
			||||
    { | 
				
			||||
        return isset($this->config[$key]) ? $this->config[$key] : $default; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Url of the resource | 
				
			||||
     *  | 
				
			||||
     * @return string | 
				
			||||
     */ | 
				
			||||
    public function url() | 
				
			||||
    { | 
				
			||||
        return $this->url; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function url_domain() | 
				
			||||
    { | 
				
			||||
        $url = $this->url(); | 
				
			||||
        $url = trim($url, '/'); | 
				
			||||
        if (strpos($url, '//') !== false) | 
				
			||||
        { | 
				
			||||
            $parts = explode('//', $url); | 
				
			||||
            $url = end($parts); | 
				
			||||
        } | 
				
			||||
        $parts = explode('/', $url); | 
				
			||||
        $result = reset($parts); | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param array|string $part | 
				
			||||
     * @return boolean  | 
				
			||||
     */ | 
				
			||||
    public function url_match($part) | 
				
			||||
    { | 
				
			||||
        $params = func_get_args(); | 
				
			||||
        $params = is_array($params) ? $params : array($params); | 
				
			||||
 | 
				
			||||
        $url = strtolower($this->url()); | 
				
			||||
        foreach ($params as $param) | 
				
			||||
        { | 
				
			||||
            if (strpos($url, strtolower($param)) !== false) | 
				
			||||
            { | 
				
			||||
                return true; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        return false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function url_params() | 
				
			||||
    { | 
				
			||||
        if (!is_null($this->url_params)) | 
				
			||||
        { | 
				
			||||
            return $this->url_params; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $url = $this->url(); | 
				
			||||
        if (strpos($url, '?') === false) | 
				
			||||
        { | 
				
			||||
            return $this->url_params = array(); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $params = explode('?', $url); | 
				
			||||
        $params = end($params); | 
				
			||||
        $params = explode('&', $params); | 
				
			||||
        foreach ($params as $param) | 
				
			||||
        { | 
				
			||||
            list($key, $val) = explode('=', $param); | 
				
			||||
            $result[$key] = $val; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        return $this->url_params = $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function url_param($name, $default = false) | 
				
			||||
    { | 
				
			||||
        $params = $this->url_params(); | 
				
			||||
        return isset($params[$name]) ? $params[$name] : $default; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * The name of the resource. I.e. the last part of the url without the ext | 
				
			||||
     *  | 
				
			||||
     * @return string | 
				
			||||
     */ | 
				
			||||
    public function name() | 
				
			||||
    { | 
				
			||||
        $url = $this->url(); | 
				
			||||
        $url = explode('/', $url); | 
				
			||||
        $title = end($url); | 
				
			||||
        $title = explode('.', $title); | 
				
			||||
        $title = reset($title); | 
				
			||||
        return $title; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Extention of the url | 
				
			||||
     *  | 
				
			||||
     * @return string | 
				
			||||
     */ | 
				
			||||
    public function ext() | 
				
			||||
    { | 
				
			||||
        $url = $this->url(); | 
				
			||||
        $url = explode('.', $url); | 
				
			||||
        $ext = end($url); | 
				
			||||
        $ext = strtolower($ext); | 
				
			||||
        return $ext; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Return true if the object has one of the extentions. Overloaded: | 
				
			||||
     *  | 
				
			||||
     *      $res->has_ext('pdf'); | 
				
			||||
     *      $res->has_ext('pdf', 'doc'); | 
				
			||||
     *      $res->has_ext(array('pdf', 'doc')); | 
				
			||||
     *  | 
				
			||||
     * @param array|string $_ | 
				
			||||
     * @return boolean true if the resource has one of the extentions passed | 
				
			||||
     */ | 
				
			||||
    public function has_ext($_) | 
				
			||||
    { | 
				
			||||
        if (is_array($_)) | 
				
			||||
        { | 
				
			||||
            $params = $_; | 
				
			||||
        } | 
				
			||||
        else | 
				
			||||
        { | 
				
			||||
            $params = func_get_args(); | 
				
			||||
            $params = is_array($params) ? $params : array($params); | 
				
			||||
        } | 
				
			||||
        $ext = $this->ext(); | 
				
			||||
        foreach ($params as $param) | 
				
			||||
        { | 
				
			||||
            if (strtolower($param) == $ext) | 
				
			||||
            { | 
				
			||||
                return true; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        return false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function charset() | 
				
			||||
    { | 
				
			||||
        $info = $this->info(); | 
				
			||||
 | 
				
			||||
        $content_type = isset($info['content_type']) ? $info['content_type'] : ''; | 
				
			||||
        if (empty($content_type)) | 
				
			||||
        { | 
				
			||||
            return null; | 
				
			||||
        } | 
				
			||||
        $items = explode(';', $content_type); | 
				
			||||
        foreach ($items as $item) | 
				
			||||
        { | 
				
			||||
            $parts = explode('=', $item); | 
				
			||||
            if (count($parts) == 2 && reset($parts) == 'charset') | 
				
			||||
            { | 
				
			||||
                return strtolower(end($parts)); | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        return null; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * The mime type of the resource or the empty string if none has been specified | 
				
			||||
     *  | 
				
			||||
     * @return string | 
				
			||||
     */ | 
				
			||||
    public function mime() | 
				
			||||
    { | 
				
			||||
        if (!is_null($this->mime)) | 
				
			||||
        { | 
				
			||||
            return $this->mime; | 
				
			||||
        } | 
				
			||||
        $info = $this->info(); | 
				
			||||
 | 
				
			||||
        $content_type = isset($info['content_type']) ? $info['content_type'] : ''; | 
				
			||||
        if ($content_type) | 
				
			||||
        { | 
				
			||||
            $result = reset(explode(';', $content_type)); | 
				
			||||
            $result = strtolower($result); | 
				
			||||
            return $this->mime = $result; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        return $this->mime = ''; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function is_xml() | 
				
			||||
    { | 
				
			||||
        $mime = $this->mime(); | 
				
			||||
        if (!empty($mime)) | 
				
			||||
        { | 
				
			||||
            return strpos($mime, 'xml') !== false; | 
				
			||||
        } | 
				
			||||
        return $this->ext() == 'xml'; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function is_image() | 
				
			||||
    { | 
				
			||||
        $mime = $this->mime(); | 
				
			||||
        if ($mime) | 
				
			||||
        { | 
				
			||||
            return strpos($mime, 'image') !== false; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $ext = $this->ext(); | 
				
			||||
        $formats = array('gif', 'jpeg', 'jpg', 'jpe', 'pjpeg', 'png', 'svg', 'tiff', 'ico'); | 
				
			||||
        foreach ($formats as $format) | 
				
			||||
        { | 
				
			||||
            if ($format == $ext) | 
				
			||||
            { | 
				
			||||
                return true; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        return false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function is_video() | 
				
			||||
    { | 
				
			||||
        $mime = $this->mime(); | 
				
			||||
        if ($mime) | 
				
			||||
        { | 
				
			||||
            return strpos($mime, 'video') !== false; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $ext = $this->ext(); | 
				
			||||
        $formats = array('mpeg', 'mp4', 'ogg', 'wmv', 'mkv'); | 
				
			||||
        foreach ($formats as $format) | 
				
			||||
        { | 
				
			||||
            if ($format == $ext) | 
				
			||||
            { | 
				
			||||
                return true; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        return false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function is_audio() | 
				
			||||
    { | 
				
			||||
        $mime = $this->mime(); | 
				
			||||
        if ($mime) | 
				
			||||
        { | 
				
			||||
            return strpos($mime, 'audio') !== false; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $ext = $this->ext(); | 
				
			||||
        $formats = array('mp3'); | 
				
			||||
        foreach ($formats as $format) | 
				
			||||
        { | 
				
			||||
            if ($format == $ext) | 
				
			||||
            { | 
				
			||||
                return true; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        return false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function is_rss() | 
				
			||||
    { | 
				
			||||
        if (!$this->is_xml()) | 
				
			||||
        { | 
				
			||||
            return false; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $doc = $this->doc(); | 
				
			||||
        $nodes = $doc->getElementsByTagName('rss'); | 
				
			||||
        return $nodes->length != 0; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function is_gadget() | 
				
			||||
    { | 
				
			||||
        if (!$this->is_xml()) | 
				
			||||
        { | 
				
			||||
            return false; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $doc = $this->doc(); | 
				
			||||
        $nodes = $doc->getElementsByTagName('ModulePrefs'); | 
				
			||||
        return $nodes->length != 0; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function canonic_url($src) | 
				
			||||
    { | 
				
			||||
        if (strpos($src, '//') === 0) | 
				
			||||
        { | 
				
			||||
            $src = "http:$src"; | 
				
			||||
        } | 
				
			||||
        else if (strpos($src, '/') === 0) //relative url to the root  | 
				
			||||
        { | 
				
			||||
            $url = $this->url(); | 
				
			||||
            $protocol = reset(explode('://', $url)); | 
				
			||||
            $domain = end(explode('://', $url)); | 
				
			||||
            $domain = reset(explode('/', $domain)); | 
				
			||||
            $src = "$protocol://$domain/$src"; | 
				
			||||
        } | 
				
			||||
        else if (strpos($src, 'http') !== 0) //relative url to the document | 
				
			||||
        { | 
				
			||||
            $url = $this->url(); | 
				
			||||
            $tail = end(explode('/', $url)); | 
				
			||||
            $base = str_replace($tail, '', $url); | 
				
			||||
 | 
				
			||||
            $src = $base . $src; | 
				
			||||
        } | 
				
			||||
        return $src; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Content of the resource. | 
				
			||||
     *  | 
				
			||||
     * @return string | 
				
			||||
     */ | 
				
			||||
    public function source() | 
				
			||||
    { | 
				
			||||
        if (!is_null($this->source)) | 
				
			||||
        { | 
				
			||||
            return $this->source; | 
				
			||||
        } | 
				
			||||
        $info = $this->info(); | 
				
			||||
 | 
				
			||||
        return $this->source = $info['content']; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Array of arrays containing the page's metadata.  | 
				
			||||
     *  | 
				
			||||
     * @return array | 
				
			||||
     */ | 
				
			||||
    public function metadata() | 
				
			||||
    { | 
				
			||||
        if (!is_null($this->metadata)) | 
				
			||||
        { | 
				
			||||
            return $this->metadata; | 
				
			||||
        } | 
				
			||||
        return $this->metadata = $this->get_metadata(); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function title() | 
				
			||||
    { | 
				
			||||
        if (!is_null($this->title)) | 
				
			||||
        { | 
				
			||||
            return $this->title; | 
				
			||||
        } | 
				
			||||
        return $this->title = $this->get_title(); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @return DOMDocument|boolean | 
				
			||||
     */ | 
				
			||||
    public function doc() | 
				
			||||
    { | 
				
			||||
        if (!is_null($this->doc)) | 
				
			||||
        { | 
				
			||||
            return $this->doc; | 
				
			||||
        } | 
				
			||||
        return $this->doc = $this->get_doc($this->source()); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    function get_meta($name) | 
				
			||||
    { | 
				
			||||
        $metadata = $this->metadata(); | 
				
			||||
        $name = strtolower($name); | 
				
			||||
        foreach ($metadata as $attributes) | 
				
			||||
        { | 
				
			||||
            $key = isset($attributes['name']) ? $attributes['name'] : false; | 
				
			||||
            $key = $key ? strtolower($key) : $key; | 
				
			||||
            if ($name == $key) | 
				
			||||
            { | 
				
			||||
                return $attributes['content']; | 
				
			||||
            } | 
				
			||||
            $key = isset($attributes['property']) ? $attributes['property'] : false; | 
				
			||||
            $key = $key ? strtolower($key) : $key; | 
				
			||||
            if ($name == $key) | 
				
			||||
            { | 
				
			||||
                return isset($attributes['content']) ? $attributes['content'] : false; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        return false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    function get_link($key, $value) | 
				
			||||
    { | 
				
			||||
        $links = $this->links(); | 
				
			||||
        $key = strtolower($key); | 
				
			||||
        $value = strtolower($value); | 
				
			||||
        foreach ($links as $attributes) | 
				
			||||
        { | 
				
			||||
            $a = isset($attributes[$key]) ? $attributes[$key] : false; | 
				
			||||
            $a = $a ? strtolower($a) : $a; | 
				
			||||
            if ($a == $value) | 
				
			||||
            { | 
				
			||||
                return $attributes; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        return false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function links() | 
				
			||||
    { | 
				
			||||
        if (!is_null($this->links)) | 
				
			||||
        { | 
				
			||||
            return $this->links; | 
				
			||||
        } | 
				
			||||
        return $this->links = $this->get_links(); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param string $xpath dom xpath | 
				
			||||
     * @return string | 
				
			||||
     */ | 
				
			||||
    public function findx($query) | 
				
			||||
    { | 
				
			||||
        $doc = $this->doc(); | 
				
			||||
        if (empty($doc)) | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
        $xpath = new DOMXpath($doc); | 
				
			||||
        $nodes = $xpath->query($query); | 
				
			||||
        if ($nodes->length > 0) | 
				
			||||
        { | 
				
			||||
            return $doc->saveXML($nodes->item(0)); | 
				
			||||
        } | 
				
			||||
        else | 
				
			||||
        { | 
				
			||||
            return ''; | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function info() | 
				
			||||
    { | 
				
			||||
        if (!is_null($this->info)) | 
				
			||||
        { | 
				
			||||
            return $this->info; | 
				
			||||
        } | 
				
			||||
        return $this->info = self::fetch($this->url()); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param string $source | 
				
			||||
     * @return boolean|DOMDocument  | 
				
			||||
     */ | 
				
			||||
    protected function get_doc($source) | 
				
			||||
    { | 
				
			||||
        if ($source == false) | 
				
			||||
        { | 
				
			||||
            return false; | 
				
			||||
        } | 
				
			||||
        $source = $this->source(); | 
				
			||||
        $result = new DOMDocument(); | 
				
			||||
        libxml_clear_errors(); | 
				
			||||
        libxml_use_internal_errors(true); | 
				
			||||
        if ($this->is_xml()) | 
				
			||||
        { | 
				
			||||
            $success = $result->loadXML($source); | 
				
			||||
        } | 
				
			||||
        else | 
				
			||||
        { | 
				
			||||
            $success = $result->loadHTML($source); | 
				
			||||
        } | 
				
			||||
        //$e = libxml_get_errors(); | 
				
			||||
        return $result ? $result : false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function get_metadata() | 
				
			||||
    { | 
				
			||||
        $result = array(); | 
				
			||||
 | 
				
			||||
        $doc = $this->doc(); | 
				
			||||
        if ($doc == false) | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
        $metas = $doc->getElementsByTagName('meta'); | 
				
			||||
        if ($metas->length == 0) | 
				
			||||
        { | 
				
			||||
            return $result; | 
				
			||||
        } | 
				
			||||
        foreach ($metas as $meta) | 
				
			||||
        { | 
				
			||||
            $values = array(); | 
				
			||||
            $attributes = $meta->attributes; | 
				
			||||
            $length = $attributes->length; | 
				
			||||
            for ($i = 0; $i < $length; ++$i) | 
				
			||||
            { | 
				
			||||
                $name = $attributes->item($i)->name; | 
				
			||||
                $value = $attributes->item($i)->value; | 
				
			||||
                $value = $attributes->item($i)->value; | 
				
			||||
                $values[$name] = $value; | 
				
			||||
            } | 
				
			||||
            $result[] = $values; | 
				
			||||
        } | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function get_title() | 
				
			||||
    { | 
				
			||||
        $doc = $this->doc(); | 
				
			||||
        if ($doc == false) | 
				
			||||
        { | 
				
			||||
            return ''; | 
				
			||||
        } | 
				
			||||
        $titles = $doc->getElementsByTagName('title'); | 
				
			||||
        if ($titles->length == 0) | 
				
			||||
        { | 
				
			||||
            return false; | 
				
			||||
        } | 
				
			||||
        $result = $titles->item(0)->nodeValue; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function get_links() | 
				
			||||
    { | 
				
			||||
        $doc = $this->doc(); | 
				
			||||
        if ($doc == false) | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
        $result = array(); | 
				
			||||
 | 
				
			||||
        $metas = $doc->getElementsByTagName('link'); | 
				
			||||
        if ($metas->length == 0) | 
				
			||||
        { | 
				
			||||
            return $result; | 
				
			||||
        } | 
				
			||||
        foreach ($metas as $meta) | 
				
			||||
        { | 
				
			||||
            $values = array(); | 
				
			||||
            $attributes = $meta->attributes; | 
				
			||||
            $length = $attributes->length; | 
				
			||||
            for ($i = 0; $i < $length; ++$i) | 
				
			||||
            { | 
				
			||||
                $name = $attributes->item($i)->name; | 
				
			||||
                $value = $attributes->item($i)->value; | 
				
			||||
                $values[$name] = $value; | 
				
			||||
            } | 
				
			||||
            $result[] = $values; | 
				
			||||
        } | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,113 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Google calendar renderer.  | 
				
			||||
 *  | 
				
			||||
 * @todo:  | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetGoogleCalendarRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function accept($asset) | 
				
			||||
    { | 
				
			||||
        $url = $asset->url(); | 
				
			||||
        $url = str_replace('http://', '', $url); | 
				
			||||
        $url = str_replace('https://', '', $url); | 
				
			||||
 | 
				
			||||
        $domain = reset(split('/', $url)); | 
				
			||||
        return strpos($domain, 'google.com/calendar') !== false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param string $url  | 
				
			||||
     */ | 
				
			||||
    public function explode_url_parameters($url = null) | 
				
			||||
    { | 
				
			||||
        if (strpos($url, '?') === false) | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $params = explode('?', $url); | 
				
			||||
        $params = end($params); | 
				
			||||
        $params = explode('&', $params); | 
				
			||||
        foreach ($params as $param) | 
				
			||||
        { | 
				
			||||
            list($key, $val) = explode('=', $param); | 
				
			||||
            $result[$key] = $val; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function implode_url_parameters($params) | 
				
			||||
    { | 
				
			||||
        $result = array(); | 
				
			||||
        foreach ($params as $key => $value) | 
				
			||||
        { | 
				
			||||
            if ($value) | 
				
			||||
            { | 
				
			||||
                $result[] = "$key=$value"; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        return join('&', $result); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function url($base = 'http:://map.google.com/', $params = array()) | 
				
			||||
    { | 
				
			||||
        $head = reset(explode('?', $base)); | 
				
			||||
        $items = $this->explode_url_parameters($base); | 
				
			||||
        foreach ($params as $key => $value) | 
				
			||||
        { | 
				
			||||
                $items[$key] = $value; | 
				
			||||
        } | 
				
			||||
        $tail = $this->implode_url_parameters($items); | 
				
			||||
        $tail = empty($tail) ? '' : "?$tail"; | 
				
			||||
        return $head . $tail; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        if (!$this->accept($asset)) | 
				
			||||
        { | 
				
			||||
            return; | 
				
			||||
        } | 
				
			||||
        $params = array('output' => 'embed'); | 
				
			||||
         | 
				
			||||
        $base = $asset->url(); | 
				
			||||
        $url = $this->url($base, $params); | 
				
			||||
         | 
				
			||||
        $title = $asset->title(); | 
				
			||||
        $description = $asset->get_meta('description'); | 
				
			||||
 | 
				
			||||
        $keywords = $asset->get_meta('keywords'); | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <iframe width="100%" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="$url"></iframe> | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::TITLE] = $title; | 
				
			||||
        $result[self::THUMBNAIL] = $image_src; | 
				
			||||
        $result[self::DESCRIPTION] = $description; | 
				
			||||
        $result[self::TAGS] = $keywords; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,57 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Internal group. I.e. a group from this instance of Mahara. | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetMaharaGroupRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    public static function get_group_id($ref) | 
				
			||||
    { | 
				
			||||
        $ref = trim($ref); | 
				
			||||
        $pattern = '#group/view.php\?id\=([0123456789]+)#'; | 
				
			||||
        $matches = array(); | 
				
			||||
        //mahara group's profile | 
				
			||||
        if (preg_match($pattern, $ref, $matches)) | 
				
			||||
        { | 
				
			||||
            return $matches[1]; | 
				
			||||
        } | 
				
			||||
        //group id | 
				
			||||
        if ($val = intval($ref)) | 
				
			||||
        { | 
				
			||||
            return $val; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        return false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        $url = $asset->url(); | 
				
			||||
        $group_id = self::get_group_id($url); | 
				
			||||
        if (empty($group_id)) | 
				
			||||
        { | 
				
			||||
            return false; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $data = get_record('group', 'id', $group_id); | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        safe_require('blocktype', 'ple/group'); | 
				
			||||
        $result[self::EMBED_SNIPPET] = PluginBlocktypeGroup::render_preview($group_id); | 
				
			||||
        $result[self::THUMBNAIL] = PluginBlocktypeGroup::get_thumbnail($group_id); | 
				
			||||
        $result[self::TITLE] = $data->name; | 
				
			||||
        $result[self::DESCRIPTION] = $data->description; | 
				
			||||
 | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,63 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * | 
				
			||||
 * Internal person. I.e. a person from this instance of Mahara. | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetMaharaPersonRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    public static function get_user_id($ref) | 
				
			||||
    { | 
				
			||||
        $ref = trim($ref); | 
				
			||||
        $pattern = '#user/view.php\?id\=([0123456789]+)#'; | 
				
			||||
        $matches = array(); | 
				
			||||
        //mahara user's profile | 
				
			||||
        if (preg_match($pattern, $ref, $matches)) | 
				
			||||
        { | 
				
			||||
            return $matches[1]; | 
				
			||||
        } | 
				
			||||
        //email | 
				
			||||
        if ($user = get_record('usr', 'email', $ref)) | 
				
			||||
        { | 
				
			||||
            return $user->id; | 
				
			||||
        } | 
				
			||||
        //user id | 
				
			||||
        if ($val = intval($ref)) | 
				
			||||
        { | 
				
			||||
            return $val; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        return false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        $url = $asset->url(); | 
				
			||||
        $id = self::get_user_id($url); | 
				
			||||
        if (empty($id)) | 
				
			||||
        { | 
				
			||||
            return false; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $data = get_record('usr', 'id', $id); | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        safe_require('blocktype', 'ple/person'); | 
				
			||||
        $result[self::EMBED_SNIPPET] = PluginBlocktypePerson::render_preview($id); | 
				
			||||
        $result[self::THUMBNAIL] = PluginBlocktypePerson::get_thumbnail($id); | 
				
			||||
        $result[self::TITLE] = $data->prefferedname ? $data->prefferedname : $data->firstname . ' ' . $data->lastname; | 
				
			||||
        $result[self::DESCRIPTION] = isset($data->description) ? $data->description : ''; | 
				
			||||
 | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,46 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Wiki renderer.  | 
				
			||||
 *  | 
				
			||||
 * @see http://en.wikipedia.org/w/api.php | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2012 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetWikiRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function accept($asset) | 
				
			||||
    {        | 
				
			||||
        return $asset->url_match('wikipedia.org/wiki', 'mediawiki.org/wiki'); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     *  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        if (!$this->accept($asset)) | 
				
			||||
        { | 
				
			||||
            return; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $domain = $asset->url_domain(); | 
				
			||||
        $description = $asset->findx('//div[@id="bodyContent"]/p'); | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = $description; | 
				
			||||
        $result[self::TITLE] = $title; | 
				
			||||
        $result[self::DESCRIPTION] = $description; | 
				
			||||
        $result[self::TAGS] = $keywords; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,75 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Google document renderer.  | 
				
			||||
 *  | 
				
			||||
 * @see http://support.google.com/docs/bin/answer.py?hl=en&answer=86101&topic=1360911&ctx=topic | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetGoogleDocumentRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function accept($asset) | 
				
			||||
    {        | 
				
			||||
        $url = $asset->url(); | 
				
			||||
         | 
				
			||||
        return strpos($url, 'docs.google.com/document/pub') !== false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        if (!$this->accept($asset)) | 
				
			||||
        { | 
				
			||||
            return; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $url = $asset->url(); | 
				
			||||
 | 
				
			||||
        $title = $asset->title(); | 
				
			||||
        $description = $asset->get_meta('description'); | 
				
			||||
        $keywords = $asset->get_meta('keywords'); | 
				
			||||
         | 
				
			||||
        $size = (int) $asset->config('size'); | 
				
			||||
        $size = (24 <= $size && $size <= 800) ? $size : 300; | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
         | 
				
			||||
        <div style="height:{$size}px;" class="resize vertical" > | 
				
			||||
            <iframe style=background-color:#ffffff;" width="100%" height="100%" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="$url"></iframe> | 
				
			||||
        </div> | 
				
			||||
        <style type="text/css"> | 
				
			||||
        div.resize.vertical { | 
				
			||||
            background-color: #EEEEEE; | 
				
			||||
            border-color: #EEEEEE; | 
				
			||||
            border-style: solid; | 
				
			||||
            border-width: 1px; | 
				
			||||
            resize:vertical; | 
				
			||||
            overflow: hidden;  | 
				
			||||
            padding-bottom:15px;  | 
				
			||||
            min-height:24px;  | 
				
			||||
            max-height:800px; | 
				
			||||
} | 
				
			||||
        </style> | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::TITLE] = $title; | 
				
			||||
        $result[self::DESCRIPTION] = $description; | 
				
			||||
        $result[self::TAGS] = $keywords; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,95 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Google document viewer renderer. Provide an embeded viewer for the following | 
				
			||||
 * documetn types: | 
				
			||||
 *  | 
				
			||||
 *     Microsoft Word (.DOC and .DOCX) | 
				
			||||
 *     Microsoft Excel (.XLS and .XLSX) | 
				
			||||
 *     Microsoft PowerPoint (.PPT and .PPTX) | 
				
			||||
 *     Adobe Portable Document Format (.PDF) | 
				
			||||
 *     Apple Pages (.PAGES) | 
				
			||||
 *     Adobe Illustrator (.AI) | 
				
			||||
 *     Adobe Photoshop (.PSD) | 
				
			||||
 *     Tagged Image File Format (.TIFF) | 
				
			||||
 *     Autodesk AutoCad (.DXF) | 
				
			||||
 *     Scalable Vector Graphics (.SVG) | 
				
			||||
 *     PostScript (.EPS, .PS) | 
				
			||||
 *     TrueType (.TTF) | 
				
			||||
 *     XML Paper Specification (.XPS) | 
				
			||||
 *     Archive file types (.ZIP and .RAR) | 
				
			||||
 *  | 
				
			||||
 * @see https://docs.google.com/viewer | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetGoogleDocumentViewerRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function accept($asset) | 
				
			||||
    { | 
				
			||||
        $supported_extentions = array('doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'pages', 'ai', 'psd', 'tiff', 'dxf', 'svg', 'eps', 'ps', 'eps', 'ttf', 'zip', 'rar'); | 
				
			||||
        return $asset->has_ext($supported_extentions); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function url($document_url) | 
				
			||||
    { | 
				
			||||
        return 'https://docs.google.com/viewer?embedded=true&url=' . urlencode($document_url); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        if (!$this->accept($asset)) | 
				
			||||
        { | 
				
			||||
            return; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $url = $this->url($asset->url()); | 
				
			||||
 | 
				
			||||
        $title = $asset->title(); | 
				
			||||
        $description = $asset->get_meta('description'); | 
				
			||||
 | 
				
			||||
        $keywords = $asset->get_meta('keywords'); | 
				
			||||
 | 
				
			||||
        $size = (int) $asset->config('size'); | 
				
			||||
        $size = (24 <= $size && $size <= 800) ? $size : 300; | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <div style="height:{$size}px;" class="resize vertical" > | 
				
			||||
            <iframe style=background-color:#ffffff;" width="100%" height="100%" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="$url"></iframe> | 
				
			||||
        </div> | 
				
			||||
        <style type="text/css"> | 
				
			||||
        div.resize.vertical { | 
				
			||||
            background-color: #EEEEEE; | 
				
			||||
            border-color: #EEEEEE; | 
				
			||||
            border-style: solid; | 
				
			||||
            border-width: 1px; | 
				
			||||
            resize:vertical; | 
				
			||||
            overflow: hidden;  | 
				
			||||
            padding-bottom:15px;  | 
				
			||||
            min-height:24px;  | 
				
			||||
            max-height:800px; | 
				
			||||
} | 
				
			||||
        </style> | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::TITLE] = $title; | 
				
			||||
        //$result[self::THUMBNAIL] = $image_src; | 
				
			||||
        $result[self::DESCRIPTION] = $description; | 
				
			||||
        $result[self::TAGS] = $keywords; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,129 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Google map page renderer.  | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetGoogleMapRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function accept($asset) | 
				
			||||
    { | 
				
			||||
        $url = $asset->url(); | 
				
			||||
        $url = str_replace('http://', '', $url); | 
				
			||||
        $url = str_replace('https://', '', $url); | 
				
			||||
 | 
				
			||||
        $domain = reset(explode('/', $url)); | 
				
			||||
        return strpos($domain, 'maps.google') !== false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param string $url  | 
				
			||||
     */ | 
				
			||||
    public function explode_url_parameters($url = null) | 
				
			||||
    { | 
				
			||||
        if (strpos($url, '?') === false) | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $params = explode('?', $url); | 
				
			||||
        $params = end($params); | 
				
			||||
        $params = explode('&', $params); | 
				
			||||
        foreach ($params as $param) | 
				
			||||
        { | 
				
			||||
            list($key, $val) = explode('=', $param); | 
				
			||||
            $result[$key] = $val; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    public function implode_url_parameters($params) | 
				
			||||
    { | 
				
			||||
        $result = array(); | 
				
			||||
        foreach ($params as $key => $value) | 
				
			||||
        { | 
				
			||||
            if ($value) | 
				
			||||
            { | 
				
			||||
                $result[] = "$key=$value"; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        return join('&', $result); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function url($base = 'http:://map.google.com/', $params = array()) | 
				
			||||
    { | 
				
			||||
        $head = reset(explode('?', $base)); | 
				
			||||
        $items = $this->explode_url_parameters($base); | 
				
			||||
        foreach ($params as $key => $value) | 
				
			||||
        { | 
				
			||||
                $items[$key] = $value; | 
				
			||||
        } | 
				
			||||
        $tail = $this->implode_url_parameters($items); | 
				
			||||
        $tail = empty($tail) ? '' : "?$tail"; | 
				
			||||
        return $head . $tail; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        if (!$this->accept($asset)) | 
				
			||||
        { | 
				
			||||
            return; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $params = array('output' => 'embed'); | 
				
			||||
         | 
				
			||||
        $base = $asset->url(); | 
				
			||||
        $url = $this->url($base, $params); | 
				
			||||
         | 
				
			||||
        $title = $asset->title(); | 
				
			||||
        $description = $asset->get_meta('description'); | 
				
			||||
 | 
				
			||||
        $keywords = $asset->get_meta('keywords'); | 
				
			||||
         | 
				
			||||
        $size = (int) $asset->config('size'); | 
				
			||||
        $size = (24 <= $size && $size <= 800) ? $size : 300; | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <div style="height:{$size}px;" class="resize vertical" > | 
				
			||||
            <iframe style=background-color:#ffffff;" width="100%" height="100%" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="$url"></iframe> | 
				
			||||
        </div> | 
				
			||||
        <style type="text/css"> | 
				
			||||
        div.resize.vertical { | 
				
			||||
            background-color: #EEEEEE; | 
				
			||||
            border-color: #EEEEEE; | 
				
			||||
            border-style: solid; | 
				
			||||
            border-width: 1px; | 
				
			||||
            resize:vertical; | 
				
			||||
            overflow: hidden;  | 
				
			||||
            padding-bottom:15px;  | 
				
			||||
            min-height:24px;  | 
				
			||||
            max-height:800px; | 
				
			||||
} | 
				
			||||
        </style> | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::TITLE] = $title; | 
				
			||||
        $result[self::DESCRIPTION] = $description; | 
				
			||||
        $result[self::TAGS] = $keywords; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,90 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Google widget/gadget renderer. | 
				
			||||
 * Accept the following urls: | 
				
			||||
 *  | 
				
			||||
 *      module:             http://www.google.com/ig/directory?type=gadgets&url=www.google.com/ig/modules/eyes/eyes.xml | 
				
			||||
 *      directory entry:    www.google.com/ig/modules/eyes/eyes.xml | 
				
			||||
 *      configured url:     www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/eyes/eyes.xml&synd=open&w=320&h=121&title=__MSG_title__&lang=fr&country=ALL&border=%23ffffff%7C3px%2C1px+solid+%23999999&output=js | 
				
			||||
 *  | 
				
			||||
 * @see http://www.google.com/ig/directory?type=gadgets&url=www.google.com/ig/modules/eyes/eyes.xml | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetGoogleWidgetRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
         | 
				
			||||
        if ($asset->url_match('gmodules.com/ig/') && $asset->url_param('url') != false) | 
				
			||||
        { | 
				
			||||
            $url = $asset->url(); | 
				
			||||
            $title = $asset->url_param('title'); | 
				
			||||
            $title = ($title == '__MSG_title__') ? '' : $title; | 
				
			||||
             | 
				
			||||
            $embed = <<<EOT | 
				
			||||
                <script src="$url"></script> | 
				
			||||
EOT; | 
				
			||||
             | 
				
			||||
            $result = array(); | 
				
			||||
            $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
            $result[self::TITLE] = $title; | 
				
			||||
            return $result; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        if (!$asset->is_gadget()) | 
				
			||||
        { | 
				
			||||
            $url = $asset->url(); | 
				
			||||
 | 
				
			||||
            if (!$asset->url_match('google.com/ig/directory')) | 
				
			||||
            { | 
				
			||||
                return false; | 
				
			||||
            } | 
				
			||||
            if (!$asset->url_match('type=gadgets')) | 
				
			||||
            { | 
				
			||||
                return false; | 
				
			||||
            } | 
				
			||||
 | 
				
			||||
            $url = $asset->url_param('url'); | 
				
			||||
            if (empty($url)) | 
				
			||||
            { | 
				
			||||
                return false; | 
				
			||||
            } | 
				
			||||
            $asset = new HttpResource($url); | 
				
			||||
            if (!$asset->is_gadget()) | 
				
			||||
            { | 
				
			||||
                return false; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $url = $asset->url(); | 
				
			||||
        if (strpos($url, 'http') !== 0) | 
				
			||||
        { | 
				
			||||
            $url = "http://$url"; | 
				
			||||
        } | 
				
			||||
        $url = urlencode($url); | 
				
			||||
        $title = $asset->title(); | 
				
			||||
        $title = $title ? $title : $asset->name(); | 
				
			||||
         | 
				
			||||
        $size = (int) $asset->config('size'); | 
				
			||||
        $size = (24 <= $size && $size <= 800) ? $size : 300; | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <script src="//www.gmodules.com/ig/ifr?url=$url&w=$size&output=js"></script> | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::TITLE] = $title; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,44 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Process image resources. I.e. png, jpeg, etc. | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetImageRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
     | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        if (! $asset->is_image()) | 
				
			||||
        { | 
				
			||||
            return false; | 
				
			||||
        } | 
				
			||||
         | 
				
			||||
        global $THEME; | 
				
			||||
        $url = $asset->url(); | 
				
			||||
        $title = $asset->title(); | 
				
			||||
        $title = $title ? $title : $asset->name(); | 
				
			||||
         | 
				
			||||
        $size = (int) $asset->config('size'); | 
				
			||||
        $size = (24 <= $size && $size <= 800) ? $size : 300; | 
				
			||||
         | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <div style="text-align:center"><a href="$url"><img src="{$url}" width="$size" alt="{$title}" title="{$title}"></a></div> | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::URL] = $url; | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::TITLE] = $title; | 
				
			||||
        $result[self::THUMBNAIL] = $url; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,65 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Media renderer. I.e. video streams that can be embeded through an embed tag. | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetMediaRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function accept($asset) | 
				
			||||
    { | 
				
			||||
        if ($asset->is_video()) | 
				
			||||
        { | 
				
			||||
            return true; | 
				
			||||
        } | 
				
			||||
         | 
				
			||||
        //swf mime type is application/x-shockwave-flash | 
				
			||||
        return $asset->has_ext('swf'); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        if (!$this->accept($asset)) | 
				
			||||
        { | 
				
			||||
            return; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $url = $asset->url(); | 
				
			||||
 | 
				
			||||
        $title = $asset->title(); | 
				
			||||
        $description = $asset->get_meta('description'); | 
				
			||||
        $keywords = $asset->get_meta('keywords'); | 
				
			||||
         | 
				
			||||
         | 
				
			||||
        $size = (int) $asset->config('size'); | 
				
			||||
        $size = (24 <= $size && $size <= 800) ? $size : 300; | 
				
			||||
         | 
				
			||||
        $width = $size; | 
				
			||||
        $height = $size *9/16; | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <div style="text-align:center;"><embed style="display:inline-block;" width="{$width}px" height="{$height}px" name="plugin" src="$url" ></div> | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::TITLE] = $title; | 
				
			||||
        $result[self::DESCRIPTION] = $description; | 
				
			||||
        $result[self::TAGS] = $keywords; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,65 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Media Server renderer.  | 
				
			||||
 *  | 
				
			||||
 * Note that some videos are protected. It is therefore not possible to use the | 
				
			||||
 * autodiscovery feature. That is to get the web page, look at the meta data headers | 
				
			||||
 * and read the oembed api call. This would only work for public content/javascript | 
				
			||||
 * bookmarklet.  | 
				
			||||
 *  | 
				
			||||
 * So here we bypass the discovery service and directly call the API endpoint  | 
				
			||||
 * with the page url to retrieve oembed metadata - which happens to be public. | 
				
			||||
 *  | 
				
			||||
 * @see https://mediaserver.unige.ch | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2012 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetMediaserverRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
     | 
				
			||||
    const API_ENDPOINT = 'http://129.194.20.121/oembed/unige-oembed-provider-test.php'; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function accept($asset) | 
				
			||||
    { | 
				
			||||
        return $asset->url_match('https://mediaserver.unige.ch/play/') ||$asset->url_match('http://mediaserver.unige.ch/play/'); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        if (!$this->accept($asset)) | 
				
			||||
        { | 
				
			||||
            return; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $width = (int) $asset->config('size'); | 
				
			||||
        $width = (24 <= $width && $width <= 800) ? $width : 300; | 
				
			||||
         | 
				
			||||
        $url = $asset->url(); | 
				
			||||
         | 
				
			||||
        $oembed = self::API_ENDPOINT . '?url=' . urlencode($url) . '&maxwidth=' . $width; | 
				
			||||
 | 
				
			||||
        $data = HttpResource::fetch_json($oembed);  | 
				
			||||
        if (empty($data)) | 
				
			||||
        { | 
				
			||||
            return false; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $result[self::THUMBNAIL] = isset($data['thumbnail_url']) ? $data['thumbnail_url'] : ''; | 
				
			||||
        $result[self::TITLE] = isset($data['title']) ? $data['title'] : ''; | 
				
			||||
        $result[self::EMBED_SNIPPET] = isset($data['html']) ? $data['html'] : ''; | 
				
			||||
 | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,124 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Process html pages that support the oembed protocol. | 
				
			||||
 *  | 
				
			||||
 * Note that here we rely on the discovery service. That is each page that contains in | 
				
			||||
 * its metadata the oembed request. | 
				
			||||
 *  | 
				
			||||
 * @see http://oembed.com/ | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 *  | 
				
			||||
 */ | 
				
			||||
class AssetOembedRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        $link = $asset->get_link('type', 'application/json+oembed'); | 
				
			||||
        if (empty($link)) | 
				
			||||
        { | 
				
			||||
            return false; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $width = (int) $asset->config('size'); | 
				
			||||
        $width = (24 <= $width && $width <= 800) ? $width : 300; | 
				
			||||
 | 
				
			||||
        $href = $link['href']; | 
				
			||||
        $data = HttpResource::fetch_json("$href&maxwidth=$width"); //&maxheight=$height | 
				
			||||
        if (empty($data)) | 
				
			||||
        { | 
				
			||||
            return false; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $data['title'] = isset($data['title']) ? $data['title'] : ''; | 
				
			||||
        $data['width'] = isset($data['width']) ? intval($data['width']) : ''; | 
				
			||||
        $data['height'] = isset($data['height']) ? intval($data['height']) : ''; | 
				
			||||
 | 
				
			||||
        $type = $data['type']; | 
				
			||||
        $f = array($this, "render_$type"); | 
				
			||||
        if (is_callable($f)) | 
				
			||||
        { | 
				
			||||
            $result = call_user_func($f, $asset, $data); | 
				
			||||
        } | 
				
			||||
        else | 
				
			||||
        { | 
				
			||||
            $result = array(); | 
				
			||||
        } | 
				
			||||
        $result[self::THUMBNAIL] = isset($data['thumbnail_url']) ? $data['thumbnail_url'] : ''; | 
				
			||||
        $result[self::TITLE] = isset($data['title']) ? $data['title'] : ''; | 
				
			||||
 | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function render_photo($asset, $data) | 
				
			||||
    { | 
				
			||||
        if ($data['type'] != 'photo') | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $html = isset($data['html']) ? $data['html'] : ''; | 
				
			||||
        if ($html) | 
				
			||||
        { | 
				
			||||
            $result[self::EMBED_SNIPPET] = '<div style="display:inline-block">' . $html . '</div>'; | 
				
			||||
            return $result; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $title = $data['title']; | 
				
			||||
        $width = (int)$data['width']; | 
				
			||||
        $height = (int)$data['height']; | 
				
			||||
//        $ratio = $height / $width; | 
				
			||||
//        $height = $ratio * $width; | 
				
			||||
 | 
				
			||||
        $url = $data['url']; | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <div><a href="$url"><img src="{$url}" width="{$width}" height="{$height}" "alt="{$title}" title="{$title}"></a></div> | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function render_video($asset, $data) | 
				
			||||
    { | 
				
			||||
        if ($data['type'] != 'video') | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = '<div style="display:inline-block">' . $data['html'] . '</div>'; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function render_rich($asset, $data) | 
				
			||||
    { | 
				
			||||
        if ($data['type'] != 'rich') | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = '<div style="display:inline-block">' . $data['html'] . '</div>'; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function render_link($asset, $data) | 
				
			||||
    { | 
				
			||||
        if ($data['type'] != 'link') | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
        return array(); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,201 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Process pages that support the open graph protocol | 
				
			||||
 *  | 
				
			||||
 * @see http://ogp.me/ | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetOgRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Renderer function. Take a http asset as input and return an array containing | 
				
			||||
     * various properties: metadata, html snippet, etc. | 
				
			||||
     *  | 
				
			||||
     * @param HttpResource $asset | 
				
			||||
     * @return array | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        $type = $asset->get_meta('og:type'); | 
				
			||||
        if (empty($type)) | 
				
			||||
        { | 
				
			||||
            if ($video = $asset->get_meta('og:video')) | 
				
			||||
            { | 
				
			||||
                $type = 'video'; | 
				
			||||
            } | 
				
			||||
            else if ($video = $asset->get_meta('og:image')) | 
				
			||||
            { | 
				
			||||
                $type = 'default'; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        if (empty($type)) | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $type = explode('.', $type); | 
				
			||||
        $type = reset($type); | 
				
			||||
        $f = array($this, "render_$type"); | 
				
			||||
        if (is_callable($f)) | 
				
			||||
        { | 
				
			||||
            $result = call_user_func($f, $asset); | 
				
			||||
        } | 
				
			||||
        else | 
				
			||||
        { | 
				
			||||
            $result = $this->render_default($asset); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $result[self::TITLE] = $asset->get_meta('og:title'); | 
				
			||||
        $result[self::THUMBNAIL] = $asset->get_meta('og:image'); | 
				
			||||
        $result[self::LANGUAGE] = $asset->get_meta('og:language'); | 
				
			||||
 | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * @param HttpResource $asset | 
				
			||||
     * @return array | 
				
			||||
     */ | 
				
			||||
    protected function render_video($asset) | 
				
			||||
    { | 
				
			||||
        $url = $asset->get_meta('og:video'); | 
				
			||||
        $url = str_replace('?autoPlay=1', '?', $url); | 
				
			||||
        $url = str_replace('&autoPlay=1', '', $url); | 
				
			||||
 | 
				
			||||
        if (empty($url)) | 
				
			||||
        { | 
				
			||||
            return array(); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $type = $asset->get_meta('og:video:type'); | 
				
			||||
        if ($type) | 
				
			||||
        { | 
				
			||||
            $type = ' type="' . $type . '" '; | 
				
			||||
        } | 
				
			||||
         | 
				
			||||
        $size = (int) $asset->config('size'); | 
				
			||||
        $size = (24 <= $size && $size <= 800) ? $size : 300; | 
				
			||||
         | 
				
			||||
        $width = $asset->get_meta('og:video:width'); | 
				
			||||
        $width = $width ? $width : $asset->get_meta('video_width'); | 
				
			||||
        $height = $asset->get_meta('og:video:height'); | 
				
			||||
        $height = $height ? $height : $asset->get_meta('video_height'); | 
				
			||||
 | 
				
			||||
        if ($width) | 
				
			||||
        { | 
				
			||||
            $ratio = $height / $width; | 
				
			||||
            $base = min($size, $width); | 
				
			||||
            $width = $base; | 
				
			||||
            $height = $ratio * $base; | 
				
			||||
            $size = 'width="' . $width . '" height="' . $height . '"'; | 
				
			||||
        } | 
				
			||||
        else | 
				
			||||
        { | 
				
			||||
            $size = 'width="' . $size . '"'; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <embed $type $size src="$url" />         | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
        $result[self::EMBED_TYPE] = $type; | 
				
			||||
        $result[self::EMBED_URL] = $url; | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::TAGS] = $asset->get_meta('og:video:tag'); | 
				
			||||
        $result[self::CREATED_TIME] = $asset->get_meta('og:video:release_date'); | 
				
			||||
        $result[self::DURATION] = $asset->get_meta('og:duration'); | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function render_article($asset) | 
				
			||||
    { | 
				
			||||
        $result = $this->render_default($asset); | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function render_audio($asset) | 
				
			||||
    { | 
				
			||||
        $result = $this->render_default($asset); | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    protected function render_book($asset) | 
				
			||||
    { | 
				
			||||
        $result = $this->render_default($asset); | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     *  | 
				
			||||
     * @param HttpResource $asset | 
				
			||||
     * @return array | 
				
			||||
     */ | 
				
			||||
    protected function render_default($asset) | 
				
			||||
    { | 
				
			||||
        $url = $asset->get_meta('og:url'); | 
				
			||||
        $url = htmlentities($url); | 
				
			||||
        $title = $asset->get_meta('og:title'); | 
				
			||||
        $image = $asset->get_meta('og:image'); | 
				
			||||
        $image = htmlentities($image); | 
				
			||||
        $width = $asset->get_meta('og:image:width'); | 
				
			||||
        $height = $asset->get_meta('og:image:height'); | 
				
			||||
        $description = $asset->get_meta('og:description'); | 
				
			||||
        $description = $description ? $description : $asset->get_meta('description'); | 
				
			||||
 | 
				
			||||
        $size = (int) $asset->config('size'); | 
				
			||||
        $size = (24 <= $size && $size <= 800) ? $size : 300; | 
				
			||||
 | 
				
			||||
        if ($width) | 
				
			||||
        { | 
				
			||||
            $ratio = $height / $width; | 
				
			||||
            $base = min($size, $width); | 
				
			||||
            $width = $base; | 
				
			||||
            $height = $ratio * $base; | 
				
			||||
            $size = 'width="' . $width . '" height="' . $height . '"'; | 
				
			||||
        } | 
				
			||||
        else | 
				
			||||
        { | 
				
			||||
            $size = 'width="' . $size . '"'; | 
				
			||||
        } | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <div> | 
				
			||||
            <a href="$url" style="float:left; margin-right:5px; margin-bottom:5px; display:block;"><img src="{$image}" {$size} alt="{$title}" title="{$title}"></a> | 
				
			||||
            <div style="clear:both;"></div> | 
				
			||||
        </div> | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::DESCRIPTION] = $asset->get_meta('description'); | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * @param HttpResource $asset | 
				
			||||
     * @return array | 
				
			||||
     */ | 
				
			||||
    protected function render_image($asset) | 
				
			||||
    { | 
				
			||||
        $size = (int) $asset->config('size'); | 
				
			||||
        $size = (24 <= $size && $size <= 800) ? $size : 300; | 
				
			||||
 | 
				
			||||
        $title = $data['title']; | 
				
			||||
        $width = $data['width']; | 
				
			||||
        $height = $data['height']; | 
				
			||||
        $ratio = $height / $width; | 
				
			||||
        $base = min($size, $width); | 
				
			||||
        $width = $base; | 
				
			||||
        $height = $ratio * $base; | 
				
			||||
 | 
				
			||||
        $url = $data['url']; | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <a href="$url"><img src="{$url}" width="{$width}" height="{$height} "alt="{$title}" title="{$title}"></a> | 
				
			||||
EOT; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,83 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Generic HTML page renderer. Process any html page. | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetPageRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        global $THEME; | 
				
			||||
        $url = $asset->url(); | 
				
			||||
        $title = $asset->title(); | 
				
			||||
        $title = $title ? $title : $asset->name(); | 
				
			||||
        $description = $asset->get_meta('description'); | 
				
			||||
        $description = $description; | 
				
			||||
 | 
				
			||||
        $keywords = $asset->get_meta('keywords'); | 
				
			||||
 | 
				
			||||
        $image_src = $asset->get_link('rel', 'image_src'); | 
				
			||||
        $image_src = $image_src ? $image_src['href'] : false; | 
				
			||||
 | 
				
			||||
        if (empty($image_src)) | 
				
			||||
        { | 
				
			||||
            $image_src = $this->get_icon($asset); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $icon = $this->get_icon($asset); | 
				
			||||
         | 
				
			||||
        $image_src = $asset->canonic_url($image_src); | 
				
			||||
        $icon = $asset->canonic_url($icon); | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <a href="$url"> | 
				
			||||
            <img src="{$image_src}" alt="{$title}" title="{$title}" style="float:left; margin-right:5px; margin-bottom:5px; " > | 
				
			||||
        </a> | 
				
			||||
        $description | 
				
			||||
        <span style="clear:both;"></span> | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::TITLE] = $title; | 
				
			||||
        $result[self::THUMBNAIL] = $image_src; | 
				
			||||
        $result[self::DESCRIPTION] = $description; | 
				
			||||
        $result[self::ICON] = $icon; | 
				
			||||
        $result[self::TAGS] = $keywords; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    function get_icon($asset) | 
				
			||||
    { | 
				
			||||
 | 
				
			||||
        $icon = $asset->get_link('rel', 'apple-touch-icon'); | 
				
			||||
        $icon = $icon ? $icon['href'] : false; | 
				
			||||
        if (empty($icon)) | 
				
			||||
        { | 
				
			||||
            $icon = $asset->get_link('rel', 'fluid-icon'); | 
				
			||||
            $icon = $icon ? $icon['href'] : false; | 
				
			||||
        } | 
				
			||||
        if (empty($icon)) | 
				
			||||
        { | 
				
			||||
            $icon = $asset->get_link('rel', 'shortcut icon'); | 
				
			||||
            $icon = $icon ? $icon['href'] : false; | 
				
			||||
        } | 
				
			||||
        if (empty($icon)) | 
				
			||||
        { | 
				
			||||
            $icon = $asset->get_link('rel', 'icon'); | 
				
			||||
            $icon = $icon ? $icon['href'] : false; | 
				
			||||
        } | 
				
			||||
        return $icon; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,95 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Rss renderer. Display RSS thanks to Google feed control. | 
				
			||||
 *  | 
				
			||||
 * @see http://www.google.com/uds/solutions/dynamicfeed/reference.html | 
				
			||||
 * @see http://code.google.com/apis/ajax/playground/#dynamic_feed_control_-_vertical | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2011 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetRssRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        if (!$asset->is_rss()) | 
				
			||||
        { | 
				
			||||
            return; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $url = $asset->url(); | 
				
			||||
        $title = $asset->title(); | 
				
			||||
        $id = 'a' . md5($url); | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <style type="text/css"> | 
				
			||||
            .gfg-root { | 
				
			||||
                border: none; | 
				
			||||
                font-family: inherit; | 
				
			||||
            } | 
				
			||||
        </style> | 
				
			||||
        <script type="text/javascript" src="http://www.google.com/jsapi"></script> | 
				
			||||
        <script src="http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.js" type="text/javascript"></script>  | 
				
			||||
        <script type="text/javascript"> | 
				
			||||
         | 
				
			||||
            function init() | 
				
			||||
            { | 
				
			||||
                if (typeof this.has_run == 'undefined' ) | 
				
			||||
                { | 
				
			||||
                    this.has_run = true; | 
				
			||||
                } | 
				
			||||
                else | 
				
			||||
                { | 
				
			||||
                    return; | 
				
			||||
                } | 
				
			||||
                var head = document.getElementsByTagName('head')[0]; | 
				
			||||
         | 
				
			||||
                var element = document.createElement('link'); | 
				
			||||
                element.type = 'text/css'; | 
				
			||||
                element.rel = 'stylesheet'; | 
				
			||||
                element.href = 'http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.css'; | 
				
			||||
                head.appendChild(element); | 
				
			||||
            } | 
				
			||||
 | 
				
			||||
            function load_$id() { | 
				
			||||
                var feeds = [ | 
				
			||||
                    { | 
				
			||||
                    title: ' ', | 
				
			||||
                    url: '$url' | 
				
			||||
                    } | 
				
			||||
                ]; | 
				
			||||
 | 
				
			||||
                var options = { | 
				
			||||
                    stacked : false, | 
				
			||||
                    horizontal : false, | 
				
			||||
                    title : '', | 
				
			||||
                    numResults : 10 | 
				
			||||
                }; | 
				
			||||
 | 
				
			||||
                new GFdynamicFeedControl(feeds, '$id', options); | 
				
			||||
                document.getElementById('content').style.width = "500px"; | 
				
			||||
            } | 
				
			||||
         | 
				
			||||
         | 
				
			||||
            init(); | 
				
			||||
            google.load('feeds', '1'); | 
				
			||||
            google.setOnLoadCallback(load_$id); | 
				
			||||
       </script>         | 
				
			||||
       <div id="$id" style="min-height:271px;">Loading...</div> | 
				
			||||
EOT; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::TITLE] = $title; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,76 @@ | 
				
			||||
<?php | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Scratch renderer.  | 
				
			||||
 *  | 
				
			||||
 * @see http://scratch.mit.edu/projects/ | 
				
			||||
 *  | 
				
			||||
 * @copyright (c) 2012 University of Geneva | 
				
			||||
 * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html | 
				
			||||
 * @author Laurent Opprecht | 
				
			||||
 */ | 
				
			||||
class AssetScratchRenderer extends AssetRenderer | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function accept($asset) | 
				
			||||
    { | 
				
			||||
        return $asset->url_match('http://scratch.mit.edu/projects/'); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * | 
				
			||||
     * @param HttpResource $asset  | 
				
			||||
     */ | 
				
			||||
    public function render($asset) | 
				
			||||
    { | 
				
			||||
        if (!$this->accept($asset)) | 
				
			||||
        { | 
				
			||||
            return; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $matches = array(); | 
				
			||||
        $pattern = "#http:\/\/scratch.mit.edu\/projects\/(\w+)/(\d*)\/?#ims"; | 
				
			||||
        preg_match($pattern, $asset->url(), $matches); | 
				
			||||
 | 
				
			||||
        $url = $matches[0]; | 
				
			||||
        $author = $matches[1]; | 
				
			||||
        $project_id = $matches[2]; | 
				
			||||
 | 
				
			||||
        $project_url = "../../static/projects/$author/$project_id.sb"; | 
				
			||||
        $image_url = "http://scratch.mit.edu/static/projects/$author/{$project_id}_med.png"; | 
				
			||||
        $thumb_url = "http://scratch.mit.edu/static/projects/$author/{$project_id}_sm.png"; | 
				
			||||
 | 
				
			||||
        $height = 387; | 
				
			||||
        $width = 482; | 
				
			||||
 | 
				
			||||
        if (function_exists('get_string')) | 
				
			||||
        { | 
				
			||||
            $no_java = get_string('no_java', 'artefact.extresource'); | 
				
			||||
        } | 
				
			||||
        else | 
				
			||||
        { | 
				
			||||
            $no_java = 'Java is not installed on your computer. You must install java first.'; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        $embed = <<<EOT | 
				
			||||
        <object type="application/x-java-applet" width="$width" height="$height"  style="display:block" id="ProjectApplet"> | 
				
			||||
 | 
				
			||||
            <param name="codebase" value="http://scratch.mit.edu/static/misc"> | 
				
			||||
            <param name="archive" value="ScratchApplet.jar"> | 
				
			||||
            <param name="code" value="ScratchApplet"> | 
				
			||||
            <param name="project" value="$project_url"> | 
				
			||||
            <pre>$no_java</pre> | 
				
			||||
            <img alt="" src="$image_url"> | 
				
			||||
        </object> | 
				
			||||
EOT; | 
				
			||||
        $result = array(); | 
				
			||||
        $result[self::EMBED_SNIPPET] = $embed; | 
				
			||||
        $result[self::THUMBNAIL] = $thumb_url; | 
				
			||||
        return $result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue