• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vortex-data / vortex / 16578751259

28 Jul 2025 07:46PM UTC coverage: 81.858% (+0.8%) from 81.087%
16578751259

Pull #3992

github

web-flow
Merge 0fe171459 into 1ae560509
Pull Request #3992: feat: teach SparseArray to canonicalize lists

222 of 241 new or added lines in 1 file covered. (92.12%)

495 existing lines in 40 files now uncovered.

43529 of 53176 relevant lines covered (81.86%)

169875.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.27
/vortex-array/src/arrays/varbinview/mod.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
use std::fmt::{Debug, Formatter};
5
use std::ops::Range;
6
use std::sync::Arc;
7

8
use static_assertions::{assert_eq_align, assert_eq_size};
9
use vortex_buffer::{Alignment, Buffer, ByteBuffer};
10
use vortex_dtype::{DType, Nullability};
11
use vortex_error::{VortexResult, VortexUnwrap, vortex_bail, vortex_panic};
12

13
use crate::builders::{ArrayBuilder, VarBinViewBuilder};
14
use crate::stats::{ArrayStats, StatsSetRef};
15
use crate::validity::Validity;
16
use crate::vtable::{
17
    ArrayVTable, CanonicalVTable, NotSupported, VTable, ValidityHelper,
18
    ValidityVTableFromValidityHelper,
19
};
20
use crate::{Canonical, EncodingId, EncodingRef, vtable};
21

22
mod accessor;
23
mod compact;
24
mod compute;
25
mod ops;
26
mod serde;
27

28
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29
#[repr(C, align(8))]
30
pub struct Inlined {
31
    size: u32,
32
    data: [u8; BinaryView::MAX_INLINED_SIZE],
33
}
34

35
impl Inlined {
36
    fn new<const N: usize>(value: &[u8]) -> Self {
911,037✔
37
        let mut inlined = Self {
911,037✔
38
            size: N.try_into().vortex_unwrap(),
911,037✔
39
            data: [0u8; BinaryView::MAX_INLINED_SIZE],
911,037✔
40
        };
911,037✔
41
        inlined.data[..N].copy_from_slice(&value[..N]);
911,037✔
42
        inlined
911,037✔
43
    }
911,037✔
44

45
    #[inline]
46
    pub fn value(&self) -> &[u8] {
20,527,569✔
47
        &self.data[0..(self.size as usize)]
20,527,569✔
48
    }
20,527,569✔
49
}
50

51
#[derive(Clone, Copy, Debug)]
52
#[repr(C, align(8))]
53
pub struct Ref {
54
    size: u32,
55
    prefix: [u8; 4],
56
    buffer_index: u32,
57
    offset: u32,
58
}
59

60
impl Ref {
61
    pub fn new(size: u32, prefix: [u8; 4], buffer_index: u32, offset: u32) -> Self {
4,232,167✔
62
        Self {
4,232,167✔
63
            size,
4,232,167✔
64
            prefix,
4,232,167✔
65
            buffer_index,
4,232,167✔
66
            offset,
4,232,167✔
67
        }
4,232,167✔
68
    }
4,232,167✔
69

70
    #[inline]
71
    pub fn buffer_index(&self) -> u32 {
14,985,138✔
72
        self.buffer_index
14,985,138✔
73
    }
14,985,138✔
74

75
    #[inline]
76
    pub fn offset(&self) -> u32 {
918,670✔
77
        self.offset
918,670✔
78
    }
918,670✔
79

80
    #[inline]
81
    pub fn prefix(&self) -> &[u8; 4] {
918,670✔
82
        &self.prefix
918,670✔
83
    }
918,670✔
84

85
    #[inline]
86
    pub fn to_range(&self) -> Range<usize> {
15,458,430✔
87
        self.offset as usize..(self.offset + self.size) as usize
15,458,430✔
88
    }
15,458,430✔
89
}
90

91
#[derive(Clone, Copy)]
92
#[repr(C, align(16))]
93
pub union BinaryView {
94
    // Numeric representation. This is logically `u128`, but we split it into the high and low
95
    // bits to preserve the alignment.
96
    le_bytes: [u8; 16],
97

98
    // Inlined representation: strings <= 12 bytes
99
    inlined: Inlined,
100

101
    // Reference type: strings > 12 bytes.
102
    _ref: Ref,
103
}
104

