moved to ocs.php from master and added dummy functions for the keyserver
This commit is contained in:
parent
d294e77721
commit
2cf64daec4
282
lib/ocs.php
282
lib/ocs.php
|
@ -4,7 +4,9 @@
|
||||||
* ownCloud
|
* ownCloud
|
||||||
*
|
*
|
||||||
* @author Frank Karlitschek
|
* @author Frank Karlitschek
|
||||||
|
* @author Michael Gapczynski
|
||||||
* @copyright 2012 Frank Karlitschek frank@owncloud.org
|
* @copyright 2012 Frank Karlitschek frank@owncloud.org
|
||||||
|
* @copyright 2012 Michael Gapczynski mtgap@owncloud.com
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -32,54 +34,48 @@ class OC_OCS {
|
||||||
/**
|
/**
|
||||||
* reads input date from get/post/cookies and converts the date to a special data-type
|
* reads input date from get/post/cookies and converts the date to a special data-type
|
||||||
*
|
*
|
||||||
* @param variable $key
|
* @param string HTTP method to read the key from
|
||||||
* @param variable-type $type
|
* @param string Parameter to read
|
||||||
* @param priority $getpriority
|
* @param string Variable type to format data
|
||||||
* @param default $default
|
* @param mixed Default value to return if the key is not found
|
||||||
* @return data
|
* @return mixed Data or if the key is not found and no default is set it will exit with a 400 Bad request
|
||||||
*/
|
*/
|
||||||
public static function readData($key,$type='raw',$getpriority=false,$default='') {
|
public static function readData($method, $key, $type = 'raw', $default = null) {
|
||||||
if($getpriority) {
|
if ($method == 'get') {
|
||||||
if (isset($_GET[$key])) {
|
if (isset($_GET[$key])) {
|
||||||
$data = $_GET[$key];
|
$data = $_GET[$key];
|
||||||
} elseif(isset($_POST[$key])) {
|
} else if (isset($default)) {
|
||||||
$data=$_POST[$key];
|
return $default;
|
||||||
} else {
|
} else {
|
||||||
if($default=='') {
|
$data = false;
|
||||||
if(($type=='int') or ($type=='float')) $data=0; else $data='';
|
|
||||||
} else {
|
|
||||||
$data=$default;
|
|
||||||
}
|
}
|
||||||
}
|
} else if ($method == 'post') {
|
||||||
} else {
|
|
||||||
if (isset($_POST[$key])) {
|
if (isset($_POST[$key])) {
|
||||||
$data = $_POST[$key];
|
$data = $_POST[$key];
|
||||||
} elseif(isset($_GET[$key])) {
|
} else if (isset($default)) {
|
||||||
$data=$_GET[$key];
|
return $default;
|
||||||
} elseif(isset($_COOKIE[$key])) {
|
|
||||||
$data=$_COOKIE[$key];
|
|
||||||
} else {
|
} else {
|
||||||
if($default=='') {
|
$data = false;
|
||||||
if(($type=='int') or ($type=='float')) $data=0; else $data='';
|
}
|
||||||
|
}
|
||||||
|
if ($data === false) {
|
||||||
|
echo self::generateXml('', 'fail', 400, 'Bad request. Please provide a valid '.$key);
|
||||||
|
exit();
|
||||||
} else {
|
} else {
|
||||||
$data=$default;
|
// NOTE: Is the raw type necessary? It might be a little risky without sanitization
|
||||||
|
if ($type == 'raw') return $data;
|
||||||
|
elseif ($type == 'text') return OC_Util::sanitizeHTML($data);
|
||||||
|
elseif ($type == 'int') return (int) $data;
|
||||||
|
elseif ($type == 'float') return (float) $data;
|
||||||
|
elseif ($type == 'array') return OC_Util::sanitizeHTML($data);
|
||||||
|
else return OC_Util::sanitizeHTML($data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if($type=='raw') return($data);
|
|
||||||
elseif($type=='text') return(addslashes(strip_tags($data)));
|
|
||||||
elseif($type=='int') { $data = (int) $data; return($data); }
|
|
||||||
elseif($type=='float') { $data = (float) $data; return($data); }
|
|
||||||
elseif($type=='array') { $data = $data; return($data); }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
main function to handle the REST request
|
main function to handle the REST request
|
||||||
**/
|
**/
|
||||||
public static function handle() {
|
public static function handle() {
|
||||||
|
|
||||||
// overwrite the 404 error page returncode
|
// overwrite the 404 error page returncode
|
||||||
header("HTTP/1.0 200 OK");
|
header("HTTP/1.0 200 OK");
|
||||||
|
|
||||||
|
@ -97,73 +93,107 @@ class OC_OCS {
|
||||||
}
|
}
|
||||||
|
|
||||||
// preprocess url
|
// preprocess url
|
||||||
$url=$_SERVER['REQUEST_URI'];
|
$url = strtolower($_SERVER['REQUEST_URI']);
|
||||||
if(substr($url,(strlen($url)-1))<>'/') $url.='/';
|
if(substr($url,(strlen($url)-1))<>'/') $url.='/';
|
||||||
$ex=explode('/',$url);
|
$ex=explode('/',$url);
|
||||||
$paracount=count($ex);
|
$paracount=count($ex);
|
||||||
|
$format = self::readData($method, 'format', 'text', '');
|
||||||
|
|
||||||
// eventhandler
|
// eventhandler
|
||||||
// CONFIG
|
// CONFIG
|
||||||
// apiconfig - GET - CONFIG
|
// apiconfig - GET - CONFIG
|
||||||
if(($method=='get') and (strtolower($ex[$paracount-3])=='v1.php') and (strtolower($ex[$paracount-2])=='config')){
|
if(($method=='get') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'config')){
|
||||||
$format=OC_OCS::readdata('format','text');
|
|
||||||
OC_OCS::apiconfig($format);
|
OC_OCS::apiconfig($format);
|
||||||
|
|
||||||
// PERSON
|
// PERSON
|
||||||
// personcheck - POST - PERSON/CHECK
|
// personcheck - POST - PERSON/CHECK
|
||||||
}elseif(($method=='post') and (strtolower($ex[$paracount-4])=='v1.php') and (strtolower($ex[$paracount-3])=='person') and (strtolower($ex[$paracount-2])=='check')){
|
}elseif(($method=='post') and ($ex[$paracount-4] == 'v1.php') and ($ex[$paracount-3]=='person') and ($ex[$paracount-2] == 'check')){
|
||||||
$format=OC_OCS::readdata('format','text');
|
$login = self::readData($method, 'login', 'text');
|
||||||
$login=OC_OCS::readdata('login','text');
|
$passwd = self::readData($method, 'password', 'text');
|
||||||
$passwd=OC_OCS::readdata('password','text');
|
|
||||||
OC_OCS::personcheck($format,$login,$passwd);
|
OC_OCS::personcheck($format,$login,$passwd);
|
||||||
|
|
||||||
// ACTIVITY
|
// ACTIVITY
|
||||||
// activityget - GET ACTIVITY page,pagesize als urlparameter
|
// activityget - GET ACTIVITY page,pagesize als urlparameter
|
||||||
}elseif(($method=='get') and (strtolower($ex[$paracount-3])=='v1.php')and (strtolower($ex[$paracount-2])=='activity')){
|
}elseif(($method=='get') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'activity')){
|
||||||
$format=OC_OCS::readdata('format','text');
|
$page = self::readData($method, 'page', 'int', 0);
|
||||||
$page=OC_OCS::readdata('page','int');
|
$pagesize = self::readData($method, 'pagesize','int', 10);
|
||||||
$pagesize=OC_OCS::readdata('pagesize','int');
|
|
||||||
if($pagesize<1 or $pagesize>100) $pagesize=10;
|
if($pagesize<1 or $pagesize>100) $pagesize=10;
|
||||||
OC_OCS::activityget($format,$page,$pagesize);
|
OC_OCS::activityget($format,$page,$pagesize);
|
||||||
|
|
||||||
// activityput - POST ACTIVITY
|
// activityput - POST ACTIVITY
|
||||||
}elseif(($method=='post') and (strtolower($ex[$paracount-3])=='v1.php')and (strtolower($ex[$paracount-2])=='activity')){
|
}elseif(($method=='post') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'activity')){
|
||||||
$format=OC_OCS::readdata('format','text');
|
$message = self::readData($method, 'message', 'text');
|
||||||
$message=OC_OCS::readdata('message','text');
|
|
||||||
OC_OCS::activityput($format,$message);
|
OC_OCS::activityput($format,$message);
|
||||||
|
|
||||||
|
|
||||||
// PRIVATEDATA
|
// PRIVATEDATA
|
||||||
// get - GET DATA
|
// get - GET DATA
|
||||||
}elseif(($method=='get') and (strtolower($ex[$paracount-4])=='v1.php')and (strtolower($ex[$paracount-2])=='getattribute')){
|
}elseif(($method=='get') and ($ex[$paracount-4] == 'v1.php') and ($ex[$paracount-2] == 'getattribute')){
|
||||||
$format=OC_OCS::readdata('format','text');
|
|
||||||
OC_OCS::privateDataGet($format);
|
OC_OCS::privateDataGet($format);
|
||||||
|
|
||||||
}elseif(($method=='get') and (strtolower($ex[$paracount-5])=='v1.php')and (strtolower($ex[$paracount-3])=='getattribute')){
|
}elseif(($method=='get') and ($ex[$paracount-5] == 'v1.php') and ($ex[$paracount-3] == 'getattribute')){
|
||||||
$format=OC_OCS::readdata('format','text');
|
|
||||||
$app=$ex[$paracount-2];
|
$app=$ex[$paracount-2];
|
||||||
OC_OCS::privateDataGet($format, $app);
|
OC_OCS::privateDataGet($format, $app);
|
||||||
}elseif(($method=='get') and (strtolower($ex[$paracount-6])=='v1.php')and (strtolower($ex[$paracount-4])=='getattribute')){
|
}elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-4] == 'getattribute')){
|
||||||
$format=OC_OCS::readdata('format','text');
|
|
||||||
$key=$ex[$paracount-2];
|
$key=$ex[$paracount-2];
|
||||||
$app=$ex[$paracount-3];
|
$app=$ex[$paracount-3];
|
||||||
OC_OCS::privateDataGet($format, $app,$key);
|
OC_OCS::privateDataGet($format, $app,$key);
|
||||||
|
|
||||||
// set - POST DATA
|
// set - POST DATA
|
||||||
}elseif(($method=='post') and (strtolower($ex[$paracount-6])=='v1.php')and (strtolower($ex[$paracount-4])=='setattribute')){
|
}elseif(($method=='post') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-4] == 'setattribute')){
|
||||||
$format=OC_OCS::readdata('format','text');
|
|
||||||
$key=$ex[$paracount-2];
|
$key=$ex[$paracount-2];
|
||||||
$app=$ex[$paracount-3];
|
$app=$ex[$paracount-3];
|
||||||
$value=OC_OCS::readdata('value','text');
|
$value = self::readData($method, 'value', 'text');
|
||||||
OC_OCS::privatedataset($format, $app, $key, $value);
|
OC_OCS::privatedataset($format, $app, $key, $value);
|
||||||
// delete - POST DATA
|
// delete - POST DATA
|
||||||
}elseif(($method=='post') and (strtolower($ex[$paracount-6])=='v1.php')and (strtolower($ex[$paracount-4])=='deleteattribute')){
|
}elseif(($method=='post') and ($ex[$paracount-6] =='v1.php') and ($ex[$paracount-4] == 'deleteattribute')){
|
||||||
$format=OC_OCS::readdata('format','text');
|
|
||||||
$key=$ex[$paracount-2];
|
$key=$ex[$paracount-2];
|
||||||
$app=$ex[$paracount-3];
|
$app=$ex[$paracount-3];
|
||||||
OC_OCS::privatedatadelete($format, $app, $key);
|
OC_OCS::privatedatadelete($format, $app, $key);
|
||||||
|
|
||||||
|
// CLOUD
|
||||||
|
// systemWebApps
|
||||||
|
}elseif(($method=='get') and ($ex[$paracount-5] == 'v1.php') and ($ex[$paracount-4]=='cloud') and ($ex[$paracount-3] == 'system') and ($ex[$paracount-2] == 'webapps')){
|
||||||
|
OC_OCS::systemwebapps($format);
|
||||||
|
|
||||||
|
// quotaget
|
||||||
|
}elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'quota')){
|
||||||
|
$user=$ex[$paracount-3];
|
||||||
|
OC_OCS::quotaget($format,$user);
|
||||||
|
|
||||||
|
// quotaset
|
||||||
|
}elseif(($method=='post') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'quota')){
|
||||||
|
$user=$ex[$paracount-3];
|
||||||
|
$quota = self::readData('post', 'quota', 'int');
|
||||||
|
OC_OCS::quotaset($format,$user,$quota);
|
||||||
|
|
||||||
|
// keygetpublic
|
||||||
|
}elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'publickey')){
|
||||||
|
$user=$ex[$paracount-3];
|
||||||
|
OC_OCS::publicKeyGet($format,$user);
|
||||||
|
|
||||||
|
// keygetprivate
|
||||||
|
}elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'privatekey')){
|
||||||
|
$user=$ex[$paracount-3];
|
||||||
|
OC_OCS::privateKeyGet($format,$user);
|
||||||
|
|
||||||
|
|
||||||
|
// add more calls here
|
||||||
|
// please document all the call in the draft spec
|
||||||
|
// http://www.freedesktop.org/wiki/Specifications/open-collaboration-services-1.7#CLOUD
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// users
|
||||||
|
// groups
|
||||||
|
// bookmarks
|
||||||
|
// sharing
|
||||||
|
// versioning
|
||||||
|
// news (rss)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
$format=OC_OCS::readdata('format','text');
|
|
||||||
$txt='Invalid query, please check the syntax. API specifications are here: http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n";
|
$txt='Invalid query, please check the syntax. API specifications are here: http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n";
|
||||||
$txt.=OC_OCS::getdebugoutput();
|
$txt.=OC_OCS::getdebugoutput();
|
||||||
echo(OC_OCS::generatexml($format,'failed',999,$txt));
|
echo(OC_OCS::generatexml($format,'failed',999,$txt));
|
||||||
|
@ -240,7 +270,6 @@ class OC_OCS {
|
||||||
*/
|
*/
|
||||||
private static function generateXml($format,$status,$statuscode,$message,$data=array(),$tag='',$tagattribute='',$dimension=-1,$itemscount='',$itemsperpage='') {
|
private static function generateXml($format,$status,$statuscode,$message,$data=array(),$tag='',$tagattribute='',$dimension=-1,$itemscount='',$itemsperpage='') {
|
||||||
if($format=='json') {
|
if($format=='json') {
|
||||||
|
|
||||||
$json=array();
|
$json=array();
|
||||||
$json['status']=$status;
|
$json['status']=$status;
|
||||||
$json['statuscode']=$statuscode;
|
$json['statuscode']=$statuscode;
|
||||||
|
@ -249,8 +278,6 @@ class OC_OCS {
|
||||||
$json['itemsperpage']=$itemsperpage;
|
$json['itemsperpage']=$itemsperpage;
|
||||||
$json['data']=$data;
|
$json['data']=$data;
|
||||||
return(json_encode($json));
|
return(json_encode($json));
|
||||||
|
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
$txt='';
|
$txt='';
|
||||||
$writer = xmlwriter_open_memory();
|
$writer = xmlwriter_open_memory();
|
||||||
|
@ -343,7 +370,6 @@ class OC_OCS {
|
||||||
}else{
|
}else{
|
||||||
xmlwriter_write_element($writer,$key,$value);
|
xmlwriter_write_element($writer,$key,$value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +385,7 @@ class OC_OCS {
|
||||||
$user=OC_OCS::checkpassword(false);
|
$user=OC_OCS::checkpassword(false);
|
||||||
$url=substr(OCP\Util::getServerHost().$_SERVER['SCRIPT_NAME'],0,-11).'';
|
$url=substr(OCP\Util::getServerHost().$_SERVER['SCRIPT_NAME'],0,-11).'';
|
||||||
|
|
||||||
$xml['version']='1.5';
|
$xml['version']='1.7';
|
||||||
$xml['website']='ownCloud';
|
$xml['website']='ownCloud';
|
||||||
$xml['host']=OCP\Util::getServerHost();
|
$xml['host']=OCP\Util::getServerHost();
|
||||||
$xml['contact']='';
|
$xml['contact']='';
|
||||||
|
@ -529,4 +555,134 @@ class OC_OCS {
|
||||||
public static function deleteData($user, $app, $key) {
|
public static function deleteData($user, $app, $key) {
|
||||||
return OC_Preferences::deleteKey($user,$app,$key);
|
return OC_Preferences::deleteKey($user,$app,$key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// CLOUD API #############################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a list of installed web apps
|
||||||
|
* @param string $format
|
||||||
|
* @return string xml/json
|
||||||
|
*/
|
||||||
|
private static function systemWebApps($format) {
|
||||||
|
$login=OC_OCS::checkpassword();
|
||||||
|
$apps=OC_App::getEnabledApps();
|
||||||
|
$values=array();
|
||||||
|
foreach($apps as $app) {
|
||||||
|
$info=OC_App::getAppInfo($app);
|
||||||
|
if(isset($info['standalone'])) {
|
||||||
|
$newvalue=array('name'=>$info['name'],'url'=>OC_Helper::linkToAbsolute($app,''),'icon'=>'');
|
||||||
|
$values[]=$newvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$txt=OC_OCS::generatexml($format, 'ok', 100, '', $values, 'cloud', '', 2, 0, 0);
|
||||||
|
echo($txt);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the quota of a user
|
||||||
|
* @param string $format
|
||||||
|
* @param string $user
|
||||||
|
* @return string xml/json
|
||||||
|
*/
|
||||||
|
private static function quotaGet($format,$user) {
|
||||||
|
$login=OC_OCS::checkpassword();
|
||||||
|
if(OC_Group::inGroup($login, 'admin') or ($login==$user)) {
|
||||||
|
|
||||||
|
if(OC_User::userExists($user)){
|
||||||
|
// calculate the disc space
|
||||||
|
$user_dir = '/'.$user.'/files';
|
||||||
|
OC_Filesystem::init($user_dir);
|
||||||
|
$rootInfo=OC_FileCache::get('');
|
||||||
|
$sharedInfo=OC_FileCache::get('/Shared');
|
||||||
|
$used=$rootInfo['size']-$sharedInfo['size'];
|
||||||
|
$free=OC_Filesystem::free_space();
|
||||||
|
$total=$free+$used;
|
||||||
|
if($total==0) $total=1; // prevent division by zero
|
||||||
|
$relative=round(($used/$total)*10000)/100;
|
||||||
|
|
||||||
|
$xml=array();
|
||||||
|
$xml['quota']=$total;
|
||||||
|
$xml['free']=$free;
|
||||||
|
$xml['used']=$used;
|
||||||
|
$xml['relative']=$relative;
|
||||||
|
|
||||||
|
$txt=OC_OCS::generatexml($format, 'ok', 100, '', $xml, 'cloud', '', 1, 0, 0);
|
||||||
|
echo($txt);
|
||||||
|
}else{
|
||||||
|
echo self::generateXml('', 'fail', 300, 'User does not exist');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
echo self::generateXml('', 'fail', 300, 'You don´t have permission to access this ressource.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the quota of a user
|
||||||
|
* @param string $format
|
||||||
|
* @param string $user
|
||||||
|
* @param string $quota
|
||||||
|
* @return string xml/json
|
||||||
|
*/
|
||||||
|
private static function quotaSet($format,$user,$quota) {
|
||||||
|
$login=OC_OCS::checkpassword();
|
||||||
|
if(OC_Group::inGroup($login, 'admin')) {
|
||||||
|
|
||||||
|
// todo
|
||||||
|
// not yet implemented
|
||||||
|
// add logic here
|
||||||
|
error_log('OCS call: user:'.$user.' quota:'.$quota);
|
||||||
|
|
||||||
|
$xml=array();
|
||||||
|
$txt=OC_OCS::generatexml($format, 'ok', 100, '', $xml, 'cloud', '', 1, 0, 0);
|
||||||
|
echo($txt);
|
||||||
|
}else{
|
||||||
|
echo self::generateXml('', 'fail', 300, 'You don´t have permission to access this ressource.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the public key of a user
|
||||||
|
* @param string $format
|
||||||
|
* @param string $user
|
||||||
|
* @return string xml/json
|
||||||
|
*/
|
||||||
|
private static function publicKeyGet($format,$user) {
|
||||||
|
$login=OC_OCS::checkpassword();
|
||||||
|
|
||||||
|
if(OC_User::userExists($user)){
|
||||||
|
// calculate the disc space
|
||||||
|
$txt='this is the public key of '.$user;
|
||||||
|
echo($txt);
|
||||||
|
}else{
|
||||||
|
echo self::generateXml('', 'fail', 300, 'User does not exist');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the private key of a user
|
||||||
|
* @param string $format
|
||||||
|
* @param string $user
|
||||||
|
* @return string xml/json
|
||||||
|
*/
|
||||||
|
private static function privateKeyGet($format,$user) {
|
||||||
|
$login=OC_OCS::checkpassword();
|
||||||
|
if(OC_Group::inGroup($login, 'admin') or ($login==$user)) {
|
||||||
|
|
||||||
|
if(OC_User::userExists($user)){
|
||||||
|
// calculate the disc space
|
||||||
|
$txt='this is the private key of '.$user;
|
||||||
|
echo($txt);
|
||||||
|
}else{
|
||||||
|
echo self::generateXml('', 'fail', 300, 'User does not exist');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
echo self::generateXml('', 'fail', 300, 'You don´t have permission to access this ressource.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue