atome 0.5.6.6.1 → 0.5.6.6.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48cee602f2cd349974871fde44b32bafb512e38eaa9c9b0206f0bbead1336092
4
- data.tar.gz: cd531edc3f602e907a21fab41249021a1e096c5045b41654780927a85bfbe94f
3
+ metadata.gz: 7f9be61ee0a8afe7d2d0945221f3b5939b87c8b580042008b3074af983e82093
4
+ data.tar.gz: d070e19b2b11923efeae91f05c28c0e309ab787c6f93570f44bac6b2d4a2e999
5
5
  SHA512:
6
- metadata.gz: 97920b22233d015e31d819acf7f4ca2dcc9300c24d8a395f99b05d0e6c20d97a60c9604f68423a009dac9adf723c9cea3d463ac6380fb9fc62c32b40cbc40948
7
- data.tar.gz: f736aae0c6cfbe55daf4a9a6083e33eb769ba00d2e129c53001f792335a829614e69cf06ba568c48cfc46e3deec0ca3f8295f02c6be509cc6c6d789ce4c77ab4
6
+ metadata.gz: 3b0e7f9c9fffea9072d6e4d09b91f99b5dc2ee2d465837b77ab7ad9fdaa20f56fd7897bc1befb047e8f81a60751ea1d074122abf30e7cf17dc72eba3109d87bf
7
+ data.tar.gz: 127a3ce37bb809b9e664c5188cdf2f0478624da98f89357f671e5de6af4a5544cb9ee35b99efe305a53e1b26fbb43a53d00a72a6103aff6eb6bfb6677ebcdd48
data/lib/atome/atome.rb CHANGED
@@ -44,8 +44,15 @@ class Atome
44
44
  @int8 = {}
45
45
  @css = {}
46
46
  @aid = identity_generator
47
- Universe.add_to_atomes(@aid, self)
47
+
48
48
  @id = new_atome[:id] || @aid
49
+ Universe.atomes.each do |_aid,atome_f|
50
+ if atome_f.id == @id
51
+ puts "===> no for #{@id}"
52
+ return false
53
+ end
54
+ end
55
+ Universe.add_to_atomes(@aid, self)
49
56
  Universe.id_to_aid(@id, @aid)
50
57
  @type = new_atome[:type] || :element
51
58
  @attached = []
@@ -2,42 +2,15 @@
2
2
 
3
3
  new({ atome: :color, type: :hash })
4
4
 
5
- # new({ post: :color }) do |params|
6
- # puts "====> #{params}"
7
- # params
8
- # end
9
- # new({ pre: :color}) do |params|
10
- # alert "==> pre color params : #{params}"
11
- # end
12
-
13
- # new({ atome: :color, type: :hash })do |params|
14
- # puts "1 #{params}______"
15
- # params
16
- # end
17
-
18
- # new ({post: :color}) do |params|
19
- # # # TODO : hack must call it properly thru renderer
20
- # # params[:affect].each do |affected|
21
- # # grab(affected).html.reset_background
22
- # # end
23
- # end
24
5
  new({ sanitizer: :color }) do |params|
25
- # alert "sanitizer color: #{params}"
26
6
  params = create_color_hash(params) unless params.instance_of? Hash
27
- # if params[:id]
28
- # alert "id is #{params[:id]}"
29
- # end
30
- # the condition below is to prevent the creation of multiple unwanted colors with same property and no ID specified
31
7
  unless params[:id]
32
8
  uniq_value = "#{params[:red].to_s.sub('.', '_')}_#{params[:green].to_s.sub('.', '_')}_#{params[:blue].to_s.sub('.', '_')}_#{params[:alpha].to_s.sub('.', '_')}_#{params[:left].to_s.sub('.', '_')}_#{params[:top].to_s.sub('.', '_')}_#{params[:diffusion].to_s.sub('.', '_')}"
33
- params[:id] = "#{@id}_color_#{uniq_value}".to_sym
9
+ params[:id] = "color_#{uniq_value}".to_sym
34
10
  end
35
11
  params
36
12
  end
