glimmer-dsl-swt 4.20.13.7 → 4.20.13.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e20d1ff3e84168b2937444cf859e28249a859789adbd3d24993e0087a51addf5
4
- data.tar.gz: 272ffc7415a569b4ef635da5919128399c19cd2077c11b280e34357d37b1ac09
3
+ metadata.gz: 59508a178a1694489ba4ec995672f08a0997b01c8ebaeb39cecd2db250d0f88b
4
+ data.tar.gz: 9610a96bf71aa15a581dedda77f9c11942286f1ff5f7ac96369624c97a798f28
5
5
  SHA512:
6
- metadata.gz: 1057ae99a81ceb633ff2ed436ef150036ab3475ca663a4b0514173f6af1e136ec0a4a822898ef3c320b4f285180d65ef1c254a245959e219667e12beca1353a6
7
- data.tar.gz: 7d62cc987fe8bbd20972d33ef7a7331844635f28f3d19273d99e4305ded7bdb60f1cb2d2b021d27f598f916fb501689017ff90208864026e5345a219778b7717
6
+ metadata.gz: 1f2219231093b33e6c32637dd2a6ee2249e3c64daf3f92355c57ab170d15c6bfd4930d540c3703c0a4c926ff9e6c322ddc4dd119938be9bc23ccf19935c84675
7
+ data.tar.gz: 98c6a6e4b2f26fde8d9741eb04054866c145366c27a728343f71f6f960c5eba411fa127167101da055d96241b3c66fb7c7d8dbba91256fa9688d694165158cdc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Change Log
2
2
 
3
+ ### 4.20.13.8
4
+
5
+ - Glimmer Klondike Solitaire elaborate sample
6
+
3
7
  ### 4.20.13.7
4
8
 
5
9
  - Support accepting ImageProxy objects in Canvas Shape DSL (not just image paths)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.20.13.7
