Return-Path: Delivered-To: apmail-directory-commits-archive@www.apache.org Received: (qmail 99476 invoked from network); 5 Apr 2007 19:39:08 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 5 Apr 2007 19:39:08 -0000 Received: (qmail 35388 invoked by uid 500); 5 Apr 2007 19:39:15 -0000 Delivered-To: apmail-directory-commits-archive@directory.apache.org Received: (qmail 35353 invoked by uid 500); 5 Apr 2007 19:39:15 -0000 Mailing-List: contact commits-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@directory.apache.org Delivered-To: mailing list commits@directory.apache.org Received: (qmail 35342 invoked by uid 99); 5 Apr 2007 19:39:15 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 05 Apr 2007 12:39:15 -0700 X-ASF-Spam-Status: No, hits=-99.5 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 05 Apr 2007 12:39:06 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id C30DB1A983E; Thu, 5 Apr 2007 12:38:46 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r525948 [2/2] - in /directory/sandbox/oersoy/guides/das.ldap.design.documentation: ./ META-INF/ source/ source/concepts/ source/concepts/0/ src/ src/main/ src/main/resources/ src/main/resources/css/ src/main/resources/images/ target/ target... Date: Thu, 05 Apr 2007 19:38:44 -0000 To: commits@directory.apache.org From: oersoy@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20070405193846.C30DB1A983E@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/2/recipexx.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/2/recipexx.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/2/recipexx.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/2/recipexx.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,153 @@ + + + + + + Writing an LDAP ObjectClass per EClass in the Model + + + + + + + +

Challenge

+ +
+

+ Writing an LDAP ObjectClass per EClass in the Model +

+
+ +

Solution

+ +
+

+ Use the LDAP Server's Dynamic Schema Capabilities +

+
+ +

Discussion

+ +
+

+ + + First create a new ObjectClass representing the SDO Type (Class) + and add it to a new instance of LDAP attributes. + +
+
+

+  Attributes ldapAttributes = new AttributesImpl();
+  Attribute objectClass = new AttributeImpl( SystemSchemaConstants.OBJECT_CLASS_AT, eClass.getName() );
+  objectClass.add( MetaSchemaConstants.META_TOP_OC );
+  objectClass.add( MetaSchemaConstants.META_OBJECT_CLASS_OC );
+  ldapAttributes.put( objectClass ); 
+            
+
+
+ + Then add the EAttributes of the EClass to the LDAP attributes list. + +
+
+
+  EList eAttributes = eClass.getEAllAttributes();
+  Iterator eAttributeIterator = eAttributes.iterator();
+  while(eAttributeIterator.hasNext() )
+  {
+  	EAttribute eAttribute = eAttributeIterator.next();
+  	if ( eAttributes.isRequired() )
+  	{
+   	ldapAttributes.put( MetaSchemaConstants.M_MUST_AT, eAttribute.getName() ); 
+  	}
+  	else
+  	{
+  		ldapAttributes.put( MetaSchemaConstants.M_MAY_AT, eAttribute.getName() );
+  	}
+  }
+            
+
+
+ + + For each EReference on the EClass, that is + not a multiplicity many EReference, + we will create another ldap attribute + using the following naming convention: + +
+
+
  EReference.getName() + "EReference"
+
+
+ + If the EReference is a multiplicity many + reference then the naming convention used + is: + + +
+
+
  EReference.getName() + "EReferenceMany"
+
+
+ + If the EReference ldap attribute + is multiplicity many, it will + store the size of the EList containing + the references. + + If it is not multiplicity many, + it will just store a boolean indicating + whether the reference was set or not. + + Thus we iterate through all the + EReferences of the EClass adding them like + this: + +
+
+
+  EList eReferences = eClass.getEAllReferences();
+  Iterator eReferenceIterator = references.iterator();
+  while(eReferenceIterator.hasNext() )
+  {
+  	EReference eReference = eReferenceIterator.next();
+  	if ( eReference.isRequired() )
+  	{
+  		if ( eReference.isMany() )
+  		{
+  			ldapAttributes.put( MetaSchemaConstants.M_MUST_AT, eReference.getName() +  "EReferenceMany");
+  		}
+  		else
+  		{
+  			ldapAttributes.put( MetaSchemaConstants.M_MUST_AT, eReference.getName() +  "EReference");
+  		}
+  	}
+  	else
+  	{
+  		if ( eReference.isMany() )
+  		{
+  			ldapAttributes.put( MetaSchemaConstants.M_MAY_AT, eReference.getName() +  "EReferenceMany");
+  		}
+  		else
+  		{
+  			ldapAttributes.put( MetaSchemaConstants.M_MAY_AT, eReference.getName() +  "EReference");
+  		}
+  	}
+  }
+            
+
+
+ + Now when the LDAP DAS attempts to retrieve references it will + know where to look based on the convention discussed in the READ-TODO + recipe, and it will know how many to retrieve based on the value stored + in the reference attribute. + +

+ + + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe30.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe30.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe30.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe30.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,56 @@ + + + + + + Creating an Instance of the DataObject's Classifier + + + + + + + +

Challenge

+ +
+

+ Creating an Instance of the DataObject's Classifier +

+
+ +

Solution

+ +
+

+ Use EcoreFactory.eINSTANCE.createEClass() +

+
+ +

Discussion

+ +
+

+ +
+
+

+            EClass eClass = EcoreFactory.eINSTANCE.createEClass();
+            eClass.setName()
+            
+
+
+ + we would get our EClass or Type name like this this: + +
+
+
+ String className = StringUtils.capitalize( JNDIUtils.getRDN(DN) );  
+
+
+ +

+ + + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe31.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe31.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe31.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe31.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,42 @@ + + + + + + Creating an Instance of the SDO DataObject's Type + + + + + + + +

Challenge

+ +
+

+ Creating an Instance of the SDO DataObject's Type +

+
+ +

Solution

+ +
+

Use EcoreFactory.eINSTANCE

+
+ +

Discussion

+ +
+

+ +
+
+

EClass eClass = EcoreFactory.eINSTANCE.createEClass()
+
+
+ +

+ + + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe32.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe32.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe32.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe32.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,77 @@ + + + + + + Getting the DataObject's Simple Properties from the LDAP + Entry + + + + + + + +

Challenge

+ +
+

+ Getting the DataObject's Simple Properties from the LDAP + Entry +

+
+ +

Solution

+ +
+

Use DirContext.getAttributes()

+
+ +

Discussion

+ +
+

+ + First get a list of all the attributes contained in the entry: +
+
+

Attributes ldapAttributes = directoryContext.getAttributes(rootDataObjectDN);
+
+
+ + Then clone it, because we need both the complex type metadata, for + retrieving DataObject references, and the + simple properties: + +
+
+
Attributes ldapAttributesClone = ldapAttributes.clone();
+
+
+ + Then delete the objectClass attribute from the ldapAttributes map: + +
+
+
ldapAttributes.remove(SystemSchemaConstants.OBJECT_CLASS_AT);
+
+
+ + Then remove all the attributes whose name contains the word EReference. + +
+
+
TODO Code
+
+
+ + We now have a map of the simple property names and their corresponding + values. + +
+
+ +

+ + + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe33.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe33.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe33.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe33.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,71 @@ + + + + + + Getting the DataObject's Complex Properties's Metadata + + + + + + + +

Challenge

+ +
+

+ Getting the DataObject's Complex Properties's Metadata +

+
+ +

Solution

+ +
+

Use DirContext.getAttributes()

+
+ +

Discussion

+ +
+

+ + First get a list of all the attributes contained in the entry: +
+
+

Attributes ldapAttributes = directoryContext.getAttributes(rootDataObjectDN);
+
+
+ +
+
+
Attributes ldapAttributesClone = ldapAttributes.clone();
+
+
+ + Then delete the objectClass attribute from the ldapAttributes map: + +
+
+
ldapAttributes.remove(SystemSchemaConstants.OBJECT_CLASS_AT);
+
+
+ + Then if the attribute's name does not contain the String "EReference", + we remove it. + +
+
+
TODO Code
+
+
+ + We now have a map of the complex property names and their corresponding + meta data values. +
+
+ +

+ + + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe34.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe34.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe34.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/3/recipe34.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,65 @@ + + + + + Adding the Root EClass's EAttributes + + + + + + +

Challenge

+ +
+

Adding the Root EClass's EAttributes

+
+ +

Solution

+ +
+

+ Use the Simple Properties Attributes Map +

+
+ +

Discussion

+ +
+

+ + For each ldapAttribute in the entry, the DAS first creates + an EAttribute instance, if one has not already been created + and added to the model's EPackage. +

 EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute(); 