37
- # new({ post: :color }) do
38
- #
39
- # # Atome.global_monitoring(self, [:red, :blue, :blue, :alpha, :left, :right, :diffusion], [:variable1, :variable2])
40
- # end
13
+
41
14
  new({ atome: :image })
42
15
  new({ sanitizer: :image }) do |params|
43
16
  unless params.instance_of? Hash
@@ -131,8 +104,6 @@ new({ atome: :vector })
131
104
  new({ atome: :matrix })
132
105
  new({ atome: :atomized, type: :hash })
133
106
 
134
- # new({ atome: :color, type: :model })
135
- # new({ atome: :color, type: :template })
136
107
 
137
108
 
138
109
 
@@ -3,6 +3,7 @@
3
3
  new({ particle: :touch, category: :event, type: :hash, store: false })
4
4
  new({ sanitizer: :touch }) do |params, user_bloc|
5
5
  # TODO: factorise code below
6
+ # alert "touch_code: #{@touch_code}"
6
7
  @touch ||= {}
7
8
  @touch_code ||= {}
8
9
  option = true
@@ -7,20 +7,23 @@ new({ sanitizer: :id }) do |params|
7
7
  # first we sanitize the the id below
8
8
 
9
9
  params = params.to_sym
10
- # # we check id is already assign
11
- # if Universe.atomes[params]
12
- # # we reassign the old id
13
- # puts "the id : #{params} is already used"
14
- # params = @id
15
- # # return false
16
- # else
17
- if @id.to_sym != params
18
- Universe.update_atome_id(params, self, @id)
19
- else
20
- Universe.add_to_atomes(params, self)
21
- end
10
+ # we check id is already assign
11
+ # the condition below is to prevent the creation of multiple unwanted colors with same property and no ID specified
12
+ # if @id.to_sym != params
13
+ # Universe.update_atome_id(params, self, @id)
14
+ # else
15
+ # Universe.add_to_atomes(params, self)
16
+ # end
22
17
 
18
+
19
+ # Universe.atomes.each do |_aid,atome_f|
20
+ #
21
+ # if atome_f.id == params
22
+ # puts "===> no for #{params}"
23
+ # end
24
+ #
23
25
  # end
26
+
24
27
  params
25
28
  end
26
29
  new({ particle: :name, category: :identity, type: :string })
@@ -114,4 +114,6 @@ new({ after: :pattern })do |params|
114
114
  params
115
115
  end
116
116
  # new({ particle: :border, category: :material, type: :int })
117
- new({particle: :fill})
117
+ new({particle: :fill, category: :material, type: :array })
118
+
119
+ new({particle: :opacity, category: :material, type: :int })
@@ -35,7 +35,7 @@ new({ particle: :delete, category: :utility, type: :boolean, render: false }) do
35
35
  id_found = @id.to_sym
36
36
  parent_found = grab(@attach)
37
37
  parent_found.attached.delete(id_found)
38
- Universe.delete(@id)
38
+ Universe.delete(@aid)
39
39
  end
40
40
  elsif params.instance_of? Hash
41
41
 
@@ -105,16 +105,21 @@ class Universe
105
105
  def id_to_aid(id, aid)
106
106
  @atomes_ids[id] = aid
107
107
  end
108
-
109
- def update_atome_id(id, atome, prev_id)
110
- @atomes[id] = atome
111
- @atomes.delete(prev_id)
112
- end
108
+ # def update_atome_id(aid, atome, prev_id)
109
+ # @atomes[id] = atome
110
+ # @atomes.delete(prev_id)
111
+ # end
112
+ # def update_atome_id(id, atome, prev_id)
113
+ # @atomes[id] = atome
114
+ # @atomes.delete(prev_id)
115
+ # end
113
116
 
114
117
  def user_atomes
115
118
  collected_id = []
116
119
  @atomes.each do |id_found, atome_found|
117
- collected_id << id_found unless atome_found.tag && atome_found.tag[:system]
120
+ # collected_id << id_found unless atome_found.tag && atome_found.tag[:system]
121
+ collected_id << atome_found.id unless atome_found.tag && atome_found.tag[:system]
122
+
118
123
  end
119
124
  collected_id
120
125
  end
