You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by pa...@apache.org on 2007/01/04 11:44:46 UTC

svn commit: r492512 - in /directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor: ./ widgets/

Author: pamarcelot
Date: Thu Jan  4 02:44:45 2007
New Revision: 492512

URL: http://svn.apache.org/viewvc?view=rev&rev=492512
Log:
Adding basic syntax coloring for the Source Editor tab of the ACI Item Editor.

Added:
    directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACICodeScanner.java
    directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACISourceViewerConfiguration.java
    directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACITextAttributeProvider.java
Modified:
    directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/Activator.java
    directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACIItemSourceEditorComposite.java

Modified: directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/Activator.java
URL: http://svn.apache.org/viewvc/directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/Activator.java?view=diff&rev=492512&r1=492511&r2=492512
==============================================================================
--- directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/Activator.java (original)
+++ directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/Activator.java Thu Jan  4 02:44:45 2007
@@ -19,7 +19,8 @@
  */
 package org.apache.directory.ldapstudio.aciitemeditor;
 
-
+import org.apache.directory.ldapstudio.aciitemeditor.widgets.ACICodeScanner;
+import org.apache.directory.ldapstudio.aciitemeditor.widgets.ACITextAttributeProvider;
 import org.apache.directory.shared.ldap.aci.ACIItemParser;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.dialogs.IDialogConstants;
@@ -52,6 +53,12 @@
     /** The shared ACI Item parser */
     private ACIItemParser aciItemParser;
 
+    /** The shared ACI Code Scanner */
+    private ACICodeScanner aciCodeScanner;
+
+    /** The shared ACI TextAttribute Provider */
+    private ACITextAttributeProvider textAttributeProvider;
+
 
     /**
      * The constructor
@@ -165,5 +172,36 @@
         int width = Dialog.convertHorizontalDLUsToPixels( fontMetrics, IDialogConstants.BUTTON_WIDTH );
         return width;
     }
+    
+    
+    /**
+     * Returns the TextAttribute Provider
+     * 
+     * @return
+     *      the TextAttribute Provider
+     */
+    public ACITextAttributeProvider getTextAttributeProvider()
+    {
+        if ( textAttributeProvider == null )
+        {
+            textAttributeProvider = new ACITextAttributeProvider();
+        }
+        return textAttributeProvider;
+    }
 
+    
+    /**
+     * Retuns the the Aci Code Scanner
+     * 
+     * @return 
+     *      the the Aci Code Scanner
+     */
+    public ACICodeScanner getAciCodeScanner()
+    {
+        if ( aciCodeScanner == null )
+        {
+            aciCodeScanner = new ACICodeScanner( getTextAttributeProvider() );
+        }
+        return aciCodeScanner;
+    }
 }