+
+
+ The EAttribute requires a DataType instance in order + to set the the EAttribute's eType property, so the DAS + uses the name of the attributeType's Syntax OID + to lookup the DataType on the EPackage. If the + DataType reference returned is null, the DAS creates + the DataType and adds it to the EPackage. +
+
+ The EAttribute instance also needs a name. + The name of the EAttribute instance is the + name of the attributeType. +
+
+ If the EAttribute instance is a multiplicity + many EAttribute, indicated by MetaSchemaConstants.M_SINGLE_VALUE_AT + property of the attributeType being set to false, the + EAttribute's upperBound property is set to "-1". +
+
+ Lastly if the attributeType is a + MetaSchemaConstants.M_MUST_AT attribute, + then the EAttribute required property is set to true. +
+
+ +

+ + + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/4/recipe13.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/4/recipe13.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/4/recipe13.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/4/recipe13.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,93 @@ + + + + + Creating an EReference Subcontext + + + + + + +

Challenge

+ +
+

Creating an EReference Subcontext

+
+ +

Solution

+ +
+

+ Use the JNDI InitialContext bind Operation +

+
+ +

Discussion

+ +
+

+ + We need to establish a subcontext for each EReference. +
+
+ The subcontext naming convention used + is +
+
+ EReference.getName() +
+
+ if the EReference is not a multiplicity many + EReference. +
+
+ If the EReference is a multiplicity many EReference, + the convention used is: +
+
+ EReference.getName() + index +
+
+ where index is an integer indicating + where the EReference is stored on the EList of its + container. +
+
+ Thus if our root object is getEObject("//account"); + and it is stored here: +
+
+ DN: cn=accounts, cn=users, cn=org, cn=example, cn=com +
+ and it has an non multiplicity many EReference + of type User named user, then user would be stored + here: +
+
+ DN: cn=user, cn=accounts, cn=users, cn=org, cn=example, cn=com +
+
+ If User was a multiplicity many EReference, and its index was 0, + it would be stored here: +
+
+ DN: cn=user0, cn=accounts, cn=users, cn=org, cn=example, cn=com +
+
+ So if there were 3 User EReferences stored on the multiplicity + many User EReference, then they would be stored under the following + contexts: +
+
+ DN: cn=user0, cn=accounts, cn=users, cn=org, cn=example, cn=com +
+ DN: cn=user1, cn=accounts, cn=users, cn=org, cn=example, cn=com +
+ DN: cn=user2, cn=accounts, cn=users, cn=org, cn=example, cn=com +
+ +

+ + + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/4/recipe40.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/4/recipe40.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/4/recipe40.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/4/recipe40.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,186 @@ + + + + + Writing a DataGraph to ADS + + + + + + +

Challenge

+ +
+

Writing a DataGraph to ADS

+
+ +

Solution

+ +
+

+ Use DAS.LDAP.write(eObject) [Just made it up] +

+
+ +

Discussion

+ +
+

+ + Creating a DataGraph in ADS means writing all the + DataObjects contained in the graph to ADS, + along with their corresponding + types (Classes), which correspond to ObjectClasses + in ADS. + +
+
+ + To do this we first get the root DataObject + in the DataGraph. + +
+
+

  EObject eObjectRoot = resource.getEObject("//@accounts");
+
+
+ + We also create the Directory Context + where this object will be stored + (using the convention discussed in the + recipe ) like this: + +
+
+
+  //I just made the below ctx method stuff up..
+  //will correct when coding :-) 
+  DirContext rootContext = DirContext.createContexts("cn=accounts, cn=users, cn=org, cn=example, cn=com");
+            
+
+
+ + Then we get the root object's type (EClass): + +
+
+
  EClass eClass = eObjectRoot.eClass();