data/lib/atome/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  # return atome version
4
4
  class Atome
5
- VERSION = '0.5.6.6.1'
5
+ VERSION = '0.5.6.6.5'
6
6
  end
@@ -24,6 +24,7 @@ class HTML
24
24
  @element ||= JS.global[:document].getElementById(id_found.to_s)
25
25
  @id = id_found
26
26
  @original_atome = current_atome
27
+ @touch_removed = {}
27
28
  end
28
29
 
29
30
  def object
@@ -200,7 +201,6 @@ class HTML
200
201
 
201
202
  # alert "hyperedit"
202
203
 
203
-
204
204
  particles_found = particles_found.merge(particles_from_style)
205
205
  current_atome = grab(@id)
206
206
  usr_bloc.call(particles_found)
@@ -496,15 +496,48 @@ class HTML
496
496
  end
497
497
 
498
498
  def fill(params)
499
- atome_path= grab(params[:atome]).path
500
- @element[:style][:backgroundImage] = "url('#{atome_path}')"
501
- @element[:style][:backgroundRepeat] = 'repeat'
502
- # @element[:style][:backgroundPosition] = '0 0, 110px 110px'
503
- # @element[:style][:backgroundPosition] = "99px 0px"
504
- # background-size: auto auto;
505
- # @element[:style][:backgroundSize] = "cover"
506
- @element[:style][:backgroundSize] = "#{params[:width]}px #{params[:height]}px"
499
+ # we remove previous background
500
+ elements_to_remove = @element.getElementsByClassName('background')
501
+
502
+ elements_to_remove = elements_to_remove.to_a
503
+ elements_to_remove.each do |child|
504
+ @element.removeChild(child)
505
+ end
506
+ params.each do |param|
507
+ background_layer = JS.global[:document].createElement("div")
508
+ background_layer[:style][:transform] = "rotate(#{param[:rotate]}deg)" # Applique une rotation de 45 degrés à l'élément
509
+ background_layer[:style][:position] = "absolute"
510
+
511
+ if param[:position]
512
+ background_layer[:style][:top] = "#{param[:position][:x]}px"
513
+ background_layer[:style][:left] = "#{param[:position][:y]}px"
514
+ else
515
+ background_layer[:style][:top] = "0"
516
+ background_layer[:style][:left] = "0"
517
+ end
507
518
 
519
+ if param[:size]
520
+ background_layer[:style][:width] = "#{param[:size][:x]}px"
521
+ background_layer[:style][:height] = "#{param[:size][:y]}px"
522
+ else
523
+ background_layer[:style][:width] = "100%"
524
+ background_layer[:style][:height] = "100%"
525
+ end
526
+
527
+ atome_path = grab(param[:atome]).path
528
+ background_layer[:style][:backgroundImage] = "url('#{atome_path}')"
529
+ background_layer[:style][:backgroundRepeat] = 'repeat'
530
+ background_layer[:className] = 'background'
531
+ background_layer[:style][:opacity] = param[:opacity]
532
+ if param[:repeat]
533
+ img_width = @original_atome.width / param[:repeat][:x]
534
+ img_height = @original_atome.height / param[:repeat][:y]
535
+ background_layer[:style][:backgroundSize] = "#{img_width}px #{img_height}px"
536
+ else
537
+ background_layer[:style][:backgroundSize] = "#{param[:width]}px #{param[:height]}px"
538
+ end
539
+ @element.appendChild(background_layer)
540
+ end
508
541
  end
509
542
 
510
543
  def filter(property, value)
@@ -1048,60 +1081,75 @@ class HTML
1048
1081
  def touch_tap(_option)
1049
1082
  interact = JS.eval("return interact('##{@id}')")
1050
1083
  @touch_tap = @original_atome.instance_variable_get('@touch_code')[:tap]