105
assert_eq_size!(BinaryView, [u8; 16]);
106
assert_eq_size!(Inlined, [u8; 16]);
107
assert_eq_size!(Ref, [u8; 16]);
108
assert_eq_align!(BinaryView, u128);
109

110
impl BinaryView {
111
    pub const MAX_INLINED_SIZE: usize = 12;
112

113
    /// Create a view from a value, block and offset
114
    ///
115
    /// Depending on the length of the provided value either a new inlined
116
    /// or a reference view will be constructed.
117
    ///
118
    /// Adapted from arrow-rs <https://github.com/apache/arrow-rs/blob/f4fde769ab6e1a9b75f890b7f8b47bc22800830b/arrow-array/src/builder/generic_bytes_view_builder.rs#L524>
119
    /// Explicitly enumerating inlined view produces code that avoids calling generic `ptr::copy_non_interleave` that's slower than explicit stores
120
    #[inline(never)]
121
    pub fn make_view(value: &[u8], block: u32, offset: u32) -> Self {
4,809,200✔
122
        match value.len() {
4,809,200✔
123
            0 => Self {
667,717✔
124
                inlined: Inlined::new::<0>(value),
667,717✔
125
            },
667,717✔
126
            1 => Self {
3,048✔
127
                inlined: Inlined::new::<1>(value),
3,048✔
128
            },
3,048✔
129
            2 => Self {
3,257✔
130
                inlined: Inlined::new::<2>(value),
3,257✔
131
            },
3,257✔
132
            3 => Self {
9,624✔
133
                inlined: Inlined::new::<3>(value),
9,624✔
134
            },
9,624✔
135
            4 => Self {
4,224✔
136
                inlined: Inlined::new::<4>(value),
4,224✔
137
            },
4,224✔
138
            5 => Self {
15,056✔
139
                inlined: Inlined::new::<5>(value),
15,056✔
140
            },
15,056✔
141
            6 => Self {
14,736✔
142
                inlined: Inlined::new::<6>(value),
14,736✔
143
            },
14,736✔
144
            7 => Self {
12,760✔
145
                inlined: Inlined::new::<7>(value),
12,760✔
146
            },
12,760✔
147
            8 => Self {
14,777✔
148
                inlined: Inlined::new::<8>(value),
14,777✔
149
            },
14,777✔
150
            9 => Self {
10,804✔
151
                inlined: Inlined::new::<9>(value),
10,804✔
152
            },
10,804✔
153
            10 => Self {
53,790✔
154
                inlined: Inlined::new::<10>(value),
53,790✔
155
            },
53,790✔
156
            11 => Self {
52,720✔
157
                inlined: Inlined::new::<11>(value),
52,720✔
158
            },
52,720✔
159
            12 => Self {
48,524✔
160
                inlined: Inlined::new::<12>(value),
48,524✔
161
            },
48,524✔
162
            _ => Self {
3,898,163✔
163
                _ref: Ref::new(
3,898,163✔
164
                    u32::try_from(value.len()).vortex_unwrap(),
3,898,163✔
165
                    value[0..4].try_into().vortex_unwrap(),
3,898,163✔
166
                    block,
3,898,163✔
167
                    offset,
3,898,163✔
168
                ),
3,898,163✔
169
            },
3,898,163✔
170
        }
171
    }
4,809,200✔
172

173
    /// Create a new empty view
174
    #[inline]
175
    pub fn empty_view() -> Self {
2,087✔
176
        Self::new_inlined(&[])
2,087✔
177
    }
2,087✔
178

179
    /// Create a new inlined binary view
180
    #[inline]
181
    pub fn new_inlined(value: &[u8]) -> Self {
2,087✔
182
        assert!(
2,087✔
183
            value.len() <= Self::MAX_INLINED_SIZE,
2,087✔
UNCOV
184
            "expected inlined value to be <= 12 bytes, was {}",
×
185
            value.len()
×
186
        );
187

188
        Self::make_view(value, 0, 0)
2,087✔
189
    }
2,087✔
190

191
    #[inline]
192
    pub fn len(&self) -> u32 {
43,230,327✔
193
        unsafe { self.inlined.size }
43,230,327✔
194
    }
43,230,327✔
195

196
    #[inline]
UNCOV
197
    pub fn is_empty(&self) -> bool {
×
198
        self.len() > 0
×
199
    }
×
200

201
    #[inline]
202
    #[allow(clippy::cast_possible_truncation)]
203
    pub fn is_inlined(&self) -> bool {
39,984,477✔
204
        self.len() <= (Self::MAX_INLINED_SIZE as u32)
39,984,477✔
205
    }
39,984,477✔
206

207
    pub fn as_inlined(&self) -> &Inlined {
20,613,661✔
208
        unsafe { &self.inlined }
20,613,661✔
209
    }
20,613,661✔
210

211
    pub fn as_view(&self) -> &Ref {
28,453,897✔
212
        unsafe { &self._ref }
28,453,897✔
213
    }
28,453,897✔
214

215
    pub fn as_u128(&self) -> u128 {
2,950,582✔
216
        // SAFETY: binary view always safe to read as u128 LE bytes
217
        unsafe { u128::from_le_bytes(self.le_bytes) }
2,950,582✔
218
    }
2,950,582✔
219

220
    /// Shifts the buffer reference by the view by a given offset, useful when merging many
221
    /// varbinview arrays into one.
222
    #[inline(always)]
223
    pub fn offset_view(self, offset: u32) -> Self {
392,933✔
224
        if self.is_inlined() {
392,933✔
225
            self
58,929✔
226
        } else {
227
            // Referencing views must have their buffer_index adjusted with new offsets
228
            let view_ref = self.as_view();
334,004✔
229
            Self {
334,004✔
230
                _ref: Ref::new(
334,004✔
231
                    self.len(),
334,004✔
232
                    *view_ref.prefix(),
334,004✔
233
                    offset + view_ref.buffer_index(),
334,004✔
234
                    view_ref.offset(),
334,004✔
235
                ),
334,004✔
236
            }
334,004✔
237
        }
238
    }
392,933✔
239
}
240

