Example usage for com.google.gwt.user.rebind SourceWriter commit

List of usage examples for com.google.gwt.user.rebind SourceWriter commit

Introduction

In this page you can find the example usage for com.google.gwt.user.rebind SourceWriter commit.

Prototype

void commit(TreeLogger logger);

Source Link

Usage

From source file:com.cgxlib.xq.rebind.SelectorGeneratorBase.java

License:Apache License

public String generate(TreeLogger treeLogger, GeneratorContext generatorContext, String requestedClass)
        throws UnableToCompleteException {
    this.treeLogger = treeLogger;
    TypeOracle oracle = generatorContext.getTypeOracle();
    nodeType = oracle.findType("com.google.gwt.dom.client.Node");

    JClassType selectorType = oracle.findType(requestedClass);

    String generatedPkgName = selectorType.getPackage().getName();
    String generatedClassName = selectorType.getName().replace('.', '_') + "_" + getImplSuffix();

    SourceWriter sw = getSourceWriter(treeLogger, generatorContext, generatedPkgName, generatedClassName,
            requestedClass);/*from  w  ww.j  a v  a  2s  .  c o  m*/
    if (sw != null) {
        for (JMethod method : selectorType.getInheritableMethods()) {
            generateMethod(sw, method, treeLogger);
        }
        genGetAllMethod(sw, selectorType.getInheritableMethods(), treeLogger);
        sw.commit(treeLogger);
    }

    return generatedPkgName + "." + generatedClassName;
}

From source file:com.cgxlib.xq.rebind.XmlBuilderGenerator.java

License:Apache License

public String generate(TreeLogger treeLogger, GeneratorContext generatorContext, String requestedClass)
        throws UnableToCompleteException {
    oracle = generatorContext.getTypeOracle();
    JClassType clazz = oracle.findType(requestedClass);
    xmlBuilderType = oracle.findType(XmlBuilder.class.getName());
    stringType = oracle.findType(String.class.getName());

    String t[] = generateClassName(clazz);

    SourceWriter sw = getSourceWriter(treeLogger, generatorContext, t[0], t[1], requestedClass);
    if (sw != null) {
        for (JMethod method : clazz.getInheritableMethods()) {
            // skip method from JsonBuilder
            if (xmlBuilderType.findMethod(method.getName(), method.getParameterTypes()) != null) {
                continue;
            }//  ww w. jav  a  2 s .c  o  m
            generateMethod(sw, method, treeLogger);
        }
        sw.commit(treeLogger);
    }
    return t[2];
}

From source file:com.chrome.gwt.linker.ComponentGenerator.java

License:Apache License

private static String emitBrowserActionCode(TreeLogger logger, GeneratorContext context, JClassType userType,
        String name, List<String> icons, List<String> iconPaths) {
    final String subclassName = userType.getSimpleSourceName().replace('.', '_') + "_generated";
    final String packageName = userType.getPackage().getName();
    final ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(packageName, subclassName);
    f.setSuperclass(userType.getQualifiedSourceName());
    final PrintWriter pw = context.tryCreate(logger, packageName, subclassName);
    if (pw != null) {
        final SourceWriter sw = f.createSourceWriter(context, pw);

        // Impl for the getter for name.
        sw.println("public String getName() {");
        // TODO(jaimeyap): Use proper string escaping from generator libs.
        sw.println("  return \"" + name + "\";");
        sw.println("}");

        emitIcons(icons, iconPaths, sw);

        sw.commit(logger);
    }//from w  w w .  j  a va  2s .com
    return f.getCreatedClassName();
}

From source file:com.chrome.gwt.linker.ComponentGenerator.java

License:Apache License

private static String emitComponentPageCode(TreeLogger logger, GeneratorContext context, JClassType userType) {
    final String subclassName = userType.getSimpleSourceName().replace('.', '_') + "_generated";
    final String packageName = userType.getPackage().getName();
    final ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(packageName, subclassName);
    f.setSuperclass(userType.getQualifiedSourceName());
    final PrintWriter pw = context.tryCreate(logger, packageName, subclassName);
    if (pw != null) {
        final SourceWriter sw = f.createSourceWriter(context, pw);

        // Write a default constructor that simply calls connect.
        sw.println("public " + subclassName + "() {");
        sw.println("  connect(\"" + userType.getSimpleSourceName() + "\");");
        sw.println("}");

        sw.commit(logger);
    }//from   w  ww.j av  a  2  s.co  m
    return f.getCreatedClassName();
}