+
+
+ + Now we write the ObjectClass corresponding + to this EClass to ADS (See Related Recipes). + +
+
+ + Once the ObjectClass is added to ADS + we create a directory attributes list and + add it like this: + +
+
+
+  Attributes ldapAttributes = new AttributesImpl();
+  ldapAttributes.put(SystemSchemaConstants.OBJECT_CLASS_NAME, eClass.getFullyQualifiedName() );            
+			
+
+
+ + Once this is done, we add the simple + properties contained in the DataObject + to a list of ldap attributes as follows. + +
+
+
+EList eAttributes = eClass.getEAllAttributes();
+Iterator attributeIterator = eAttributes.iterator();
+while ( attributeIterator.hasNext() )
+  {
+	  EAttribute eAttribute    = attributeIterator.next();
+	  EObject eAttributeObject = eObjectRoot.eGet(eAttribute);
+	
+	 ldapAttributes.put(eAttribute.getName(), eAttributeObject.toString() );
+  }
+          
+
+
+ + We must also add the directory attributes that contain + metadata (size() for multiplicity many EReferences and isSet() otherwise) + for the EReferences (Complex properties) on the + root object like this. + +
+
+
+  EList eReferences = eClass.getEAllReferences();
+  Iterator eReferenceIterator = eReferences.iterator();
+  while ( eReferenceIterator.hasNext() )
+  {
+	  EReference eReference    = eReferenceIterator.next();
+	  if (eReference.isMany())
+	  {
+		  if ( eObjectRoot.isSet(eReference) )
+		  {
+			  EList eReferenceList = eObjectRoot.eGet(eReference);
+ 		  ldapAttributes.put(eReference.getName(), eReferenceList.size() );
+		  }
+		  else
+		  {
+			  ldapAttributes.put(eReference.getName(), 0 );
+		  }
+	  }
+	  else
+	  {
+		  ldapAttributes.put(eReference.getName(), eObjectRoot.isSet(eReference);
+	  }
+  }
+            
+
+
+ + Finally we add the list of ldap attributes, effectively adding the + root DataGraph object, to the server: + +
+
+
+  //I'm making this up too
+  ctx.addAttributes(ldapAttributes);
+            
+
+
+ +

+ + +

Related Challenges

+ + + + + + + + +
+ + 
+				Providing the DAS With an Initial Context
+			+ + + Providing the DAS With an Initial Context +
+ + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe50.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe50.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe50.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe50.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,52 @@ + + + + + Creating a DataObject Instance + + + + + + +

Challenge

+ +
+

Creating a DataObject Instance

+
+ +

Solution

+ +
+

Use the RDN from the current directory context

+
+ +

Discussion

+ +
+

+ + First get the model's Factory from the EPackage. +
+
+

EFactory eFactory = modelEPackage.getFactory()
+
+
+ Then create an instance of the + + Therefore we can get our model root object like this: + +
+
+
  EObject eObject = eFactory.create("FileUtils.capitalize(rdnValue);
+
+
+ + Note that if the rdnValue corresponds to a multiplicity many + EReference then the integer at the end of the rdnValue must + be removed. + +

+ + + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe51.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe51.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe51.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe51.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,33 @@ + + + + + Setting a DataObject's Simple Properties + + + + + + +

Challenge

+ +
+

Setting a DataObject's Simple Properties

+
+ +

Solution

+ +
+

+
+ +

Discussion

+ +
+

+ + +

+ + + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe52.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe52.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe52.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/5/recipe52.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,33 @@ + + + + + Setting the DataObject's Complex Properties + + + + + + +

Challenge

+ +
+

Setting the DataObject's Complex Properties

+
+ +

Solution

+ +
+

+
+ +

Discussion

+ +
+

+ + +

+ + + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/x/recipex0.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/x/recipex0.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/x/recipex0.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/x/recipex0.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,32 @@ + + + + + Creating the Prototype Project + + + + + + +

Challenge

+ +
+

Creating the Prototype Project

+
+ +

Solution

+ +
+

+ Run mvn archetype:create -DartifactId=das.ldap.prototype -DgroupId=org.apache.tuscany +

+
+ +

Discussion

+ +
+

null

+ + + \ No newline at end of file Added: directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/x/recipex1.html URL: http://svn.apache.org/viewvc/directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/x/recipex1.html?view=auto&rev=525948 ============================================================================== --- directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/x/recipex1.html (added) +++ directory/sandbox/oersoy/guides/das.ldap.design.documentation/target/html/recipes/x/recipex1.html Thu Apr 5 12:38:41 2007 @@ -0,0 +1,34 @@ + + + + + + Adding the EMF Dependencies to the Build + + + + + + + +

Challenge

+ +
+

+ Adding the EMF Dependencies to the Build +

+
+ +

Solution

+ +
+

See Discussion

+
+ +

Discussion

+ +
+

+ + + \ No newline at end of file