code: private ValFrame scalar_op_frame(final String str, Frame fr) {
      Frame res = new MRTask() {
        @Override
        public void map(Chunk[] chks, NewChunk[] cress) {
          BufferedString vstr = new BufferedString();
          for (int c = 0; c < chks.length; c++) {
            Chunk chk = chks[c];
            NewChunk cres = cress[c];
            Vec vec = chk.vec();
            // String Vectors: apply str_op as BufferedStrings to all elements
            if (vec.isString()) {
              final BufferedString conStr = new BufferedString(str);
              for (int i = 0; i < chk._len; i++)
                cres.addNum(str_op(conStr, chk.atStr(vstr, i)));
            } else if (vec.isCategorical()) {
              // categorical Vectors: convert string to domain value; apply op (not
              // str_op).  Not sure what the "right" behavior here is, can
              // easily argue that should instead apply str_op to the categorical
              // string domain value - except that this whole operation only
              // makes sense for EQ/NE, and is much faster when just comparing
              // doubles vs comparing strings.
              final double d = (double) ArrayUtils.find(vec.domain(), str);
              for (int i = 0; i < chk._len; i++)
                cres.addNum(op(d, chk.atd(i)));
            } else { // mixing string and numeric
              final double d = op(1, 2); // false or true only
              for (int i = 0; i < chk._len; i++)
                cres.addNum(d);
            }
          }
        }
      }.doAll(fr.numCols(), Vec.T_NUM, fr).outputFrame(fr._names, null);
      return new ValFrame(res);
    }
docs: Auto-widen the scalar to every element of the frame