241
impl From<u128> for BinaryView {
UNCOV
242
    fn from(value: u128) -> Self {
×
243
        BinaryView {
×
244
            le_bytes: value.to_le_bytes(),
×
245
        }
×
246
    }
×
247
}
248

249
impl Debug for BinaryView {
UNCOV
250
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
×
251
        let mut s = f.debug_struct("BinaryView");
×
252
        if self.is_inlined() {
×
253
            s.field("inline", &"i".to_string());
×
254
        } else {
×
255
            s.field("ref", &"r".to_string());
×
256
        }
×
257
        s.finish()
×
258
    }
×
259
}
260

261
vtable!(VarBinView);
262

263
impl VTable for VarBinViewVTable {
264
    type Array = VarBinViewArray;
265
    type Encoding = VarBinViewEncoding;
266

267
    type ArrayVTable = Self;
268
    type CanonicalVTable = Self;
269
    type OperationsVTable = Self;
270
    type ValidityVTable = ValidityVTableFromValidityHelper;
271
    type VisitorVTable = Self;
272
    type ComputeVTable = NotSupported;
273
    type EncodeVTable = NotSupported;
274
    type SerdeVTable = Self;
275

276
    fn id(_encoding: &Self::Encoding) -> EncodingId {
84,534✔
277
        EncodingId::new_ref("vortex.varbinview")
84,534✔
278
    }
84,534✔
279

280
    fn encoding(_array: &Self::Array) -> EncodingRef {
17,258✔
281
        EncodingRef::new_ref(VarBinViewEncoding.as_ref())
17,258✔
282
    }
17,258✔
283
}
284

285
#[derive(Clone, Debug)]
286
pub struct VarBinViewArray {
287
    dtype: DType,
288
    buffers: Arc<[ByteBuffer]>,
289
    views: Buffer<BinaryView>,
290
    validity: Validity,
291
    stats_set: ArrayStats,
292
}
293

294
#[derive(Clone, Debug)]
295
pub struct VarBinViewEncoding;
296