From source file:com.chrome.gwt.linker.ComponentGenerator.java

License:Apache License

private static String emitPageActionCode(TreeLogger logger, GeneratorContext context, JClassType userType,
        String pageActionId, String name, List<String> icons, List<String> iconPaths) {
    final String subclassName = userType.getSimpleSourceName().replace('.', '_') + "_generated";
    final String packageName = userType.getPackage().getName();
    final ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(packageName, subclassName);
    f.setSuperclass(userType.getQualifiedSourceName());
    final PrintWriter pw = context.tryCreate(logger, packageName, subclassName);
    if (pw != null) {
        final SourceWriter sw = f.createSourceWriter(context, pw);

        // Impls for the getters for id and name.
        sw.println("public String getId() {");
        sw.println("  return \"" + pageActionId + "\";");
        sw.println("}");
        sw.println("public String getName() {");
        sw.println("  return \"" + name + "\";");
        sw.println("}");

        emitIcons(icons, iconPaths, sw);

        sw.commit(logger);
    }/*from   w  w  w.j  av a  2  s . c om*/
    return f.getCreatedClassName();
}

From source file:com.chrome.gwt.linker.ExtensionGenerator.java

License:Apache License

private static String generateExtensionType(TreeLogger logger, GeneratorContext context, JClassType userType,
        ExtensionArtifact spec) {/*from  w w  w  . j  a  v a2  s.  c o m*/
    final String subclassName = userType.getSimpleSourceName().replace('.', '_') + "_generated";
    final String packageName = userType.getPackage().getName();
    final ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(packageName, subclassName);
    f.setSuperclass(userType.getQualifiedSourceName());
    final PrintWriter pw = context.tryCreate(logger, packageName, subclassName);
    if (pw != null) {
        final SourceWriter sw = f.createSourceWriter(context, pw);

        final String version = (spec.getVersion() != null) ? spec.getVersion() : "";
        sw.println("@Override public String getVersion() {");
        sw.println("  return \"" + GeneratorUtils.toJavaLiteral(version) + "\";");
        sw.println("}");

        sw.commit(logger);
    }
    return f.getCreatedClassName();
}

From source file:com.colinalworth.celltable.columns.rebind.ColumnsGenerator.java

License:Apache License