1
+ 4.20.13.8
Binary file
@@ -0,0 +1,86 @@
1
+ require 'glimmer-dsl-swt'
2
+
3
+ require_relative 'klondike_solitaire/model/game'
4
+
5
+ require_relative 'klondike_solitaire/view/action_panel'
6
+ require_relative 'klondike_solitaire/view/tableau'
7
+
8
+ class KlondikeSolitaire
9
+ include Glimmer::UI::CustomShell
10
+
11
+ PLAYING_CARD_WIDTH = 50
12
+ PLAYING_CARD_HEIGHT = 80
13
+ PLAYING_CARD_SPACING = 5
14
+
15
+ ## Add options like the following to configure CustomShell by outside consumers
16
+ #
17
+ # options :title, :background_color
18
+ # option :width, default: 320
19
+ # option :height, default: 240
20
+
21
+ ## Use before_body block to pre-initialize variables to use in body
22
+ #
23
+ #
24
+ before_body {
25
+ @game = Model::Game.new
26
+ Display.app_name = 'Glimmer Klondike Solitaire'
27
+ @display = display {
28
+ on_about {
29
+ display_about_dialog
30
+ }
31
+ on_preferences {
32
+ display_about_dialog
33
+ }
34
+ }
35
+ }
36
+
37
+ ## Use after_body block to setup observers for widgets in body
38
+ #
39
+ # after_body {
40
+ #
41
+ # }
42
+
43
+ ## Add widget content inside custom shell body
44
+ ## Top-most widget must be a shell or another custom shell
45
+ #
46
+ body {
47
+ shell(:no_resize) {
48
+ row_layout(:vertical) {
49
+ fill true
50
+ center true
51
+ }
52
+ minimum_size 400, 400
53
+ text "Glimmer Klondike Solitaire"
54
+ background :dark_green
55
+
56
+ action_panel(game: @game)
57
+ tableau(game: @game) {
58
+ layout_data {
59
+ width 380
60
+ height 400
61
+ }
62
+ }
63
+
64
+ menu_bar {
65
+ menu {
66
+ text '&Help'
67
+ menu_item {
68
+ text '&About...'
69
+ on_widget_selected {
70
+ display_about_dialog
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+
78
+ def display_about_dialog
79
+ message_box(body_root) {
80
+ text 'About'
81
+ message "Glimmer Klondike Solitaire\nGlimmer DSL for SWT Elaborate Sample"
82
+ }.open
83
+ end
84
+ end
85
+
86
+ KlondikeSolitaire.launch
@@ -0,0 +1,60 @@
1
+ class KlondikeSolitaire
2
+ module Model
3
+ class ColumnPile
4
+ include Glimmer::DataBinding::ObservableModel
5
+ attr_reader :count
6
+
7
+ def initialize(game, count)
8
+ @game = game
9
+ @count = count
10
+ reset!
11
+ end
12
+
13
+ def reset!
14
+ playing_cards.clear
15
+ populate!(count.times.map { @game.deck.pop })
16
+ notify_observers(:playing_cards)
17
+ end
18
+
19
+ # this method does not validate
20
+ def populate!(new_playing_cards)
21
+ new_playing_cards.each_with_index do |playing_card, index|
22
+ playing_card.hidden = true if index < (new_playing_cards.size - 1)
23
+ playing_cards.push(playing_card)
24
+ end
25
+ end
26
+
27
+ # this method validates that playing card fits at the bottom of the column (opposite color and one number smaller)
28
+ # throws an error if it does not fit
29
+ def add!(new_playing_card)
30
+ bottom_card = playing_cards.last
31
+ if (playing_cards.empty? && new_playing_card.rank == 13) ||
32
+ (new_playing_card.color != bottom_card.color && new_playing_card.rank == (bottom_card.rank - 1))
33
+ playing_cards.push(new_playing_card)
34
+ else
35
+ raise "Cannot add #{new_playing_card} to #{self}"
36
+ end
37
+ end
38
+
39
+ def remove!(card)
40
+ remove_cards_starting_at(playing_cards.index(card)).tap do |result|
41
+ playing_cards.last&.hidden = false
42
+ end
43
+ end
44
+
45
+ def remove_cards_starting_at(index)
46
+ removed_cards = playing_cards[index...playing_cards.size]
47
+ playing_cards[index...playing_cards.size] = []
48
+ removed_cards
49
+ end
50
+
51
+ def playing_cards
52
+ @playing_cards ||= []
53
+ end
54
+
55
+ def to_s
56
+ "Column Pile #{count} (#{playing_cards.map {|card| "#{card.rank}#{card.suit.to_s[0].upcase}"}.join(" | ")})"
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,33 @@
1
+ class KlondikeSolitaire
2
+ module Model
3
+ class DealingPile
4
+ DEALING_INITIAL_COUNT = 24
5
+
6
+ def initialize(game)
7
+ @game = game
8
+ reset!
9
+ end
10
+
11
+ def reset!
12
+ playing_cards.clear
13
+ DEALING_INITIAL_COUNT.times { playing_cards << @game.deck.pop }
14
+ end
15
+
16
+ def deal!
17
+ playing_card = playing_cards.shift
18
+ if playing_card.nil?
19
+ @game.dealt_pile.playing_cards.each do |a_playing_card|
20
+ playing_cards << a_playing_card
21
+ end
22
+ @game.dealt_pile.playing_cards.clear
23
+ else
24
+ @game.dealt_pile.push!(playing_card)
25
+ end
26
+ end
27
+
28
+ def playing_cards
29
+ @playing_cards ||= []
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ class KlondikeSolitaire
2
+ module Model
3
+ class DealtPile
4
+ def initialize(game)
5
+ @game = game
6
+ end
7
+
8
+ def reset!
9
+ playing_cards.clear
10
+ end
11
+
12
+ def push!(playing_card)
13
+ playing_cards.push(playing_card)
14
+ end
15
+
16
+ def remove!(card)
17
+ playing_cards.delete(card)
18
+ end
19
+
20
+ def playing_cards
21
+ @playing_cards ||= []
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,40 @@
1
+ class KlondikeSolitaire
2
+ module Model
3
+ class FoundationPile
4
+ attr_reader :suit
5
+
6
+ def initialize(game, suit)
7
+ @game = game
8
+ @suit = suit
9
+ reset!
10
+ end
11
+
12
+ def reset!
13
+ playing_cards.clear
14
+ end
15
+
16
+ # adds a card
17
+ # validates if it is a card that belongs to the suit
18
+ def add!(playing_card)
19
+ if playing_card.suit == suit &&
20
+ (
21
+ (playing_cards.empty? && playing_card.rank == 1) ||
22
+ playing_card.rank == (playing_cards.last.rank + 1)
23
+ )
24
+ playing_cards.push(playing_card)
25
+ else
26
+ raise "Cannot add #{playing_card} to #{self}"
27
+ end
28
+ end
29
+
30
+ def playing_cards
31
+ @playing_cards ||= []
32
+ end
33
+
34
+ def to_s
35
+ "Foundation Pile #{suit} (#{playing_cards.map {|card| "#{card.rank}#{card.suit.to_s[0].upcase}"}.join(" | ")})"
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,37 @@
1
+ require_relative 'playing_card'
2
+ require_relative 'dealt_pile'
3
+ require_relative 'dealing_pile'
4
+ require_relative 'column_pile'
5
+ require_relative 'foundation_pile'
6
+
7
+ class KlondikeSolitaire
8
+ module Model
9
+ class Game
10
+ COLUMN_PILE_COUNT = 7
11
+
12
+ attr_reader :deck, :dealing_pile, :dealt_pile, :column_piles, :foundation_piles
13
+
14
+ def initialize
15
+ @deck = new_deck
16
+ @dealt_pile = DealtPile.new(self)
17
+ @dealing_pile = DealingPile.new(self)
18
+ @column_piles = COLUMN_PILE_COUNT.times.map {|n| ColumnPile.new(self, n + 1)}
19
+ @foundation_piles = PlayingCard::SUITS.map {|suit| FoundationPile.new(self, suit)}
20
+ end
21
+
22
+ def restart!
23
+ @deck = new_deck
24
+ @dealt_pile.reset!
25
+ @dealing_pile.reset!
26
+ @column_piles.each(&:reset!)
27
+ @foundation_piles.each(&:reset!)
28
+ end
29
+
30
+ private
31
+
32
+ def new_deck
33
+ PlayingCard.deck.shuffle
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,50 @@
1
+ class KlondikeSolitaire
2
+ module Model
3
+ class PlayingCard
4
+ SUITS = [:spades, :hearts, :clubs, :diamonds]
5
+ BLACK_SUITS = [:spades, :clubs]
6
+ RED_SUITS = [:hearts, :diamonds]
7
+ RANK_COUNT = 13
8
+
9
+ class << self
10
+ def deck
11
+ suit_decks.flatten
12
+ end
13
+
14
+ def suit_decks
15
+ SUITS.map do |suit|
16
+ suit_deck(suit)
17
+ end
18
+ end
19
+
20
+ def suit_deck(suit)
21
+ 1.upto(RANK_COUNT).map do |rank|
22
+ new(rank, suit)
23
+ end
24
+ end
25
+ end
26
+
27
+ attr_reader :rank, :suit
28
+ attr_accessor :hidden
29
+ alias hidden? hidden
30
+
31
+ def initialize(rank, suit, hidden = false)
32
+ @rank = rank
33
+ @suit = suit
34
+ @hidden = hidden
35
+ end
36
+
37
+ def color
38
+ if BLACK_SUITS.include?(suit)
39
+ :black
40
+ elsif RED_SUITS.include?(suit)
41
+ :red
42
+ end
43
+ end
44
+
45
+ def to_s
46
+ "Playing Card #{rank}#{suit.to_s[0].upcase}"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,30 @@
1
+ class KlondikeSolitaire
2
+ module View
3
+ class ActionPanel
4
+ include Glimmer::UI::CustomWidget
5
+
6
+ option :game
7
+
8
+ body {
9
+ composite {
10
+ grid_layout(1, false) {
11
+ margin_width 0
12
+ margin_height 0
13
+ }
14
+
15
+ background :dark_green
16
+
17
+ button {
18
+ layout_data :center, :center, true, false
19
+
20
+ text 'Restart Game'
21
+
22
+ on_widget_selected {
23
+ game.restart!
24
+ }
25
+ }
26
+ }
27
+ }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,66 @@
1
+ require_relative '../model/column_pile'
2
+
3
+ require_relative 'playing_card'
4
+
5
+ class KlondikeSolitaire
6
+ module View
7
+ class ColumnPile
8
+ include Glimmer::UI::CustomShape
9
+
10
+ IMAGE_EMPTY = image(50, 80) {
11
+ rectangle(0, 0, 50, 80) {
12
+ background :dark_green
13
+
14
+ rectangle(0, 0, 49, 79, 15, 15) {
15
+ foreground :gray
16
+ }
17
+ }
18
+ }
19
+
20
+ options :pile_x, :pile_y, :model
21
+
22
+ after_body {
23
+ observe(model, 'playing_cards.last.hidden') do
24
+ build_column_pile(model.playing_cards)
25
+ end
26
+ build_column_pile(model.playing_cards)
27
+ }
28
+
29
+ body {
30
+ shape(pile_x, pile_y) {
31
+ on_drop do |drop_event|
32
+ begin
33
+ card_shape = drop_event.dragged_shape.get_data('custom_shape')
34
+ card = card_shape.model
35
+ model.add!(card)
36
+ card_parent_pile = card_shape.parent_pile
37
+ card_source_model = card_parent_pile.model
38
+ cards = card_source_model.remove!(card)
39
+ if cards.is_a?(Array) # if it is a column pile
40
+ cards[1..-1].each do |card|
41
+ model.add!(card)
42
+ end
43
+ end
44
+ drop_event.dragged_shape.dispose
45
+ rescue => e
46
+ # pd e
47
+ drop_event.doit = false
48
+ end
49
+ end
50
+ }
51
+ }
52
+
53
+ def build_column_pile(playing_cards)
54
+ body_root.shapes.to_a.each(&:dispose)
55
+ current_parent = body_root
56
+ playing_cards.each_with_index do |card, i|
57
+ current_parent.content {
58
+ current_parent = playing_card(card_x: 0, card_y: 20, model: card, parent_pile: self) {
59
+ drag_source true unless card.hidden?
60
+ }.body_root
61
+ }
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,36 @@
1
+ require_relative '../model/dealing_pile'
2
+
3
+ require_relative 'empty_playing_card'
4
+ require_relative 'hidden_playing_card'
5
+
6
+ class KlondikeSolitaire
7
+ module View
8
+ class DealingPile
9
+ include Glimmer::UI::CustomShape
10
+
11
+ options :pile_x, :pile_y, :model
12
+
13
+ after_body {
14
+ observe(model, 'playing_cards.empty?') do |empty_value|
15
+ body_root.shapes.to_a.each(&:dispose)
16
+ if empty_value
17
+ body_root.content {
18
+ empty_playing_card
19
+ }
20
+ else
21
+ body_root.content {
22
+ hidden_playing_card
23
+ }
24
+ end
25
+ end
26
+ }
27
+
28
+ body {
29
+ shape(pile_x, pile_y) {
30
+ hidden_playing_card
31
+ }
32
+ }
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ require_relative '../model/dealt_pile'
2
+
3
+ require_relative 'empty_playing_card'
4
+ require_relative 'playing_card'
5
+
6
+ class KlondikeSolitaire
7
+ module View
8
+ class DealtPile
9
+ include Glimmer::UI::CustomShape
10
+
11
+ options :pile_x, :pile_y, :model
12
+
13
+ after_body do
14
+ observe(model, 'playing_cards.empty?') do |empty_value|
15
+ if empty_value
16
+ body_root.shapes.to_a.dup.each(&:dispose)
17
+ body_root.content {
18
+ empty_playing_card
19
+ }
20
+ else
21
+ body_root.content {
22
+ playing_card(model: model.playing_cards.last, parent_pile: self) {
23
+ drag_source true
24
+ }
25
+ }
26
+ end
27
+ end
28
+ end
29
+
30
+ body {
31
+ shape(pile_x, pile_y) {
32
+ empty_playing_card
33
+ }
34
+ }
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,25 @@
1
+ class KlondikeSolitaire
2
+ module View
3
+ class EmptyPlayingCard
4
+ include Glimmer::UI::CustomShape
5
+
6
+ option :suit
7
+
8
+ body {
9
+ rectangle(0, 0, 49, 79, 15, 15) {
10
+ foreground :gray
11
+
12
+ if suit
13
+ text {
14
+ string suit.to_s[0].upcase
15
+ x :default
16
+ y :default
17
+ is_transparent true
18
+ }
19
+ end
20
+ }
21
+ }
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,59 @@
1
+ require_relative '../model/playing_card'
2
+ require_relative '../model/foundation_pile'
3
+
4
+ class KlondikeSolitaire
5
+ module View
6
+ class FoundationPile
7
+ include Glimmer::UI::CustomShape
8
+
9
+ options :pile_x, :pile_y, :game, :suit
10
+
11
+ attr_accessor :current_image, :model
12
+
13
+ before_body {
14
+ self.current_image = image(50, 80) {empty_playing_card(suit: suit)}
15
+ self.model = game.foundation_piles[Model::PlayingCard::SUITS.index(suit)]
16
+ }
17
+
18
+ after_body {
19
+ observe(model, 'playing_cards.last') do |last_card|
20
+ if last_card
21
+ body_root.content {
22
+ playing_card(model: last_card)
23
+ }
24
+ else
25
+ body_root.clear_shapes
26
+ body_root.content {
27
+ empty_playing_card(suit: suit)
28
+ }
29
+ end
30
+ end
31
+ }
32
+
33
+ body {
34
+ shape(pile_x, pile_y) {
35
+ empty_playing_card(suit: suit)
36
+
37
+ on_drop do |drop_event|
38
+ begin
39
+ # TODO make sure one cannot drag a column pile of cards here
40
+ card_shape = drop_event.dragged_shape.get_data('custom_shape')
41
+ card = card_shape.model
42
+ card_parent_pile = card_shape.parent_pile
43
+ card_source_model = card_parent_pile.model
44
+ raise 'Cannot accept multiple cards' if card_source_model.playing_cards.index(card) != (card_source_model.playing_cards.size - 1)
45
+ model.add!(card)
46
+ card_source_model.remove!(card)
47
+ drop_event.dragged_shape.dispose
48
+ rescue => e
49
+ # pd e
50
+ drop_event.doit = false
51
+ end
52
+ end
53
+ }
54
+ }
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,19 @@
1
+ class KlondikeSolitaire
2
+ module View
3
+ class HiddenPlayingCard
4
+ include Glimmer::UI::CustomShape
5
+
6
+ body {
7
+ rectangle(0, 0, 49, 79, 15, 15) {
8
+ background :red
9
+
10
+ # border
11
+ rectangle(0, 0, 49, 79, 15, 15) {
12
+ foreground :black
13
+ }
14
+ }
15
+ }
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ class KlondikeSolitaire
2
+ module View
3
+ class PlayingCard
4
+ include Glimmer::UI::CustomShape
5
+
6
+ options :card_x, :card_y, :model, :parent_pile
7
+
8
+ before_body {
9
+ self.card_x ||= 0
10
+ self.card_y ||= 0
11
+ }
12
+
13
+ body {
14
+ rectangle(card_x, card_y, 49, 79, 15, 15) {
15
+ background model.hidden ? :red : :white
16
+
17
+ # border
18
+ rectangle(0, 0, 49, 79, 15, 15) {
19
+ foreground :black
20
+ }
21
+
22
+ unless model.hidden?
23
+ text {
24
+ string model ? "#{model.rank} #{model.suit.to_s[0].upcase}" : ""
25
+ x 5
26
+ y 5
27
+ foreground model ? model.color : :transparent
28
+ }
29
+ end
30
+ }
31
+ }
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ require_relative 'dealing_pile'
2
+ require_relative 'dealt_pile'
3
+ require_relative 'column_pile'
4
+ require_relative 'foundation_pile'
5
+
6
+ require_relative '../model/game'
7
+
8
+ class KlondikeSolitaire
9
+ module View
10
+ class Tableau
11
+ include Glimmer::UI::CustomWidget
12
+
13
+ option :game
14
+
15
+ body {
16
+ canvas {
17
+ background :dark_green
18
+
19
+ # row 1
20
+ @foundation_piles = Model::PlayingCard::SUITS.each_with_index.map do |suit, i|
21
+ foundation_pile(pile_x: i*(PLAYING_CARD_WIDTH + PLAYING_CARD_SPACING), pile_y: 0, game: game, suit: suit)
22
+ end
23
+ @dealt_pile = dealt_pile(pile_x: 5*(PLAYING_CARD_WIDTH + PLAYING_CARD_SPACING), pile_y: 0, model: game.dealt_pile)
24
+ @dealing_pile = dealing_pile(pile_x: 6*(PLAYING_CARD_WIDTH + PLAYING_CARD_SPACING), pile_y: 0, model: game.dealing_pile)
25
+
26
+ # row 2
27
+ @column_piles = 7.times.map do |n|
28
+ column_pile(pile_x: n*(PLAYING_CARD_WIDTH + PLAYING_CARD_SPACING), pile_y: PLAYING_CARD_HEIGHT + PLAYING_CARD_SPACING, model: game.column_piles[n])
29
+ end
30
+
31
+ on_mouse_up do |event|
32
+ if @dealing_pile.body_root.include?(event.x, event.y)
33
+ game.dealing_pile.deal!
34
+ end
35
+ end
36
+ }
37
+ }
38
+
39
+ end
40
+ end
41
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-swt
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.20.13.7
4
+ version: 4.20.13.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
@@ -545,6 +545,22 @@ files:
545
545
  - samples/elaborate/contact_manager/contact.rb
546
546
  - samples/elaborate/contact_manager/contact_manager_presenter.rb
547
547
  - samples/elaborate/contact_manager/contact_repository.rb
548
+ - samples/elaborate/klondike_solitaire.rb
549
+ - samples/elaborate/klondike_solitaire/model/column_pile.rb
550
+ - samples/elaborate/klondike_solitaire/model/dealing_pile.rb
551
+ - samples/elaborate/klondike_solitaire/model/dealt_pile.rb
552
+ - samples/elaborate/klondike_solitaire/model/foundation_pile.rb
553
+ - samples/elaborate/klondike_solitaire/model/game.rb
554
+ - samples/elaborate/klondike_solitaire/model/playing_card.rb
555
+ - samples/elaborate/klondike_solitaire/view/action_panel.rb
556
+ - samples/elaborate/klondike_solitaire/view/column_pile.rb
557
+ - samples/elaborate/klondike_solitaire/view/dealing_pile.rb
558
+ - samples/elaborate/klondike_solitaire/view/dealt_pile.rb
559
+ - samples/elaborate/klondike_solitaire/view/empty_playing_card.rb
560
+ - samples/elaborate/klondike_solitaire/view/foundation_pile.rb
561
+ - samples/elaborate/klondike_solitaire/view/hidden_playing_card.rb
562
+ - samples/elaborate/klondike_solitaire/view/playing_card.rb
563
+ - samples/elaborate/klondike_solitaire/view/tableau.rb
548
564
  - samples/elaborate/login.rb
549
565
  - samples/elaborate/mandelbrot_fractal.rb
550
566
  - samples/elaborate/meta_sample.rb