297
impl VarBinViewArray {
298
    pub fn try_new(
19,607✔
299
        views: Buffer<BinaryView>,
19,607✔
300
        buffers: Arc<[ByteBuffer]>,
19,607✔
301
        dtype: DType,
19,607✔
302
        validity: Validity,
19,607✔
303
    ) -> VortexResult<Self> {
19,607✔
304
        if views.alignment() != Alignment::of::<BinaryView>() {
19,607✔
UNCOV
305
            vortex_bail!("Views must be aligned to a 128 bits");
×
306
        }
19,607✔
307

308
        if !matches!(dtype, DType::Binary(_) | DType::Utf8(_)) {
19,607✔
UNCOV
309
            vortex_bail!(MismatchedTypes: "utf8 or binary", dtype);
×
310
        }
19,607✔
311

312
        if dtype.is_nullable() == (validity == Validity::NonNullable) {
19,607✔
UNCOV
313
            vortex_bail!("incorrect validity {:?}", validity);
×
314
        }
19,607✔
315

316
        Ok(Self {
19,607✔
317
            dtype,
19,607✔
318
            buffers,
19,607✔
319
            views,
19,607✔
320
            validity,
19,607✔
321
            stats_set: Default::default(),
19,607✔
322
        })
19,607✔
323
    }
19,607✔
324

325
    /// Number of raw string data buffers held by this array.
326
    pub fn nbuffers(&self) -> usize {
2,248,891✔
327
        self.buffers.len()
2,248,891✔
328
    }
2,248,891✔
329

330
    /// Access to the primitive views buffer.
331
    ///
332
    /// Variable-sized binary view buffer contain a "view" child array, with 16-byte entries that
333
    /// contain either a pointer into one of the array's owned `buffer`s OR an inlined copy of
334
    /// the string (if the string has 12 bytes or fewer).
335
    #[inline]
336
    pub fn views(&self) -> &Buffer<BinaryView> {
2,361,364✔
337
        &self.views
2,361,364✔
338
    }
2,361,364✔
339

340
    /// Access value bytes at a given index
341
    ///
342
    /// Will return a bytebuffer pointing to the underlying data without performing a copy
343
    #[inline]
344
    pub fn bytes_at(&self, index: usize) -> ByteBuffer {
2,298,602✔
345
        let views = self.views();
2,298,602✔
346
        let view = &views[index];
2,298,602✔
347
        // Expect this to be the common case: strings > 12 bytes.
348
        if !view.is_inlined() {
2,298,602✔
349
            let view_ref = view.as_view();
2,133,047✔
350
            self.buffer(view_ref.buffer_index() as usize)
2,133,047✔
351
                .slice(view_ref.to_range())
2,133,047✔
352
        } else {
353
            // Return access to the range of bytes around it.
354
            views
165,555✔
355
                .clone()
165,555✔
356
                .into_byte_buffer()
165,555✔
357
                .slice_ref(view.as_inlined().value())
165,555✔
358
        }
359
    }
2,298,602✔
360

361
    /// Access one of the backing data buffers.
362
    ///
363
    /// # Panics
364
    ///
365
    /// This method panics if the provided index is out of bounds for the set of buffers provided
366
    /// at construction time.
367
    #[inline]
368
    pub fn buffer(&self, idx: usize) -> &ByteBuffer {
2,221,771✔
369
        if idx >= self.nbuffers() {
2,221,771✔
UNCOV
370
            vortex_panic!(
×
371
                "{idx} buffer index out of bounds, there are {} buffers",
×
372
                self.nbuffers()
×
373
            );
374
        }
2,221,771✔
375
        &self.buffers[idx]
2,221,771✔
376
    }
2,221,771✔
377

378
    /// Iterate over the underlying raw data buffers, not including the views buffer.
379
    #[inline]
380
    pub fn buffers(&self) -> &Arc<[ByteBuffer]> {
39,257✔
381
        &self.buffers
39,257✔
382
    }
39,257✔
383

384
    /// Accumulate an iterable set of values into our type here.
385
    #[allow(clippy::same_name_method)]
386
    pub fn from_iter<T: AsRef<[u8]>, I: IntoIterator<Item = Option<T>>>(
11✔
387
        iter: I,
11✔
388
        dtype: DType,
11✔
389
    ) -> Self {
11✔
390
        let iter = iter.into_iter();
11✔
391
        let mut builder = VarBinViewBuilder::with_capacity(dtype, iter.size_hint().0);
11✔
392

393
        for item in iter {
2,093✔
394
            match item {
2,082✔
395
                None => builder.append_null(),
7✔
396
                Some(v) => builder.append_value(v),
2,075✔
397
            }
398
        }
399

400
        builder.finish_into_varbinview()
11✔
401
    }
11✔
402

403
    pub fn from_iter_str<T: AsRef<str>, I: IntoIterator<Item = T>>(iter: I) -> Self {
13✔
404
        let iter = iter.into_iter();
13✔
405
        let mut builder = VarBinViewBuilder::with_capacity(
13✔
406
            DType::Utf8(Nullability::NonNullable),
13✔
407
            iter.size_hint().0,
13✔
408
        );
409

410
        for item in iter {
56✔
411
            builder.append_value(item.as_ref());
43✔
412
        }
43✔
413

414
        builder.finish_into_varbinview()
13✔
415
    }
13✔
416

417
    pub fn from_iter_nullable_str<T: AsRef<str>, I: IntoIterator<Item = Option<T>>>(
17✔
418
        iter: I,
17✔
419
    ) -> Self {
17✔
420
        let iter = iter.into_iter();
17✔
421
        let mut builder = VarBinViewBuilder::with_capacity(
17✔
422
            DType::Utf8(Nullability::Nullable),
17✔
423
            iter.size_hint().0,
17✔
424
        );
425

426
        for item in iter {
124✔
427
            match item {
107✔
428
                None => builder.append_null(),
29✔
429
                Some(v) => builder.append_value(v.as_ref()),
78✔
430
            }
431
        }
432

433
        builder.finish_into_varbinview()
17✔
434
    }
17✔
435

436
    pub fn from_iter_bin<T: AsRef<[u8]>, I: IntoIterator<Item = T>>(iter: I) -> Self {
2✔
437
        let iter = iter.into_iter();
2✔
438
        let mut builder = VarBinViewBuilder::with_capacity(
2✔
439
            DType::Binary(Nullability::NonNullable),
2✔
440
            iter.size_hint().0,
2✔
441
        );
442

443
        for item in iter {
6✔
444
            builder.append_value(item.as_ref());
4✔
445
        }
4✔
446

447
        builder.finish_into_varbinview()
2✔
448
    }
2✔
449

450
    pub fn from_iter_nullable_bin<T: AsRef<[u8]>, I: IntoIterator<Item = Option<T>>>(
3✔
451
        iter: I,
3✔
452
    ) -> Self {
3✔
453
        let iter = iter.into_iter();
3✔
454
        let mut builder = VarBinViewBuilder::with_capacity(
3✔
455
            DType::Binary(Nullability::Nullable),
3✔
456
            iter.size_hint().0,
3✔
457
        );
458

459
        for item in iter {
34✔
460
            match item {
31✔
461
                None => builder.append_null(),
11✔
462
                Some(v) => builder.append_value(v.as_ref()),
20✔
463
            }
464
        }
465

466
        builder.finish_into_varbinview()
3✔
467
    }
3✔
468
}
469

