diff --git a/README.md b/README.md index 92a24d5..e942d29 100644 --- a/README.md +++ b/README.md @@ -484,6 +484,10 @@ Squib supports importing data from `xlsx` files and `csv` files. These methods a Of course, you can always import your game data other ways using just Ruby. There's nothing special about Squib's methods other than their convenience. +###Quantity Explosion + +If you want more than one copy of a card, then have a column called `Qty` and fill it with counts. Squib's `xlsx` and `csv` methods will automatically expand those rows according to those counts. You can also customize that "Qty" to anything you like by setting the `explode` option (e.g. `explode: 'Quantity'`). See the `excel.rb` and the `csv_import.rb` samples found [here](https://github.com/andymeneely/squib/tree/master/samples/) for an example. + ## Making Squib Verbose By default, Squib's logger is set to WARN, but more fine-grained logging is embedded in the code. To set the logger, just put this at the top of your script: diff --git a/lib/squib/api/data.rb b/lib/squib/api/data.rb index 97ec66d..90c40bd 100644 --- a/lib/squib/api/data.rb +++ b/lib/squib/api/data.rb @@ -22,7 +22,7 @@ module Squib # @option opts file [String] the file to open. Must end in `.xlsx`. Opens relative to the current directory. # @option opts sheet [Integer] (0) The zero-based index of the sheet from which to read. # @option opts strip [Boolean] (true) When true, strips leading and trailing whitespace on values and headers - # @option opts qty_header [String] ('qty']) Quantity explosion will be applied to the column this name + # @option opts explode [String] ('qty') Quantity explosion will be applied to the column this name. See README for example. # @return [Hash] a hash of arrays based on columns in the spreadsheet # @api public def xlsx(opts = {}) @@ -44,7 +44,7 @@ module Squib data[header] << cell end#row end#col - data + explode_quantities(data, import.explode) end#xlsx module_function :xlsx @@ -66,7 +66,7 @@ module Squib # # @option opts file [String] the CSV-formatted file to open. Opens relative to the current directory. # @option opts strip [Boolean] (true) When true, strips leading and trailing whitespace on values and headers - # @option opts qty_header [String] ('qty']) Quantity explosion will be applied to the column this name + # @option opts explode [String] ('qty') Quantity explosion will be applied to the column this name. See README for example. # @return [Hash] a hash of arrays based on columns in the table # @api public def csv(opts = {}) @@ -87,7 +87,7 @@ module Squib end hash = new_hash end - return hash + return explode_quantities(hash, import.explode) end module_function :csv @@ -101,6 +101,20 @@ module Squib end module_function :check_duplicate_csv_headers + def explode_quantities(data, qty) + return data unless data.key? qty.to_s.strip + qtys = data[qty] + new_data = {} + data.each do |col, arr| + new_data[col] = [] + qtys.each_with_index do |qty, index| + qty.to_i.times { new_data[col] << arr[index] } + end + end + return new_data + end + module_function :explode_quantities + class Deck # Convenience call on deck goes to the module function diff --git a/lib/squib/args/import.rb b/lib/squib/args/import.rb index 512b0ac..4a0194d 100644 --- a/lib/squib/args/import.rb +++ b/lib/squib/args/import.rb @@ -8,7 +8,9 @@ module Squib include ArgLoader def self.parameters - { strip: true } + { strip: true, + explode: 'Qty' + } end def self.expanding_parameters @@ -24,6 +26,10 @@ module Squib arg end + def validate_explode(arg) + arg + end + def strip? strip end diff --git a/samples/csv_import.rb b/samples/csv_import.rb index 72a9ff0..df9d7ef 100644 --- a/samples/csv_import.rb +++ b/samples/csv_import.rb @@ -15,4 +15,12 @@ Squib::Deck.new(cards: 2) do end # CSV is also a Squib-module-level function, so this also works: -data = Squib.csv file: 'sample.csv' +data = Squib.csv file: 'quantity_explosion.csv' # 2 rows... +num_cards = data['Name'].size # ...but 4 cards! + +Squib::Deck.new(cards: num_cards) do + background color: :white + rect # card border + text str: data['Name'], font: 'Arial 54' + save_sheet prefix: 'sample_csv_qty_', columns: 4 +end diff --git a/samples/excel.rb b/samples/excel.rb index 936ab20..9bf3406 100644 --- a/samples/excel.rb +++ b/samples/excel.rb @@ -14,6 +14,18 @@ Squib::Deck.new(cards: 3) do save format: :png, prefix: 'sample_excel_' #save to individual pngs end +# xlsx is also a Squib-module-level function, so this also works: +data = Squib.xlsx file: 'explode_quantities.xlsx' # 2 rows... +num_cards = data['Name'].size # ...but 4 cards! + +Squib::Deck.new(cards: num_cards) do + background color: :white + rect # card border + text str: data['Name'], font: 'Arial 54' + save_sheet prefix: 'sample_xlsx_qty_', columns: 4 +end + + # Here's another example, a bit more realistic. Here's what's going on: # * We call xlsx from Squib directly - BEFORE Squib::Deck creation. This # allows us to infer the number of cards based on the size of the "Name" diff --git a/samples/explode_quantities.xlsx b/samples/explode_quantities.xlsx new file mode 100644 index 0000000..9e8b0ab Binary files /dev/null and b/samples/explode_quantities.xlsx differ diff --git a/samples/quantity_explosion.csv b/samples/quantity_explosion.csv new file mode 100644 index 0000000..efaa11c --- /dev/null +++ b/samples/quantity_explosion.csv @@ -0,0 +1,3 @@ +Name,Qty +Basilisk,3 +High Templar,1 \ No newline at end of file diff --git a/spec/api/api_data_spec.rb b/spec/api/api_data_spec.rb index 855bac5..d38750e 100644 --- a/spec/api/api_data_spec.rb +++ b/spec/api/api_data_spec.rb @@ -36,6 +36,20 @@ describe Squib::Deck do }) end + it 'explodes quantities' do + expect(Squib.csv(file: csv_file('qty.csv'))).to eq({ + 'Name' => %w(Ha Ha Ha Ho), + 'Qty' => [3, 3, 3, 1], + }) + end + + it 'explodes quantities on specified header' do + expect(Squib.csv(explode: 'Quantity', file: csv_file('qty_named.csv'))).to eq({ + 'Name' => %w(Ha Ha Ha Ho), + 'Quantity' => [3, 3, 3, 1], + }) + end + end context '#xlsx' do diff --git a/spec/data/csv/qty.csv b/spec/data/csv/qty.csv new file mode 100644 index 0000000..e99bf95 --- /dev/null +++ b/spec/data/csv/qty.csv @@ -0,0 +1,3 @@ +Name,Qty +Ha, 3 +Ho, 1 \ No newline at end of file diff --git a/spec/data/csv/qty_named.csv b/spec/data/csv/qty_named.csv new file mode 100644 index 0000000..6fa8afe --- /dev/null +++ b/spec/data/csv/qty_named.csv @@ -0,0 +1,3 @@ +Name,Quantity +Ha, 3 +Ho, 1 \ No newline at end of file diff --git a/spec/data/samples/csv_import.rb.txt b/spec/data/samples/csv_import.rb.txt index 55d2f52..e79248a 100644 --- a/spec/data/samples/csv_import.rb.txt +++ b/spec/data/samples/csv_import.rb.txt @@ -74,3 +74,140 @@ pango: ellipsized?([]) cairo: restore([]) surface: write_to_png(["_output/sample_csv_00.png"]) surface: write_to_png(["_output/sample_csv_01.png"]) +cairo: antialias=(["subpixel"]) +cairo: antialias=(["subpixel"]) +cairo: antialias=(["subpixel"]) +cairo: antialias=(["subpixel"]) +cairo: save([]) +cairo: set_source_color(["white"]) +cairo: paint([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["white"]) +cairo: paint([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["white"]) +cairo: paint([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["white"]) +cairo: paint([]) +cairo: restore([]) +cairo: save([]) +cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0]) +cairo: set_source_color(["#0000"]) +cairo: fill_preserve([]) +cairo: set_source_color(["black"]) +cairo: set_line_width([2.0]) +cairo: set_line_join([0]) +cairo: set_line_cap([0]) +cairo: set_dash([[]]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) +cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0]) +cairo: set_source_color(["#0000"]) +cairo: fill_preserve([]) +cairo: set_source_color(["black"]) +cairo: set_line_width([2.0]) +cairo: set_line_join([0]) +cairo: set_line_cap([0]) +cairo: set_dash([[]]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) +cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0]) +cairo: set_source_color(["#0000"]) +cairo: fill_preserve([]) +cairo: set_source_color(["black"]) +cairo: set_line_width([2.0]) +cairo: set_line_join([0]) +cairo: set_line_cap([0]) +cairo: set_dash([[]]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) +cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0]) +cairo: set_source_color(["#0000"]) +cairo: fill_preserve([]) +cairo: set_source_color(["black"]) +cairo: set_line_width([2.0]) +cairo: set_line_join([0]) +cairo: set_line_cap([0]) +cairo: set_dash([[]]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["Basilisk"]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["Basilisk"]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["Basilisk"]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["High Templar"]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: set_source([MockDouble, 0, 0]) +cairo: paint([]) +cairo: set_source([MockDouble, 100, 0]) +cairo: paint([]) +cairo: set_source([MockDouble, 200, 0]) +cairo: paint([]) +cairo: set_source([MockDouble, 300, 0]) +cairo: paint([]) +surface: write_to_png(["_output/sample_csv_qty_00.png"]) diff --git a/spec/data/samples/excel.rb.txt b/spec/data/samples/excel.rb.txt index 7469999..75d3014 100644 --- a/spec/data/samples/excel.rb.txt +++ b/spec/data/samples/excel.rb.txt @@ -163,6 +163,11 @@ surface: write_to_png(["_output/sample_excel_02.png"]) cairo: antialias=(["subpixel"]) cairo: antialias=(["subpixel"]) cairo: antialias=(["subpixel"]) +cairo: antialias=(["subpixel"]) +cairo: save([]) +cairo: set_source_color(["white"]) +cairo: paint([]) +cairo: restore([]) cairo: save([]) cairo: set_source_color(["white"]) cairo: paint([]) @@ -209,6 +214,186 @@ cairo: set_dash([[]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) +cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0]) +cairo: set_source_color(["#0000"]) +cairo: fill_preserve([]) +cairo: set_source_color(["black"]) +cairo: set_line_width([2.0]) +cairo: set_line_join([0]) +cairo: set_line_cap([0]) +cairo: set_dash([[]]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["Zergling"]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["Zergling"]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["Zergling"]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["High Templar"]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: set_source([MockDouble, 0, 0]) +cairo: paint([]) +cairo: set_source([MockDouble, 100, 0]) +cairo: paint([]) +cairo: set_source([MockDouble, 200, 0]) +cairo: paint([]) +cairo: set_source([MockDouble, 300, 0]) +cairo: paint([]) +surface: write_to_png(["_output/sample_xlsx_qty_00.png"]) +cairo: antialias=(["subpixel"]) +cairo: antialias=(["subpixel"]) +cairo: antialias=(["subpixel"]) +cairo: antialias=(["subpixel"]) +cairo: antialias=(["subpixel"]) +cairo: antialias=(["subpixel"]) +cairo: save([]) +cairo: set_source_color(["white"]) +cairo: paint([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["white"]) +cairo: paint([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["white"]) +cairo: paint([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["white"]) +cairo: paint([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["white"]) +cairo: paint([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["white"]) +cairo: paint([]) +cairo: restore([]) +cairo: save([]) +cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0]) +cairo: set_source_color(["#0000"]) +cairo: fill_preserve([]) +cairo: set_source_color(["black"]) +cairo: set_line_width([2.0]) +cairo: set_line_join([0]) +cairo: set_line_cap([0]) +cairo: set_dash([[]]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) +cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0]) +cairo: set_source_color(["#0000"]) +cairo: fill_preserve([]) +cairo: set_source_color(["black"]) +cairo: set_line_width([2.0]) +cairo: set_line_join([0]) +cairo: set_line_cap([0]) +cairo: set_dash([[]]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) +cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0]) +cairo: set_source_color(["#0000"]) +cairo: fill_preserve([]) +cairo: set_source_color(["black"]) +cairo: set_line_width([2.0]) +cairo: set_line_join([0]) +cairo: set_line_cap([0]) +cairo: set_dash([[]]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) +cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0]) +cairo: set_source_color(["#0000"]) +cairo: fill_preserve([]) +cairo: set_source_color(["black"]) +cairo: set_line_width([2.0]) +cairo: set_line_join([0]) +cairo: set_line_cap([0]) +cairo: set_dash([[]]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) +cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0]) +cairo: set_source_color(["#0000"]) +cairo: fill_preserve([]) +cairo: set_source_color(["black"]) +cairo: set_line_width([2.0]) +cairo: set_line_join([0]) +cairo: set_line_cap([0]) +cairo: set_dash([[]]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) +cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0]) +cairo: set_source_color(["#0000"]) +cairo: fill_preserve([]) +cairo: set_source_color(["black"]) +cairo: set_line_width([2.0]) +cairo: set_line_join([0]) +cairo: set_line_cap([0]) +cairo: set_dash([[]]) +cairo: stroke([]) +cairo: restore([]) +cairo: save([]) cairo: set_source_color(["black"]) cairo: translate([0, 0]) cairo: rotate([0]) @@ -235,6 +420,69 @@ cairo: translate([0, 0]) cairo: rotate([0]) cairo: move_to([0, 0]) pango: font_description=([MockDouble]) +pango: text=(["Wood"]) +pango: width=([844800]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +cairo: rounded_rectangle([0, 0, 0, 0, 0, 0]) +cairo: set_source_color(["red"]) +cairo: set_line_width([2.0]) +cairo: stroke([]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["Wood"]) +pango: width=([844800]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +cairo: rounded_rectangle([0, 0, 0, 0, 0, 0]) +cairo: set_source_color(["red"]) +cairo: set_line_width([2.0]) +cairo: stroke([]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["Metal"]) +pango: width=([844800]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +cairo: rounded_rectangle([0, 0, 0, 0, 0, 0]) +cairo: set_source_color(["red"]) +cairo: set_line_width([2.0]) +cairo: stroke([]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) pango: text=(["Metal"]) pango: width=([844800]) pango: wrap=([#]) @@ -298,6 +546,69 @@ cairo: translate([0, 0]) cairo: rotate([0]) cairo: move_to([0, 0]) pango: font_description=([MockDouble]) +pango: text=(["$2k"]) +pango: width=([844800]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +cairo: rounded_rectangle([0, 0, 0, 0, 0, 0]) +cairo: set_source_color(["red"]) +cairo: set_line_width([2.0]) +cairo: stroke([]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["$2k"]) +pango: width=([844800]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +cairo: rounded_rectangle([0, 0, 0, 0, 0, 0]) +cairo: set_source_color(["red"]) +cairo: set_line_width([2.0]) +cairo: stroke([]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) +pango: text=(["$3k"]) +pango: width=([844800]) +pango: wrap=([#]) +pango: ellipsize=([#]) +pango: alignment=([#]) +pango: justify=([false]) +cairo: move_to([0, 0]) +cairo: move_to([0, 0]) +cairo: show_pango_layout([MockDouble]) +cairo: rounded_rectangle([0, 0, 0, 0, 0, 0]) +cairo: set_source_color(["red"]) +cairo: set_line_width([2.0]) +cairo: stroke([]) +pango: ellipsized?([]) +cairo: restore([]) +cairo: save([]) +cairo: set_source_color(["black"]) +cairo: translate([0, 0]) +cairo: rotate([0]) +cairo: move_to([0, 0]) +pango: font_description=([MockDouble]) pango: text=(["$3k"]) pango: width=([844800]) pango: wrap=([#]) @@ -340,4 +651,11 @@ cairo: set_source([MockDouble, 100, 0]) cairo: paint([]) cairo: set_source([MockDouble, 200, 0]) cairo: paint([]) +cairo: set_source([MockDouble, 300, 0]) +cairo: paint([]) +cairo: set_source([MockDouble, 400, 0]) +cairo: paint([]) surface: write_to_png(["_output/sample_excel_resources_00.png"]) +cairo: set_source([MockDouble, 0, 0]) +cairo: paint([]) +surface: write_to_png(["_output/sample_excel_resources_01.png"])