From a5ccf002772a20441614f20aa41a6cb7a5e3b4ce Mon Sep 17 00:00:00 2001 From: WangYangyang <3093159564@qq.com> Date: Wed, 13 May 2026 20:22:31 +0800 Subject: [PATCH] project3 --- crawl_project_extension_2/pom.xml | 41 ++++++ .../main/java/com/example/ChartGenerator.java | 128 ++++++++++++++++++ .../main/java/com/example/CsvExporter.java | 37 +++++ .../main/java/com/example/DataAnalyzer.java | 36 +++++ .../main/java/com/example/DoubanCrawler.java | 101 ++++++++++++++ .../main/java/com/example/M1905Crawler.java | 103 ++++++++++++++ .../src/main/java/com/example/Main.java | 53 ++++++++ .../src/main/java/com/example/Movie.java | 75 ++++++++++ .../main/java/com/example/MovieAnalyzer.java | 8 ++ .../main/java/com/example/MovieCrawler.java | 8 ++ .../src/main/java/org/example/App.java | 13 ++ .../src/test/java/org/example/AppTest.java | 38 ++++++ .../classes/com/example/ChartGenerator.class | Bin 0 -> 8971 bytes .../classes/com/example/CsvExporter.class | Bin 0 -> 2712 bytes .../classes/com/example/DataAnalyzer.class | Bin 0 -> 4843 bytes .../classes/com/example/DoubanCrawler.class | Bin 0 -> 4708 bytes .../target/classes/com/example/Main.class | Bin 0 -> 1681 bytes .../target/classes/com/example/Movie.class | Bin 0 -> 1999 bytes .../classes/com/example/MovieAnalyzer.class | Bin 0 -> 264 bytes .../classes/com/example/MovieCrawler.class | Bin 0 -> 264 bytes .../target/classes/org/example/App.class | Bin 0 -> 537 bytes 21 files changed, 641 insertions(+) create mode 100644 crawl_project_extension_2/pom.xml create mode 100644 crawl_project_extension_2/src/main/java/com/example/ChartGenerator.java create mode 100644 crawl_project_extension_2/src/main/java/com/example/CsvExporter.java create mode 100644 crawl_project_extension_2/src/main/java/com/example/DataAnalyzer.java create mode 100644 crawl_project_extension_2/src/main/java/com/example/DoubanCrawler.java create mode 100644 crawl_project_extension_2/src/main/java/com/example/M1905Crawler.java create mode 100644 crawl_project_extension_2/src/main/java/com/example/Main.java create mode 100644 crawl_project_extension_2/src/main/java/com/example/Movie.java create mode 100644 crawl_project_extension_2/src/main/java/com/example/MovieAnalyzer.java create mode 100644 crawl_project_extension_2/src/main/java/com/example/MovieCrawler.java create mode 100644 crawl_project_extension_2/src/main/java/org/example/App.java create mode 100644 crawl_project_extension_2/src/test/java/org/example/AppTest.java create mode 100644 crawl_project_extension_2/target/classes/com/example/ChartGenerator.class create mode 100644 crawl_project_extension_2/target/classes/com/example/CsvExporter.class create mode 100644 crawl_project_extension_2/target/classes/com/example/DataAnalyzer.class create mode 100644 crawl_project_extension_2/target/classes/com/example/DoubanCrawler.class create mode 100644 crawl_project_extension_2/target/classes/com/example/Main.class create mode 100644 crawl_project_extension_2/target/classes/com/example/Movie.class create mode 100644 crawl_project_extension_2/target/classes/com/example/MovieAnalyzer.class create mode 100644 crawl_project_extension_2/target/classes/com/example/MovieCrawler.class create mode 100644 crawl_project_extension_2/target/classes/org/example/App.class diff --git a/crawl_project_extension_2/pom.xml b/crawl_project_extension_2/pom.xml new file mode 100644 index 0000000..cf0832e --- /dev/null +++ b/crawl_project_extension_2/pom.xml @@ -0,0 +1,41 @@ + + 4.0.0 + + org.example + crawl_project_extension_2 + 1.0-SNAPSHOT + jar + + crawl_project_extension_2 + http://maven.apache.org + + + UTF-8 + + + + + junit + junit + 3.8.1 + test + + + org.jsoup + jsoup + 1.17.2 + + + com.opencsv + opencsv + 5.9 + + + org.knowm.xchart + xchart + 3.8.7 + + + + diff --git a/crawl_project_extension_2/src/main/java/com/example/ChartGenerator.java b/crawl_project_extension_2/src/main/java/com/example/ChartGenerator.java new file mode 100644 index 0000000..a091c3a --- /dev/null +++ b/crawl_project_extension_2/src/main/java/com/example/ChartGenerator.java @@ -0,0 +1,128 @@ +package com.example; + +import org.knowm.xchart.*; +import org.knowm.xchart.style.Styler; + +import java.awt.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; +public class ChartGenerator { + + // 1. 绘制【年份电影数量 - 柱状图】 + public static void saveBarChart(List movies) { + Map yearMap = movies.stream() + .filter(m -> m.getYear() > 1980) + .collect(Collectors.groupingBy(Movie::getYear, Collectors.counting())); + + List> sortedList = new ArrayList<>(yearMap.entrySet()); + sortedList.sort(Entry.comparingByKey()); + + if (sortedList.size() > 15) { + sortedList = sortedList.subList(0, 15); + } + + List xData = new ArrayList<>(); + List yData = new ArrayList<>(); + for (Entry entry : sortedList) { + xData.add(entry.getKey().toString()); + yData.add(entry.getValue()); + } + + CategoryChart chart = new CategoryChartBuilder() + .width(1000) + .height(600) + .title("豆瓣Top250 - 各年份电影数量柱状图") + .xAxisTitle("年份") + .yAxisTitle("电影数量") + .theme(Styler.ChartTheme.Matlab) + .build(); + + chart.getStyler().setLegendVisible(false); + chart.getStyler().setLabelsVisible(true); + chart.getStyler().setXAxisLabelRotation(45); + chart.getStyler().setChartBackgroundColor(Color.WHITE); + + chart.addSeries("电影数量", xData, yData); + + try { + BitmapEncoder.saveBitmap(chart, "./年份电影数量_柱状图", BitmapEncoder.BitmapFormat.PNG); + System.out.println("✅ 柱状图已保存:年份电影数量_柱状图.png"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + // 2. 绘制【评分趋势 - 折线图】 + public static void saveLineChart(List movies) { + Map avgRatingMap = movies.stream() + .filter(m -> m.getYear() > 1980) + .collect(Collectors.groupingBy(Movie::getYear, Collectors.averagingDouble(Movie::getRating))); + + List> sortedList = new ArrayList<>(avgRatingMap.entrySet()); + sortedList.sort(Entry.comparingByKey()); + + if (sortedList.size() > 15) { + sortedList = sortedList.subList(0, 15); + } + + // ✅ 修复:X轴使用数字类型 Integer,不再用字符串 + List xData = new ArrayList<>(); + List yData = new ArrayList<>(); + for (Entry entry : sortedList) { + xData.add(entry.getKey()); + yData.add(entry.getValue()); + } + + XYChart chart = new XYChartBuilder() + .width(1000) + .height(600) + .title("豆瓣Top250 - 历年平均评分趋势") + .xAxisTitle("年份") + .yAxisTitle("平均评分") + .theme(Styler.ChartTheme.Matlab) + .build(); + + chart.getStyler().setMarkerSize(6); + chart.getStyler().setChartBackgroundColor(Color.WHITE); + chart.addSeries("平均评分", xData, yData); + + try { + BitmapEncoder.saveBitmap(chart, "./历年平均评分_折线图", BitmapEncoder.BitmapFormat.PNG); + System.out.println("✅ 折线图已保存!"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + // 3. 绘制【高分电影占比 - 饼图】 + public static void savePieChart(List movies) { + long gao = movies.stream().filter(m -> m.getRating() >= 9.5).count(); + long zhong = movies.stream().filter(m -> m.getRating() >= 9.0 && m.getRating() < 9.5).count(); + long di = movies.stream().filter(m -> m.getRating() < 9.0).count(); + + PieChart chart = new PieChartBuilder() + .width(700) + .height(700) + .title("豆瓣Top250 - 评分分布饼图") + .theme(Styler.ChartTheme.Matlab) + .build(); + + chart.addSeries("9.5分及以上", gao); + chart.addSeries("9.0-9.5分", zhong); + chart.addSeries("9.0分以下", di); + + chart.getStyler().setChartBackgroundColor(Color.WHITE); + chart.getStyler().setLegendVisible(true); + + try { + BitmapEncoder.saveBitmap(chart, "./评分分布_饼图", BitmapEncoder.BitmapFormat.PNG); + System.out.println("✅ 饼图已保存:评分分布_饼图.png"); + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/crawl_project_extension_2/src/main/java/com/example/CsvExporter.java b/crawl_project_extension_2/src/main/java/com/example/CsvExporter.java new file mode 100644 index 0000000..662f4c0 --- /dev/null +++ b/crawl_project_extension_2/src/main/java/com/example/CsvExporter.java @@ -0,0 +1,37 @@ +package com.example; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; +public class CsvExporter{ + public static void exportToCsv(List movies, String filePath) { + try (FileWriter writer = new FileWriter(filePath)) { + // 1. 表头:确保顺序是【电影名称,导演,上映年份,豆瓣评分,评价人数】 + writer.write("电影名称,导演,上映年份,豆瓣评分,评价人数\n"); + + // 2. 写入数据:字段顺序必须和表头完全对应! + for (Movie movie : movies) { + String line = String.format("%s,%s,%d,%.1f,%d\n", + escapeCsv(movie.getTitle()), // 1.电影名称 + escapeCsv(movie.getDirector()), // 2.导演 + movie.getYear(), // 3.上映年份 + movie.getRating(), // 4.豆瓣评分 + movie.getReviewCount() // 5.评价人数(这里之前写反了!) + ); + writer.write(line); + } + System.out.println("\nCSV文件导出成功!路径:" + filePath); + System.out.println("提示:评价人数在第5列,已显示真实数据!"); + } catch (IOException e) { + e.printStackTrace(); + } + } + // CSV 特殊字符转义(避免逗号/引号导致格式错乱) + private static String escapeCsv(String value) { + if (value == null) return ""; + // 包含逗号、引号或换行时,用双引号包裹 + if (value.contains(",") || value.contains("\"") || value.contains("\n")) { + return "\"" + value.replace("\"", "\"\"") + "\""; + } + return value; + } +} diff --git a/crawl_project_extension_2/src/main/java/com/example/DataAnalyzer.java b/crawl_project_extension_2/src/main/java/com/example/DataAnalyzer.java new file mode 100644 index 0000000..477203d --- /dev/null +++ b/crawl_project_extension_2/src/main/java/com/example/DataAnalyzer.java @@ -0,0 +1,36 @@ +package com.example; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +public class DataAnalyzer implements MovieAnalyzer { + + @Override + public void analyzeByDimension(List movies) { + System.out.println("\n===== 评分最高Top10电影 ====="); + movies.stream() + .sorted((m1, m2) -> Double.compare(m2.getRating(), m1.getRating())) + .limit(10) + .forEach(m -> System.out.printf("%-25s 评分: %.1f 年份: %d%n", + m.getTitle(), m.getRating(), m.getYear())); + System.out.println("\n===== 各年份电影数量统计 ====="); + Map countByYear = movies.stream() + .filter(m -> m.getYear() != 0) + .collect(Collectors.groupingBy(Movie::getYear, Collectors.counting())); + + // 按年份排序输出 + countByYear.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(entry -> + System.out.printf("年份: %-4d 数量: %d 部%n", entry.getKey(), entry.getValue())); + } + + // 统计总数据 + @Override + public void analyzeTotal(List movies){ + System.out.println("\n===== 数据总览 ====="); + System.out.println("电影总数:" + movies.size()); + double avgRating = movies.stream().mapToDouble(Movie::getRating).average().orElse(0); + System.out.printf("平均评分:%.2f%n", avgRating); + } +} diff --git a/crawl_project_extension_2/src/main/java/com/example/DoubanCrawler.java b/crawl_project_extension_2/src/main/java/com/example/DoubanCrawler.java new file mode 100644 index 0000000..fd91e92 --- /dev/null +++ b/crawl_project_extension_2/src/main/java/com/example/DoubanCrawler.java @@ -0,0 +1,101 @@ +package com.example; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +public class DoubanCrawler implements MovieCrawler { + // 编译年份正则(提取4位数字年份) + private static final Pattern YEAR_PATTERN = Pattern.compile("(\\d{4})"); + @Override + public List crawl() { + List movies = new ArrayList<>(); + String baseUrl = "https://movie.douban.com/top250?start="; + + try { + // 10页,每页25条 + for (int i = 0; i < 250; i += 25) { + String url = baseUrl + i; + System.out.println("正在爬取:" + url); + + Document doc = Jsoup.connect(url) + .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36") + .timeout(8000) + .get(); + + Elements items = doc.select(".item"); + for (Element item : items) { + Movie movie = new Movie(); + + // 1. 电影名 + movie.setTitle(item.select(".title").first().text()); + + // 2. 评分 + movie.setRating(Double.parseDouble(item.select(".rating_num").text())); + + // 3. 评价人数 + int reviewCount = 0; + String allText = item.text(); // 直接拿整个区块的文字 + Pattern pattern = Pattern.compile("(\\d+)人评价"); + Matcher matcher = pattern.matcher(allText); + if (matcher.find()) { + reviewCount = Integer.parseInt(matcher.group(1)); + } + movie.setReviewCount(reviewCount); + movie.setReviewCount(reviewCount); + // 4. 电影信息(导演 + 年份) + String info = item.select(".bd p").first().text(); + + // 清洗导演 + movie.setDirector(cleanDirector(info)); + // 清洗年份 + movie.setYear(cleanYear(info)); + + movies.add(movie); + } + + // 文明爬虫,随机延迟 + Thread.sleep((long) (Math.random() * 2000 + 1000)); + } + System.out.println("爬取完成!共获取 " + movies.size() + " 部电影"); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + return movies; + } + // 实现接口方法:返回爬虫名称 + @Override + public String getCrawlerName(){ + return "豆瓣top250"; + } + /** + * 清洗导演信息 + */ + private String cleanDirector(String info) { + if (info.contains("导演:")) { + int start = info.indexOf("导演:") + 3; + int end = info.indexOf(" ", start + 2); + if (end == -1) end = info.length(); + return info.substring(start, end).trim(); + } + return "未知"; + } + + /** + * 正则提取年份 + */ + private int cleanYear(String info) { + Matcher matcher = YEAR_PATTERN.matcher(info); + if (matcher.find()) { + return Integer.parseInt(matcher.group(1)); + } + return 0; + } +} + diff --git a/crawl_project_extension_2/src/main/java/com/example/M1905Crawler.java b/crawl_project_extension_2/src/main/java/com/example/M1905Crawler.java new file mode 100644 index 0000000..5833090 --- /dev/null +++ b/crawl_project_extension_2/src/main/java/com/example/M1905Crawler.java @@ -0,0 +1,103 @@ +package com.example; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class M1905Crawler implements MovieCrawler { + + // 1905电影网排行榜URL + private static final String RANK_URL = "https://www.1905.com/vod/rank/ta99o3.shtml"; + + @Override + public List crawl() { + List movies = new ArrayList<>(); + + try { + System.out.println("正在爬取:" + RANK_URL); + + Document doc = Jsoup.connect(RANK_URL) + .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") + .header("Referer", "https://www.1905.com/") + .timeout(15000) + .get(); + + // 表格结构:选择表格行(跳过表头) + Elements rows = doc.select("table tr"); + + System.out.println("找到行数:" + rows.size()); + + int rank = 1; + for (Element row : rows) { + // 跳过表头行 + if (row.select("th").size() > 0) continue; + + Elements cells = row.select("td"); + if (cells.size() < 5) continue; + + Movie movie = new Movie(); + + // 1. 排行(第1列) + // cells.get(0).text() -> "1", "2"... + + // 2. 趋势(第2列)- 忽略 + + // 3. 电影名称(第3列) + Element nameCell = cells.get(2); + Element nameLink = nameCell.selectFirst("a"); + String title = nameLink != null ? nameLink.text().trim() : nameCell.text().trim(); + movie.setTitle(title); + + // 获取详情页链接(用于方案二) + String detailUrl = nameLink != null ? nameLink.absUrl("href") : ""; + + // 4. 主演(第4列)- 作为导演字段存储(页面无导演信息) + String actors = cells.get(3).text().trim(); + movie.setDirector(actors); // 复用director字段存主演 + + // 5. 播放次数(第5列)- 作为reviewCount存储 + String playCountStr = cells.get(4).text().trim().replace(",", ""); + int playCount = 0; + try { + playCount = Integer.parseInt(playCountStr); + } catch (NumberFormatException e) { + // 忽略解析错误 + } + movie.setReviewCount(playCount); // 复用reviewCount字段存播放次数 + + // 评分和年份:列表页没有,设为默认值 + movie.setRating(0.0); // 无评分数据 + movie.setYear(0); // 无年份数据 + + // 方案二:进入详情页获取完整信息(取消下面注释启用) + // if (!detailUrl.isEmpty()) { + // fillDetailInfo(movie, detailUrl); + // Thread.sleep(1000); // 礼貌延迟 + // } + + movies.add(movie); + System.out.printf("已解析 [%d] %s | 主演: %s | 播放: %d%n", + rank, title, actors, playCount); + rank++; + } + + System.out.println("爬取完成!共获取 " + movies.size() + " 部电影"); + + } catch (IOException e) { + System.err.println("爬取失败:" + e.getMessage()); + e.printStackTrace(); + } + + return movies; + + } + @Override + public String getCrawlerName () { + return "1905电影网播放排行榜"; + } +} \ No newline at end of file diff --git a/crawl_project_extension_2/src/main/java/com/example/Main.java b/crawl_project_extension_2/src/main/java/com/example/Main.java new file mode 100644 index 0000000..38d06ac --- /dev/null +++ b/crawl_project_extension_2/src/main/java/com/example/Main.java @@ -0,0 +1,53 @@ +package com.example; + +import java.util.List; + +public class Main { + public static void main(String[] args) { + // 通过参数切换爬虫:1905 或 douban(默认) + String source = "1905"; + if (args.length > 0) { + source = args[0].toLowerCase(); + } + + MovieCrawler crawler; + String csvName; + + switch (source) { + case "1905": + crawler = new M1905Crawler(); + csvName = "1905_rank.csv"; + break; + case "douban": + default: + crawler = new DoubanCrawler(); + csvName = "douban_top250.csv"; + break; + } + + System.out.println("使用爬虫:" + crawler.getCrawlerName()); + List movies = crawler.crawl(); + + if (movies.isEmpty()) { + System.err.println("未获取到任何电影数据!"); + return; + } + + // 数据分析 + MovieAnalyzer analyzer = new DataAnalyzer(); + analyzer.analyzeTotal(movies); + analyzer.analyzeByDimension(movies); + + // 导出CSV + CsvExporter.exportToCsv(movies, csvName); + + // 生成图表(1905数据缺少评分/年份,图表可能为空或需调整) + if (!"1905".equals(source)) { + ChartGenerator.saveBarChart(movies); + ChartGenerator.saveLineChart(movies); + ChartGenerator.savePieChart(movies); + } else { + System.out.println("⚠️ 1905数据缺少评分/年份,跳过图表生成"); + } + } +} \ No newline at end of file diff --git a/crawl_project_extension_2/src/main/java/com/example/Movie.java b/crawl_project_extension_2/src/main/java/com/example/Movie.java new file mode 100644 index 0000000..3308675 --- /dev/null +++ b/crawl_project_extension_2/src/main/java/com/example/Movie.java @@ -0,0 +1,75 @@ +package com.example; + +public class Movie { + private String title; // 电影名称 + private String director; // 导演 + private int year; // 上映年份 + private double rating; // 评分 + private int reviewCount; // 评价人数 + + // 无参构造 + public Movie() {} + + // 全参构造 + public Movie(String title, String director, int year, double rating, int reviewCount) { + this.title = title; + this.director = director; + this.year = year; + this.rating = rating; + this.reviewCount = reviewCount; + } + + // Getter & Setter + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDirector() { + return director; + } + + public void setDirector(String director) { + this.director = director; + } + + public int getYear() { + return year; + } + + public void setYear(int year) { + this.year = year; + } + + public double getRating() { + return rating; + } + + public void setRating(double rating) { + this.rating = rating; + } + + public int getReviewCount() { + return reviewCount; + } + + public void setReviewCount(int reviewCount) { + this.reviewCount = reviewCount; + } + + // 打印输出 + @Override + public String toString() { + return "Movie{" + + "片名='" + title + '\'' + + ", 导演='" + director + '\'' + + ", 年份=" + year + + ", 评分=" + rating + + ", 评价人数=" + reviewCount + + '}'; + } +} + diff --git a/crawl_project_extension_2/src/main/java/com/example/MovieAnalyzer.java b/crawl_project_extension_2/src/main/java/com/example/MovieAnalyzer.java new file mode 100644 index 0000000..d8edf81 --- /dev/null +++ b/crawl_project_extension_2/src/main/java/com/example/MovieAnalyzer.java @@ -0,0 +1,8 @@ +package com.example; +import java.util.List; +public interface MovieAnalyzer { + // 总览分析 + void analyzeTotal(List movies); + // 按维度分析(TopN、年份等) + void analyzeByDimension(List movies); +} diff --git a/crawl_project_extension_2/src/main/java/com/example/MovieCrawler.java b/crawl_project_extension_2/src/main/java/com/example/MovieCrawler.java new file mode 100644 index 0000000..f9589bd --- /dev/null +++ b/crawl_project_extension_2/src/main/java/com/example/MovieCrawler.java @@ -0,0 +1,8 @@ +package com.example; +import java.util.List; +public interface MovieCrawler { + // 爬取电影列表 + List crawl(); + // 获取爬虫名称(如"豆瓣Top250"、"IMDB Top100") + String getCrawlerName(); +} diff --git a/crawl_project_extension_2/src/main/java/org/example/App.java b/crawl_project_extension_2/src/main/java/org/example/App.java new file mode 100644 index 0000000..5f21d2e --- /dev/null +++ b/crawl_project_extension_2/src/main/java/org/example/App.java @@ -0,0 +1,13 @@ +package org.example; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + } +} diff --git a/crawl_project_extension_2/src/test/java/org/example/AppTest.java b/crawl_project_extension_2/src/test/java/org/example/AppTest.java new file mode 100644 index 0000000..d5f435d --- /dev/null +++ b/crawl_project_extension_2/src/test/java/org/example/AppTest.java @@ -0,0 +1,38 @@ +package org.example; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } +} diff --git a/crawl_project_extension_2/target/classes/com/example/ChartGenerator.class b/crawl_project_extension_2/target/classes/com/example/ChartGenerator.class new file mode 100644 index 0000000000000000000000000000000000000000..a7b119464780b0b8b63f2301cf3ee0140d38e79e GIT binary patch literal 8971 zcmcIp4R}=5nSQ?{lbZ||NWzZ<5%~$203nD*AVCBINH75;A^fz8m*g@TGMR}p6G*Vu zKSaeUS`<;Vc3Ul7+ir#GKmavc+wE?(UAMb+ySrVwtweBt+O6CDYqzrRIrq-w4l_aA z=UK>e=bUrTdCzyg?>*o5oqN9j(TUdqTq|GnBL}$#@=W-UFDTk>?XapsRya_#X6tsl zH7>|s7z_vFiv+pl6)nS1fI9kfg z>6f)7oO*8@1bltybKw9flH&GBDc27>pHMHUu^$ z*cJ@M?WkZuxkrF3h!>MjFwR6N#tVE_S68T4aAkG@SGbba`Y{1l7?^0{N=)MNGvup_ zghJG3BpMSGv_`ta@nAS0n3#s^>M7M%!%i_V6=ec{AR6iJ;;5yRXG7N2rNr?pJp(h# z!Urc*dY*3LDwGS1R!3&R9PeyH0eV~K8V+hmgx#c7&h6O}O&a}`mq5tMo*a>XZOY86GRah-vACgx*7+Kd#UY`MZG zaa$vuT~<^p^Cp`OTHi2Of1F{)j7D! z*1M)&VbqyehUHXhtb41oS4NlD*L!WDTJ;)pRsWSH>amI%36jkUUNAOI#(KA%5;maG zz-kj~uvSnqsN!T7&f0FpR@*%kp1XLn8nMnq6PhVzST~POVtcKqRM}!;gX)(bu;bK} zflV}xoM0@L0 zZE1Hf)TZPNAXhy)OoTu`<=Yu-i*xwQa@ryTBFNQ6!&a!ui$NO&5HZoE#^<-&!9aVw z0JKl#xg&ed?*DRgq-$>VoJp0F1|Hiz(D%xjldqk9;?;rIj=cZm%O57im-8Q$|om4=6 zqZJQXTLm*RjWNU^ZH|Xb?8U=Mkq%CC`K6D)WCg3$K4Rig?BhgR6`=%ExNkC+m!>_+ z_c%UpV84kc@FYF{#k&g%$#q9Hg2~z7y^5fxeJUIIojyrH95_D?;As=j;1C0S%#Js3 z=Z4!_g0bLMMZPKJo3pGXZ8C-MoQW^sc^ARjYKLMegc%n>NEd}lIeD2TJut=0||ZNqKu@T=WzGdS+!RrNT&Y2sxZp+)KCn(S!M zX6#>|WdnMmwGILo*0ao&Qm2OH*8CQkHM=U)-)u=aoI<>cgn?rwj-!v-&EVnEV7$}n zS{`nV&{LKNadR<{rwvge~Z84 zB(!4G3NQgkqSU#Z{}>Q&G8EIARlC>8n(62MKFux;wt=59H_u@5#!b#PP6qwcD(Ig^ zhk8T`a7J*|g|Yh4Jv7rm-?s*yd*IwRcMm+c=Un39fxU025pnf6tD@;SL3Nh>n`M8d zOF)MFBSWVbUSa;T3Z3Uv=^^#_m5MF@DwvSX>AQg3R3EBn@^4I8hg!CQf6t~A$8m1l z9~$?`wS$NgTgCW~G!^kWy+ zv+B)pl+@UH$D?H!X3P6~51u{o22-d45oY6h-zA$o`|h3+~O68ASujXu%cP44j;=wm^8m9l2n3wF26=_sq!`&m7KSrjf~7;+OvA12?%ZleYqMC1vL?+Wlj*n@%$`%} z2wWgjNp#jJyq5f7%0t4+^lUnID5cPJD(IJKBo!Y|7YNUfV`f)*HM+%7X@T$@S*eWf z)IAn|CQEniU}d&c88XL|t7R^aFFgEJ**#Wg7n9J&$c`YBAC+{iW8R_8SRox$FlY%6L=tzf(tPE+PaJDfbT<<&8m(wq&!uNsgd^<0Vs8T+b*T-PV*RK(J*H+29eh)}A* zXy%C*e3##;ltMw=Y$^4DhwqGDuA4w=O@k**Ht?NaosaD{=XmSuS!Ts83exNTwyID~ z7G#FzWHO@{M4Ykdy6Npo>Zc}sO6N4c&}r0^t#^*2-h@D%5Nj6^b(&|e5^-UgmNgG_ zziU1HxUNfuZ}1Fr;M3IeNn};hmSuj_v9?oEF8@$G6SaRoVTL4HomRBdt$IWQ(< zb#865%9MGM&1KiB??qV{Ua^_@%x6bsc{c>qHAA%1m5%jHonl7W)#(G4x~{5>ANc%D zk?v@#y&|YioTD_6Qr>d5(j=YE(nuuE{LkuYwBzlOwpbCYk@?c?mm1k&N<@N1>W?4o zrhDU;^SzqUYS12T(@3ApD-wPQA=kZ*)!Fji0ZI44={~EbyUUcYn(H1eDBE1i2whnu zyNA;CG6L;UKo6MId5|^c0X4GMl#s4{PSqYUrCrzd`Qp-pqsK22Gqo=yk3K^C)CC`)81dvS2itIS~yKo-yFgCRJ9;XogXb6C0zJjh>u9FzMn zEeHLmXgGgIRsx^-a;p7chKQZqdj-EX_ru>U#_;R=dA7 zdF*wgpvG6~>%&cgr!ilZZWba}*W_20=J#Q}s%%VPb02Qa!G_X2)yR)^{ji;u!{@(q z5&_}{i*wHJWxqdC#iK{@%5j`HivE&6N#IWp!(WqMnxDWs zM`(mpuc74uH11Z5bFxh&OEu`4hRYjHV0YEOWLD{vPkVn1(o zUgVgsVhWD(M&=|(yoqUe3)ArqFHGJ=Iev-?{G7KGzr-y3j&>--Y#GOUjj6n{sN{89 zHRe%*Y7*r-xdHRF?bq>R|6Q0ab+U{{^cwhNxvU^NXmhzyR#L_?X7u&4iX53MBjhHw z%>SUt{PTXC)@1$#3nlL*Fra=(=J!iJNZ_9| zng4}N3H;I_^RN5yn<8@WKQv`kO;h%_il-lF%KlCjKT1({lpuq%!(^gNPH}b@c?jM` z4a4;qPYYM@s%ajU@L7kOc)zqBD{%|&jkaMGcC+P4Ui2JBBVOXw&?{v0Yq%NT#X9_e zcRxQuGk(Gmr_qA<$fsYcn;mSHVZ6f`gIi@H?`I~HQB!f7lyjFWKc%?38&h4bPW5oL z!sTiOech)tSLfkFm#eqnZI`Rt@TSYv_ppLo{j`Ux4(=_Qs|rnV)j_+JTy@a4kgE>b zZRDzhW_h`~J{wnS&tpdxu6~%o)vZac$}8k*Aq9BX<*LxJYq#4cxq_rKCf7Z!OOt&I zysh(mC#7)HF&S2zb1ETbzZB}ia27_%h=dfeptvK&EF`3)#wayL$(SpT%Vi0nPL(-f=ZD)w}$c?l`k!zw()n&}d&ptQhohKvwzkyc4(xQ@;bROnb< zam+$H>9n1+=^!;i*n&>Bg!w;$7;eYih~g2J4)N~lC2IB{gN^z<{S5nG+nd{Ic+po?C4@3zI{!BpvCmYyWq6dJ0UUgSVNuO#Iu Xd3tdvFF{VqGmA^*kUS^Pqx63PXX6o& literal 0 HcmV?d00001 diff --git a/crawl_project_extension_2/target/classes/com/example/CsvExporter.class b/crawl_project_extension_2/target/classes/com/example/CsvExporter.class new file mode 100644 index 0000000000000000000000000000000000000000..867bc5690a9779495b75b78fca569a813cc66206 GIT binary patch literal 2712 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 DK@8wv literal 0 HcmV?d00001 diff --git a/crawl_project_extension_2/target/classes/com/example/Main.class b/crawl_project_extension_2/target/classes/com/example/Main.class new file mode 100644 index 0000000000000000000000000000000000000000..b3ba57d1ff24881c217e558aadafaf0d19627022 GIT binary patch literal 1681 zcmZuxTXz#x6#h=qcG6@ZC7}fhUQi2ZNgKqXXiAl)T&ig)G*l1}Pm*IgbuyDRnFQ*S zYw4S>^1?6hfwd6VBE2b#Xa0mQ74XS_;BxPolqPL6YtH2C%eVLb_CDwNe``+xjKT~f zfS`sB9i8YB=vkC?nKGqSN?pz`s)8%fHD*|bJ1!7R49;r^2^=ce<&?T7%N0|lChb~Y zS{X;)HI);FhF}B{=oOyKbnau|Q{m-2`HZ!K@d!<{D-yYgFBIH})Z> zA+BRTdfW1vTdKOMOzGG)%C6UUH0;!@V_5E->nK@HYd9cqV5=4q8&+weW|&1zvJb%! z`UM7FJo)+6qx=8<@!;jdhZ`$D{PW|lFMoOR_n(hnJ^E>5eR*ST?Zy4y&a(Xx9dF=G zB12Xx$|?#BC;Y%3RX%*WSwxGd88IEf+c>J>9UbrDJ%PRL#ZoOL#kC}+S|R)fP%Xy< z_U#}si~%Hc3}T4z$o;A!X76U~nng&|swqx8$!QM@9BD^xqa)3RDIF*AzCg&eeWk$u z&8D=}L$)7aRKsZcTVHmwD8={x3ZSJEuSn<2MGX>gv=CUj&ND%LcgSei7-%BmW+6~cL9 zxabY?9oMd$I(>4aP_2h?5tlSf>G&L9&^WcWAXBZMzgMvxS2+R^<^9dsB&DI+k-%;o zgfWd74VQJya#sCq;0w}mFDgqp(zOX+ugbcbkWPl>?08kj9DD6yMb@y?Yt1zs^Q`e) zX6dN0i-zlTf?6X?OM|-8k+F+PAj$|cwQ^oLIhi*}63f~JY0gW>;C)lr;Vu|e)@=t$ z6H?g&>`UC-tya=Yr$oN-UDPx#-YvjH_P1lV+!Yj~tIT^s>G5N1HJHY>*;K+fyc1({ zRtTi8y|SgsW_1JGK*x5%q{j&$JZIOOg1TTZPu&Dl(LlSoW3mx4V+rX8M63fW;nTubO8K07eF#Lxq=JH6=dnX zLT`?f3WAdwp^KYS3(+kerF9fxIyezJH+%%5G^sJ<5XW`8lW(EdOMb{t5Z^$OZwS|r jM}g9hVg^MhVq=WB`4%OLu|O7FtgkaXrWQ#Sz<2)xqVc)X literal 0 HcmV?d00001 diff --git a/crawl_project_extension_2/target/classes/com/example/Movie.class b/crawl_project_extension_2/target/classes/com/example/Movie.class new file mode 100644 index 0000000000000000000000000000000000000000..b132f6bce97edf3101a7d11c6257fc9afd3050be GIT binary patch literal 1999 zcmaJ>U2hvz5Ixs%{FSxixK8Vmq;;WfoUKzANFm_ZKw=7}>4#`#sgIjv6}EEhXuByO zgv0~l;{l0>@-L85q}UNj;RoIfC zkuZW9MiEj-J~SR1g}Tw$EZkXpXs$a7p(U$fIc0^B+*~b+2%=%cG>k!0m{@Oa70fS; zt?jy5xYc}YnF^zh<t} z_4kk8AOHMQX;wa5(C{i=<0Z!Sw%OQFn9mLJo*Qs=QWqt~B}s8vVLG=mJTQWsLM)#> z-hKA`*^|<21iC_$=im2^4*w`gp1kClmps*%#=H<|%SGE6okgb$r!on74Pf)=c}pvF1&> zxo*^JhHc5Y;|w~VS&tM>tqw?psdS$v5A?WLtyJe~WVUHK_dQKT9(A{qJ}D%6jM0^j zw0I(*cM9{{16N_xa#bPBuiiPxo)a8pz^5IxF{DBdL;m*!*Kp~RDb%d`T1f)RwdW(BNYX(6oVTZrp3EhP0!u!Xcf8EPTZ z%X`j^PasH=Q6!PT1WBcEmi9c-?tNw6&YYe5WG96QpR8M&l$({;&D&)sR4WRiADfAc%+AQ}tl-fU9>7D1u@rvFFX!BI z&b{3)R{(u9JQN6>$iz$>dAwJG&CNlIvF7S@7Kw)vp}FG+&J@>Mw%F`MWC;!aGOUc{ ziqH=?USSV9F=&lL1rQB+6vqTVrU&k=~D;QWOj)x0T4D)%OlQQA!t!NZP;6$a;01c7SYsU#RS zZIn`|SeK{12o4@%f?F#rGn literal 0 HcmV?d00001