1051
- interact.on('tap') do |native_event|
1052
- event = Native(native_event)
1053
- # we use .call instead of instance_eval because instance_eval bring the current object as context
1054
- # and it's lead to a problem of context and force the use of grab(:view) when suing atome method such as shape ,
1055
- # group etc..
1056
- @touch_tap.call(event) if @touch_tap.is_a?(Proc)
1084
+ unless @touch_removed[:tap]
1085
+ interact.on('tap') do |native_event|
1086
+ event = Native(native_event)
1087
+ # we use .call instead of instance_eval because instance_eval bring the current object as context
1088
+ # and it's lead to a problem of context and force the use of grab(:view) when suing atome method such as shape ,
1089
+ # group etc..
1090
+ @touch_tap.call(event) if @touch_tap.is_a?(Proc)
1091
+ end
1057
1092
  end
1093
+
1058
1094
  end
1059
1095
 
1060
1096
  def touch_double(_option)
1061
1097
  interact = JS.eval("return interact('##{@id}')")
1062
1098
  @touch_double = @original_atome.instance_variable_get('@touch_code')[:double]
1063
- interact.on('doubletap') do |native_event|
1064
- event = Native(native_event)
1065
- # we use .call instead of instance_eval because instance_eval bring the current object as context
1066
- # and it's lead to a problem of context and force the use of grab(:view) when suing atome method such as shape ,
1067
- # group etc..
1068
- @touch_double.call(event) if @touch_double.is_a?(Proc)
1099
+ unless @touch_removed[:double]
1100
+ interact.on('doubletap') do |native_event|
1101
+ event = Native(native_event)
1102
+ # we use .call instead of instance_eval because instance_eval bring the current object as context
1103
+ # and it's lead to a problem of context and force the use of grab(:view) when suing atome method such as shape ,
1104
+ # group etc..
1105
+ @touch_double.call(event) if @touch_double.is_a?(Proc)
1106
+ end
1069
1107
  end
1108
+
1070
1109
  end
1071
1110
 
1072
1111
  def touch_long(_option)
1073
1112
  @touch_long = @original_atome.instance_variable_get('@touch_code')[:long]
1074
1113
  interact = JS.eval("return interact('##{@id}')")
1075
- interact.on('hold') do |native_event|
1076
- event = Native(native_event)
1077
- # we use .call instead of instance_eval because instance_eval bring the current object as context
1078
- # and it's lead to a problem of context and force the use of grab(:view) when suing atome method such as shape ,
1079
- # group etc..
1080
- @touch_long.call(event) if @touch_long.is_a?(Proc)
1114
+ unless @touch_removed[:long]
1115
+ interact.on('hold') do |native_event|
1116
+ event = Native(native_event)
1117
+ # we use .call instead of instance_eval because instance_eval bring the current object as context
1118
+ # and it's lead to a problem of context and force the use of grab(:view) when suing atome method such as shape ,
1119
+ # group etc..
1120
+ @touch_long.call(event) if @touch_long.is_a?(Proc)
1121
+ end
1081
1122
  end
1123
+
1082
1124
  end
1083
1125
 
1084
1126
  def touch_down(_option)
1085
1127
  @touch_down = @original_atome.instance_variable_get('@touch_code')[:down]
1086
1128
  interact = JS.eval("return interact('##{@id}')")
1087
- interact.on('down') do |native_event|
1088
- event = Native(native_event)
1089
- # we use .call instead of instance_eval because instance_eval bring the current object as context
1090
- # and it's lead to a problem of context and force the use of grab(:view) when suing atome method such as shape ,
1091
- # group etc..
1092
- @touch_down.call(event) if @touch_down.is_a?(Proc)
1129
+ unless @touch_removed[:down]
1130
+ interact.on('down') do |native_event|
1131
+ event = Native(native_event)
1132
+ # we use .call instead of instance_eval because instance_eval bring the current object as context
1133
+ # and it's lead to a problem of context and force the use of grab(:view) when suing atome method such as shape ,
1134
+ # group etc..
1135
+ @touch_down.call(event) if @touch_down.is_a?(Proc)
1136
+ end
1137
+
1093
1138
  end
1094
1139
  end
1095
1140
 
1096
1141
  def touch_up(_option)
1097
- @touch_up = @original_atome.instance_variable_get('@touch_code')[:up]
1098
1142
  interact = JS.eval("return interact('##{@id}')")
