mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			584 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			584 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
/* RestrictedORB.java --
 | 
						|
   Copyright (C) 2005 Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package gnu.CORBA;
 | 
						|
 | 
						|
import gnu.CORBA.CDR.BufferedCdrOutput;
 | 
						|
import gnu.CORBA.typecodes.AliasTypeCode;
 | 
						|
import gnu.CORBA.typecodes.ArrayTypeCode;
 | 
						|
import gnu.CORBA.typecodes.PrimitiveTypeCode;
 | 
						|
import gnu.CORBA.typecodes.RecordTypeCode;
 | 
						|
import gnu.CORBA.typecodes.StringTypeCode;
 | 
						|
 | 
						|
import org.omg.CORBA.Any;
 | 
						|
import org.omg.CORBA.BAD_PARAM;
 | 
						|
import org.omg.CORBA.Context;
 | 
						|
import org.omg.CORBA.ContextList;
 | 
						|
import org.omg.CORBA.Environment;
 | 
						|
import org.omg.CORBA.ExceptionList;
 | 
						|
import org.omg.CORBA.NO_IMPLEMENT;
 | 
						|
import org.omg.CORBA.NVList;
 | 
						|
import org.omg.CORBA.NamedValue;
 | 
						|
import org.omg.CORBA.ORB;
 | 
						|
import org.omg.CORBA.ORBPackage.InvalidName;
 | 
						|
import org.omg.CORBA.Request;
 | 
						|
import org.omg.CORBA.StructMember;
 | 
						|
import org.omg.CORBA.TCKind;
 | 
						|
import org.omg.CORBA.TypeCode;
 | 
						|
import org.omg.CORBA.TypeCodePackage.BadKind;
 | 
						|
import org.omg.CORBA.UnionMember;
 | 
						|
import org.omg.CORBA.portable.OutputStream;
 | 
						|
import org.omg.CORBA.portable.ValueFactory;
 | 
						|
import org.omg.PortableInterceptor.ClientRequestInterceptorOperations;
 | 
						|
import org.omg.PortableInterceptor.IORInterceptor_3_0Operations;
 | 
						|
import org.omg.PortableInterceptor.ServerRequestInterceptorOperations;
 | 
						|
 | 
						|
import java.applet.Applet;
 | 
						|
 | 
						|
import java.util.Hashtable;
 | 
						|
import java.util.Properties;
 | 
						|
 | 
						|
/**
 | 
						|
 * This class implements so-called Singleton ORB, a highly restricted version
 | 
						|
 * that cannot communicate over network. This ORB is provided for the
 | 
						|
 * potentially malicious applets with heavy security restrictions. It, however,
 | 
						|
 * supports some basic features that might be needed even when the network
 | 
						|
 * access is not granted.
 | 
						|
 *
 | 
						|
 * This ORB can only create typecodes, {@link Any}, {@link ContextList},
 | 
						|
 * {@link NVList} and {@link org.omg.CORBA.portable.OutputStream} that writes to
 | 
						|
 * an internal buffer.
 | 
						|
 *
 | 
						|
 * All other methods throw the {@link NO_IMPLEMENT} exception.
 | 
						|
 *
 | 
						|
 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
 | 
						|
 */
 | 
						|