Added: directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACICodeScanner.java
URL: http://svn.apache.org/viewvc/directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACICodeScanner.java?view=auto&rev=492512
==============================================================================
--- directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACICodeScanner.java (added)
+++ directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACICodeScanner.java Thu Jan  4 02:44:45 2007
@@ -0,0 +1,193 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldapstudio.aciitemeditor.widgets;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.text.rules.IRule;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.IWhitespaceDetector;
+import org.eclipse.jface.text.rules.IWordDetector;
+import org.eclipse.jface.text.rules.RuleBasedScanner;
+import org.eclipse.jface.text.rules.SingleLineRule;
+import org.eclipse.jface.text.rules.Token;
+import org.eclipse.jface.text.rules.WhitespaceRule;
+import org.eclipse.jface.text.rules.WordRule;
+
+
+/**
+ * Scanner used to analyse ACI code. Allows syntax coloring.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class ACICodeScanner extends RuleBasedScanner
+{
+    /** 'identificationTag' keyword */
+    public static final String identificationTagPartition = "identificationTag";
+
+    /** 'precedence' keyword */
+    public static final String precedencePartition = "precedence";
+
+    /** 'authenticationLevel' keyword */
+    public static final String authenticationLevelPartition = "authenticationLevel";
+
+    /** Keywords for the itemOrUserFirst Section */
+    public static final String[] itemOrUserFirstSectionPartition = new String[]
+        { "itemOrUserFirst", "itemFirst", "userFirst" };
+
+    /** Keywords for 'userFirst' section */
+    public static final String[] userSection = new String[]
+        { "userClasses", "userPermissions" };
+
+    /** Keywords for AciItems values */
+    public static final String[] aciKeywords = new String[]
+        { "protectedItems", "itemPermissions", "entry", "allowUserAttributeTypes", "attributeType",
+            "allAttributeValues", "allUserAttributeTypesAndValues", "attributeValue", "selfValue", "rangeOfValues",
+            "maxValueCount", "maxImmSub", "restrictedBy", "classes", "grantsAndDenials", "allUsers", "thisEntry",
+            "name", "userGroup", "subtree", "type", "valuesIn", "none", "simple", "strong" };
+
+    /** Keywords for grant values */
+    public static final String[] aciGrantValues = new String[]
+        { "grantAdd", "grantDiscloseOnError", "grantRead", "grantRemove", "grantBrowse", "grantExport", "grantImport",
+            "grantModify", "grantRename", "grantReturnDN", "grantCompare", "grantFilterMatch", "grantInvoke", };
+
+    /** Keywords for deny values */
+    public static final String[] aciDenyValues = new String[]
+        { "denyAdd", "denyDiscloseOnError", "denyRead", "denyRemove", "denyBrowse", "denyExport", " denyImport",
+            "denyModify", "denyRename", "denyReturnDN", "denyCompare", "denyFilterMatch", "denyInvoke" };
+
+
+    /**
+     * Creates a new instance of AciCodeScanner.
+     *
+     * @param provider
+     *      the provider
+     */
+    public ACICodeScanner( ACITextAttributeProvider provider )
+    {
+        List<IRule> rules = new ArrayList<IRule>();
+
+        IToken keyword = new Token( provider.getAttribute( ACITextAttributeProvider.KEYWORD_ATTRIBUTE ) );
+        IToken undefined = new Token( provider.getAttribute( ACITextAttributeProvider.DEFAULT_ATTRIBUTE ) );
+        IToken string = new Token( provider.getAttribute( ACITextAttributeProvider.STRING_ATTRIBUTE ) );
+        IToken grantValue = new Token( provider.getAttribute( ACITextAttributeProvider.GRANT_VALUE ) );
+        IToken denyValue = new Token( provider.getAttribute( ACITextAttributeProvider.DENY_VALUE ) );
+        IToken identification = new Token( provider.getAttribute( ACITextAttributeProvider.IDENTIFICATION_ATTRIBUTE ) );
+        IToken precedence = new Token( provider.getAttribute( ACITextAttributeProvider.PRECEDENCE_ATTRIBUTE ) );
+        IToken authenticationLevel = new Token( provider
+            .getAttribute( ACITextAttributeProvider.AUTHENTICATIONLEVEL_ATTRIBUTE ) );
+        IToken itemOrUserFirst = new Token( provider.getAttribute( ACITextAttributeProvider.ITEMORUSERFIRST_ATTRIBUTE ) );
+        IToken user = new Token( provider.getAttribute( ACITextAttributeProvider.USER_ATTRIBUTE ) );
+
+        // Rules for Strings
+        rules.add( new SingleLineRule( "\"", "\"", string, '\0', true ) );
+        rules.add( new SingleLineRule( "'", "'", string, '\0', true ) );
+        // Generic rule for whitespaces
+        rules.add( new WhitespaceRule( new IWhitespaceDetector()
+        {
+            /**
+             * Indicates if the given character is a whitespace
+             * @param c the character to analyse
+             * @return <code>true</code> if the character is to be considered as a whitespace,  <code>false</code> if not.
+             * @see org.eclipse.jface.text.rules.IWhitespaceDetector#isWhitespace(char)
+             */
+            public boolean isWhitespace( char c )
+            {
+                return Character.isWhitespace( c );
+            }
+        } ) );
+
+        // If the word isn't in the List, returns undefined
+        WordRule wr = new WordRule( new AciWordDetector(), undefined );
+
+        // Adding Keywords
+        for ( int i = 0; i < aciKeywords.length; ++i )
+        {
+            wr.addWord( aciKeywords[i], keyword );
+        }
+
+        // Adding GrantValues
+        for ( int i = 0; i < aciGrantValues.length; ++i )
+        {
+            wr.addWord( aciGrantValues[i], grantValue );
+        }
+
+        // Adding DenyValues
+        for ( int i = 0; i < aciDenyValues.length; ++i )
+        {
+            wr.addWord( aciDenyValues[i], denyValue );
+        }
+
+        // Adding itemOrUserFirstSectionPartition
+        for ( int i = 0; i < itemOrUserFirstSectionPartition.length; ++i )
+        {
+            wr.addWord( itemOrUserFirstSectionPartition[i], itemOrUserFirst );
+        }
+
+        // Adding User
+        for ( int i = 0; i < userSection.length; ++i )
+        {
+            wr.addWord( userSection[i], user );
+        }
+
+        wr.addWord( identificationTagPartition, identification );
+
+        wr.addWord( precedencePartition, precedence );
+
+        wr.addWord( authenticationLevelPartition, authenticationLevel );
+
+        rules.add( wr );
+
+        // Conversion de la List en tableau pour la passer à la méthode setRules
+        IRule[] param = new IRule[rules.size()];
+        rules.toArray( param );
+        setRules( param );
+    }
+
+    /**
+     * This class implements a word detector for ACI Items
+     *
+     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+     * @version $Rev$, $Date$
+     */
+    static class AciWordDetector implements IWordDetector
+    {
+        /* (non-Javadoc)
+         * @see org.eclipse.jface.text.rules.IWordDetector#isWordPart(char)
+         */
+        public boolean isWordPart( char c )
+        {
+            return ( Character.isLetterOrDigit( c ) || c == '_' || c == '$' || c == '#' || c == '@' || c == '~'
+                || c == '.' || c == '?' );
+        }
+
+
+        /* (non-Javadoc)
+         * @see org.eclipse.jface.text.rules.IWordDetector#isWordStart(char)
+         */
+        public boolean isWordStart( char c )
+        {
+            return ( Character.isLetter( c ) || c == '.' || c == '_' || c == '?' || c == '$' );
+        }
+    }
+}