470
impl ArrayVTable<VarBinViewVTable> for VarBinViewVTable {
471
    fn len(array: &VarBinViewArray) -> usize {
2,647,134✔
472
        array.views.len()
2,647,134✔
473
    }
2,647,134✔
474

475
    fn dtype(array: &VarBinViewArray) -> &DType {
189,273✔
476
        &array.dtype
189,273✔
477
    }
189,273✔
478

479
    fn stats(array: &VarBinViewArray) -> StatsSetRef<'_> {
149,312✔
480
        array.stats_set.to_ref(array.as_ref())
149,312✔
481
    }
149,312✔
482
}
483

484
impl ValidityHelper for VarBinViewArray {
485
    fn validity(&self) -> &Validity {
2,500,537✔
486
        &self.validity
2,500,537✔
487
    }
2,500,537✔
488
}
489

490
impl CanonicalVTable<VarBinViewVTable> for VarBinViewVTable {
491
    fn canonicalize(array: &VarBinViewArray) -> VortexResult<Canonical> {
24,959✔
492
        Ok(Canonical::VarBinView(array.clone()))
24,959✔
493
    }
24,959✔
494

495
    fn append_to_builder(
5,283✔
496
        array: &VarBinViewArray,
5,283✔
497
        builder: &mut dyn ArrayBuilder,
5,283✔
498
    ) -> VortexResult<()> {
5,283✔
499
        builder.extend_from_array(array.as_ref())
5,283✔
500
    }
5,283✔
501
}
502