@Override
public String generate(TreeLogger logger, GeneratorContext context, String typeName)
        throws UnableToCompleteException {
    //this.logger = logger;
    this.context = context;

    TypeOracle oracle = context.getTypeOracle();
    JClassType toGenerate = oracle.findType(typeName).isInterface();
    if (toGenerate == null) {
        logger.log(TreeLogger.ERROR, typeName + " is not an interface type");
        throw new UnableToCompleteException();
    }// w w  w .  ja va  2 s.  co m

    String packageName = toGenerate.getPackage().getName();
    String simpleSourceName = toGenerate.getName().replace('.', '_') + "_Impl";
    PrintWriter pw = context.tryCreate(logger, packageName, simpleSourceName);
    if (pw == null) {
        return packageName + "." + simpleSourceName;
    }

    ColumnSetModel columnSet = new ColumnSetModel(toGenerate, context, logger, names);

    //public class X implements X {
    ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(packageName, simpleSourceName);
    factory.addImplementedInterface(typeName);

    factory.addImport(Name.getSourceNameForClass(GWT.class));
    factory.addImport(Name.getSourceNameForClass(CellTable.class));
    factory.addImport(Name.getSourceNameForClass(HasDataFlushableEditor.class));
    factory.addImport(Name.getSourceNameForClass(Column.class));
    factory.addImport(Name.getSourceNameForClass(HasHorizontalAlignment.class));
    factory.addImport(Name.getSourceNameForClass(HasVerticalAlignment.class));
    factory.addImport(Name.getSourceNameForClass(FieldUpdater.class));
    factory.addImport(columnSet.getBeanName());

    SourceWriter sw = factory.createSourceWriter(context, pw);

    //wire up the factory, if any
    if (columnSet.hasFactory()) {
        names.add("factory");
        sw.println("private %1$s factory;", columnSet.getFactoryClassName());
        sw.println("public void setFactory(%1$s factory) {", columnSet.getFactoryClassName());
        sw.indent();
        sw.println(
                "assert factory != null && this.factory == null : \"Factory cannot be reset, and factory cannot be set as null\";");
        sw.println("this.factory = factory;");
        sw.outdent();
        sw.println("}");
    }

    // generate column methods
    for (ColumnModel c : columnSet.getColumnModels()) {
        // make the field 
        // TODO: no sense in building multiple copies, right?
        sw.println("private %1$s %2$s;", c.getCellClassName(), c.getCellFieldName());

        sw.println("private Column<%1$s,%2$s> %3$s;", columnSet.getBeanName(), c.getCellDataTypeName(),
                c.getColumnFieldName());
        sw.println();

        // make the method: public MyCell myDataMember() {
        //sw.println("@Override");//jdk 5 doesnt like this
        sw.println("public %1$s %2$s() {", c.getCellClassName(), c.getMethodName());
        sw.indent();
        sw.println("if (%s == null) {", c.getCellFieldName());
        sw.indent();

        //create the cell
        sw.println("%1$s = %2$s;", c.getCellFieldName(), c.getCellCreateExpression());

        //create the column - probably should be done later in the case of using HasDataFlushableEditor
        sw.println("%1$s = new Column<%2$s,%3$s> (%4$s) {", c.getColumnFieldName(), columnSet.getBeanName(),
                c.getCellDataTypeName(), c.getCellFieldName());
        sw.indent();

        sw.println("@Override");
        sw.println("public %1$s getValue(%2$s bean) {", c.getCellDataTypeName(), columnSet.getBeanName());
        sw.indent();
        sw.println("return %1$s;", c.getGetterInModel("bean"));
        sw.outdent();
        sw.println("}");

        sw.outdent();// end anon Column class
        sw.println("};");

        // Refactor at least this part out, in anticipation of a proper link to the Editor framework
        // TODO this is done by replacement right now, fix that.
        if (c.isEditable()) {
            if (!c.hasCustomFieldUpdater()) {
                sw.println("%1$s.setFieldUpdater(new FieldUpdater<%2$s,%3$s>() {", c.getColumnFieldName(),
                        columnSet.getBeanName(), c.getCellDataTypeName());
                sw.indent();

                sw.println("public void update(int index, %1$s object, %2$s value) {", columnSet.getBeanName(),
                        c.getCellDataTypeName());
                sw.indent();
                sw.println("%1$s;", c.getSetterInModel("object", "value"));
                sw.outdent();
                sw.println("}");

                sw.outdent();// end anon FieldUpdater class
                sw.println("});");
            } else {
                sw.println("%1$s.setFieldUpdater(GWT.<%2$s>create(%2$s.class));", c.getColumnFieldName(),
                        c.getFieldUpdaterType().getQualifiedSourceName());
            }
        }
        sw.println("%1$s.setHorizontalAlignment(%2$s);", c.getColumnFieldName(), c.getHorizontalAlignment());
        sw.println("%1$s.setVerticalAlignment(%2$s);", c.getColumnFieldName(), c.getVerticalAlignment());

        if (supportsSortable()) {
            sw.println("%1$s.setSortable(%2$s);", c.getColumnFieldName(), c.isSortable());
        } else {
            if (c.isSortable()) {
                logger.log(Type.WARN,
                        "Your version of GWT does not appear to support Column.setSortable, compilation may fail.");
            }
        }
        //end column creation/setup

        sw.outdent();
        sw.println("}");// end column/cell creation
        sw.println("return %s;", c.getCellFieldName());
        sw.outdent();
        sw.println("}");
    }

    // generate configure methods

    // simple overload
    sw.println("public final void configure(CellTable<%1$s> table) {", columnSet.getBeanName());
    sw.indent();
    sw.println("configure(table, null);");
    sw.outdent();
    sw.println("}");

    // actual heavy-lifting one
    sw.println("public final void configure(CellTable<%1$s> table, HasDataFlushableEditor<%1$s> ed) {",
            columnSet.getBeanName());
    sw.indent();
    if (columnSet.hasFactory()) {
        sw.println(
                "assert factory != null : \"setFactory() must be called before configure() can be called.\";");
    }
    for (ColumnModel c : columnSet.getColumnModels()) {
        //wire up the cell and column
        sw.println("%1$s();", c.getMethodName());

        if (c.isEditable() && !c.hasCustomFieldUpdater()) {
            // if there is an editor, replace the FieldUpdater
            sw.println("if (ed != null) {");
            sw.indent();
            sw.println("final FieldUpdater<%1$s, %2$s> wrapped = %3$s.getFieldUpdater();",
                    columnSet.getBeanName(), c.getCellDataTypeName(), c.getColumnFieldName());
            sw.println("%1$s.setFieldUpdater(ed.new PendingFieldUpdateChange<%2$s>(){", c.getColumnFieldName(),
                    c.getCellDataTypeName());
            sw.indent();
            sw.println("public void commit(int index, %1$s object, %2$s value) {", columnSet.getBeanName(),
                    c.getCellDataTypeName());
            sw.indent();
            sw.println("wrapped.update(index, object, value);");
            sw.outdent();
            sw.println("}");
            sw.outdent();
            sw.println("});");
            sw.outdent();
            sw.println("}");
        }

        // attach the column
        sw.println("table.addColumn(%1$s, %2$s);", c.getColumnFieldName(), c.getHeaderValue());
    }
    sw.outdent();
    sw.println("}");

    sw.println("public String[] getPaths() {");
    sw.indent();
    sw.println("return %1$s;", columnSet.getPaths());
    sw.outdent();
    sw.println("}");

    sw.commit(logger);

    return factory.getCreatedClassName();
}