Modified: directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACIItemSourceEditorComposite.java
URL: http://svn.apache.org/viewvc/directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACIItemSourceEditorComposite.java?view=diff&rev=492512&r1=492511&r2=492512
==============================================================================
--- directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACIItemSourceEditorComposite.java (original)
+++ directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACIItemSourceEditorComposite.java Thu Jan  4 02:44:45 2007
@@ -74,7 +74,7 @@
 
         // setup basic configuration
         // TODO: configuration with syntax highlighting, content assistent, ...
-        SourceViewerConfiguration configuration = new SourceViewerConfiguration();
+        SourceViewerConfiguration configuration = new ACISourceViewerConfiguration();
         sourceEditor.configure( configuration );
 
         // set text font
@@ -145,5 +145,4 @@
     {
         return sourceEditor.getDocument().get();
     }
-
 }

Added: directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACISourceViewerConfiguration.java
URL: http://svn.apache.org/viewvc/directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACISourceViewerConfiguration.java?view=auto&rev=492512
==============================================================================
--- directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACISourceViewerConfiguration.java (added)
+++ directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACISourceViewerConfiguration.java Thu Jan  4 02:44:45 2007
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldapstudio.aciitemeditor.widgets;
+
+import org.apache.directory.ldapstudio.aciitemeditor.Activator;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.presentation.IPresentationReconciler;
+import org.eclipse.jface.text.presentation.PresentationReconciler;
+import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewerConfiguration;
+
+
+/**
+ * This class enables the features of the editor (Syntax coloring, code completion, etc.)
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class ACISourceViewerConfiguration extends SourceViewerConfiguration
+{
+    /* (non-Javadoc)
+     * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getPresentationReconciler(org.eclipse.jface.text.source.ISourceViewer)
+     */
+    public IPresentationReconciler getPresentationReconciler( ISourceViewer sourceViewer )
+    {
+        PresentationReconciler reconciler = new PresentationReconciler();
+        reconciler.setDocumentPartitioning( getConfiguredDocumentPartitioning( sourceViewer ) );
+
+        // Creating the damager/repairer for code
+        DefaultDamagerRepairer dr = new DefaultDamagerRepairer( Activator.getDefault().getAciCodeScanner() );
+        reconciler.setDamager( dr, IDocument.DEFAULT_CONTENT_TYPE );
+        reconciler.setRepairer( dr, IDocument.DEFAULT_CONTENT_TYPE );
+
+        return reconciler;
+    }
+}