1099
- interact.on('up') do |native_event|
1100
- event = Native(native_event)
1101
- # we use .call instead of instance_eval because instance_eval bring the current object as context
1102
- # and it's lead to a problem of context and force the use of grab(:view) when suing atome method such as shape ,
1103
- # group etc..
1104
- @touch_up.call(event) if @touch_up.is_a?(Proc)
1143
+ @touch_up = @original_atome.instance_variable_get('@touch_code')[:up]
1144
+ unless @touch_removed[:up]
1145
+ interact.on('up') do |native_event|
1146
+ event = Native(native_event)
1147
+ # we use .call instead of instance_eval because instance_eval bring the current object as context
1148
+ # and it's lead to a problem of context and force the use of grab(:view) when suing atome method such as shape ,
1149
+ # group etc..
1150
+ @touch_up.call(event) if @touch_up.is_a?(Proc)
1151
+ end
1152
+
1105
1153
  end
1106
1154
  end
1107
1155
 
@@ -1109,15 +1157,25 @@ class HTML
1109
1157
  case option
1110
1158
  when :double
1111
1159
  @touch_double = ''
1160
+ @touch_removed[:double] = true
1112
1161
  when :down
1113
1162
  @touch_down = ''
1163
+ @touch_removed[:down] = true
1114
1164
  when :long
1165
+ @touch_removed[:long] = true
1115
1166
  @touch_long = ''
1116
1167
  when :tap
1168
+ @touch_removed[:tap] = true
1117
1169
  @touch_tap = ''
1118
1170
  when :up
1171
+ @touch_removed[:up] = true
1119
1172
  @touch_up = ''
1120
1173
  else
1174
+ @touch_removed[:double] = true
1175
+ @touch_removed[:down] = true
1176
+ @touch_removed[:long] = true
1177
+ @touch_removed[:tap] = true
1178
+ @touch_removed[:up] = true
1121
1179
  @touch_double = ''
1122
1180
  @touch_down = ''
1123
1181
  @touch_long = ''
@@ -76,4 +76,9 @@ new({ method: :pattern, type: :integer, renderer: :html})
76
76
 
77
77
  new({ method: :fill, renderer: :html }) do |params|
78
78
  html.fill(params)
79
+ end
80
+
81
+ new({ method: :opacity, type: :integer, renderer: :html}) do |value|
82
+ # html.opacity(value)
83
+ html.style('opacity',value)
79
84
  end
@@ -4,4 +4,7 @@
4
4
  # aid is used to provide an unique and persistent id for any atome
5
5
  b=box({ left: 12, id: :the_first_box })
6
6
 
7
- puts " atome aid is : #{ b.aid}"
7
+ puts " atome aid is : #{b.aid}"
8
+ wait 1 do
9
+ hook(b.aid).color(:red)
10
+ end
@@ -1,17 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- b=box({width: 300, height: 333})
3
+ b=box({width: 300, height: 333, color: {alpha: 0}})
4
4
  image({id: :logo,path: 'medias/images/logos/atome.svg', width: 66, left: 555})
5
5
  grab(:black_matter).image({id: :planet,path: 'medias/images/red_planet.png', width: 66,height: 66, left: 555, top: 180})
6
6
 
7
7
 
8
- new({particle: :fill})
9
-
10
- new({ method: :fill, renderer: :html }) do |params|
11
- html.fill(params)
8
+ b.fill([atome: :logo, width: 33, height: 33 ])
9
+ b.overflow(:hidden)
10
+ wait 1 do
11
+ b.fill([atome: :planet, width: 33, height: 33 ])
12
+ wait 1 do
13
+ b.fill([{atome: :planet,repeat: {x: 5, y: 3}}])
14
+ wait 1 do
15
+ b.fill([{atome: :planet,width: 33, height: 33 ,rotate: 33, size: { x: 800,y: 600 }, position: { x:-200,y: -200 } }])
16
+ wait 3 do
17
+ b.fill([{atome: :planet,repeat: {x: 5, y: 3}}, { atome: :logo, width: 33, height: 33 , opacity: 0.3} ])
18
+ end
19
+ end
20
+ end
12
21
  end
13
- b.fill({atome: :logo, width: 33, height: 33 })
14
22
 
15
- wait 1 do
16
- b.fill({atome: :planet, width: 33, height: 33 })
17
- end
23
+ b.drag(true)
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ image({id: :planet,path: 'medias/images/red_planet.png', width: 66,height: 66, left: 33, top: 33})
4
+ b=box({width: 66, height: 66, color: :yellowgreen})
5
+
6
+ wait 1 do
7
+
8
+ b.opacity(0.3)
9
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ color({ id: :creation_layer_col, alpha: 1 })
4
+
5
+ b = box({ top: :auto, bottom: 0, id: :box_tool })
6
+
7
+ b.touch(:down) do
8
+ creation_layer = box({ top: 0, left: 0, id: :creation_layer, width: '100%', height: '100%', apply: :creation_layer_col })
9
+ creation_layer.touch(:down) do |event|
10
+ left_found = event[:pageX].to_i
11
+ top_found = event[:pageY].to_i
12
+ box({ left: left_found, top: top_found ,id: "tutu_#{Universe.atomes.length}", color: :red})
13
+ creation_layer.delete(true)
14
+ creation_layer.touch({ remove: :down })
15
+ puts Universe.atomes.length
16
+ puts "=> #{Universe.user_atomes}"
17
+ end
18
+ end
19
+
20
+ # c= color({ red: 1, id: :toto })
21
+ # # puts c.aid
22
+ # puts Universe.atomes.length
23
+ # wait 0.5 do
24
+ # c= color({ red: 1, id: :toto })
25
+ # # puts c.aid
26
+ # puts Universe.atomes.length
27
+ # end
28
+
29
+ # wait 1 do
30
+ # c= color({ red: 1, id: :toto })
31
+ # puts c.aid
32
+ # puts Universe.atomes.length
33
+ # wait 1 do
34
+ # c= color({ red: 1, id: :toto })
35
+ # puts c.aid
36
+ # puts Universe.atomes.length
37
+ # wait 1 do
38
+ # c= color({ red: 1, id: :toto })
39
+ # puts c.aid
40
+ # puts Universe.atomes.length
41
+ # wait 1 do
42
+ # c= color({ red: 1, id: :toto })
43
+ # puts c.aid
44
+ # puts Universe.atomes.length
45
+ # alert "=> #{Universe.user_atomes}"
46
+ # end
47
+ # end
48
+ # end
49
+ # end
@@ -4,7 +4,10 @@ b = box({ left: 666, color: :blue, smooth: 6, id: :the_box2 })
4
4
 
5
5
  t=text({id: :the_text, data: 'type of touch : ?'})
6
6
 
7
- t.touch(:down) do
7
+ t.touch(:down) do |event|
8
+
9
+ puts event[:pageX]
10
+ puts event[:pageY]
8
11
  b.touch({remove: :down})
9
12
  # b.touch(:remove) # or b.touch(false) to remove all touches bindings
10
13
  t.data('touch down killed')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atome
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.6.6.1
4
+ version: 0.5.6.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean-Eric Godard
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-10 00:00:00.000000000 Z
11
+ date: 2024-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: artoo
@@ -580,6 +580,7 @@ files:
580
580
  - vendor/assets/application/examples/on_resize.rb
581
581
  - vendor/assets/application/examples/on_the_fly_ruby_code_loading.rb
582
582
  - vendor/assets/application/examples/online.rb
583
+ - vendor/assets/application/examples/opacity.rb
583
584
  - vendor/assets/application/examples/over.rb
584
585
  - vendor/assets/application/examples/paint.rb
585
586
  - vendor/assets/application/examples/particles.rb
@@ -611,6 +612,7 @@ files:
611
612
  - vendor/assets/application/examples/terminal.rb
612
613
  - vendor/assets/application/examples/test.rb
613
614
  - vendor/assets/application/examples/text.rb
615
+ - vendor/assets/application/examples/tools.rb
614
616
  - vendor/assets/application/examples/touch.rb
615
617
  - vendor/assets/application/examples/type_mutation.rb
616
618
  - vendor/assets/application/examples/unit.rb