From source file:com.colinalworth.gwt.websockets.rebind.ServerBuilderGenerator.java

License:Apache License

@Override
public String generate(TreeLogger logger, GeneratorContext context, String typeName)
        throws UnableToCompleteException {
    TypeOracle oracle = context.getTypeOracle();
    JClassType toGenerate = oracle.findType(typeName).isInterface();

    if (toGenerate == null) {
        logger.log(Type.ERROR, "Error generating " + typeName
                + ", either not an interface, or cannot be reached from client code.");
        throw new UnableToCompleteException();
    }// w w  w  . j  a va 2 s .  co  m
    JClassType serverBuilderType = oracle.findType(ServerBuilder.class.getName());
    JClassType serverImplType = ModelUtils.findParameterizationOf(serverBuilderType, toGenerate)[0];

    // Build an impl so we can call it ourselves
    ServerCreator creator = new ServerCreator(serverImplType);
    creator.create(logger, context);

    String packageName = toGenerate.getPackage().getName();
    String simpleName = toGenerate.getName().replace('.', '_') + "_Impl";

    PrintWriter pw = context.tryCreate(logger, packageName, simpleName);
    if (pw == null) {
        return packageName + "." + simpleName;
    }

    ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(packageName, simpleName);
    factory.setSuperclass(Name.getSourceNameForClass(ServerBuilderImpl.class) + "<"
            + serverImplType.getQualifiedSourceName() + ">");
    factory.addImplementedInterface(typeName);

    SourceWriter sw = factory.createSourceWriter(context, pw);

    RemoteServiceRelativePath path = serverImplType.getAnnotation(RemoteServiceRelativePath.class);
    if (path != null) {
        sw.println("public %1$s() {", simpleName);
        sw.indentln("setPath(\"%1$s\");", path.value());
        sw.println("}");
    }

    sw.println();
    // start method
    sw.println("public %1$s start() {", serverImplType.getQualifiedSourceName());
    sw.indent();
    sw.println("String url = getUrl();");
    sw.println("if (url == null) {");
    sw.indentln("return new %1$s(getErrorHandler());", creator.getQualifiedSourceName());
    sw.println("} else {");
    sw.indentln("return new %1$s(getErrorHandler(), url);", creator.getQualifiedSourceName());
    sw.println("}");

    sw.outdent();
    sw.println("}");

    sw.commit(logger);

    return factory.getCreatedClassName();

}