503
impl<'a> FromIterator<Option<&'a [u8]>> for VarBinViewArray {
UNCOV
504
    fn from_iter<T: IntoIterator<Item = Option<&'a [u8]>>>(iter: T) -> Self {
×
505
        Self::from_iter_nullable_bin(iter)
×
506
    }
×
507
}
508

509
impl FromIterator<Option<Vec<u8>>> for VarBinViewArray {
UNCOV
510
    fn from_iter<T: IntoIterator<Item = Option<Vec<u8>>>>(iter: T) -> Self {
×
511
        Self::from_iter_nullable_bin(iter)
×
512
    }
×
513
}
514

515
impl FromIterator<Option<String>> for VarBinViewArray {
UNCOV
516
    fn from_iter<T: IntoIterator<Item = Option<String>>>(iter: T) -> Self {
×
517
        Self::from_iter_nullable_str(iter)
×
518
    }
×
519
}
520

521
impl<'a> FromIterator<Option<&'a str>> for VarBinViewArray {
522
    fn from_iter<T: IntoIterator<Item = Option<&'a str>>>(iter: T) -> Self {
6✔
523
        Self::from_iter_nullable_str(iter)
6✔
524
    }
6✔
525
}
526

527
#[cfg(test)]
528
mod test {
529
    use vortex_scalar::Scalar;
530

531
    use crate::arrays::varbinview::{BinaryView, VarBinViewArray};
532
    use crate::{Array, Canonical, IntoArray};
533

534
    #[test]
535
    pub fn varbin_view() {
1✔
536
        let binary_arr =
1✔
537
            VarBinViewArray::from_iter_str(["hello world", "hello world this is a long string"]);
1✔
538
        assert_eq!(binary_arr.len(), 2);
1✔
539
        assert_eq!(
1✔
540
            binary_arr.scalar_at(0).unwrap(),
1✔
541
            Scalar::from("hello world")
1✔
542
        );
543
        assert_eq!(
1✔
544
            binary_arr.scalar_at(1).unwrap(),
1✔
545
            Scalar::from("hello world this is a long string")
1✔
546
        );
547
    }
1✔
548

549
    #[test]
550
    pub fn slice_array() {
1✔
551
        let binary_arr =
1✔
552
            VarBinViewArray::from_iter_str(["hello world", "hello world this is a long string"])
1✔
553
                .slice(1, 2)
1✔
554
                .unwrap();
1✔
555
        assert_eq!(
1✔
556
            binary_arr.scalar_at(0).unwrap(),
1✔
557
            Scalar::from("hello world this is a long string")
1✔
558
        );
559
    }
1✔
560

561
    #[test]
562
    pub fn flatten_array() {
1✔
563
        let binary_arr = VarBinViewArray::from_iter_str(["string1", "string2"]);
1✔
564

565
        let flattened = binary_arr.to_canonical().unwrap();
1✔
566
        assert!(matches!(flattened, Canonical::VarBinView(_)));
1✔
567

568
        let var_bin = flattened.into_varbinview().unwrap().into_array();
1✔
569
        assert_eq!(var_bin.scalar_at(0).unwrap(), Scalar::from("string1"));
1✔
570
        assert_eq!(var_bin.scalar_at(1).unwrap(), Scalar::from("string2"));
1✔
571
    }
1✔
572

573
    #[test]
574
    pub fn binary_view_size_and_alignment() {
1✔
575
        assert_eq!(size_of::<BinaryView>(), 16);
1✔
576
        assert_eq!(align_of::<BinaryView>(), 16);
1✔
577
    }
1✔
578
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc