glimmer 2.2.1 → 2.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +121 -183
- data/VERSION +1 -1
- data/glimmer.gemspec +3 -3
- data/lib/glimmer/data_binding/observable_array.rb +26 -0
- data/lib/glimmer/data_binding/observable_hash.rb +19 -0
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 672161d98054249c5d807ee86ba9209a471fdc7bf1ce6a2a861f2b363493cb13
|
4
|
+
data.tar.gz: 1d811ea1139eda01c8593416669b1088624def2df0fbc3ee9dc9deb992ab8215
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38e7efff7b054c7eb1ebbdc1c32fb6f9df7b19522e17124f6e63076295a0e46e22c8f12b061cfba2a789326c9a2ef1d24921ae2fdb999ab4f6ad9dec22865ee3
|
7
|
+
data.tar.gz: d149a78a300cc1f572d61fa894bb265948ed11fa0ee5b8ba8fcba8f2e3af096dfa492cb7f6b3e51d1dc0f37585491846bdbd17abee335902bc9ab36c40543bb1
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,12 @@
|
|
3
3
|
Related Change Logs:
|
4
4
|
- [glimmer-dsl-swt/CHANGELOG.md](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/CHANGELOG.md)
|
5
5
|
|
6
|
+
### 2.2.2
|
7
|
+
|
8
|
+
- Support auto-notifying on `ObservableArray#replace` observed changes
|
9
|
+
- Support auto-notifying on `ObservableArray#filter!` observed changes explicitly (even if `filter!` aliases `select!`)
|
10
|
+
- Support auto-notifying on `ObservableHash#filter!` observed changes explicitly (even if `filter!` aliases `select!`)
|
11
|
+
|
6
12
|
### 2.2.1
|
7
13
|
|
8
14
|
- Have `ObservableHash` call `notify_observers(key)` upon performing all mutation operations (as expected): `delete`, `delete_if`, `filter!`, `select!`, `keep_if`, `reject!`, `merge!`, `replace`, `shift`, `transform_keys!`, `transform_values!`
|
data/README.md
CHANGED
@@ -210,7 +210,7 @@ end
|
|
210
210
|
### Setup
|
211
211
|
|
212
212
|
Follow these steps to author a [Glimmer](https://rubygems.org/gems/glimmer) DSL:
|
213
|
-
- Add `gem 'glimmer', '~> 2.2.
|
213
|
+
- Add `gem 'glimmer', '~> 2.2.2'` to `Gemfile` and run `bundle` or run `gem install glimmer -v2.2.2` and add `require 'glimmer'`
|
214
214
|
- Create `glimmer/dsl/[dsl_name]/dsl.rb`, which requires and adds all dynamic expressions for the [dsl_name] Glimmer DSL module as per the code shown in the previous section (or [Official DSLs](#official-dsls) as examples)
|
215
215
|
- Create `glimmer/dsl/[dsl_name]/[expresion_name]_expresion.rb` for every [expresion_name] expression needed, whether dynamic or static
|
216
216
|
|
@@ -972,10 +972,10 @@ require 'glimmer-dsl-libui'
|
|
972
972
|
|
973
973
|
include Glimmer
|
974
974
|
|
975
|
-
window('hello world', 300, 200) {
|
975
|
+
window('hello world', 300, 200) {
|
976
976
|
button('Button') {
|
977
977
|
on_clicked do
|
978
|
-
msg_box(
|
978
|
+
msg_box('Information', 'You clicked the button')
|
979
979
|
end
|
980
980
|
}
|
981
981
|
|
@@ -995,223 +995,161 @@ Linux
|
|
995
995
|
![glimmer-dsl-libui-linux-basic-button.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-button.png)
|
996
996
|
![glimmer-dsl-libui-linux-basic-button-msg-box.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-button-msg-box.png)
|
997
997
|
|
998
|
-
######
|
998
|
+
###### Basic Table Progress Bar
|
999
999
|
|
1000
1000
|
```ruby
|
1001
1001
|
require 'glimmer-dsl-libui'
|
1002
1002
|
|
1003
1003
|
include Glimmer
|
1004
1004
|
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
menu_item('Save') {
|
1014
|
-
on_clicked do
|
1015
|
-
file = save_file(MAIN_WINDOW)
|
1016
|
-
puts file unless file.nil?
|
1017
|
-
end
|
1018
|
-
}
|
1019
|
-
|
1020
|
-
quit_menu_item {
|
1021
|
-
on_clicked do
|
1022
|
-
puts 'Bye Bye'
|
1023
|
-
end
|
1024
|
-
}
|
1025
|
-
|
1026
|
-
preferences_menu_item # Can optionally contain an on_clicked listener
|
1027
|
-
}
|
1028
|
-
|
1029
|
-
menu('Edit') {
|
1030
|
-
check_menu_item('Checkable Item_')
|
1031
|
-
separator_menu_item
|
1032
|
-
menu_item('Disabled Item_') {
|
1033
|
-
enabled false
|
1034
|
-
}
|
1035
|
-
}
|
1036
|
-
|
1037
|
-
menu('Help') {
|
1038
|
-
menu_item('Help')
|
1039
|
-
|
1040
|
-
about_menu_item # Can optionally contain an on_clicked listener
|
1041
|
-
}
|
1005
|
+
data = [
|
1006
|
+
['task 1', 0],
|
1007
|
+
['task 2', 15],
|
1008
|
+
['task 3', 100],
|
1009
|
+
['task 4', 75],
|
1010
|
+
['task 5', -1],
|
1011
|
+
]
|
1042
1012
|
|
1043
|
-
|
1044
|
-
margined true
|
1045
|
-
|
1046
|
-
on_closing do
|
1047
|
-
puts 'Bye Bye'
|
1048
|
-
end
|
1049
|
-
|
1013
|
+
window('Task Progress', 300, 200) {
|
1050
1014
|
vertical_box {
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
button('Button') {
|
1055
|
-
stretchy false
|
1056
|
-
|
1057
|
-
on_clicked do
|
1058
|
-
msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')
|
1059
|
-
end
|
1060
|
-
}
|
1061
|
-
|
1062
|
-
checkbox('Checkbox') {
|
1063
|
-
stretchy false
|
1064
|
-
|
1065
|
-
on_toggled do |c|
|
1066
|
-
checked = c.checked == 1
|
1067
|
-
MAIN_WINDOW.title = "Checkbox is #{checked}"
|
1068
|
-
c.text = "I am the checkbox (#{checked})"
|
1069
|
-
end
|
1070
|
-
}
|
1071
|
-
|
1072
|
-
label('Label') { stretchy false }
|
1073
|
-
|
1074
|
-
horizontal_separator { stretchy false }
|
1075
|
-
|
1076
|
-
date_picker { stretchy false }
|
1077
|
-
|
1078
|
-
time_picker { stretchy false }
|
1079
|
-
|
1080
|
-
date_time_picker { stretchy false }
|
1081
|
-
|
1082
|
-
font_button { stretchy false }
|
1083
|
-
|
1084
|
-
color_button { stretchy false }
|
1085
|
-
}
|
1086
|
-
}
|
1087
|
-
|
1088
|
-
vertical_box {
|
1089
|
-
group('Numbers') {
|
1090
|
-
stretchy false
|
1091
|
-
|
1092
|
-
vertical_box {
|
1093
|
-
spinbox(0, 100) {
|
1094
|
-
stretchy false
|
1095
|
-
value 42
|
1096
|
-
|
1097
|
-
on_changed do |s|
|
1098
|
-
puts "New Spinbox value: #{s.value}"
|
1099
|
-
end
|
1100
|
-
}
|
1101
|
-
|
1102
|
-
slider(0, 100) {
|
1103
|
-
stretchy false
|
1104
|
-
|
1105
|
-
on_changed do |s|
|
1106
|
-
v = s.value
|
1107
|
-
puts "New Slider value: #{v}"
|
1108
|
-
@progress_bar.value = v
|
1109
|
-
end
|
1110
|
-
}
|
1111
|
-
|
1112
|
-
@progress_bar = progress_bar { stretchy false }
|
1113
|
-
}
|
1114
|
-
}
|
1115
|
-
|
1116
|
-
group('Lists') {
|
1117
|
-
stretchy false
|
1118
|
-
|
1119
|
-
vertical_box {
|
1120
|
-
combobox {
|
1121
|
-
stretchy false
|
1122
|
-
items 'combobox Item 1', 'combobox Item 2', 'combobox Item 3' # also accepts a single array argument
|
1123
|
-
|
1124
|
-
on_selected do |c|
|
1125
|
-
puts "New combobox selection: #{c.selected}"
|
1126
|
-
end
|
1127
|
-
}
|
1128
|
-
|
1129
|
-
editable_combobox {
|
1130
|
-
stretchy false
|
1131
|
-
items 'Editable Item 1', 'Editable Item 2', 'Editable Item 3' # also accepts a single array argument
|
1132
|
-
}
|
1133
|
-
|
1134
|
-
radio_buttons {
|
1135
|
-
items 'Radio Button 1', 'Radio Button 2', 'Radio Button 3' # also accepts a single array argument
|
1136
|
-
}
|
1137
|
-
}
|
1138
|
-
}
|
1139
|
-
|
1140
|
-
tab {
|
1141
|
-
tab_item('Page 1') {
|
1142
|
-
horizontal_box {
|
1143
|
-
entry {
|
1144
|
-
text 'Please enter your feelings'
|
1015
|
+
table {
|
1016
|
+
text_column('Task')
|
1017
|
+
progress_bar_column('Progress')
|
1145
1018
|
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
tab_item('Page 3') {
|
1158
|
-
horizontal_box
|
1159
|
-
}
|
1160
|
-
}
|
1161
|
-
}
|
1019
|
+
cell_rows data # implicit data-binding
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
button('Mark All As Done') {
|
1023
|
+
stretchy false
|
1024
|
+
|
1025
|
+
on_clicked do
|
1026
|
+
data.each_with_index do |row_data, row|
|
1027
|
+
data[row] = [row_data[0], 100] # automatically updates table due to implicit data-binding
|
1028
|
+
end
|
1029
|
+
end
|
1162
1030
|
}
|
1163
1031
|
}
|
1164
|
-
}
|
1165
|
-
|
1166
|
-
MAIN_WINDOW.show
|
1032
|
+
}.show
|
1167
1033
|
```
|
1168
1034
|
|
1169
1035
|
Mac
|
1170
1036
|
|
1171
|
-
![glimmer-dsl-libui-mac-
|
1037
|
+
![glimmer-dsl-libui-mac-basic-table-progress-bar.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-basic-table-progress-bar.png)
|
1172
1038
|
|
1173
1039
|
Linux
|
1174
1040
|
|
1175
|
-
![glimmer-dsl-libui-linux-
|
1041
|
+
![glimmer-dsl-libui-linux-basic-table-progress-bar.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-basic-table-progress-bar.png)
|
1176
1042
|
|
1177
|
-
######
|
1043
|
+
###### Area Gallery
|
1178
1044
|
|
1179
1045
|
```ruby
|
1180
1046
|
require 'glimmer-dsl-libui'
|
1181
1047
|
|
1182
1048
|
include Glimmer
|
1183
1049
|
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1050
|
+
window('Area Gallery', 400, 400) {
|
1051
|
+
area {
|
1052
|
+
path { # declarative stable path
|
1053
|
+
square(0, 0, 100)
|
1054
|
+
square(100, 100, 400)
|
1055
|
+
|
1056
|
+
fill r: 102, g: 102, b: 204
|
1057
|
+
}
|
1058
|
+
path { # declarative stable path
|
1059
|
+
rectangle(0, 100, 100, 400)
|
1060
|
+
rectangle(100, 0, 400, 100)
|
1061
|
+
|
1062
|
+
fill r: 204, g: 102, b: 204
|
1063
|
+
}
|
1064
|
+
path { # declarative stable path
|
1065
|
+
figure(100, 100) {
|
1066
|
+
line(100, 400)
|
1067
|
+
line(400, 100)
|
1068
|
+
line(400, 400)
|
1191
1069
|
|
1192
|
-
|
1193
|
-
|
1194
|
-
table {
|
1195
|
-
text_column('Animal')
|
1196
|
-
text_column('Description')
|
1070
|
+
closed true
|
1071
|
+
}
|
1197
1072
|
|
1198
|
-
|
1073
|
+
fill r: 202, g: 102, b: 104, a: 0.5
|
1074
|
+
stroke r: 0, g: 0, b: 0
|
1199
1075
|
}
|
1076
|
+
path { # declarative stable path
|
1077
|
+
figure(0, 0) {
|
1078
|
+
bezier(200, 100, 100, 200, 400, 100)
|
1079
|
+
bezier(300, 100, 100, 300, 100, 400)
|
1080
|
+
bezier(100, 300, 300, 100, 400, 400)
|
1081
|
+
|
1082
|
+
closed true
|
1083
|
+
}
|
1084
|
+
|
1085
|
+
fill r: 202, g: 102, b: 204, a: 0.5
|
1086
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
1087
|
+
}
|
1088
|
+
path { # declarative stable path
|
1089
|
+
arc(200, 200, 90, 0, 360, false)
|
1090
|
+
|
1091
|
+
fill r: 202, g: 102, b: 204, a: 0.5
|
1092
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
1093
|
+
}
|
1094
|
+
|
1095
|
+
on_mouse_event do |area_mouse_event|
|
1096
|
+
p area_mouse_event
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
on_mouse_moved do |area_mouse_event|
|
1100
|
+
puts 'moved'
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
on_mouse_down do |area_mouse_event|
|
1104
|
+
puts 'mouse down'
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
on_mouse_up do |area_mouse_event|
|
1108
|
+
puts 'mouse up'
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
on_mouse_drag_started do |area_mouse_event|
|
1112
|
+
puts 'drag started'
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
on_mouse_dragged do |area_mouse_event|
|
1116
|
+
puts 'dragged'
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
on_mouse_dropped do |area_mouse_event|
|
1120
|
+
puts 'dropped'
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
on_mouse_entered do
|
1124
|
+
puts 'entered'
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
on_mouse_exited do
|
1128
|
+
puts 'exited'
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
on_key_event do |area_key_event|
|
1132
|
+
p area_key_event
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
on_key_up do |area_key_event|
|
1136
|
+
puts 'key up'
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
on_key_down do |area_key_event|
|
1140
|
+
puts 'key down'
|
1141
|
+
end
|
1200
1142
|
}
|
1201
|
-
|
1202
|
-
on_closing do
|
1203
|
-
puts 'Bye Bye'
|
1204
|
-
end
|
1205
1143
|
}.show
|
1206
1144
|
```
|
1207
1145
|
|
1208
1146
|
Mac
|
1209
1147
|
|
1210
|
-
![glimmer-dsl-libui-mac-
|
1148
|
+
![glimmer-dsl-libui-mac-area-gallery.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-mac-area-gallery.png)
|
1211
1149
|
|
1212
1150
|
Linux
|
1213
1151
|
|
1214
|
-
![glimmer-dsl-libui-linux-
|
1152
|
+
![glimmer-dsl-libui-linux-area-gallery.png](https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-libui/master/images/glimmer-dsl-libui-linux-area-gallery.png)
|
1215
1153
|
|
1216
1154
|
## Data-Binding Library
|
1217
1155
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.2.
|
1
|
+
2.2.2
|
data/glimmer.gemspec
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: glimmer 2.2.
|
5
|
+
# stub: glimmer 2.2.2 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "glimmer".freeze
|
9
|
-
s.version = "2.2.
|
9
|
+
s.version = "2.2.2"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["AndyMaleh".freeze]
|
14
14
|
s.date = "2021-10-03"
|
15
|
-
s.description = "Glimmer is a Ruby DSL Framework for Ruby GUI and More, consisting of a DSL Engine and an Observable/Observer/Data-Binding Library. Used in the Glimmer DSL for SWT (JRuby Desktop Development GUI Framework), the Glimmer DSL for Tk (Ruby Desktop Development GUI Library), the Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps), the Glimmer DSL for XML (& HTML), and the Glimmer DSL for CSS.".freeze
|
15
|
+
s.description = "Glimmer is a Ruby DSL Framework for Ruby GUI and More, consisting of a DSL Engine and an Observable / Observer / Data-Binding Library (including ObservableModel, ObservableArray, and ObservableHash). Used in the Glimmer DSL for SWT (JRuby Desktop Development GUI Framework), the Glimmer DSL for Tk (Ruby Desktop Development GUI Library), the Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps), the Glimmer DSL for XML (& HTML), and the Glimmer DSL for CSS.".freeze
|
16
16
|
s.email = "andy.am@gmail.com".freeze
|
17
17
|
s.extra_rdoc_files = [
|
18
18
|
"CHANGELOG.md",
|
@@ -237,6 +237,21 @@ module Glimmer
|
|
237
237
|
end
|
238
238
|
end
|
239
239
|
|
240
|
+
def filter!(&block)
|
241
|
+
if block_given?
|
242
|
+
old_array = Array.new(self)
|
243
|
+
super(&block).tap do
|
244
|
+
(old_array - self).each do |old_value|
|
245
|
+
unregister_dependent_observers(old_value)
|
246
|
+
remove_element_observers(old_value)
|
247
|
+
end
|
248
|
+
notify_observers
|
249
|
+
end
|
250
|
+
else
|
251
|
+
super
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
240
255
|
def shuffle!(hash = nil)
|
241
256
|
(hash.nil? ? super() : super(random: hash[:random])).tap { notify_observers }
|
242
257
|
end
|
@@ -294,6 +309,17 @@ module Glimmer
|
|
294
309
|
end
|
295
310
|
end
|
296
311
|
|
312
|
+
def replace(other_array)
|
313
|
+
old_array = Array.new(self)
|
314
|
+
super(other_array).tap do
|
315
|
+
(old_array - self).each do |old_value|
|
316
|
+
unregister_dependent_observers(old_value)
|
317
|
+
remove_element_observers(old_value)
|
318
|
+
end
|
319
|
+
notify_observers
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
297
323
|
def unregister_dependent_observers(old_value)
|
298
324
|
return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
|
299
325
|
property_observer_list.each { |observer| observer.unregister_dependents_with_observable(observer.registration_for(self), old_value) }
|
@@ -226,6 +226,25 @@ module Glimmer
|
|
226
226
|
end
|
227
227
|
end
|
228
228
|
|
229
|
+
def filter!(&block)
|
230
|
+
if block_given?
|
231
|
+
old_hash = self.dup
|
232
|
+
super(&block).tap do |new_hash|
|
233
|
+
deleted_keys = old_hash.keys - new_hash.keys
|
234
|
+
deleted_keys.each do |deleted_key|
|
235
|
+
deleted_value = old_hash[deleted_key]
|
236
|
+
unless deleted_value.nil?
|
237
|
+
unregister_dependent_observers(deleted_key, deleted_value)
|
238
|
+
unregister_dependent_observers(nil, deleted_value)
|
239
|
+
notify_observers(deleted_key)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
else
|
244
|
+
super
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
229
248
|
def keep_if(&block)
|
230
249
|
if block_given?
|
231
250
|
old_hash = self.dup
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glimmer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AndyMaleh
|
@@ -203,11 +203,11 @@ dependencies:
|
|
203
203
|
- !ruby/object:Gem::Version
|
204
204
|
version: '0'
|
205
205
|
description: Glimmer is a Ruby DSL Framework for Ruby GUI and More, consisting of
|
206
|
-
a DSL Engine and an Observable/Observer/Data-Binding Library
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
DSL for CSS.
|
206
|
+
a DSL Engine and an Observable / Observer / Data-Binding Library (including ObservableModel,
|
207
|
+
ObservableArray, and ObservableHash). Used in the Glimmer DSL for SWT (JRuby Desktop
|
208
|
+
Development GUI Framework), the Glimmer DSL for Tk (Ruby Desktop Development GUI
|
209
|
+
Library), the Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop
|
210
|
+
Apps), the Glimmer DSL for XML (& HTML), and the Glimmer DSL for CSS.
|
211
211
|
email: andy.am@gmail.com
|
212
212
|
executables: []
|
213
213
|
extensions: []
|