From source file:com.colinalworth.gwt.websockets.rebind.ServerCreator.java

License:Apache License

public void create(TreeLogger logger, GeneratorContext context) throws UnableToCompleteException {
    String typeName = this.serverType.getQualifiedSourceName();

    String packageName = getPackageName();
    String simpleName = getSimpleName();

    TypeOracle oracle = context.getTypeOracle();

    PrintWriter pw = context.tryCreate(logger, packageName, simpleName);
    if (pw == null) {
        return;//from   w w w. ja va 2s  . com
    }
    JClassType serverType = oracle.findType(Name.getSourceNameForClass(Server.class));
    JClassType clientType = ModelUtils.findParameterizationOf(serverType, this.serverType)[1];

    ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(packageName, simpleName);
    factory.setSuperclass(Name.getSourceNameForClass(ServerImpl.class) + "<" + typeName + ","
            + clientType.getQualifiedSourceName() + ">");
    factory.addImplementedInterface(typeName);

    SourceWriter sw = factory.createSourceWriter(context, pw);

    //TODO move this check before the printwriter creation can fail, and allow the warn to be optional
    sw.println("public %1$s(%2$s errorHandler) {", simpleName,
            Name.getSourceNameForClass(ServerBuilder.ConnectionErrorHandler.class));
    RemoteServiceRelativePath path = this.serverType.getAnnotation(RemoteServiceRelativePath.class);
    if (path == null) {
        //         logger.log(Type.WARN, "@RemoteServiceRelativePath required on " + typeName + " to make a connection to the server without a ServerBuilder");
        //         throw new UnableToCompleteException();
        sw.indentln("super(null);");
        sw.indentln(
                "throw new RuntimeException(\"@RemoteServiceRelativePath annotation required on %1$s to make a connection without a path defined in ServerBuilder\");");
    } else {
        sw.indentln("super(errorHandler, "
                + "com.google.gwt.user.client.Window.Location.getProtocol().toLowerCase().startsWith(\"https\") ? \"wss://\": \"ws://\", "
                + "com.google.gwt.user.client.Window.Location.getHost(), \"%1$s\");", path.value());
    }
    sw.println("}");

    sw.println("public %1$s(%2$s errorHandler, String url) {", simpleName,
            Name.getSourceNameForClass(ServerBuilder.ConnectionErrorHandler.class));
    sw.indentln("super(errorHandler, url);");
    sw.println("}");

    //Find all types that may go over the wire
    // Collect the types the server will send to the client using the Client interface
    SerializableTypeOracleBuilder serverSerializerBuilder = new SerializableTypeOracleBuilder(logger, context);
    appendMethodParameters(logger, clientType, Client.class, serverSerializerBuilder);
    // Also add the wrapper object ClientInvocation
    serverSerializerBuilder.addRootType(logger, oracle.findType(ClientInvocation.class.getName()));
    serverSerializerBuilder.addRootType(logger, oracle.findType(ClientCallbackInvocation.class.getName()));

    // Collect the types the client will send to the server using the Server interface
    SerializableTypeOracleBuilder clientSerializerBuilder = new SerializableTypeOracleBuilder(logger, context);
    appendMethodParameters(logger, this.serverType, Server.class, clientSerializerBuilder);
    // Also add the ServerInvocation wrapper
    clientSerializerBuilder.addRootType(logger, oracle.findType(ServerInvocation.class.getName()));
    clientSerializerBuilder.addRootType(logger, oracle.findType(ServerCallbackInvocation.class.getName()));

    String tsName = simpleName + "_TypeSerializer";
    TypeSerializerCreator serializerCreator = new TypeSerializerCreator(logger,
            clientSerializerBuilder.build(logger), serverSerializerBuilder.build(logger), context,
            packageName + "." + tsName, tsName);
    serializerCreator.realize(logger);

    // Make the newly created Serializer available at runtime
    sw.println("protected %1$s __getSerializer() {", Serializer.class.getName());
    sw.indentln("return %2$s.<%1$s>create(%1$s.class);", tsName, GWT.class.getName());
    sw.println("}");

    // Build methods that call from the client to the server
    for (JMethod m : this.serverType.getInheritableMethods()) {
        if (isRemoteMethod(m, Server.class)) {
            printServerMethodBody(logger, context, sw, m);
        }
    }

    // Read incoming calls and dispatch them to the correct client method
    sw.println("protected void __invoke(String method, Object[] params) {");
    for (JMethod m : clientType.getInheritableMethods()) {
        if (isRemoteMethod(m, Client.class)) {
            JParameter[] params = m.getParameters();
            sw.println("if (method.equals(\"%1$s\") && params.length == %2$d) {", m.getName(), params.length);
            sw.indent();
            sw.println("getClient().%1$s(", m.getName());
            sw.indent();
            for (int i = 0; i < params.length; i++) {
                if (i != 0) {
                    sw.print(",");
                }
                sw.println("(%1$s)params[%2$d]", params[i].getType().getQualifiedSourceName(), i);
            }
            sw.outdent();
            sw.println(");");
            sw.outdent();
            sw.println("}");
        }
    }
    sw.println("}");

    sw.println("protected void __onError(Exception error) {");
    sw.println("}");

    sw.commit(logger);
}

