I get this error:
ChartUtilities.saveChartAsJPEG(new File(path), chart, 300, 300);
The method saveChartAsJPEG(java.io.File, org.jfree.chart.JFreeChart, int, int)
in the type ChartUtilities is not applicable for the arguments
(org.apache.tomcat.jni.File, org.jfree.chart.JFreeChart, int, int)
Here is my code:
package com.manish.location.util;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import org.apache.tomcat.jni.File;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
public class ReportUtilImpl implements ReportUtil {
#SuppressWarnings("deprecation")
#Override
public void generatePieChart(String path, List<Object[]> data) {
DefaultPieDataset dataset= new DefaultPieDataset();
for(Object[] object:data) {
dataset.setValue(object[0].toString(), new Double(object[1].toString()));
}
JFreeChart chart = ChartFactory.createPieChart3D("Location Type Report", dataset);
try {
ChartUtilities.saveChartAsJPEG(new File(path), chart, 300, 300);
}
catch(IOException e) {
e.printStackTrace();
}
}
}
I am getting above error. Please fix it; it's about report utility program. I am using jfreechart API.
Related
I need to change the page orientation of some parts of a HTML. I followed the accepted answer for this question but the resulting PDF document had neither header nor footer (actually, no style at all).
Here is my first attempt:
package my.awesome.app.html2pdf;
import static com.itextpdf.styledxmlparser.css.media.MediaType.PRINT;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.attach.ITagWorker;
import com.itextpdf.html2pdf.attach.ProcessorContext;
import com.itextpdf.html2pdf.attach.impl.DefaultTagWorkerFactory;
import com.itextpdf.html2pdf.attach.impl.tags.DivTagWorker;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.IPropertyContainer;
import com.itextpdf.layout.element.AreaBreak;
import com.itextpdf.layout.element.Div;
import com.itextpdf.layout.element.IBlockElement;
import com.itextpdf.layout.layout.LayoutContext;
import com.itextpdf.layout.layout.LayoutResult;
import com.itextpdf.layout.renderer.AreaBreakRenderer;
import com.itextpdf.styledxmlparser.css.media.MediaDeviceDescription;
import com.itextpdf.styledxmlparser.node.IElementNode;
#RestController
#RequestMapping("/html2pdf")
public class Html2PdfController {
#PostMapping(produces = MediaType.APPLICATION_PDF_VALUE)
public #ResponseBody byte[] convert(#RequestBody String html) throws IOException {
try (var baos = new ByteArrayOutputStream()) {
var mediaDeviceDescription = new MediaDeviceDescription(PRINT);
var converterProperties = new ConverterProperties();
converterProperties.setMediaDeviceDescription(mediaDeviceDescription);
var pdfDocument = new PdfDocument(new PdfWriter(baos));
converterProperties.setTagWorkerFactory(new CustomTagWorkerFactory(pdfDocument));
var document = new Document(pdfDocument);
var elements = HtmlConverter.convertToElements(html, converterProperties);
for (var element : elements) {
if (element instanceof IBlockElement) {
document.add((IBlockElement) element);
}
}
pdfDocument.close();
return baos.toByteArray();
}
}
private static class CustomTagWorkerFactory extends DefaultTagWorkerFactory {
PdfDocument pdfDocument;
public CustomTagWorkerFactory(PdfDocument pdfDocument) {
this.pdfDocument = pdfDocument;
}
#Override
public ITagWorker getCustomTagWorker(IElementNode tag, ProcessorContext context) {
if ("landscape".equalsIgnoreCase(tag.name())) {
return new LandscapeDivTagWorker(tag, context, pdfDocument);
}
return null;
}
}
private static class LandscapeDivTagWorker extends DivTagWorker {
private PdfDocument pdfDocument;
public LandscapeDivTagWorker(IElementNode tag, ProcessorContext context, PdfDocument pdfDocument) {
super(tag, context);
this.pdfDocument = pdfDocument;
}
#Override
public IPropertyContainer getElementResult() {
IPropertyContainer baseElementResult = super.getElementResult();
if (baseElementResult instanceof Div) {
var div = new Div();
var landscapeAreaBreak = new AreaBreak(new PageSize(PageSize.A4).rotate());
landscapeAreaBreak.setNextRenderer(
new DefaultPageSizeChangingAreaBreakRenderer(landscapeAreaBreak, pdfDocument));
div.add(landscapeAreaBreak);
div.add((IBlockElement) baseElementResult);
var portraitAreaBreak = new AreaBreak(new PageSize(PageSize.A4));
portraitAreaBreak.setNextRenderer(
new DefaultPageSizeChangingAreaBreakRenderer(portraitAreaBreak, pdfDocument));
div.add(portraitAreaBreak);
baseElementResult = div;
}
return baseElementResult;
}
}
private static class DefaultPageSizeChangingAreaBreakRenderer extends AreaBreakRenderer {
private PdfDocument pdfDocument;
private AreaBreak areaBreak;
public DefaultPageSizeChangingAreaBreakRenderer(AreaBreak areaBreak, PdfDocument pdfDocument) {
super(areaBreak);
this.pdfDocument = pdfDocument;
this.areaBreak = areaBreak;
}
#Override
public LayoutResult layout(LayoutContext layoutContext) {
pdfDocument.setDefaultPageSize(areaBreak.getPageSize());
return super.layout(layoutContext);
}
}
}
And here is my first result. There is an additional blank page at its end:
After some small changes in the main method:
#PostMapping(produces = MediaType.APPLICATION_PDF_VALUE)
public #ResponseBody byte[] convert(#RequestBody String html) throws IOException {
try (var baos = new ByteArrayOutputStream()) {
var mediaDeviceDescription = new MediaDeviceDescription(PRINT);
var converterProperties = new ConverterProperties();
converterProperties.setMediaDeviceDescription(mediaDeviceDescription);
var pdfDocument = new PdfDocument(new PdfWriter(baos));
converterProperties.setTagWorkerFactory(new CustomTagWorkerFactory(pdfDocument));
var document = HtmlConverter.convertToDocument(html, pdfDocument, converterProperties);
document.close();
pdfDocument.close();
return baos.toByteArray();
}
}
I've got this PDF with nice headers and footers, except for the rotated pages. Also, only the first in a series is in landscape mode:
Actually the landscape pages do have footers, but they are misaligned.
Is there a way to achieve this using iText7 HTML to PDF conversion?
I want to create a minecraft GUI that use a inventory. I have make all the GUI with the items inside. But when I try to interact with the GUI (like clicking on a item), it's make nothing. So I'm pretty sure that it's the InventoryClickEvent that don't work.
This is my code:
package can.evilestvirus.randomtp;
import java.util.Arrays;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.PluginManager;
public class CommandRtp implements CommandExecutor {
#Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;
Inventory inv = Bukkit.createInventory(null, 9, "Menu de tp aléatoire");
ItemStack goldBlock = new ItemStack(Material.GOLD_BLOCK, 1);
ItemMeta goldBlockM = goldBlock.getItemMeta();
goldBlockM.setDisplayName("§8[§a+§8] §aRandomTP Normal §8[§a+§8]");
goldBlockM.setLore(Arrays.asList("§b- §6Distance de TP: 2500 Blocks", "§b- §6Prix: $0", "§b- §6Cooldown de 60 secondes", "§a§lCliquez ici pour utiliser"));
goldBlockM.addEnchant(Enchantment.DURABILITY, 10, true);
goldBlockM.addItemFlags(ItemFlag.HIDE_ENCHANTS);
goldBlock.setItemMeta(goldBlockM);
inv.setItem(3, goldBlock);
ItemStack diamondBlock = new ItemStack(Material.DIAMOND_BLOCK, 1);
ItemMeta diamondBlockM = diamondBlock.getItemMeta();
diamondBlockM.setDisplayName("§8[§a+§8] §aRandomTP §6§lVIP §8[§a+§8]");
diamondBlockM.setLore(Arrays.asList("§b- §6Distance de TP: 5000 Blocks", "§b- §6Prix: $1000", "§b- §6Cooldown de 5 minutes", "§a§lCliquez ici pour utiliser"));
diamondBlockM.addEnchant(Enchantment.DURABILITY, 10, true);
diamondBlockM.addItemFlags(ItemFlag.HIDE_ENCHANTS);
diamondBlock.setItemMeta(diamondBlockM);
inv.setItem(5, diamondBlock);
player.openInventory(inv);
}
return true;
}
#EventHandler
public void onClick(InventoryClickEvent event) {
Player player = (Player) event.getWhoClicked();
ItemStack current = event.getCurrentItem();
if(current == null) return;
if(event.getInventory().getTitle().equals("Menu de tp aléatoire")) {
event.setCancelled(true);
if(current.getType() == Material.GOLD_BLOCK) {
player.closeInventory();
player.chat("/rtpPlayer");
}
if(current.getType() == Material.DIAMOND_BLOCK) {
player.closeInventory();
player.setFlying(true);
}
}
}
}
The code of my main class is this:
package can.evilestvirus.randomtp;
import org.bukkit.Bukkit;
import org.bukkit.event.Listener;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import can.evilestvirus.randomtp.CommandRtpPlayer;
public class Main extends JavaPlugin {
#Override
public void onEnable() {
System.out.println("HELLO PEOPLE!");
this.getCommand("rtpplayer").setExecutor(new CommandRtpPlayer());
this.getCommand("rtp").setExecutor(new CommandRtp());
Bukkit.getPluginManager().registerEvents((Listener) this, Bukkit.getPluginManager().getPlugins()[0]);
Bukkit.getPluginManager().registerEvents((Listener) new CommandRtp(), this);
}
}
You need to implement Listener in your CommandRtp class. Once you do this it should work.
So your class will look like this:
public class CommandRtp implements Listener, CommandExecutor {
// Code
}
Okay, so I have found my error. I have create I new class and I register correctly the new class. After I change the IF that check if my menu is the same than the command menu because the function that I use was not fonctional.
So this is my new code for those that have the same problem that me:
package can.evilestvirus.randomtp;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
public class MenuHandler implements Listener {
#EventHandler
public void onMenuClick(InventoryClickEvent e){
Player player = (Player) e.getWhoClicked();
if(e.getView().getTitle().equalsIgnoreCase("Menu de tp aleatoire")){
e.setCancelled(true);
if (e.getCurrentItem().getType() == Material.GOLD_BLOCK) {
player.closeInventory();
player.chat("/rtpPlayer");
}
if (e.getCurrentItem().getType() == Material.DIAMOND_BLOCK) {
player.closeInventory();
player.setFlying(true);
}
}
}
}
This is the main class:
package can.evilestvirus.randomtp;
import org.bukkit.Bukkit;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
public class Main extends JavaPlugin{
#Override
public void onEnable() {
getCommand("rtpplayer").setExecutor(new CommandRtpPlayer());
getCommand("rtp").setExecutor(new CommandRtp());
Bukkit.getPluginManager().registerEvents(new MenuHandler(), this);
}
}
You can use this event:
#EventHandler
public void onInventoryClick(InventoryClickEvent event) {
}
For me it works
I'm new to htmlunit (2.23) and I can't get this test to work:
I'm getting this ClassCastException thrown out of HtmlUnit and I don't know if it is a bug, or if I am doing something wrong.
java.lang.ClassCastException: com.gargoylesoftware.htmlunit.TextPage cannot be cast to com.gargoylesoftware.htmlunit.html.HtmlPage
at com.gargoylesoftware.htmlunit.WebClient.makeWebResponseForJavaScriptUrl(WebClient.java:1241)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:375)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:304)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:451)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:436)
at org.wyttenbach.dale.mlec.OutageTest.test(OutageTest.java:46)
...
The code
import java.awt.Desktop;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.JavaScriptPage;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.TextPage;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
public class OutageTest {
private static final String SITE_URL = "https://ebill.mlecmn.net/woViewer/";
private static final String OUTAGE_MAP_URL = SITE_URL + "mapviewer.html?config=Outage+Web+Map";
#Test
public void test() throws FailingHttpStatusCodeException, MalformedURLException, IOException {
try (final WebClient webClient = new WebClient()) {
webClient.waitForBackgroundJavaScript(20000);
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
webClient.getOptions().setUseInsecureSSL(true);
Map<String, Page> urls = new HashMap<String, Page>();
LinkedList<String> urlsToVisit = new LinkedList<String>();
urlsToVisit.add(OUTAGE_MAP_URL);
while (!urlsToVisit.isEmpty()) {
String url = urlsToVisit.remove();
if (urls.containsKey(url)) {
continue;
}
Page page = webClient.getPage(url);
urls.put(url, page);
if (page instanceof HtmlPage) {
HtmlPage page2 = (HtmlPage) page;
System.err.println("================================================================");
System.err.println(page2.asXml());
System.err.println("================================================================");
Assert.assertFalse("Outage in Nordland township: " + url, page2.asText().contains("Nordland"));
urlsToVisit.addAll(extractLinks(page2));
} else if (page instanceof JavaScriptPage) {
JavaScriptPage page2 = (JavaScriptPage) page;
Assert.assertFalse("Outage in Nordland township: " + url, page2.getContent().contains("Nordland"));
} else if (page instanceof TextPage) {
TextPage page2 = (TextPage) page;
Assert.assertFalse("Outage in Nordland township: " + url, page2.getContent().contains("Nordland"));
} else {
System.err.println(String.format("%s => %s", url, page.getClass().getName()));
}
}
} catch (AssertionError e) {
reportOutage();
throw e;
}
}
private Collection<String> extractLinks(HtmlPage page) {
List<String> links = new ArrayList<String>();
for (DomElement x : page.getElementsByTagName("script")) {
String src = x.getAttribute("src");
if (!src.contains(":")) {
src = SITE_URL + src;
System.err.println("script src="+src);
}
links.add(src);
}
for (DomElement x : page.getElementsByTagName("link")) {
String href = x.getAttribute("href");
if (!href.contains(":")) {
href = SITE_URL + href;
System.err.println("link href="+href);
}
links.add(href);
}
// Causes ClassCastException com.gargoylesoftware.htmlunit.TextPage cannot be cast to com.gargoylesoftware.htmlunit.html.HtmlPage
//at com.gargoylesoftware.htmlunit.WebClient.makeWebResponseForJavaScriptUrl(WebClient.java:1241)
for (DomElement x : page.getElementsByTagName("iframe")) {
String src = x.getAttribute("src");
if (!src.contains(":")) {
src = SITE_URL + src;
System.err.println("iframe src="+src);
}
links.add(src);
}
return links;
}
private void reportOutage() {
try {
Desktop.getDesktop().browse(new URI(OUTAGE_MAP_URL));
} catch (Exception e) {
e.printStackTrace();
}
}
}
More or less yes - but i have to do a more deeper analysis.
But there is some hope for you ;-)
Your code tries to extract urls from a given web page. During the process you are adding the url 'javascript:""' to your list of urls to be processes. This url results in this class cast exception. If you do not add this url to the list, the test is working (at least for me).
Attempting to use AndroidPlot to create an XY scatter plot, encountering a problem... whereby the plot only draws points from left to right, a scrolling chart essentially.
Example... say I have the following co-ordinates, (0,1), (1,0), (0,-1), (-1,0) I would expect to see a diamond shape (if all the points were joined by a line)
I've used the AndroidPlot library successfully before so am somewhat familiar with the methods available.
Is there any examples for a scatter plot using the AndroidPlot library?
Hope I'm making sense here..
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import pl.flex_it.androidplot.XYSeries;
import com.androidplot.series.XYSeries;
import com.androidplot.xy.BoundaryMode;
import com.androidplot.xy.LineAndPointFormatter;
import com.androidplot.xy.SimpleXYSeries;
import com.androidplot.xy.XYPlot;
import android.app.Fragment;
import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Temp extends Fragment {
private static XYPlot xyPlot;
private XYSeriesShimmer series;
private LineAndPointFormatter series1Format;
private ArrayList<Number> ALdata1, ALdata2;
private int Adata1[], Adata2[];
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_test, container, false);
// Import plot from the layout
xyPlot = (XYPlot) rootView.findViewById(R.id.xyPlot);
xyPlot.setDomainBoundaries(-2, 2, BoundaryMode.FIXED); // freeze the domain boundary:
xyPlot.setRangeBoundaries(-2, 2, BoundaryMode.FIXED);
ALdata1 = new ArrayList<Number>();
ALdata2 = new ArrayList<Number>();
ALdata1.clear();
ALdata2.clear();
Adata1 = new int[]{0,1,0,-1};
Adata2 = new int[]{1,0,-1,0};
series = new XYSeriesShimmer(ALdata1, ALdata2, 0, "Sightings in USA");
series1Format = new LineAndPointFormatter(Color.TRANSPARENT, Color.BLACK, null); // line color, point color, fill color
xyPlot.addSeries(series, series1Format);
plotDataMethod();
return rootView;
}
private void plotDataMethod() {
for(int i=0; i<Adata1.length; i++){
ALdata1.add(Adata1[i]);
ALdata2.add(Adata2[i]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
series.updateData(ALdata1, ALdata2);
xyPlot.redraw();
}
}
}
EDIT:
package pl.flex_it.androidplot;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.androidplot.series.XYSeries;
public class XYSeriesShimmer implements XYSeries {
private List<Number> dataX;
private List<Number> dataY;
private int seriesIndex;
private String title;
public XYSeriesShimmer(List<Number> datasource, int seriesIndex, String title) {
this.dataY = datasource;
this.seriesIndex = seriesIndex;
this.title = title;
}
public XYSeriesShimmer(List<Number> datasourceX, List<Number> datasourceY, int seriesIndex, String title) {
this.dataX = datasourceX;
this.dataY = datasourceY;
this.seriesIndex = seriesIndex;
this.title = title;
}
#Override
public String getTitle() {
return title;
}
#Override
public int size() {
return dataY.size();
}
#Override
public Number getY(int index) {
return dataY.get(index);
}
#Override
public Number getX(int index) {
return index;
}
public void updateData(List<Number> datasourceX){ //dont need to use this cause, the reference is only stored, modifying the datasource externally will cause this to be updated as well
this.dataY=datasourceX;
}
public void updateData(List<Number> datasourceX, List<Number> datasourceY){ //dont need to use this cause, the reference is only stored, modifying the datasource externally will cause this to be updated as well
this.dataX=datasourceX;
this.dataY=datasourceY;
}
}
This looks like it could be the problem - in XYSeriesShimmer:
#Override
public Number getX(int index) {
return index;
}
This is always going to return i, which means each element's x value is 1 larger than the previous...exactly what you are experiencing. Try changing it to this:
#Override
public Number getX(int index) {
return dataX.get(i);
}
I am getting this error when creating a command for this youtube tutorial, he explains how to make a plugin where when you join fireworks explode and I wanted to make a command for it.
I got the error Syntax error on token "}", { expected. Here is my code:
package me.gecco123.EnterWithABang;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.FireworkEffect;
import org.bukkit.FireworkEffect.Type;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.plugin.java.JavaPlugin;
public class Main extends JavaPlugin implements Listener{
public void onDisable(){
getLogger().info("[EWAB] Disabled");
}
public void onEnable(){
getLogger().info("[EWAB] Enabled");
Bukkit.getServer().getPluginManager().registerEvents(this, this);
}
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
if (sender instanceof Player){
Player player = (Player) sender;
if (cmd.getName().equalsIgnoreCase("forcebang")){
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable(){
public void run(){
PlayerJoinEvent pje;
Firework f = (Firework) pje.getPlayer().getWorld().spawn(pje.getPlayer().getLocation(), Firework.class);
FireworkMeta fm = f.getFireworkMeta();
fm.addEffect(FireworkEffect.builder()
.flicker(false)
.trail(true)
.with(Type.BALL)
.with(Type.BALL_LARGE)
.with(Type.STAR)
.withColor(Color.YELLOW)
.withColor(Color.ORANGE)
.withFade(Color.RED)
.withFade(Color.PURPLE)
.build());
fm.setPower(2);
f.setFireworkMeta(fm);
}
}, 20);
}
}
}
#EventHandler
public void onPlayerJoin (final PlayerJoinEvent pje){
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable(){
public void run(){
Firework f = (Firework) pje.getPlayer().getWorld().spawn(pje.getPlayer().getLocation(), Firework.class);
FireworkMeta fm = f.getFireworkMeta();
fm.addEffect(FireworkEffect.builder()
.flicker(false)
.trail(true)
.with(Type.BALL)
.with(Type.BALL_LARGE)
.with(Type.STAR)
.withColor(Color.YELLOW)
.withColor(Color.ORANGE)
.withFade(Color.RED)
.withFade(Color.PURPLE)
.build());
fm.setPower(2);
f.setFireworkMeta(fm);
}
}, 20);
}
}
}
}
The error is on the 3rd last bracket
Remove the last two brackets. You have 11 opening and 13 closing brackets.