Added: directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACITextAttributeProvider.java
URL: http://svn.apache.org/viewvc/directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACITextAttributeProvider.java?view=auto&rev=492512
==============================================================================
--- directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACITextAttributeProvider.java (added)
+++ directory/sandbox/seelmann/trunk/ldapstudio-aciitemeditor/src/main/java/org/apache/directory/ldapstudio/aciitemeditor/widgets/ACITextAttributeProvider.java Thu Jan  4 02:44:45 2007
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldapstudio.aciitemeditor.widgets;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jface.text.TextAttribute;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+
+
+/**
+ * This class provides the TextAttributes elements for each kind of attribute
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class ACITextAttributeProvider
+{
+    public static final String DEFAULT_ATTRIBUTE = "__pos_aci_default_attribute";
+    public static final String KEYWORD_ATTRIBUTE = "__pos_aci_keyword_attribute";
+    public static final String STRING_ATTRIBUTE = "__pos_aci_string_attribute";
+    public static final String GRANT_DENY_ATTRIBUTE = "__pos_aci_grant_deny_attribute";
+    public static final String IDENTIFICATION_ATTRIBUTE = "__pos_aci_identification_attribute";
+    public static final String PRECEDENCE_ATTRIBUTE = "__pos_aci_precedence_attribute";
+    public static final String AUTHENTICATIONLEVEL_ATTRIBUTE = "__pos_aci_authenticationlevel_attribute";
+    public static final String ITEMORUSERFIRST_ATTRIBUTE = "__pos_aci_itemoruserfirst_attribute";
+    public static final String USER_ATTRIBUTE = "__pos_aci_user_attribute";
+
+    public static final String GRANT_VALUE = "__pos_aci_grant_value";
+    public static final String DENY_VALUE = "__pos_aci_deny_value";
+
+    private Map<String, TextAttribute> attributes = new HashMap<String, TextAttribute>();
+
+
+    /**
+     * Creates a new instance of AciTextAttributeProvider.
+     */
+    public ACITextAttributeProvider()
+    {
+        attributes.put( DEFAULT_ATTRIBUTE, new TextAttribute( new Color( Display.getCurrent(), new RGB( 0, 0, 0 ) ) ) );
+
+        attributes.put( KEYWORD_ATTRIBUTE, new TextAttribute( new Color( Display.getCurrent(), new RGB( 127, 0, 85 ) ),
+            null, SWT.BOLD ) );
+
+        attributes.put( STRING_ATTRIBUTE, new TextAttribute( new Color( Display.getCurrent(), new RGB( 0, 0, 255 ) ) ) );
+
+        attributes.put( GRANT_DENY_ATTRIBUTE, new TextAttribute( new Color( Display.getCurrent(), new RGB( 125, 125,
+            125 ) ) ) );
+
+        attributes.put( GRANT_VALUE, new TextAttribute( new Color( Display.getCurrent(), new RGB( 0, 150, 0 ) ) ) );
+        attributes.put( DENY_VALUE, new TextAttribute( new Color( Display.getCurrent(), new RGB( 150, 0, 0 ) ) ) );
+
+        attributes.put( IDENTIFICATION_ATTRIBUTE, new TextAttribute( new Color( Display.getCurrent(), new RGB( 125, 0,
+            0 ) ), null, SWT.BOLD ) );
+
+        attributes.put( PRECEDENCE_ATTRIBUTE, new TextAttribute(
+            new Color( Display.getCurrent(), new RGB( 0, 0, 125 ) ), null, SWT.BOLD ) );
+
+        attributes.put( AUTHENTICATIONLEVEL_ATTRIBUTE, new TextAttribute( new Color( Display.getCurrent(), new RGB( 0,
+            125, 0 ) ), null, SWT.BOLD ) );
+
+        attributes.put( ITEMORUSERFIRST_ATTRIBUTE, new TextAttribute( new Color( Display.getCurrent(), new RGB( 125, 0,
+            125 ) ), null, SWT.BOLD ) );
+
+        attributes.put( USER_ATTRIBUTE, new TextAttribute( new Color( Display.getCurrent(), new RGB( 0, 122, 255 ) ),
+            null, SWT.BOLD ) );
+
+    }
+
+
+    /**
+     * Gets the correct TextAttribute for the given type
+     *
+     * @param type
+     *      the type of element
+     * @return
+     *      the correct TextAttribute for the given type
+     */
+    public TextAttribute getAttribute( String type )
+    {
+        TextAttribute attr = ( TextAttribute ) attributes.get( type );
+        if ( attr == null )
+        {
+            attr = ( TextAttribute ) attributes.get( DEFAULT_ATTRIBUTE );
+        }
+        return attr;
+    }
+}