From source file:com.colinalworth.xmlview.rebind.XmlValidatorGenerator.java

License:Apache License

@Override
public String generate(TreeLogger logger, GeneratorContext context, String typeName)
        throws UnableToCompleteException {
    // validate the interface, annotations
    TypeOracle oracle = context.getTypeOracle();
    JClassType toGenerate = oracle.findType(typeName).isInterface();
    if (toGenerate == null) {
        logger.log(Type.ERROR, typeName + " is not an interface type");
        throw new UnableToCompleteException();
    }//  w  ww .  j a v a2 s . c  om
    JClassType schema = oracle.findType(Name.getSourceNameForClass(Schema.class)).isInterface();
    if (!schema.isAssignableFrom(toGenerate)) {
        // this shouldn't be possible unless the generator is deliberately invoked
        logger.log(Type.ERROR, "Declared interface must be assignable from XmlValidator");
        throw new UnableToCompleteException();
    }

    SchemaURL urlAnnotation = toGenerate.getAnnotation(SchemaURL.class);
    SchemaPath pathAnnotation = toGenerate.getAnnotation(SchemaPath.class);
    // get a handle on the file that has the schema
    final Sources sources = new Sources();
    if (urlAnnotation != null) {
        for (String url : urlAnnotation.value()) {
            try {
                sources.urls.add(new URL(url));
            } catch (MalformedURLException e) {
                logger.log(Type.ERROR, "Problem with @SchemaURL(\"" + url + "\")", e);
                throw new UnableToCompleteException();
            }
        }
    }
    if (pathAnnotation != null) {
        for (String file : pathAnnotation.value()) {
            sources.files.add(new File(file));
        }
    }
    if (urlAnnotation == null && pathAnnotation == null) {
        assert urlAnnotation == null && pathAnnotation == null;
        logger.log(Type.ERROR, "A Path or URL must be defined");
        throw new UnableToCompleteException();
    }

    // make the impl class
    String packageName = toGenerate.getPackage().getName();
    String simpleSourceName = toGenerate.getName().replace('.', '_') + "_Impl";
    PrintWriter pw = context.tryCreate(logger, packageName, simpleSourceName);
    if (pw == null) {
        return packageName + "." + simpleSourceName;
    }

    //public class X implements X {
    ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(packageName, simpleSourceName);
    factory.setSuperclass(Name.getSourceNameForClass(AbstractSchemaImpl.class));
    factory.addImplementedInterface(typeName);

    //factory.addImport(Name.getSourceNameForClass(GWT.class));
    factory.addImport(Name.getSourceNameForClass(Node.class));
    factory.addImport(Name.getSourceNameForClass(Element.class));
    factory.addImport(Name.getSourceNameForClass(Attr.class));
    factory.addImport(Name.getSourceNameForClass(CharacterData.class));
    factory.addImport(Name.getSourceNameForClass(JsArray.class));

    SourceWriter sw = factory.createSourceWriter(context, pw);

    // generate the class
    ValidatorCreator c = new ValidatorCreator(simpleSourceName, sources, context, logger, sw);

    c.generateCtor();
    c.generateMethods();

    sw.commit(logger);
    return packageName + "." + simpleSourceName;
}