You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							643 lines
						
					
					
						
							15 KiB
						
					
					
				
			
		
		
	
	
							643 lines
						
					
					
						
							15 KiB
						
					
					
				<?php
 | 
						|
/* For licensing terms, see /license.txt */
 | 
						|
/*
 | 
						|
 * This file contains several classes related to portfolios management to avoid
 | 
						|
 * having too much files under the lib/.
 | 
						|
 *
 | 
						|
 * Once external libraries are moved to their own directory it would be worth
 | 
						|
 * moving them to their own files under a common portfolio directory.
 | 
						|
 * @package chamilo.portfolio
 | 
						|
 */
 | 
						|
/**
 | 
						|
 * Init
 | 
						|
 */
 | 
						|
use Model\Document;
 | 
						|
use Model\Course;
 | 
						|
 | 
						|
/**
 | 
						|
 * A portfolio is used to present content to other people. In most cases it is
 | 
						|
 * an external application.
 | 
						|
 *
 | 
						|
 * From the application point of view it is an end point to which the user can send
 | 
						|
 * content.
 | 
						|
 *
 | 
						|
 * Available portfolios are configured in /main/inc/config/portfolio.conf.php
 | 
						|
 *
 | 
						|
 * The Portfolio class serves as an entry point to other portfolio components:
 | 
						|
 *
 | 
						|
 *      - portfolio controller
 | 
						|
 *      - portfolio share button
 | 
						|
 *      - portfolio action
 | 
						|
 *
 | 
						|
 * Note:
 | 
						|
 * @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva
 | 
						|
 */
 | 
						|
//class Portfolio extends Portfolio\Portfolio
 | 
						|
