min_max 0.1.1 → 0.1.3

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: 80798043e91a2c00c6bda06b9cee1fe9544d9eb57c38d2d1ef41c4147614ff80
4
- data.tar.gz: 7394b9168a389e57917780169a0a2574ea5982a4a373c67c36770bc893dfae75
3
+ metadata.gz: 5b1020f3ac8e632e3b2b4d99318a78edf48a06d3099e5812637d8dfd5fdf1623
4
+ data.tar.gz: b774055ca657edf4a01712a71020cbb55df034e38f3db676b0c85484ae1f155e
5
5
  SHA512:
6
- metadata.gz: 5c746c1cbdba8f6e5e752949145bd2604eefa14b75a5c5cb6b6b1a0c81eaaa75538451438cc001769336cbdf9d2e118a2c2c9a397b3d6ea00ce70f37227de576
7
- data.tar.gz: 172aa5d4652493bcfbcd92bbad0ffbd06c72910c63ddf7c59e665ed017d300ba453d18953983c44e95fb5362e4c37ebfad5d79c4167e3736deed47ebc32e0f74
6
+ metadata.gz: 2c7a1e0c3893382526f5c94c488618a3d01b7e19aa3a6d1b3cfc0aa012ede494bfb033c1b9544224bcfa3f9147d3d96779d11c83f2723a384c36109c5f837dba
7
+ data.tar.gz: 4c60344475780f72a7369cac4fc0a22e156750fee690b326a2cbc9b6d1c492446f05dbdda5e39910e9f9549b848730ade850fda8e282d418ba1fa0e8e8c19793
data/Cargo.lock CHANGED
@@ -13,16 +13,16 @@ dependencies = [
13
13
 
14
14
  [[package]]
15
15
  name = "bindgen"
16
- version = "0.66.1"
16
+ version = "0.69.4"
17
17
  source = "registry+https://github.com/rust-lang/crates.io-index"
18
- checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7"
18
+ checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
19
19
  dependencies = [
20
20
  "bitflags",
21
21
  "cexpr",
22
22
  "clang-sys",
23
+ "itertools",
23
24
  "lazy_static",
24
25
  "lazycell",
25
- "peeking_take_while",
26
26
  "proc-macro2",
27
27
  "quote",
28
28
  "regex",
@@ -63,12 +63,27 @@ dependencies = [
63
63
  "libloading",
64
64
  ]
65
65
 
66
+ [[package]]
67
+ name = "either"
68
+ version = "1.10.0"
69
+ source = "registry+https://github.com/rust-lang/crates.io-index"
70
+ checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
71
+
66
72
  [[package]]
67
73
  name = "glob"
68
74
  version = "0.3.1"
69
75
  source = "registry+https://github.com/rust-lang/crates.io-index"
70
76
  checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
71
77
 
78
+ [[package]]
79
+ name = "itertools"
80
+ version = "0.12.1"
81
+ source = "registry+https://github.com/rust-lang/crates.io-index"
82
+ checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
83
+ dependencies = [
84
+ "either",
85
+ ]
86
+
72
87
  [[package]]
73
88
  name = "lazy_static"
74
89
  version = "1.4.0"
@@ -139,6 +154,7 @@ dependencies = [
139
154
  "lazy_static",
140
155
  "magnus",
141
156
  "min-max-heap",
157
+ "rb-sys",
142
158
  ]
143
159
 
144
160
  [[package]]
@@ -157,12 +173,6 @@ dependencies = [
157
173
  "minimal-lexical",
158
174
  ]
159
175
 
160
- [[package]]
161
- name = "peeking_take_while"
162
- version = "0.1.2"
163
- source = "registry+https://github.com/rust-lang/crates.io-index"
164
- checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
165
-
166
176
  [[package]]
167
177
  name = "proc-macro2"
168
178
  version = "1.0.66"
@@ -183,18 +193,18 @@ dependencies = [
183
193
 
184
194
  [[package]]
185
195
  name = "rb-sys"
186
- version = "0.9.81"
196
+ version = "0.9.89"
187
197
  source = "registry+https://github.com/rust-lang/crates.io-index"
188
- checksum = "a57240b308b155b09dce81e32829966a99f52d1088b45957e4283e526c5317a1"
198
+ checksum = "0d197f2c03751ef006f29d593d22aa9068c9c358e04ca503afea0329c366147c"
189
199
  dependencies = [
190
200
  "rb-sys-build",
191
201
  ]
192
202
 
193
203
  [[package]]
194
204
  name = "rb-sys-build"
195
- version = "0.9.81"
205
+ version = "0.9.89"
196
206
  source = "registry+https://github.com/rust-lang/crates.io-index"
197
- checksum = "f24ce877a4c5d07f06f6aa6fec3ac95e4b357b9f73b0f5445d8cbb7266d410e8"
207
+ checksum = "2b50caf8fd028f12abe00d6debe2ae2adf6202c9ca3caa59487eda710d90fa28"
198
208
  dependencies = [
199
209
  "bindgen",
200
210
  "lazy_static",
@@ -10,6 +10,7 @@ publish = false
10
10
  crate-type = ["cdylib"]
11
11
 
12
12
  [dependencies]
13
- magnus = { version = "0.6.1" }
13
+ magnus = { version = "0.6.1"}
14
14
  min-max-heap = "1.3.0"
15
15
  lazy_static = "1.4.0"
16
+ rb-sys = { version = "0.9.89", features=["stable-api-compiled-fallback"]}
@@ -1,4 +1,3 @@
1
- use magnus::block::Proc;
2
1
  use magnus::scan_args::scan_args;
3
2
  use magnus::value::{BoxValue, ReprValue};
4
3
  use magnus::{
@@ -7,7 +6,7 @@ use magnus::{
7
6
  prelude::*,
8
7
  Error, IntoValue, RArray, Ruby, Value,
9
8
  };
10
- use magnus::{eval, DataTypeFunctions, RHash, RString, TypedData};
9
+ use magnus::{DataTypeFunctions, Integer, TypedData};
11
10
  use min_max_heap::MinMaxHeap;
12
11
  use std::cell::RefCell;
13
12
  use std::collections::HashMap;
@@ -36,45 +35,6 @@ lazy_static! {
36
35
  static ref MEMORY: MEM = MEM::new();
37
36
  }
38
37
 
39
- fn get_rb_obj(key: i64) -> Option<Value> {
40
- let binding = (*MEMORY).0.read().unwrap();
41
- let v = binding.get(&key).unwrap();
42
- Some(**v)
43
- }
44
-
45
- fn pop_rb_obj(key: i64) -> Option<Value> {
46
- let binding = (*MEMORY).1.read().unwrap();
47
- let mut count = binding.get(&key).unwrap().borrow_mut();
48
- if *count == 0 {
49
- return None;
50
- }
51
- *count -= 1;
52
- let res = if *count == 0 {
53
- let val = (*MEMORY).0.write().unwrap().remove(&key).unwrap();
54
- Some(*val)
55
- } else {
56
- let binding = (*MEMORY).0.read().unwrap();
57
- let v = binding.get(&key).unwrap();
58
- Some(**v)
59
- };
60
- res
61
- }
62
-
63
- fn push_rb_obj(key: i64, value: Value) -> i64 {
64
- let mut binding = (*MEMORY).1.write().unwrap();
65
- let mut count = binding.entry(key).or_insert(RefCell::new(0)).borrow_mut();
66
-
67
- *count += 1;
68
- if *count == 1 {
69
- (*MEMORY)
70
- .0
71
- .write()
72
- .unwrap()
73
- .insert(key, BoxValue::new(value));
74
- };
75
- return key;
76
- }
77
-
78
38
  impl PartialOrd for PriorityOrderableValue {
79
39
  fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
80
40
  Some(self.cmp(other))
@@ -95,9 +55,7 @@ impl PartialEq for PriorityOrderableValue {
95
55
  fn eq(&self, other: &Self) -> bool {
96
56
  match (self, other) {
97
57
  (PriorityOrderableValue(p1, v1), PriorityOrderableValue(p2, v2)) => {
98
- let v1_obj = get_rb_obj(*v1).unwrap();
99
- let v2_obj = get_rb_obj(*v2).unwrap();
100
- p1.eq(p2) && (v1_obj).eql(v2_obj).unwrap_or_default()
58
+ p1.eq(p2) && (v1).eq(v2)
101
59
  }
102
60
  }
103
61
  }
@@ -108,49 +66,36 @@ unsafe impl Send for RubyMinMaxHeap {}
108
66
  #[magnus(class = "MinMax", size, free_immediately, mark)]
109
67
  struct RubyMinMaxHeap {
110
68
  heap: Arc<RefCell<MinMaxHeap<PriorityOrderableValue>>>,
111
- priority_proc: Arc<Proc>,
112
69
  }
113
70
 
114
71
  impl RubyMinMaxHeap {
115
- fn new(args: &[Value]) -> Result<Self, Error> {
116
- let args = scan_args::<(), (), (), (), RHash, Option<Proc>>(args)?;
117
- let prc: Option<Proc> = args.block;
118
-
72
+ fn new() -> Result<Self, Error> {
119
73
  Ok(RubyMinMaxHeap {
120
74
  heap: Arc::new(RefCell::new(MinMaxHeap::new())),
121
- priority_proc: prc
122
- .unwrap_or_else(|| {
123
- let value: Value =
124
- eval("Proc.new {|x| x.respond_to?(:priority) ? x.priority : x.to_i }")
125
- .unwrap();
126
- Proc::from_value(value).unwrap()
127
- })
128
- .into(),
129
75
  })
130
76
  }
131
77
 
132
- fn push(&self, value: &[Value]) -> Result<(), Error> {
78
+ fn push(&self, values: RArray) -> Result<(), Error> {
133
79
  let mut hp = self.heap.borrow_mut();
134
- value.iter().for_each(|v| {
135
- let priority: i64 = (*self.priority_proc).call([*v]).unwrap_or_default();
136
- let key = v.hash().unwrap().to_i64().unwrap();
137
- hp.push(PriorityOrderableValue(priority, push_rb_obj(key, *v)));
80
+ let values_vec = values.to_vec::<(i64, i64)>().unwrap();
81
+ values_vec.into_iter().for_each(|(priority, key)| {
82
+ hp.push(PriorityOrderableValue(priority, key));
138
83
  });
139
84
  Ok(())
140
85
  }
141
86
 
142
- fn peek_max(&self) -> Result<Option<Value>, Error> {
87
+ fn peek_max(&self) -> Result<Option<i64>, Error> {
143
88
  let hp = self.heap.borrow();
144
89
  match hp.peek_max() {
145
- Some(PriorityOrderableValue(_, value)) => Ok(get_rb_obj(*value)),
90
+ Some(PriorityOrderableValue(_, value)) => Ok(Some(*value)),
146
91
  _ => Ok(None),
147
92
  }
148
93
  }
149
94
 
150
- fn peek_min(&self) -> Result<Option<Value>, Error> {
95
+ fn peek_min(&self) -> Result<Option<i64>, Error> {
151
96
  let hp = self.heap.borrow();
152
97
  match hp.peek_min() {
153
- Some(PriorityOrderableValue(_, value)) => Ok(get_rb_obj(*value)),
98
+ Some(PriorityOrderableValue(_, value)) => Ok(Some(*value)),
154
99
  _ => Ok(None),
155
100
  }
156
101
  }
@@ -163,20 +108,20 @@ impl RubyMinMaxHeap {
163
108
  let mut result = vec![];
164
109
  for _ in 0..c {
165
110
  match { self.heap.borrow_mut() }.pop_max() {
166
- Some(PriorityOrderableValue(_, value)) => {
167
- result.push(pop_rb_obj(value).unwrap())
168
- }
111
+ Some(PriorityOrderableValue(_, value)) => result.push(Integer::from_i64(value)),
169
112
  _ => break,
170
113
  }
171
114
  }
172
115
  let ary = RArray::new();
173
116
  ary.cat(&result)?;
174
- Ok(Some(ary.into_value()))
117
+ Ok(Some(ary.as_value()))
175
118
  } else {
176
119
  let mut hp = self.heap.borrow_mut();
177
120
  let val = hp.pop_max();
178
121
  match val {
179
- Some(PriorityOrderableValue(_, value)) => Ok(pop_rb_obj(value)),
122
+ Some(PriorityOrderableValue(_, value)) => {
123
+ Ok(Some(Integer::from_i64(value).as_value()))
124
+ }
180
125
  _ => Ok(None),
181
126
  }
182
127
  }
@@ -189,19 +134,21 @@ impl RubyMinMaxHeap {
189
134
  if let Some(c) = count {
190
135
  let mut result = vec![];
191
136
  for _ in 0..c {
192
- match { self.heap.borrow_mut().pop_min() } {
193
- Some(PriorityOrderableValue(_, value)) => {
194
- result.push(pop_rb_obj(value).unwrap())
195
- }
137
+ match { self.heap.borrow_mut() }.pop_min() {
138
+ Some(PriorityOrderableValue(_, value)) => result.push(Integer::from_i64(value)),
196
139
  _ => break,
197
140
  }
198
141
  }
199
142
  let ary = RArray::new();
200
143
  ary.cat(&result)?;
201
- Ok(Some(ary.into_value()))
144
+ Ok(Some(ary.as_value()))
202
145
  } else {
203
- match { self.heap.borrow_mut().pop_min() } {
204
- Some(PriorityOrderableValue(_, value)) => Ok(pop_rb_obj(value)),
146
+ let mut hp = self.heap.borrow_mut();
147
+ let val = hp.pop_min();
148
+ match val {
149
+ Some(PriorityOrderableValue(_, value)) => {
150
+ Ok(Some(Integer::from_i64(value).as_value()))
151
+ }
205
152
  _ => Ok(None),
206
153
  }
207
154
  }
@@ -224,45 +171,14 @@ impl RubyMinMaxHeap {
224
171
  .into_vec()
225
172
  .into_iter()
226
173
  .map(|orderable_value| match orderable_value {
227
- PriorityOrderableValue(_, value) => get_rb_obj(value).unwrap(),
174
+ PriorityOrderableValue(_, value) => Integer::from_i64(value).as_value(),
228
175
  });
229
176
  Yield::Iter(Box::new(iter))
230
177
  } else {
231
- Yield::Enumerator(self.clone().into_value().enumeratorize("each", ()))
178
+ Yield::Enumerator(self.clone().into_value().enumeratorize("_each", ()))
232
179
  }
233
180
  }
234
181
 
235
- fn to_a(&self) -> Result<RArray, Error> {
236
- let each: Value = self.clone().into_value().funcall("each", ())?;
237
- Ok(each.funcall("to_a", ())?)
238
- }
239
-
240
- fn inspect(&self) -> Result<RString, Error> {
241
- let mut visited = std::collections::HashSet::new();
242
- Ok(self.build_inspect(&mut visited)?)
243
- }
244
-
245
- fn build_inspect(
246
- &self,
247
- visited: &mut std::collections::HashSet<*const Self>,
248
- ) -> Result<RString, Error> {
249
- // Check for circular reference
250
- if !visited.insert(self as *const Self) {
251
- return Ok(RString::new("[Circular Reference Detected]"));
252
- }
253
-
254
- let to_a: Value = self.to_a()?.into_value();
255
- let r: String = match to_a.funcall("inspect", ()) {
256
- Ok(inspect_value) => inspect_value,
257
- Err(_) => return Ok(RString::new("[Error inspecting array]")),
258
- };
259
-
260
- // Ensure the current object is removed from the visited set to allow re-visiting in future calls
261
- visited.remove(&(self as *const Self));
262
-
263
- Ok(RString::new(&format!("MinMax{}", r)))
264
- }
265
-
266
182
  fn to_a_asc(&self) -> Result<RArray, Error> {
267
183
  let ary = RArray::new();
268
184
 
@@ -273,7 +189,7 @@ impl RubyMinMaxHeap {
273
189
  .into_vec_asc()
274
190
  .iter()
275
191
  .map(|orderable_value| match orderable_value {
276
- PriorityOrderableValue(_, value) => get_rb_obj(*value).unwrap(),
192
+ PriorityOrderableValue(_, value) => Integer::from_i64(*value).as_value(),
277
193
  })
278
194
  .collect();
279
195
  ary.cat(&sorted)?;
@@ -290,7 +206,7 @@ impl RubyMinMaxHeap {
290
206
  .into_vec_desc()
291
207
  .iter()
292
208
  .map(|orderable_value| match orderable_value {
293
- PriorityOrderableValue(_, value) => get_rb_obj(*value).unwrap(),
209
+ PriorityOrderableValue(_, value) => Integer::from_i64(*value).as_value(),
294
210
  })
295
211
  .collect();
296
212
  ary.cat(&sorted)?;
@@ -305,20 +221,18 @@ impl RubyMinMaxHeap {
305
221
  #[magnus::init]
306
222
  fn init(ruby: &Ruby) -> Result<(), Error> {
307
223
  let rb_c_min_max = define_class("MinMax", ruby.class_object())?;
308
- rb_c_min_max.define_singleton_method("new", function!(RubyMinMaxHeap::new, -1))?;
309
- rb_c_min_max.define_method("_push", method!(RubyMinMaxHeap::push, -1))?;
224
+ rb_c_min_max.define_singleton_method("_new", function!(RubyMinMaxHeap::new, 0))?;
225
+ rb_c_min_max.define_method("_push", method!(RubyMinMaxHeap::push, 1))?;
310
226
  rb_c_min_max.define_method("_pop_max", method!(RubyMinMaxHeap::pop_max, -1))?;
311
227
  rb_c_min_max.define_method("_pop_min", method!(RubyMinMaxHeap::pop_min, -1))?;
312
228
  rb_c_min_max.define_method("empty?", method!(RubyMinMaxHeap::is_empty, 0))?;
313
- rb_c_min_max.define_method("each", method!(RubyMinMaxHeap::each, 0))?;
314
- rb_c_min_max.define_method("peek_min", method!(RubyMinMaxHeap::peek_min, 0))?;
315
- rb_c_min_max.define_method("peek_max", method!(RubyMinMaxHeap::peek_max, 0))?;
316
- rb_c_min_max.define_method("to_a", method!(RubyMinMaxHeap::to_a, 0))?;
317
- rb_c_min_max.define_method("to_a_asc", method!(RubyMinMaxHeap::to_a_asc, 0))?;
318
- rb_c_min_max.define_method("to_a_desc", method!(RubyMinMaxHeap::to_a_desc, 0))?;
229
+ rb_c_min_max.define_method("_each", method!(RubyMinMaxHeap::each, 0))?;
230
+ rb_c_min_max.define_method("_peek_min", method!(RubyMinMaxHeap::peek_min, 0))?;
231
+ rb_c_min_max.define_method("_peek_max", method!(RubyMinMaxHeap::peek_max, 0))?;
232
+ rb_c_min_max.define_method("_to_a_asc", method!(RubyMinMaxHeap::to_a_asc, 0))?;
233
+ rb_c_min_max.define_method("_to_a_desc", method!(RubyMinMaxHeap::to_a_desc, 0))?;
319
234
  rb_c_min_max.define_method("clear", method!(RubyMinMaxHeap::clear, 0))?;
320
235
  rb_c_min_max.define_method("size", method!(RubyMinMaxHeap::size, 0))?;
321
236
  rb_c_min_max.define_method("length", method!(RubyMinMaxHeap::size, 0))?;
322
- rb_c_min_max.define_method("inspect", method!(RubyMinMaxHeap::inspect, 0))?;
323
237
  Ok(())
324
238
  }
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class MinMax
4
- VERSION = "0.1.1"
5
-
4
+ VERSION = "0.1.3"
6
5
  end
data/lib/min_max.rb CHANGED
@@ -7,7 +7,26 @@ class MinMax
7
7
  class Error < StandardError; end
8
8
 
9
9
  def self.[](*args, &blk)
10
- new(&blk).tap{|s| s.push(*args) }
10
+ new(*args, &blk)
11
+ end
12
+
13
+ def self.new(*args, &blk)
14
+ self._new.tap{|s|
15
+ s.priority_blk =(blk || proc{|x| (x.respond_to?(:priority) ? x.priority : x.to_i ) rescue 0})
16
+ s.push(*args)
17
+ }
18
+ end
19
+
20
+ def priority_blk=(bll)
21
+ @priority_blk = bll
22
+ end
23
+
24
+ def storage
25
+ @storage ||= Hash.new
26
+ end
27
+
28
+ def counts
29
+ @counts ||= Hash.new(0)
11
30
  end
12
31
 
13
32
  def mtx
@@ -15,19 +34,82 @@ class MinMax
15
34
  end
16
35
 
17
36
  def push(*args)
18
- mtx.synchronize { _push(*args) }
37
+ mtx.synchronize do
38
+ mapped = args.map do |a|
39
+ counts[a.hash] += 1
40
+ storage[a.hash] = a
41
+ [
42
+ @priority_blk.call(a),
43
+ a.hash
44
+ ]
45
+ end
46
+ _push(mapped)
47
+ end
48
+ self
19
49
  end
20
50
 
21
51
  def add(*args)
22
- mtx.synchronize { _push(*args) }
52
+ push(*args)
23
53
  end
24
54
 
25
55
  def pop_max(*args)
26
- mtx.synchronize { _pop_max(*args) }
56
+ mtx.synchronize {
57
+ popped = _pop_max(*args)
58
+ popped.kind_of?(Array) ? popped.map{|p| retrieve(p) } : retrieve(popped)
59
+ }
27
60
  end
28
61
 
29
62
  def pop_min(*args)
30
- mtx.synchronize { _pop_min(*args) }
63
+ mtx.synchronize {
64
+ popped = _pop_min(*args)
65
+ popped.kind_of?(Array) ? popped.map{|p| retrieve(p) } : retrieve(popped)
66
+ }
67
+ end
68
+
69
+ def retrieve(hash, remove=true)
70
+ if remove
71
+ if (counts[hash] -= 1) == 0
72
+ storage.delete(hash)
73
+ else
74
+ storage[hash]
75
+ end
76
+ else
77
+ storage[hash]
78
+ end
79
+ end
80
+
81
+ def peek_min(*args)
82
+ peeked = _peek_min(*args)
83
+ peeked.kind_of?(Array) ? peeked.map{|p| retrieve(p, false) } : retrieve(popped, false)
84
+ end
85
+
86
+ def peek_max(*args)
87
+ peeked = _peek_max(*args)
88
+ peeked.kind_of?(Array) ? peeked.map{|p| retrieve(p, false) } : retrieve(popped, false)
89
+ end
90
+
91
+ def each(*args, &blk)
92
+ if block_given?
93
+ mtx.synchronize { _each(*args).map{|p| blk[retrieve(p, false)] } }
94
+ else
95
+ to_enum(:each, *args)
96
+ end
97
+ end
98
+
99
+ def to_a
100
+ each.to_a
101
+ end
102
+
103
+ def to_a_asc
104
+ mtx.synchronize { _to_a_asc.map{|p| retrieve(p, false) } }
105
+ end
106
+
107
+ def to_a_desc
108
+ mtx.synchronize { _to_a_desc.map{|p| retrieve(p, false) } }
109
+ end
110
+
111
+ def inspect
112
+ "MinMax[#{to_a_asc.first(10).map{|v| v.to_s}.join(", ")}#{size > 10 ? ", ..." : ""}]"
31
113
  end
32
114
  end
33
115
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: min_max
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wouter Coppieters
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-24 00:00:00.000000000 Z
11
+ date: 2024-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rb_sys