public class OrbRestricted extends org.omg.CORBA_2_3.ORB
 | 
						|
{
 | 
						|
  /**
 | 
						|
   * The singleton instance of this ORB.
 | 
						|
   */
 | 
						|
  public static final ORB Singleton = new OrbRestricted();
 | 
						|
 | 
						|
  /**
 | 
						|
   * The cumulated listener for all IOR interceptors. Interceptors are used by
 | 
						|
   * {@link gnu.CORBA.Poa.ORB_1_4}.
 | 
						|
   */
 | 
						|
  public IORInterceptor_3_0Operations iIor;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The cumulated listener for all server request interceptors. Interceptors
 | 
						|
   * are used by {@link gnu.CORBA.Poa.ORB_1_4}.
 | 
						|
   */
 | 
						|
  public ServerRequestInterceptorOperations iServer;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The cumulated listener for all client request interceptros. Interceptors
 | 
						|
   * are used by {@link gnu.CORBA.Poa.ORB_1_4}.
 | 
						|
   */
 | 
						|
  public ClientRequestInterceptorOperations iClient;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The required size of the interceptor slot array.
 | 
						|
   */
 | 
						|
  public int icSlotSize = 0;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The value factories.
 | 
						|
   */
 | 
						|
  protected Hashtable factories = new Hashtable();
 | 
						|
 | 
						|
  /**
 | 
						|
   * The policy factories.
 | 
						|
   */
 | 
						|
  protected Hashtable policyFactories = new Hashtable();
 | 
						|
 | 
						|
  /**
 | 
						|
       * Create a new instance of the RestrictedORB. This is used in derived classes
 | 
						|
   * only.
 | 
						|
   */
 | 
						|
  protected OrbRestricted()
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public TypeCode create_alias_tc(String id, String name, TypeCode typecode)
 | 
						|
  {
 | 
						|
    return new AliasTypeCode(typecode, id, name);
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public Any create_any()
 | 
						|
  {
 | 
						|
    gnuAny any = new gnuAny();
 | 
						|
    any.setOrb(this);
 | 
						|
    return any;
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public TypeCode create_array_tc(int length, TypeCode element_type)
 | 
						|
  {
 | 
						|
    ArrayTypeCode p =
 | 
						|
      new ArrayTypeCode(TCKind.tk_array, element_type);
 | 
						|
    p.setLength(length);
 | 
						|
    return p;
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public ContextList create_context_list()
 | 
						|
  {
 | 
						|
    return new gnuContextList();
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public TypeCode create_enum_tc(String id, String name, String[] values)
 | 
						|
  {
 | 
						|
    RecordTypeCode r = new RecordTypeCode(TCKind.tk_enum);
 | 
						|
    for (int i = 0; i < values.length; i++)
 | 
						|
      {
 | 
						|
        r.field().name = values [ i ];
 | 
						|
      }
 | 
						|
 | 
						|
    r.setId(id);
 | 
						|
    r.setName(name);
 | 
						|
 | 
						|
    return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public Environment create_environment()
 | 
						|
  {
 | 
						|
    return new gnuEnvironment();
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public ExceptionList create_exception_list()
 | 
						|
  {
 | 
						|
    return new gnuExceptionList();
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public TypeCode create_exception_tc(String id, String name,
 | 
						|
    StructMember[] members
 | 
						|
  )
 | 
						|
  {
 | 
						|
    RecordTypeCode r = new RecordTypeCode(TCKind.tk_except);
 | 
						|
    r.setId(id);
 | 
						|
    r.setName(name);
 | 
						|
 | 
						|
    for (int i = 0; i < members.length; i++)
 | 
						|
      {
 | 
						|
        r.add(members [ i ]);
 | 
						|
      }
 | 
						|
 | 
						|
    return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method is not allowed for a RestrictedORB.
 | 
						|
   *
 | 
						|
   * @throws NO_IMPLEMENT, always.
 | 
						|
   */
 | 
						|
  public TypeCode create_interface_tc(String id, String name)
 | 
						|
  {
 | 
						|
    no();
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public NVList create_list(int count)
 | 
						|
  {
 | 
						|
    return new gnuNVList(count);
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public NamedValue create_named_value(String s, Any any, int flags)
 | 
						|
  {
 | 
						|
    return new gnuNamedValue();
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public OutputStream create_output_stream()
 | 
						|
  {
 | 
						|
    BufferedCdrOutput stream = new BufferedCdrOutput();
 | 
						|
    stream.setOrb(this);
 | 
						|
    return stream;
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public TypeCode create_sequence_tc(int bound, TypeCode element_type)
 | 
						|
  {
 | 
						|
    ArrayTypeCode p =
 | 
						|
      new ArrayTypeCode(TCKind.tk_sequence, element_type);
 | 
						|
    p.setLength(bound);
 | 
						|
    return p;
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public TypeCode create_string_tc(int bound)
 | 
						|
  {
 | 
						|
    StringTypeCode p = new StringTypeCode(TCKind.tk_string);
 | 
						|
    p.setLength(bound);
 | 
						|
    return p;
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public TypeCode create_struct_tc(String id, String name,
 | 
						|
    StructMember[] members
 | 
						|
  )
 | 
						|
  {
 | 
						|
    RecordTypeCode r = new RecordTypeCode(TCKind.tk_struct);
 | 
						|
    r.setId(id);
 | 
						|
    r.setName(name);
 | 
						|
 | 
						|
    for (int i = 0; i < members.length; i++)
 | 
						|
      {
 | 
						|
        r.add(members [ i ]);
 | 
						|
      }
 | 
						|
 | 
						|
    return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public TypeCode create_union_tc(String id, String name,
 | 
						|
    TypeCode discriminator_type, UnionMember[] members
 | 
						|
  )
 | 
						|
  {
 | 
						|
    RecordTypeCode r = new RecordTypeCode(TCKind.tk_union);
 | 
						|
    r.setId(id);
 | 
						|
    r.setName(name);
 | 
						|
    r.setDiscriminator_type(discriminator_type);
 | 
						|
    r.setDefaultIndex(0);
 | 
						|
 | 
						|
    for (int i = 0; i < members.length; i++)
 | 
						|
      {
 | 
						|
        r.add(members [ i ]);
 | 
						|
      }
 | 
						|
 | 
						|
    return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public TypeCode create_wstring_tc(int bound)
 | 
						|
  {
 | 
						|
    StringTypeCode p = new StringTypeCode(TCKind.tk_wstring);
 | 
						|
    p.setLength(bound);
 | 
						|
    return p;
 | 
						|
  }
 | 
						|
 | 
						|
  /** {@inheritDoc} */
 | 
						|
  public TypeCode get_primitive_tc(TCKind tcKind)
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        return TypeKindNamer.getPrimitveTC(tcKind);
 | 
						|
      }
 | 
						|
    catch (BadKind ex)
 | 
						|
      {
 | 
						|
        throw new BAD_PARAM("This is not a primitive type code: " +
 | 
						|
          tcKind.value()
 | 
						|
        );
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method is not allowed for a RestrictedORB.
 | 
						|
   *
 | 
						|
   * @throws NO_IMPLEMENT, always.
 | 
						|
   */
 | 
						|
  public String[] list_initial_services()
 | 
						|
  {
 | 
						|
    no();
 | 
						|
    throw new InternalError();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method is not allowed for a RestrictedORB.
 | 
						|
   *
 | 
						|
   * @throws NO_IMPLEMENT, always.
 | 
						|
   */
 | 
						|
  public String object_to_string(org.omg.CORBA.Object forObject)
 | 
						|
  {
 | 
						|
    no();
 | 
						|
    throw new InternalError();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method is not allowed for a RestrictedORB.
 | 
						|
   *
 | 
						|
   * @throws InvalidName never in this class, but it is thrown in the derived
 | 
						|
   * classes.
 | 
						|
   *
 | 
						|
   * @throws NO_IMPLEMENT, always.
 | 
						|
   */
 | 
						|
  public org.omg.CORBA.Object resolve_initial_references(String name)
 | 
						|
    throws InvalidName
 | 
						|
  {
 | 
						|
    no();
 | 
						|
    throw new InternalError();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Shutdown the ORB server.
 | 
						|
   *
 | 
						|
   * For RestrictedORB, returns witout action.
 | 
						|
   */
 | 
						|
  public void run()
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Shutdown the ORB server.
 | 
						|
   *
 | 
						|
   * For RestrictedORB, returns witout action.
 | 
						|
   */
 | 
						|
  public void shutdown(boolean wait_for_completion)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method is not allowed for a RestrictedORB.
 | 
						|
   *
 | 
						|
   * @throws NO_IMPLEMENT, always.
 | 
						|
   */
 | 
						|
  public org.omg.CORBA.Object string_to_object(String IOR)
 | 
						|
  {
 | 
						|
    no();
 | 
						|
    throw new InternalError();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method is not allowed for a RestrictedORB.
 | 
						|
   *
 | 
						|
   * @throws NO_IMPLEMENT, always.
 | 
						|
   */
 | 
						|
  protected void set_parameters(Applet app, Properties props)
 | 
						|
  {
 | 
						|
    no();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method is not allowed for a RestrictedORB.
 | 
						|
   *
 | 
						|
   * @throws NO_IMPLEMENT, always.
 | 
						|
   */
 | 
						|
  protected void set_parameters(String[] args, Properties props)
 | 
						|
  {
 | 
						|
    no();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Throws an exception, stating that the given method is not supported by the
 | 
						|
   * Restricted ORB.
 | 
						|
   */
 | 
						|
  private final void no()
 | 
						|
  {
 | 
						|
    // Apart the programming errors, this can only happen if the
 | 
						|
    // malicious code is trying to do that it is not allowed.
 | 
						|
    throw new NO_IMPLEMENT("Use init(args, props) for the functional version.");
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method is not allowed for a RestrictedORB.
 | 
						|
   *
 | 
						|
   * @throws NO_IMPLEMENT, always.
 | 
						|
   */
 | 
						|
  public Request get_next_response() throws org.omg.CORBA.WrongTransaction
 | 
						|
  {
 | 
						|
    no();
 | 
						|
    throw new InternalError();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method is not allowed for a RestrictedORB.
 | 
						|
   *
 | 
						|
   * @throws NO_IMPLEMENT, always.
 | 
						|
   */
 | 
						|
  public boolean poll_next_response()
 | 
						|
  {
 | 
						|
    no();
 | 
						|
    throw new InternalError();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method is not allowed for a RestrictedORB.
 | 
						|
   *
 | 
						|
   * @throws NO_IMPLEMENT, always.
 | 
						|
   */
 | 
						|
  public void send_multiple_requests_deferred(Request[] requests)
 | 
						|
  {
 | 
						|
    no();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method is not allowed for a RestrictedORB.
 | 
						|
   *
 | 
						|
   * @throws NO_IMPLEMENT, always.
 | 
						|
   */
 | 
						|
  public void send_multiple_requests_oneway(Request[] requests)
 | 
						|
  {
 | 
						|
    no();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Register the value factory under the given repository id.
 | 
						|
   */
 | 
						|
  public ValueFactory register_value_factory(String repository_id,
 | 
						|
    ValueFactory factory
 | 
						|
  )
 | 
						|
  {
 | 
						|
    factories.put(repository_id, factory);
 | 
						|
    return factory;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Unregister the value factroy.
 | 
						|
   */
 | 
						|
  public void unregister_value_factory(String id)
 | 
						|
  {
 | 
						|
    factories.remove(id);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Look for the value factory for the value, having the given repository id.
 | 
						|
       * The implementation checks for the registered value factories first. If none
 | 
						|
       * found, it tries to load and instantiate the class, mathing the given naming
 | 
						|
   * convention. If this faild, null is returned.
 | 
						|
   *
 | 
						|
   * @param repository_id a repository id.
 | 
						|
   *
 | 
						|
   * @return a found value factory, null if none.
 | 
						|
   */
 | 
						|
  public ValueFactory lookup_value_factory(String repository_id)
 | 
						|
  {
 | 
						|
    ValueFactory f = (ValueFactory) factories.get(repository_id);
 | 
						|
    if (f != null)
 | 
						|
      {
 | 
						|
        return f;
 | 
						|
      }
 | 
						|
 | 
						|
    f = (ValueFactory) ObjectCreator.createObject(repository_id,
 | 
						|
        "DefaultFactory"
 | 
						|
      );
 | 
						|
    if (f != null)
 | 
						|
      {
 | 
						|
        factories.put(repository_id, f);
 | 
						|
      }
 | 
						|
    return f;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Destroy the interceptors, if they are present.
 | 
						|
   */
 | 
						|
  public void destroy()
 | 
						|
  {
 | 
						|
    if (iIor != null)
 | 
						|
      {
 | 
						|
        iIor.destroy();
 | 
						|
        iIor = null;
 | 
						|
      }
 | 
						|
 | 
						|
    if (iServer != null)
 | 
						|
      {
 | 
						|
        iServer.destroy();
 | 
						|
        iServer = null;
 | 
						|
      }
 | 
						|
 | 
						|
    if (iClient != null)
 | 
						|
      {
 | 
						|
        iClient.destroy();
 | 
						|
        iClient = null;
 | 
						|
      }
 | 
						|
 | 
						|
    super.destroy();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Create a typecode, representing a tree-like structure.
 | 
						|
   * This structure contains a member that is a sequence of the same type,
 | 
						|
   * as the structure itself. You can imagine as if the folder definition
 | 
						|
   * contains a variable-length array of the enclosed (nested) folder
 | 
						|
   * definitions. In this way, it is possible to have a tree like
 | 
						|
   * structure that can be transferred via CORBA CDR stream.
 | 
						|
   *
 | 
						|
   * @deprecated It is easier and clearler to use a combination of
 | 
						|
   * create_recursive_tc and create_sequence_tc instead.
 | 
						|
   *
 | 
						|
   * @param bound the maximal expected number of the nested components
 | 
						|
   * on each node; 0 if not limited.
 | 
						|
   *
 | 
						|
   * @param offset the position of the field in the returned structure
 | 
						|
   * that contains the sequence of the structures of the same field.
 | 
						|
   * The members before this field are intialised using parameterless
 | 
						|
   * StructMember constructor.
 | 
						|
   *
 | 
						|
   * @return a typecode, defining a stucture, where a member at the
 | 
						|
   * <code>offset</code> position defines an array of the identical
 | 
						|
   * structures.
 | 
						|
   *
 | 
						|
   * @see #create_recursive_tc(String)
 | 
						|
   * @see #create_sequence_tc(int, TypeCode)
 | 
						|
   */
 | 
						|
  public TypeCode create_recursive_sequence_tc(int bound, int offset)
 | 
						|
  {
 | 
						|
    RecordTypeCode r = new RecordTypeCode(TCKind.tk_struct);
 | 
						|
    for (int i = 0; i < offset; i++)
 | 
						|
      r.add(new StructMember());
 | 
						|
 | 
						|
    TypeCode recurs = new PrimitiveTypeCode(TCKind.tk_sequence);
 | 
						|
 | 
						|
    r.add(new StructMember("", recurs, null));
 | 
						|
    return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Get the default context of this ORB. This is an initial root of all
 | 
						|
   * contexts.
 | 
						|
   *
 | 
						|
   * The default method returns a new context with the empty name and
 | 
						|
   * no parent context.
 | 
						|
   *
 | 
						|
   * @return the default context of this ORB.
 | 
						|
   */
 | 
						|
  public Context get_default_context()
 | 
						|
  {
 | 
						|
    return new gnuContext("", null);
 | 
						|
  }
 | 
						|
 | 
						|
}
 |