class Portfolio
 | 
						|
{
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns all portfolios available
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public static function all()
 | 
						|
    {
 | 
						|
        $conf = api_get_path(SYS_CODE_PATH).'inc/conf/portfolio.conf.php';
 | 
						|
        if (!is_readable($conf)) {
 | 
						|
            return array();
 | 
						|
        }
 | 
						|
        include $conf;
 | 
						|
        return isset($portfolios) ? $portfolios : array();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a portfolio from its name.
 | 
						|
     *
 | 
						|
     * @param string $name
 | 
						|
     * @return Portfolio\Portfolio
 | 
						|
     */
 | 
						|
    public static function get($name)
 | 
						|
    {
 | 
						|
        $items = self::all();
 | 
						|
        foreach ($items as $item) {
 | 
						|
            if ($item->get_name() == $name) {
 | 
						|
                return $item;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return Portfolio\Portfolio::none();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * True if portfolios are enabled. False otherwise.
 | 
						|
     *
 | 
						|
     * @return boolean
 | 
						|
     */
 | 
						|
    public static function is_enabled()
 | 
						|
    {
 | 
						|
        if (api_is_anonymous()) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        $user_id = api_get_user_id();
 | 
						|
        if (empty($user_id)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        $portfolios = self::all();
 | 
						|
        if (count($portfolios) == 0) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * The controller for portfolio.
 | 
						|
     *
 | 
						|
     * @return \PortfolioController
 | 
						|
     */
 | 
						|
    public static function controller()
 | 
						|
    {
 | 
						|
        return PortfolioController::instance();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a share component/button.
 | 
						|
     *
 | 
						|
     * @param string $tool
 | 
						|
     * @param int $id
 | 
						|
     * @param array $attributes
 | 
						|
     * @return \PortfolioShare
 | 
						|
     */
 | 
						|
    public static function share($tool, $id, $attributes = array())
 | 
						|
    {
 | 
						|
        return PortfolioShare::factory($tool, $id, $attributes);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the list of actions.
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public static function actions()
 | 
						|
    {
 | 
						|
        return PortfolioController::actions();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a temporary url to download files and/or folders.
 | 
						|
     *
 | 
						|
     * @param string|array $ids
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    public static function download_url($ids, $tool)
 | 
						|
    {
 | 
						|
        $ids = is_array($ids) ? implode(',', $ids) : $ids;
 | 
						|
 | 
						|
        $params = Uri::course_params();
 | 
						|
        $params['id'] = $ids;
 | 
						|
        $params[KeyAuth::PARAM_ACCESS_TOKEN] = KeyAuth::create_temp_token();
 | 
						|
        $result = Uri::url("/main/$tool/file.php", $params, false);
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * The portfolio controller. Responsible to dispatch/process portfolio actions.
 | 
						|
 *
 | 
						|
 * Usage:
 | 
						|
 *
 | 
						|
 *      if(Porfolio::contoller()->accept()){
 | 
						|
 *          Portfolio::controller()->run();
 | 
						|
 *      }
 | 
						|
 *
 | 
						|
 *
 | 
						|
 */
 | 
						|
class PortfolioController
 | 
						|
{
 | 
						|
 | 
						|
    const PARAM_ACTION = 'action';
 | 
						|
    const PARAM_ID = 'id';
 | 
						|
    const PARAM_TOOL = 'tool';
 | 
						|
    const PARAM_PORTFOLIO = 'portfolio';
 | 
						|
    const PARAM_CONTROLLER = 'controller';
 | 
						|
    const PARAM_SECURITY_TOKEN = 'sec_token';
 | 
						|
    const ACTION_SHARE = 'share';
 | 
						|
    const NAME = 'portfolio';
 | 
						|
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * @return \PortfolioController
 | 
						|
     */
 | 
						|
    static function instance()
 | 
						|
    {
 | 
						|
        static $result = null;
 | 
						|
        if (empty($result)) {
 | 
						|
            $result = new self();
 | 
						|
        }
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
    protected $message = '';
 | 
						|
 | 
						|
    protected function __construct()
 | 
						|
    {
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    public static function portfolios()
 | 
						|
    {
 | 
						|
        return Portfolio::all();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * List of actions for the SortableTable.
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public static function actions()
 | 
						|
    {
 | 
						|
        static $result = null;
 | 
						|
        if (!is_null($result)) {
 | 
						|
            return $result;
 | 
						|
        }
 | 
						|
 | 
						|
        $items = self::portfolios();
 | 
						|
        if (empty($items)) {
 | 
						|
            $result = array();
 | 
						|
            return $result;
 | 
						|
        }
 | 
						|
 | 
						|
        $result = array();
 | 
						|
        foreach ($items as $item) {
 | 
						|
            $action = PortfolioBulkAction::create($item);
 | 
						|
            $result[] = $action;
 | 
						|
        }
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns true if the controller accept to process the current request.
 | 
						|
     * Returns false otherwise.
 | 
						|
     *
 | 
						|
     * @return boolean
 | 
						|
     */
 | 
						|
    function accept()
 | 
						|
    {
 | 
						|
        if (!Portfolio::is_enabled()) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        $actions = self::actions();
 | 
						|
        foreach ($actions as $action) {
 | 
						|
            if ($action->accept()) {
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ($this->get_controller() != self::NAME) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        if (!Security::check_token('get')) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        $id = $this->get_id();
 | 
						|
        if (empty($id)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        return $this->get_action() == self::ACTION_SHARE;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the value of the current controller request parameters. That is
 | 
						|
     * the name of the controller which shall handle the current request.
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    function get_controller()
 | 
						|
    {
 | 
						|
        return Request::get(self::PARAM_CONTROLLER);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the value of the action parameter. That is which action shall be
 | 
						|
     * performed. That is share to send an object to a portfolio.
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    function get_action()
 | 
						|
    {
 | 
						|
        $result = Request::get(self::PARAM_ACTION);
 | 
						|
        return ($result == self::ACTION_SHARE) ? self::ACTION_SHARE : '';
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the value of the id parameter: id of object to send.
 | 
						|
     *
 | 
						|
     * @return int
 | 
						|
     */
 | 
						|
    function get_id()
 | 
						|
    {
 | 
						|
        return (int) Request::get(self::PARAM_ID);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * The course code (id) to which the object belongs.
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    function course_code()
 | 
						|
    {
 | 
						|
        return ChamiloSession::instance()->course()->code();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * The name of the porfolio where to send.
 | 
						|
     *
 | 
						|
     * @return type
 | 
						|
     */
 | 
						|
    function get_portfolio()
 | 
						|
    {
 | 
						|
        return Request::get(self::PARAM_PORTFOLIO);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Name of the tool: document, work, etc. Defaults to current_course_tool.
 | 
						|
     *
 | 
						|
     * @global string $current_course_tool
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    function get_tool()
 | 
						|
    {
 | 
						|
        global $current_course_tool;
 | 
						|
        return Request::get(self::PARAM_TOOL, $current_course_tool);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the end user message after running the controller..
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    function message()
 | 
						|
    {
 | 
						|
        return $this->message;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Execute the controller action as required. If a registered action accept
 | 
						|
     * the current request the controller calls it.
 | 
						|
     *
 | 
						|
     * If not action is accept the current request and current action is "share"
 | 
						|
     * the controller execute the "send to portfolio" action
 | 
						|
     *
 | 
						|
     * @return PortfolioController
 | 
						|
     */
 | 
						|
    function run()
 | 
						|
    {
 | 
						|
        if (!$this->accept()) {
 | 
						|
            return $this;
 | 
						|
        }
 | 
						|
 | 
						|
        $actions = self::actions();
 | 
						|
        foreach ($actions as $action) {
 | 
						|
            if ($action->accept()) {
 | 
						|
                return $action->run();
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        $action = $this->get_action();
 | 
						|
        if ($action == self::ACTION_SHARE) {
 | 
						|
 | 
						|
            $user = new \Portfolio\User();
 | 
						|
            $user->email = Chamilo::user()->email();
 | 
						|
 | 
						|
            $tool = $this->get_tool();
 | 
						|
            $id = $this->get_id();
 | 
						|
            $url = Portfolio::download_url($id, $tool);
 | 
						|
 | 
						|
            $artefact = new Portfolio\Artefact($url);
 | 
						|
 | 
						|
            $name = $this->get_portfolio();
 | 
						|
            $result = Portfolio::get($name)->send($user, $artefact);
 | 
						|
            if ($result) {
 | 
						|
                $this->message = Display::return_message(get_lang('SentSuccessfully'), 'normal');
 | 
						|
            } else {
 | 
						|
                $this->message = Display::return_message(get_lang('SentFailed'), 'error');
 | 
						|
            }
 | 
						|
            return $this;
 | 
						|
        } else {
 | 
						|
            $this->message = '';
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * This component is used to display a "send to portfolio" button for a specific
 | 
						|
 * object.
 | 
						|
 *
 | 
						|
 * Note that the component implement the __toString() magic method and can be
 | 
						|
 * therefore used in situation where a string is expected: for ex echo $button.
 | 
						|
 *
 | 
						|
 * Usage
 | 
						|
 *
 | 
						|
 *      $button = Portfolio::share(...);
 | 
						|
 *      echo $button;
 | 
						|
 *
 | 
						|
 */
 | 
						|
class PortfolioShare
 | 
						|
{
 | 
						|
 | 
						|
    /**
 | 
						|
     * Create a "send to portfolio" button
 | 
						|
     *
 | 
						|
     * @param string $tool          The name of the tool: document, work.
 | 
						|
     * @param int $c_id             The id of the course
 | 
						|
     * @param int $id               The id of the object
 | 
						|
     * @param array $attributes     Html attributes
 | 
						|
     * @return \PortfolioShare
 | 
						|
     */
 | 
						|
    static function factory($tool, $id, $attributes = array())
 | 
						|
    {
 | 
						|
        $result = new self($tool, $id, $attributes);
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the current secuirty token. Used to avoid see surfing attacks.
 | 
						|
     *
 | 
						|
     * @return type
 | 
						|
     */
 | 
						|
    static function security_token()
 | 
						|
    {
 | 
						|
        static $result = null;
 | 
						|
        if (empty($result)) {
 | 
						|
            $result = Security::get_token();
 | 
						|
        }
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
    protected $id = 0;
 | 
						|
    protected $attributes = array();
 | 
						|
    protected $tool = '';
 | 
						|
 | 
						|
    function __construct($tool, $id, $attributes = array())
 | 
						|
    {
 | 
						|
        $this->tool = $tool;
 | 
						|
        $this->id = (int) $id;
 | 
						|
        $this->attributes = $attributes;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Object id to send
 | 
						|
     * @return int
 | 
						|
     */
 | 
						|
    function get_id()
 | 
						|
    {
 | 
						|
        return $this->id;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Object id to send
 | 
						|
     * @return int
 | 
						|
     */
 | 
						|
    function get_c_id()
 | 
						|
    {
 | 
						|
        return $this->c_id;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Html attributes.
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    function get_attributes()
 | 
						|
    {
 | 
						|
        return $this->attributes;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Name of the tool. I.e. the type of the id parameter. Can be document, work.
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    function get_tool()
 | 
						|
    {
 | 
						|
        return $this->tool;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Display the component.
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    function display()
 | 
						|
    {
 | 
						|
        if (!Portfolio::is_enabled()) {
 | 
						|
            return '';
 | 
						|
        }
 | 
						|
        $id = $this->id;
 | 
						|
        $tool = $this->tool;
 | 
						|
 | 
						|
        $attributes = $this->attributes;
 | 
						|
        $attributes['z-index'] = 100000;
 | 
						|
        $s = ' ';
 | 
						|
        foreach ($attributes as $key => $value) {
 | 
						|
            $s .= $key . '="' . $value . '" ';
 | 
						|
        }
 | 
						|
 | 
						|
        $result = array();
 | 
						|
        $result[] = '<span ' . $s . ' >';
 | 
						|
        $result[] = '<span class="dropdown" >';
 | 
						|
        $result[] = '<a href="#" data-toggle="dropdown" class="dropdown-toggle">';
 | 
						|
        $result[] = Display::return_icon('document_send.png', get_lang('Send'), array(), ICON_SIZE_SMALL) . '<b class="caret"></b>';
 | 
						|
        $result[] = '</a>';
 | 
						|
        $result[] = '<ul class="dropdown-menu">';
 | 
						|
 | 
						|
        $portfolios = Portfolio::all();
 | 
						|
        foreach ($portfolios as $portfolio) {
 | 
						|
            $parameters = Uri::course_params();
 | 
						|
            $parameters[PortfolioController::PARAM_ACTION] = PortfolioController::ACTION_SHARE;
 | 
						|
            $parameters[PortfolioController::PARAM_CONTROLLER] = PortfolioController::NAME;
 | 
						|
            $parameters[PortfolioController::PARAM_PORTFOLIO] = $portfolio->get_name();
 | 
						|
            $parameters[PortfolioController::PARAM_SECURITY_TOKEN] = self::security_token();
 | 
						|
            $parameters[PortfolioController::PARAM_TOOL] = $this->get_tool();
 | 
						|
            $parameters[PortfolioController::PARAM_ID] = $id;
 | 
						|
            $parameters[PortfolioController::PARAM_TOOL] = $tool;
 | 
						|
            $url = api_get_path(WEB_CODE_PATH).'portfolio/share.php?';
 | 
						|
            $result[] = '<li>';
 | 
						|
            $result[] = '<a href="' . $url . '">' . $portfolio->get_title() . '</a>';
 | 
						|
            $result[] = '</li>';
 | 
						|
        }
 | 
						|
        $result[] = '</ul>';
 | 
						|
        $result[] = '</span>';
 | 
						|
        $result[] = '</span>';
 | 
						|
        return implode("\n", $result);
 | 
						|
    }
 | 
						|
 | 
						|
    function __toString()
 | 
						|
    {
 | 
						|
        return $this->display();
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * A "send to this portfolio" action. Actions are used by the SortableTable to
 | 
						|
 * perform actions on a set of objects. An action is composed of
 | 
						|
 *
 | 
						|
 *      - a name
 | 
						|
 *      - a title (displayed to the user)
 | 
						|
 *      - code to execute
 | 
						|
 *
 | 
						|
 * Usage:
 | 
						|
 *
 | 
						|
 *       $form_actions = array();
 | 
						|
 *       $form_action['...'] = get_lang('...');
 | 
						|
 *       $portfolio_actions = Portfolio::actions();
 | 
						|
 *       foreach($portfolio_actions as $action){
 | 
						|
 *           $form_action[$action->get_name()] = $action->get_title();
 | 
						|
 *       }
 | 
						|
 *       $table->set_form_actions($form_action, 'path');
 | 
						|
 *
 | 
						|
 * @see SortableTable
 | 
						|
 */
 | 
						|
class PortfolioBulkAction
 | 
						|
{
 | 
						|
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * @param \Portfolio\Portfolio $portfolio
 | 
						|
     * @return PortfolioBulkAction
 | 
						|
     */
 | 
						|
    public static function create($portfolio)
 | 
						|
    {
 | 
						|
        return new self($portfolio);
 | 
						|
    }
 | 
						|
 | 
						|
    protected $name = '';
 | 
						|
    protected $title = '';
 | 
						|
    protected $portfolio = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * @param \Portfolio\Portfolio $portfolio
 | 
						|
     */
 | 
						|
    public function __construct($portfolio)
 | 
						|
    {
 | 
						|
        $this->name = md5(__CLASS__) . '_' . $portfolio->get_name();
 | 
						|
        $this->title = $portfolio->get_title() ? $portfolio->get_title() : get_lang('SendTo') . ' ' . $portfolio->get_name();
 | 
						|
        $this->portfolio = $portfolio;
 | 
						|
    }
 | 
						|
 | 
						|
    public function get_name()
 | 
						|
    {
 | 
						|
        return $this->name;
 | 
						|
    }
 | 
						|
 | 
						|
    public function get_title()
 | 
						|
    {
 | 
						|
        return $this->title;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * @return \Portfolio\Portfolio
 | 
						|
     */
 | 
						|
    public function get_portfolio()
 | 
						|
    {
 | 
						|
        return $this->portfolio;
 | 
						|
    }
 | 
						|
 | 
						|
    public function accept()
 | 
						|
    {
 | 
						|
        $name = $this->get_name();
 | 
						|
        $action = Request::get(PortfolioController::PARAM_ACTION);
 | 
						|
        if ($name != $action) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        $pathes = Request::get('path');
 | 
						|
        if (empty($pathes)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        $course = Course::current();
 | 
						|
        if (empty($course)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    public function run()
 | 
						|
    {
 | 
						|
        if (!$this->accept()) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        $course = Course::current();
 | 
						|
 | 
						|
        $pathes = Request::get('path');
 | 
						|
        $pathes = is_array($pathes) ? $pathes : array($pathes);
 | 
						|
 | 
						|
        $ids = array();
 | 
						|
        foreach ($pathes as $path) {
 | 
						|
            $doc = Document::get_by_path($course, $path);
 | 
						|
            if ($doc) {
 | 
						|
                $ids[] = $doc->get_id();
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (empty($ids)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        $user = new \Portfolio\User();
 | 
						|
        $user->email = Chamilo::user()->email();
 | 
						|
 | 
						|
        $artefact = new Portfolio\Artefact();
 | 
						|
        $artefact->url = Portfolio::download_url($ids);
 | 
						|
 | 
						|
        $portfolio = $this->get_portfolio();
 | 
						|
        $result = $portfolio->send($user, $artefact);
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 |