<commit_before>function match(state, matches) {
  // Try to match the type
  let token = state.next();
  let type = token === null ? 'null' : token.type;
  let matched = matches[type];
  if (matched == null) {
    if (matches.else != null) return matches.else(state, token);
    throw new Error('Token error; Expected ' +
      Object.keys(matches).join(',') + ', But received ' + type
    );
  }
  return matched(state, token);
}

function pull(state, type) {
  // Try to match the type
  let token = state.next();
  let tokenType = (token === null ? 'null' : token.type);
  if (tokenType !== type) {
    throw new Error('Token error; Expected ' +
      type + ', But received ' + tokenType
    );
  }
  return token;
}

function pullIf(state, type, then) {
  // Try to match the type
  let token = state.next();
  let tokenType = (token === null ? 'null' : token.type);
  if (tokenType !== type) {
    state.push(token);
    return false;
  }
  if (then != null) then(state, token);
  return token;
}

function main(state) {
  // Loop until we meet null. This looks awkward, but this'll do.
  while (match(state, {
    null: () => false,
    enum: (state) => {
      let data = defineEnum(state);
      state.namespace[getIdentifier(data)] = data;
    },
    struct: (state) => {
      let data = defineStruct(state);
      state.namespace[getIdentifier(data)] = data;
    },
  }) !== false);
}

function defineEnum(state) {
  let data = getName(state);
  let exited = false;
  let index = 0;
  // Pull enum target for structs
  if (pullIf(state, 'parenOpen')) {
    data.typeTarget = getVariable(state);
    if (pullIf(state, 'comma')) {
      data.typeType = getType(state);
    }
    pull(state, 'parenClose');
  }
  data.namespace = {};
  pull(state, 'curlyOpen');
  // Now, pull each character.
  function next() {
    // If curlyClose is reached, escape!
    if (pullIf(state, 'curlyClose')) {
      exited = true;
      return;
    }
    let key, strategy;
    // We have to choose strategy.
    match(state, {
      number: (state, token) => {
        strategy = 'match';
        key = token.value;
        pull(state, 'arrow');
      },
      string: (state, token) => {
        strategy = 'object';
        key = token.value;
        pull(state, 'arrow');
      },
      keyword: (state, token) => {
        // Just continue
        strategy = 'array';
        key = index++;
        state.push(token);
      },
    });
    // Now, pull the struct.
    let value = defineStruct(state, true);
    // Enforce the type mode.
    let dataType = null;
    switch (value.type) {
      case 'structObject':
        dataType = 'enumObject';
        break;
      case 'structArray':
        dataType = 'enumArray';
        break;
    }
    if (data.type != null && dataType != null && data.type !== dataType) {
      throw new Error('Enum data type can\'t be mixed');
    }
    data.type = dataType;
    if (data.strategy == null) {
      data.strategy = strategy;
      // Set up indexes
      switch (strategy) {
        case 'match':
          data.entries = [];
          break;
        case 'object':
          data.entries = {};
          break;
        case 'array':
          data.entries = [];
          break;
      }
    } else if (data.strategy !== strategy) {
      throw new Error('Enum indexing type can\'t be mixed');
    }
    data.namespace[getIdentifier(value)] = value;
    value.enumKey = key;
    switch (strategy) {
      case 'match':
        data.entries.push([key, value]);
        break;
      case 'object':
        data.entries[key] = value;
        break;
      case 'array':
        data.entries.push(value);
        break;
    }
    pullIf(state, 'comma', next);
  }
  next();
  if (data.type == null) data.type = 'enumEmpty';
  if (!exited) pull(state, 'curlyClose');
  return data;
}

function defineStruct(state, allowEmpty = false) {
  let data = getName(state);
  return match(state, {
    else: allowEmpty && ((state, token) => {
      // Just push the token and return the data.
      state.push(token);
      data.type = 'structEmpty';
      data.keys = [];
      return data;
    }),
    curlyOpen: () => {
      data.type = 'structObject';
      data.values = {};
      data.keys = [];
      let exited = false;
      function next() {
        // If curlyClose is reached, escape!
        if (pullIf(state, 'curlyClose')) {
          exited = true;
          return;
        }
        let name = getVariable(state);
        pull(state, 'colon');
        let type = getType(state);
        data.keys.push(name);
        data.values[name] = type;
        pullIf(state, 'comma', next);
      }
      next();
      if (!exited) pull(state, 'curlyClose');
      return data;
    },
    parenOpen: () => {
      data.type = 'structArray';
      // Quite simple, since we just need to accept keywords again and again.
      data.keys = [];
      function next() {
        data.keys.push(getType(state));
        pullIf(state, 'comma', next);
      }
      next();
      // Close the paren...
      pull(state, 'parenClose');
      // And expect a semicolon
      pullIf(state, 'semicolon');
      return data;
    },
  });
}

function getType(state) {
  // Read keyword or paren. If paren is specified, that means a tuple is
  // specified.
  return match(state, {
    keyword: (state, token) => {
      // If the next token is period, that means a namespace is specified,
      // so resolve it. However, since only 1 level is supported for now,
      // we can just check single level.
      return match(state, {
        else: (state, tokenNext) => {
          // Restore tokens, then just process as name. :P
          state.push(token);
          state.push(tokenNext);
          return getName(state);
        },
        period: (state) => {
          let data = getName(state);
          data.name = [token.name, data.name];
          return data;
        },
      });
    },
    parenOpen: (state) => {
      // Process tuple.
      let result = [];
      function next() {
        // Receive a keyword...
        result.push(getType(state));
        // Continue to next if comma is provided
        pullIf(state, 'comma', next);
      }
      next();
      pull(state, 'parenClose');
      return result;
    },
    squareOpen: (state) => {
      let data = { array: true };
      data.type = getType(state);
      pull(state, 'semicolon');
      match(state, {
        number: (state, token) => data.size = token.value,
        keyword: (state, token) => data.size = token.name,
      });
      pull(state, 'squareClose');
      return data;
    },
  });
}

function getVariable(state) {
  return pull(state, 'keyword').name;
}

function getIdentifier(data) {
  if (data.generics == null) return data.name;
  return data.name + '<' + data.generics.map(() => '_').join(',') + '>';
}

function getName(state) {
  let data = {};
  // Get keyword.
  data.name = pull(state, 'keyword').name;
  // Support generics - continue if we have generics.
  // We're suddenly using continuation-passing style. I'm not sure why.
  pullIf(state, 'angleOpen', (state) => {
    data.generics = [];
    function next() {
      // Receive a keyword...
      data.generics.push(getName(state));
      // Continue to next if comma is provided
      pullIf(state, 'comma', next);
    }
    next();
    // Digest angleClose
    pull(state, 'angleClose');
  });
  return data;
}

export default function parse(tokenizer) {
  let state = { next, push, lookahead: [], namespace: {} };
  function next() {
    if (state.lookahead.length > 0) {
      return state.lookahead.shift();
    }
    const { value, done } = tokenizer.next();
    if (done) return null;
    return value;
  }
  // Lookahead support
  function push(token) {
    state.lookahead.push(token);
  }
  // Read each line and process. Since this uses JS's own stack, it'd be really
  // simple to describe the language.
  main(state);
  console.log(state.namespace);
  return state;
}
<commit_msg>Implement const values in definition<commit_after>function match(state, matches) {
  // Try to match the type
  let token = state.next();
  let type = token === null ? 'null' : token.type;
  let matched = matches[type];
  if (matched == null) {
    if (matches.else != null) return matches.else(state, token);
    throw new Error('Token error; Expected ' +
      Object.keys(matches).join(',') + ', But received ' + type
    );
  }
  return matched(state, token);
}

function pull(state, type) {
  // Try to match the type
  let token = state.next();
  let tokenType = (token === null ? 'null' : token.type);
  if (tokenType !== type) {
    throw new Error('Token error; Expected ' +
      type + ', But received ' + tokenType
    );
  }
  return token;
}

function pullIf(state, type, then) {
  // Try to match the type
  let token = state.next();
  let tokenType = (token === null ? 'null' : token.type);
  if (tokenType !== type) {
    state.push(token);
    return false;
  }
  if (then != null) then(state, token);
  return token;
}

function main(state) {
  // Loop until we meet null. This looks awkward, but this'll do.
  while (match(state, {
    null: () => false,
    enum: (state) => {
      let data = defineEnum(state);
      state.namespace[getIdentifier(data)] = data;
    },
    struct: (state) => {
      let data = defineStruct(state);
      state.namespace[getIdentifier(data)] = data;
    },
  }) !== false);
}

function defineEnum(state) {
  let data = getName(state);
  let exited = false;
  let index = 0;
  // Pull enum target for structs
  if (pullIf(state, 'parenOpen')) {
    data.typeTarget = getVariable(state);
    if (pullIf(state, 'comma')) {
      data.typeType = getType(state);
    }
    pull(state, 'parenClose');
  }
  data.namespace = {};
  pull(state, 'curlyOpen');
  // Now, pull each character.
  function next() {
    // If curlyClose is reached, escape!
    if (pullIf(state, 'curlyClose')) {
      exited = true;
      return;
    }
    let key, strategy;
    // We have to choose strategy.
    match(state, {
      number: (state, token) => {
        strategy = 'match';
        key = token.value;
        pull(state, 'arrow');
      },
      string: (state, token) => {
        strategy = 'object';
        key = token.value;
        pull(state, 'arrow');
      },
      keyword: (state, token) => {
        // Just continue
        strategy = 'array';
        key = index++;
        state.push(token);
      },
    });
    // Now, pull the struct.
    let value = defineStruct(state, true);
    // Enforce the type mode.
    let dataType = null;
    switch (value.type) {
      case 'structObject':
        dataType = 'enumObject';
        break;
      case 'structArray':
        dataType = 'enumArray';
        break;
    }
    if (data.type != null && dataType != null && data.type !== dataType) {
      throw new Error('Enum data type can\'t be mixed');
    }
    data.type = dataType;
    if (data.strategy == null) {
      data.strategy = strategy;
      // Set up indexes
      switch (strategy) {
        case 'match':
          data.entries = [];
          break;
        case 'object':
          data.entries = {};
          break;
        case 'array':
          data.entries = [];
          break;
      }
    } else if (data.strategy !== strategy) {
      throw new Error('Enum indexing type can\'t be mixed');
    }
    data.namespace[getIdentifier(value)] = value;
    value.enumKey = key;
    switch (strategy) {
      case 'match':
        data.entries.push([key, value]);
        break;
      case 'object':
        data.entries[key] = value;
        break;
      case 'array':
        data.entries.push(value);
        break;
    }
    pullIf(state, 'comma', next);
  }
  next();
  if (data.type == null) data.type = 'enumEmpty';
  if (!exited) pull(state, 'curlyClose');
  return data;
}

function defineStruct(state, allowEmpty = false) {
  let data = getName(state);
  return match(state, {
    else: allowEmpty && ((state, token) => {
      // Just push the token and return the data.
      state.push(token);
      data.type = 'structEmpty';
      data.keys = [];
      return data;
    }),
    curlyOpen: () => {
      data.type = 'structObject';
      data.values = {};
      data.keys = [];
      let exited = false;
      function processKeyword(state, token) {
        state.push(token);
        let name = getVariable(state);
        pull(state, 'colon');
        let type = getType(state);
        data.keys.push(name);
        data.values[name] = type;
        return pullIf(state, 'comma', next);
      }
      function processValue(state, token) {
        let value = token.value;
        pull(state, 'colon');
        let type = getType(state);
        // Don't put it in values.
        data.keys.push({ const: true, type, value });
        return pullIf(state, 'comma', next);
      }
      function next() {
        // If curlyClose is reached, escape!
        if (pullIf(state, 'curlyClose')) {
          exited = true;
          return;
        }
        return match(state, {
          keyword: processKeyword,
          string: processValue,
          number: processValue,
        });
      }
      next();
      if (!exited) pull(state, 'curlyClose');
      return data;
    },
    parenOpen: () => {
      data.type = 'structArray';
      // Quite simple, since we just need to accept keywords again and again.
      data.keys = [];
      function next() {
        data.keys.push(getType(state));
        pullIf(state, 'comma', next);
      }
      next();
      // Close the paren...
      pull(state, 'parenClose');
      // And expect a semicolon
      pullIf(state, 'semicolon');
      return data;
    },
  });
}

function getType(state) {
  // Read keyword or paren. If paren is specified, that means a tuple is
  // specified.
  return match(state, {
    keyword: (state, token) => {
      // If the next token is period, that means a namespace is specified,
      // so resolve it. However, since only 1 level is supported for now,
      // we can just check single level.
      return match(state, {
        else: (state, tokenNext) => {
          // Restore tokens, then just process as name. :P
          state.push(token);
          state.push(tokenNext);
          return getName(state);
        },
        period: (state) => {
          let data = getName(state);
          data.name = [token.name, data.name];
          return data;
        },
      });
    },
    parenOpen: (state) => {
      // Process tuple.
      let result = [];
      function next() {
        // Receive a keyword...
        result.push(getType(state));
        // Continue to next if comma is provided
        pullIf(state, 'comma', next);
      }
      next();
      pull(state, 'parenClose');
      return result;
    },
    squareOpen: (state) => {
      let data = { array: true };
      data.type = getType(state);
      pull(state, 'semicolon');
      match(state, {
        number: (state, token) => data.size = token.value,
        keyword: (state, token) => data.size = token.name,
      });
      pull(state, 'squareClose');
      return data;
    },
  });
}

function getVariable(state) {
  return pull(state, 'keyword').name;
}

function getIdentifier(data) {
  if (data.generics == null) return data.name;
  return data.name + '<' + data.generics.map(() => '_').join(',') + '>';
}

function getName(state) {
  let data = {};
  // Get keyword.
  data.name = pull(state, 'keyword').name;
  // Support generics - continue if we have generics.
  // We're suddenly using continuation-passing style. I'm not sure why.
  pullIf(state, 'angleOpen', (state) => {
    data.generics = [];
    function next() {
      match(state, {
        keyword: (state, token) => {
          state.push(token);
          // Receive a keyword...
          data.generics.push(getType(state));
        },
        // These two are absurd, however, it is required to specify string's
        // encoding and size.
        string: (state, token) => {
          data.generics.push({ const: true, value: token.value });
        },
        number: (state, token) => {
          data.generics.push({ const: true, value: token.value });
        },
      });
      // Continue to next if comma is provided
      pullIf(state, 'comma', next);
    }
    next();
    // Digest angleClose
    pull(state, 'angleClose');
  });
  return data;
}

export default function parse(tokenizer) {
  let state = { next, push, lookahead: [], namespace: {} };
  function next() {
    if (state.lookahead.length > 0) {
      return state.lookahead.shift();
    }
    const { value, done } = tokenizer.next();
    if (done) return null;
    return value;
  }
  // Lookahead support
  function push(token) {
    state.lookahead.push(token);
  }
  // Read each line and process. Since this uses JS's own stack, it'd be really
  // simple to describe the language.
  main(state);
  console.log(state.namespace);
  return state;
}
<|endoftext|>


<commit_before>(function() {

function read(m)
{
    var handlers = {};

    function lift(f, amount) {
        return function(attributes, length) {
            return [f.call(that, attributes, length), amount || length];
        };
    }

    function bind(m, f) {
        return function(attributes, length) {
            var t = m.call(that, attributes, length);
            var t2 = f(t[0])(attributes, length - t[1]);
            return [t2[0], t[1] + t2[1]];
        };
    }

    function unfold(f) {
        return function(attributes, length) {
            var result = [];
            var old_length = length;
            while (length > 0) {
                var t = f.call(that, attributes, length);
                result.push(t[0]);
                length -= t[1];
            }
            return [result, old_length];
        };
    }

    var that = {
        offset: 0,
        data_view: m.make(Rserve.EndianAwareDataView),
        msg: m,

        //////////////////////////////////////////////////////////////////////

        read_int: function() {
            var old_offset = this.offset;
            this.offset += 4;
            return this.data_view.getInt32(old_offset);
        },
        read_string: function(length) {
            // FIXME SLOW
            var result = "";
            while (length--) {
                var c = this.data_view.getInt8(this.offset++);
                if (c) result = result + String.fromCharCode(c);
            }
            return decodeURIComponent(escape(result)); // UTF-8 to UTF-16
        },
        read_stream: function(length) {
            var old_offset = this.offset;
            this.offset += length;
            return this.msg.view(old_offset, length);
        },
        read_int_vector: function(length) {
            var old_offset = this.offset;
            this.offset += length;
            return this.msg.make(Int32Array, old_offset, length);
        },
        read_double_vector: function(length) {
            var old_offset = this.offset;
            this.offset += length;
            return this.msg.make(Float64Array, old_offset, length);
        },

        //////////////////////////////////////////////////////////////////////
        // these are members of the reader monad

        read_null: lift(function(a, l) { return Rserve.Robj.null(a); }),

        read_unknown: lift(function(a, l) {
            this.offset += l;
            return Rserve.Robj.null(a);
        }),

        read_string_array: function(attributes, length) {
            var a = this.read_stream(length).make(Uint8Array);
            var result = [];
            var current_str = "";
            for (var i=0; i<a.length; ++i)
                if (a[i] === 0) {
                    current_str = decodeURIComponent(escape(current_str));
                    result.push(current_str);
                    current_str = "";
                } else {
                    current_str = current_str + String.fromCharCode(a[i]);
                }
            return [Rserve.Robj.string_array(result, attributes), length];
        },
        read_bool_array: function(attributes, length) {
            var l2 = this.read_int();
            var s = this.read_stream(length-4);
            var a = _.map(s.make(Uint8Array).subarray(0, l2), function(v) {
                return v ? true : false;
            });
            return [Rserve.Robj.bool_array(a, attributes), length];
        },
        read_raw: function(attributes, length) {
            var l2 = this.read_int();
            var s = this.read_stream(length-4);
            var a = new Uint8Array(s.make(Uint8Array).subarray(0, l2)).buffer;
            return [Rserve.Robj.raw(a, attributes), length];
        },

        read_sexp: function() {
            var d = this.read_int();
            var _ = Rserve.Rsrv.par_parse(d);
            var t = _[0], l = _[1];
            var total_read = 4;
            var attributes = undefined;
            if (Rserve.Rsrv.IS_LARGE(t)) {
                var extra_length = this.read_int();
                total_read += 4;
                l += extra_length * Math.pow(2, 24);
                t &= ~64;
            }
            if (t & Rserve.Rsrv.XT_HAS_ATTR) {
                t = t & ~Rserve.Rsrv.XT_HAS_ATTR;
                var attr_result = this.read_sexp();
                attributes = attr_result[0];
                total_read += attr_result[1];
                l -= attr_result[1];
            }
            if (handlers[t] === undefined) {
                throw new Rserve.RserveError("Unimplemented " + t, -1);
            } else {
                var result = handlers[t].call(this, attributes, l);
                return [result[0], total_read + result[1]];
            }
        }
    };

    that.read_clos = bind(that.read_sexp, function(formals) {
              return bind(that.read_sexp, function(body)    {
              return lift(function(a, l) {
              return Rserve.Robj.clos(formals, body, a);
              }, 0);
              } );
    });

    that.read_list = unfold(that.read_sexp);

    function read_symbol_value_pairs(lst) {
        var result = [];
        for (var i=0; i<lst.length; i+=2) {
            var value = lst[i], tag = lst[i+1];
            if (tag.type === "symbol") {
                result.push({ name: tag.value,
                              value: value });
            } else {
                result.push({ name: null,
                              value: value });
            }
        }
        return result;
    }
    that.read_list_tag = bind(that.read_list, function(lst) {
        return lift(function(attributes, length) {
            var result = read_symbol_value_pairs(lst);
            return Rserve.Robj.tagged_list(result, attributes);
        }, 0);
    });
    that.read_lang_tag = bind(that.read_list, function(lst) {
        return lift(function(attributes, length) {
            var result = read_symbol_value_pairs(lst);
            return Rserve.Robj.tagged_lang(result, attributes);
        }, 0);
    });

    function xf(f, g) { return bind(f, function(t) {
        return lift(function(a, l) { return g(t, a); }, 0);
    }); }
    that.read_vector       = xf(that.read_list, Rserve.Robj.vector);
    that.read_list_no_tag  = xf(that.read_list, Rserve.Robj.list);
    that.read_lang_no_tag  = xf(that.read_list, Rserve.Robj.lang);
    that.read_vector_exp   = xf(that.read_list, Rserve.Robj.vector_exp);

    function sl(f, g) { return lift(function(a, l) {
        return g(f.call(that, l), a);
    }); }
    that.read_symname      = sl(that.read_string,        Rserve.Robj.symbol);
    that.read_int_array    = sl(that.read_int_vector,    Rserve.Robj.int_array);
    that.read_double_array = sl(that.read_double_vector, Rserve.Robj.double_array);

    handlers[Rserve.Rsrv.XT_NULL]         = that.read_null;
    handlers[Rserve.Rsrv.XT_UNKNOWN]      = that.read_unknown;
    handlers[Rserve.Rsrv.XT_VECTOR]       = that.read_vector;
    handlers[Rserve.Rsrv.XT_CLOS]         = that.read_clos;
    handlers[Rserve.Rsrv.XT_SYMNAME]      = that.read_symname;
    handlers[Rserve.Rsrv.XT_LIST_NOTAG]   = that.read_list_no_tag;
    handlers[Rserve.Rsrv.XT_LIST_TAG]     = that.read_list_tag;
    handlers[Rserve.Rsrv.XT_LANG_NOTAG]   = that.read_lang_no_tag;
    handlers[Rserve.Rsrv.XT_LANG_TAG]     = that.read_lang_tag;
    handlers[Rserve.Rsrv.XT_VECTOR_EXP]   = that.read_vector_exp;
    handlers[Rserve.Rsrv.XT_ARRAY_INT]    = that.read_int_array;
    handlers[Rserve.Rsrv.XT_ARRAY_DOUBLE] = that.read_double_array;
    handlers[Rserve.Rsrv.XT_ARRAY_STR]    = that.read_string_array;
    handlers[Rserve.Rsrv.XT_ARRAY_BOOL]   = that.read_bool_array;
    handlers[Rserve.Rsrv.XT_RAW]          = that.read_raw;

    handlers[Rserve.Rsrv.XT_STR]          = sl(that.read_string, Rserve.Robj.string);

    return that;
}

var incomplete_ = [], incomplete_header_ = null, msg_bytes_ = 0, remaining_ = 0;
function clear_incomplete() {
    incomplete_ = [];
    incomplete_header_ = null;
    remaining_ = 0;
    msg_bytes_ = 0;
}

function parse(msg)
{
    var result = {};
    if(incomplete_.length) {
        result.header = incomplete_header_;
        incomplete_.push(msg);
        remaining_ -= msg.byteLength;
        if(remaining_ < 0) {
            result.ok = false;
            result.message = "Messages add up to more than expected length: got " +
                            (msg_bytes_-remaining_) + ", expected " + msg_bytes_;
            clear_incomplete();
            return result;
        }
        else if(remaining_ === 0) {
            var complete_msg = new ArrayBuffer(msg_bytes_),
                array = new Uint8Array(complete_msg),
                offset = 0;
            incomplete_.forEach(function(frame, i) {
                array.set(new Uint8Array(frame), offset);
                offset += frame.byteLength;
            });
            if(offset !== msg_bytes_) {
                result.ok = false;
                result.message = "Internal error - frames added up to " + offset + " not " + msg_bytes_;
                clear_incomplete();
                return result;
            }
            clear_incomplete();
            msg = complete_msg;
        }
        else {
            result.ok = true;
            result.incomplete = true;
            return result;
        }
    }

    var header = new Int32Array(msg, 0, 4);
    var resp = header[0] & 16777215, status_code = header[0] >>> 24;
    var length = header[1], length_high = header[3];
    var msg_id = header[2];
    result.header = [resp, status_code, msg_id];

    if(length_high) {
        result.ok = false;
        result.message = "rserve.js cannot handle messages larger than 4GB";
        return result;
    }

    var full_msg_length = length + 16; // header length + data length
    if(full_msg_length > msg.byteLength) {
        incomplete_.push(msg);
        incomplete_header_ = header;
        msg_bytes_ = full_msg_length;
        remaining_ = msg_bytes_ - msg.byteLength;
        result.header = header;
        result.ok = true;
        result.incomplete = true;
        return result;
    }

    if (resp === Rserve.Rsrv.RESP_ERR) {
        result.ok = false;
        result.status_code = status_code;
        result.message = "ERROR FROM R SERVER: " + (Rserve.Rsrv.status_codes[status_code] ||
                                         status_code)
               + " " + result.header[0] + " " + result.header[1]
               + " " + msg.byteLength
               + " " + msg;
        return result;
    }

    if (!( resp === Rserve.Rsrv.RESP_OK || Rserve.Rsrv.IS_OOB_SEND(resp) || Rserve.Rsrv.IS_OOB_MSG(resp))) {
        result.ok = false;
        result.message = "Unexpected response from Rserve: " + resp + " status: " + Rserve.Rsrv.status_codes[status_code];
        return result;
    }
    try {
        result.payload = parse_payload(msg);
        result.ok = true;
    } catch (e) {
        result.ok = false;
        result.message = e.message;
    }
    return result;
}

function parse_payload(msg)
{
    var payload = Rserve.my_ArrayBufferView(msg, 16, msg.byteLength - 16);
    if (payload.length === 0)
        return null;

    var reader = read(payload);

    var d = reader.read_int();
    var _ = Rserve.Rsrv.par_parse(d);
    var t = _[0], l = _[1];
    if (Rserve.Rsrv.IS_LARGE(t)) {
        var more_length = reader.read_int();
        l += more_length * Math.pow(2, 24);
        if (l > (Math.pow(2, 32))) { // resist the 1 << 32 temptation here!
            // total_length is greater than 2^32.. bail out because of node limits
            // even though in theory we could go higher than that.
            throw new Error("Payload too large: " + l + " bytes");
        }
        t &= ~64;
    }
    if (t === Rserve.Rsrv.DT_INT) {
        return { type: "int", value: reader.read_int() };
    } else if (t === Rserve.Rsrv.DT_STRING) {
        return { type: "string", value: reader.read_string(l) };
    } else if (t === Rserve.Rsrv.DT_BYTESTREAM) { // NB this returns a my_ArrayBufferView()
        return { type: "stream", value: reader.read_stream(l) };
    } else if (t === Rserve.Rsrv.DT_SEXP) {
        _ = reader.read_sexp();
        var sexp = _[0], l2 = _[1];
        return { type: "sexp", value: sexp };
    } else
        throw new Rserve.RserveError("Bad type for parse? " + t + " " + l, -1);
}

Rserve.parse_websocket_frame = parse;
Rserve.parse_payload = parse_payload;

})();
<commit_msg>preserve bad UTF8 in error message when decoding fails<commit_after>(function() {

function read(m)
{
    var handlers = {};

    function lift(f, amount) {
        return function(attributes, length) {
            return [f.call(that, attributes, length), amount || length];
        };
    }

    function bind(m, f) {
        return function(attributes, length) {
            var t = m.call(that, attributes, length);
            var t2 = f(t[0])(attributes, length - t[1]);
            return [t2[0], t[1] + t2[1]];
        };
    }

    function unfold(f) {
        return function(attributes, length) {
            var result = [];
            var old_length = length;
            while (length > 0) {
                var t = f.call(that, attributes, length);
                result.push(t[0]);
                length -= t[1];
            }
            return [result, old_length];
        };
    }

    function UTF8toUTF16(s) {
        // UTF-8 to UTF-16
        // http://monsur.hossa.in/2012/07/20/utf-8-in-javascript.html
        // also, we don't want to lose the value when reporting an error in decoding
        try {
            return decodeURIComponent(escape(s));
        }
        catch(xep) {
            throw new Error('Invalid UTF8: ' + s);
        }
    }

    var that = {
        offset: 0,
        data_view: m.make(Rserve.EndianAwareDataView),
        msg: m,

        //////////////////////////////////////////////////////////////////////

        read_int: function() {
            var old_offset = this.offset;
            this.offset += 4;
            return this.data_view.getInt32(old_offset);
        },
        read_string: function(length) {
            // FIXME SLOW
            var result = "";
            while (length--) {
                var c = this.data_view.getInt8(this.offset++);
                if (c) result = result + String.fromCharCode(c);
            }
            return UTF8toUTF16(result);
        },
        read_stream: function(length) {
            var old_offset = this.offset;
            this.offset += length;
            return this.msg.view(old_offset, length);
        },
        read_int_vector: function(length) {
            var old_offset = this.offset;
            this.offset += length;
            return this.msg.make(Int32Array, old_offset, length);
        },
        read_double_vector: function(length) {
            var old_offset = this.offset;
            this.offset += length;
            return this.msg.make(Float64Array, old_offset, length);
        },

        //////////////////////////////////////////////////////////////////////
        // these are members of the reader monad

        read_null: lift(function(a, l) { return Rserve.Robj.null(a); }),

        read_unknown: lift(function(a, l) {
            this.offset += l;
            return Rserve.Robj.null(a);
        }),

        read_string_array: function(attributes, length) {
            var a = this.read_stream(length).make(Uint8Array);
            var result = [];
            var current_str = "";
            for (var i=0; i<a.length; ++i)
                if (a[i] === 0) {
                    current_str = UTF8toUTF16(current_str);
                    result.push(current_str);
                    current_str = "";
                } else {
                    current_str = current_str + String.fromCharCode(a[i]);
                }
            return [Rserve.Robj.string_array(result, attributes), length];
        },
        read_bool_array: function(attributes, length) {
            var l2 = this.read_int();
            var s = this.read_stream(length-4);
            var a = _.map(s.make(Uint8Array).subarray(0, l2), function(v) {
                return v ? true : false;
            });
            return [Rserve.Robj.bool_array(a, attributes), length];
        },
        read_raw: function(attributes, length) {
            var l2 = this.read_int();
            var s = this.read_stream(length-4);
            var a = new Uint8Array(s.make(Uint8Array).subarray(0, l2)).buffer;
            return [Rserve.Robj.raw(a, attributes), length];
        },

        read_sexp: function() {
            var d = this.read_int();
            var _ = Rserve.Rsrv.par_parse(d);
            var t = _[0], l = _[1];
            var total_read = 4;
            var attributes = undefined;
            if (Rserve.Rsrv.IS_LARGE(t)) {
                var extra_length = this.read_int();
                total_read += 4;
                l += extra_length * Math.pow(2, 24);
                t &= ~64;
            }
            if (t & Rserve.Rsrv.XT_HAS_ATTR) {
                t = t & ~Rserve.Rsrv.XT_HAS_ATTR;
                var attr_result = this.read_sexp();
                attributes = attr_result[0];
                total_read += attr_result[1];
                l -= attr_result[1];
            }
            if (handlers[t] === undefined) {
                throw new Rserve.RserveError("Unimplemented " + t, -1);
            } else {
                var result = handlers[t].call(this, attributes, l);
                return [result[0], total_read + result[1]];
            }
        }
    };

    that.read_clos = bind(that.read_sexp, function(formals) {
              return bind(that.read_sexp, function(body)    {
              return lift(function(a, l) {
              return Rserve.Robj.clos(formals, body, a);
              }, 0);
              } );
    });

    that.read_list = unfold(that.read_sexp);

    function read_symbol_value_pairs(lst) {
        var result = [];
        for (var i=0; i<lst.length; i+=2) {
            var value = lst[i], tag = lst[i+1];
            if (tag.type === "symbol") {
                result.push({ name: tag.value,
                              value: value });
            } else {
                result.push({ name: null,
                              value: value });
            }
        }
        return result;
    }
    that.read_list_tag = bind(that.read_list, function(lst) {
        return lift(function(attributes, length) {
            var result = read_symbol_value_pairs(lst);
            return Rserve.Robj.tagged_list(result, attributes);
        }, 0);
    });
    that.read_lang_tag = bind(that.read_list, function(lst) {
        return lift(function(attributes, length) {
            var result = read_symbol_value_pairs(lst);
            return Rserve.Robj.tagged_lang(result, attributes);
        }, 0);
    });

    function xf(f, g) { return bind(f, function(t) {
        return lift(function(a, l) { return g(t, a); }, 0);
    }); }
    that.read_vector       = xf(that.read_list, Rserve.Robj.vector);
    that.read_list_no_tag  = xf(that.read_list, Rserve.Robj.list);
    that.read_lang_no_tag  = xf(that.read_list, Rserve.Robj.lang);
    that.read_vector_exp   = xf(that.read_list, Rserve.Robj.vector_exp);

    function sl(f, g) { return lift(function(a, l) {
        return g(f.call(that, l), a);
    }); }
    that.read_symname      = sl(that.read_string,        Rserve.Robj.symbol);
    that.read_int_array    = sl(that.read_int_vector,    Rserve.Robj.int_array);
    that.read_double_array = sl(that.read_double_vector, Rserve.Robj.double_array);

    handlers[Rserve.Rsrv.XT_NULL]         = that.read_null;
    handlers[Rserve.Rsrv.XT_UNKNOWN]      = that.read_unknown;
    handlers[Rserve.Rsrv.XT_VECTOR]       = that.read_vector;
    handlers[Rserve.Rsrv.XT_CLOS]         = that.read_clos;
    handlers[Rserve.Rsrv.XT_SYMNAME]      = that.read_symname;
    handlers[Rserve.Rsrv.XT_LIST_NOTAG]   = that.read_list_no_tag;
    handlers[Rserve.Rsrv.XT_LIST_TAG]     = that.read_list_tag;
    handlers[Rserve.Rsrv.XT_LANG_NOTAG]   = that.read_lang_no_tag;
    handlers[Rserve.Rsrv.XT_LANG_TAG]     = that.read_lang_tag;
    handlers[Rserve.Rsrv.XT_VECTOR_EXP]   = that.read_vector_exp;
    handlers[Rserve.Rsrv.XT_ARRAY_INT]    = that.read_int_array;
    handlers[Rserve.Rsrv.XT_ARRAY_DOUBLE] = that.read_double_array;
    handlers[Rserve.Rsrv.XT_ARRAY_STR]    = that.read_string_array;
    handlers[Rserve.Rsrv.XT_ARRAY_BOOL]   = that.read_bool_array;
    handlers[Rserve.Rsrv.XT_RAW]          = that.read_raw;

    handlers[Rserve.Rsrv.XT_STR]          = sl(that.read_string, Rserve.Robj.string);

    return that;
}

var incomplete_ = [], incomplete_header_ = null, msg_bytes_ = 0, remaining_ = 0;
function clear_incomplete() {
    incomplete_ = [];
    incomplete_header_ = null;
    remaining_ = 0;
    msg_bytes_ = 0;
}

function parse(msg)
{
    var result = {};
    if(incomplete_.length) {
        result.header = incomplete_header_;
        incomplete_.push(msg);
        remaining_ -= msg.byteLength;
        if(remaining_ < 0) {
            result.ok = false;
            result.message = "Messages add up to more than expected length: got " +
                            (msg_bytes_-remaining_) + ", expected " + msg_bytes_;
            clear_incomplete();
            return result;
        }
        else if(remaining_ === 0) {
            var complete_msg = new ArrayBuffer(msg_bytes_),
                array = new Uint8Array(complete_msg),
                offset = 0;
            incomplete_.forEach(function(frame, i) {
                array.set(new Uint8Array(frame), offset);
                offset += frame.byteLength;
            });
            if(offset !== msg_bytes_) {
                result.ok = false;
                result.message = "Internal error - frames added up to " + offset + " not " + msg_bytes_;
                clear_incomplete();
                return result;
            }
            clear_incomplete();
            msg = complete_msg;
        }
        else {
            result.ok = true;
            result.incomplete = true;
            return result;
        }
    }

    var header = new Int32Array(msg, 0, 4);
    var resp = header[0] & 16777215, status_code = header[0] >>> 24;
    var length = header[1], length_high = header[3];
    var msg_id = header[2];
    result.header = [resp, status_code, msg_id];

    if(length_high) {
        result.ok = false;
        result.message = "rserve.js cannot handle messages larger than 4GB";
        return result;
    }

    var full_msg_length = length + 16; // header length + data length
    if(full_msg_length > msg.byteLength) {
        incomplete_.push(msg);
        incomplete_header_ = header;
        msg_bytes_ = full_msg_length;
        remaining_ = msg_bytes_ - msg.byteLength;
        result.header = header;
        result.ok = true;
        result.incomplete = true;
        return result;
    }

    if (resp === Rserve.Rsrv.RESP_ERR) {
        result.ok = false;
        result.status_code = status_code;
        result.message = "ERROR FROM R SERVER: " + (Rserve.Rsrv.status_codes[status_code] ||
                                         status_code)
               + " " + result.header[0] + " " + result.header[1]
               + " " + msg.byteLength
               + " " + msg;
        return result;
    }

    if (!( resp === Rserve.Rsrv.RESP_OK || Rserve.Rsrv.IS_OOB_SEND(resp) || Rserve.Rsrv.IS_OOB_MSG(resp))) {
        result.ok = false;
        result.message = "Unexpected response from Rserve: " + resp + " status: " + Rserve.Rsrv.status_codes[status_code];
        return result;
    }
    try {
        result.payload = parse_payload(msg);
        result.ok = true;
    } catch (e) {
        result.ok = false;
        result.message = e.message;
    }
    return result;
}

function parse_payload(msg)
{
    var payload = Rserve.my_ArrayBufferView(msg, 16, msg.byteLength - 16);
    if (payload.length === 0)
        return null;

    var reader = read(payload);

    var d = reader.read_int();
    var _ = Rserve.Rsrv.par_parse(d);
    var t = _[0], l = _[1];
    if (Rserve.Rsrv.IS_LARGE(t)) {
        var more_length = reader.read_int();
        l += more_length * Math.pow(2, 24);
        if (l > (Math.pow(2, 32))) { // resist the 1 << 32 temptation here!
            // total_length is greater than 2^32.. bail out because of node limits
            // even though in theory we could go higher than that.
            throw new Error("Payload too large: " + l + " bytes");
        }
        t &= ~64;
    }
    if (t === Rserve.Rsrv.DT_INT) {
        return { type: "int", value: reader.read_int() };
    } else if (t === Rserve.Rsrv.DT_STRING) {
        return { type: "string", value: reader.read_string(l) };
    } else if (t === Rserve.Rsrv.DT_BYTESTREAM) { // NB this returns a my_ArrayBufferView()
        return { type: "stream", value: reader.read_stream(l) };
    } else if (t === Rserve.Rsrv.DT_SEXP) {
        _ = reader.read_sexp();
        var sexp = _[0], l2 = _[1];
        return { type: "sexp", value: sexp };
    } else
        throw new Rserve.RserveError("Bad type for parse? " + t + " " + l, -1);
}

Rserve.parse_websocket_frame = parse;
Rserve.parse_payload = parse_payload;

})();
<|endoftext|>


<commit_before>'use strict';

var BOB_MAGNITUDE = 16;
var BOB_TIME = 1.0;

////////////////////////////////////////////////////////////////////////
// Door

function Door(level, sprite, info) {
	this.level = level;
	this.sprite = sprite;
}
Door.prototype.markerOffset = 64;
Door.prototype.interact = function() {
	console.log('Door');
};

////////////////////////////////////////////////////////////////////////
// Chest

function Chest(level, sprite, info) {
	this.level = level;
	this.sprite = sprite;
}
Chest.prototype.markerOffset = 48;
Chest.prototype.interact = function() {
	console.log('INTERACT');
	var level = this.level;
	this.sprite.frame = 3;
	level.setPaused(true);
	level.gProps.setTarget(null);
	var tsprite, tframe;
	if (true) {
		tsprite = 'hearts';
		tframe = 0;
	}
	var treasure = level.add.sprite(
		this.sprite.x,
		this.sprite.y - 24,
		tsprite,
		tframe);
	treasure.anchor.setTo(0.5, 0.5);
	var tpre = 0.25, tmove = 1.0;
	var tween = level.add.tween(treasure);
	tween.to(
		{y: this.sprite.y - 96}, tmove * 1000,
		Phaser.Easing.Sinusoidal.InOut,
		true, tpre * 1000, 0, false);
	tween.onComplete.addOnce(function() {
		console.log('FIRE');
		level.setPaused(false);
		treasure.destroy();
	});
};

////////////////////////////////////////////////////////////////////////
// Save point

function SavePoint(level, sprite, info) {
	this.level = level;
	this.sprite = sprite;
}
SavePoint.prototype.markerOffset = 48;
SavePoint.prototype.interact = function() {
	console.log('Save Point');
};

////////////////////////////////////////////////////////////////////////
// Prop factories

var PROP_TYPES = {
	0: Door,
	2: Chest,
	4: SavePoint,
};

////////////////////////////////////////////////////////////////////////
// Prop manager

function Props(level) {
	this.level = level;
	this.group = level.add.group();
	this.objs = {};
	this.counter = 0;
	this.markerSprite = null;
	this.markerTarget = null;
	this.markerTween = null;
}

// Spawn a prop from the map.
Props.prototype.spawn = function(index, info) {
	var Constructor = PROP_TYPES[index];
	var sprite = this.group.create(
		info.x + 32, info.y - 32,
		'props', index);
	sprite.anchor.set(0.5, 0.5);
	if (Constructor) {
		var name = 'Prop ' + this.counter;
		this.counter++;
		sprite.name = name;
		var obj = new Constructor(this.level, sprite, info);
		game.physics.arcade.enable(sprite);
		this.objs[name] = obj;
	}
};

// Update all props.
Props.prototype.update = function(index, info) {
	var player = this.level.gPlayer.getInteractSprite();
	if (!player) {
		this.setTarget(null);
		return;
	}
	var best_dist = Infinity, best_sprite = null;
	game.physics.arcade.overlap(
		player, this.group, function(player_, sprite) {
			var u = player_.position, v = sprite.position;
			var dist = Math.max(
				Math.abs(u.x - v.x),
				Math.abs(u.y - v.y));
			if (dist < best_dist) {
				best_dist = dist;
				best_sprite = sprite;
			}
		});
	this.setTarget(best_sprite);
};

// Set the interaction target.
Props.prototype.setTarget = function(sprite) {
	if (!sprite) {
		if (this.markerTarget) {
			this.markerSprite.kill();
			this.markerTarget = null;
			this.markerTween.stop();
			this.markerTween = null;
		}
		return;
	}
	var obj = this.objs[sprite.name];
	if (!obj) {
		console.log(this.objs);
		console.error('Invalid interaction target:', sprite);
		return;
	}
	if (this.markerTarget == obj) {
		return;
	}
	this.markerTarget = obj;
	var tx = sprite.x;
	var ty0 = sprite.y - BOB_MAGNITUDE -obj.markerOffset;
	var ty1 = ty0 + BOB_MAGNITUDE * 2;
	if (!this.markerSprite) {
		this.markerSprite = this.group.create(tx, ty0, 'props', 6);
		this.markerSprite.anchor.setTo(0.5, 0.5);
	} else {
		this.markerSprite.reset(tx, ty0);
	}
	if (this.markerTween) {
		this.markerTween.stop();
		this.markerTween = null;
	}
	this.markerTween = game.add.tween(this.markerSprite);
	this.markerTween.to(
		{x: tx, y: ty1}, BOB_TIME * 500, Phaser.Easing.Sinusoidal.InOut,
		true, 0, -1, true);
};

// Try to interact with something, as the player.
Props.prototype.interact = function() {
	if (!this.markerTarget) {
		console.log('Cannot interact');
	} else {
		this.markerTarget.interact(this.level);
	}
};

////////////////////////////////////////////////////////////////////////
// Exports

module.exports = {
	Props: Props,
};
<commit_msg>Play fanfare when picking up treasure<commit_after>'use strict';

var BOB_MAGNITUDE = 16;
var BOB_TIME = 1.0;

////////////////////////////////////////////////////////////////////////
// Door

function Door(level, sprite, info) {
	this.level = level;
	this.sprite = sprite;
}
Door.prototype.markerOffset = 64;
Door.prototype.interact = function() {
	console.log('Door');
};

////////////////////////////////////////////////////////////////////////
// Chest

function Chest(level, sprite, info) {
	this.level = level;
	this.sprite = sprite;
}
Chest.prototype.markerOffset = 48;
Chest.prototype.interact = function() {
	console.log('INTERACT');
	var level = this.level;
	this.sprite.frame = 3;
	level.setPaused(true);
	level.gProps.setTarget(null);
	var tsprite, tframe;
	if (true) {
		tsprite = 'hearts';
		tframe = 0;
	}
	var treasure = level.add.sprite(
		this.sprite.x,
		this.sprite.y - 24,
		tsprite,
		tframe);
	treasure.anchor.setTo(0.5, 0.5);
	var tpre = 0.25, tmove = 1.0;
	var tween = level.add.tween(treasure);
	tween.to(
		{y: this.sprite.y - 96}, tmove * 1000,
		Phaser.Easing.Sinusoidal.InOut,
		true, tpre * 1000, 0, false);
	game.sound.play('fanfare');
	tween.onComplete.addOnce(function() {
		console.log('FIRE');
		level.setPaused(false);
		treasure.destroy();
	});
};

////////////////////////////////////////////////////////////////////////
// Save point

function SavePoint(level, sprite, info) {
	this.level = level;
	this.sprite = sprite;
}
SavePoint.prototype.markerOffset = 48;
SavePoint.prototype.interact = function() {
	console.log('Save Point');
};

////////////////////////////////////////////////////////////////////////
// Prop factories

var PROP_TYPES = {
	0: Door,
	2: Chest,
	4: SavePoint,
};

////////////////////////////////////////////////////////////////////////
// Prop manager

function Props(level) {
	this.level = level;
	this.group = level.add.group();
	this.objs = {};
	this.counter = 0;
	this.markerSprite = null;
	this.markerTarget = null;
	this.markerTween = null;
}

// Spawn a prop from the map.
Props.prototype.spawn = function(index, info) {
	var Constructor = PROP_TYPES[index];
	var sprite = this.group.create(
		info.x + 32, info.y - 32,
		'props', index);
	sprite.anchor.set(0.5, 0.5);
	if (Constructor) {
		var name = 'Prop ' + this.counter;
		this.counter++;
		sprite.name = name;
		var obj = new Constructor(this.level, sprite, info);
		game.physics.arcade.enable(sprite);
		this.objs[name] = obj;
	}
};

// Update all props.
Props.prototype.update = function(index, info) {
	var player = this.level.gPlayer.getInteractSprite();
	if (!player) {
		this.setTarget(null);
		return;
	}
	var best_dist = Infinity, best_sprite = null;
	game.physics.arcade.overlap(
		player, this.group, function(player_, sprite) {
			var u = player_.position, v = sprite.position;
			var dist = Math.max(
				Math.abs(u.x - v.x),
				Math.abs(u.y - v.y));
			if (dist < best_dist) {
				best_dist = dist;
				best_sprite = sprite;
			}
		});
	this.setTarget(best_sprite);
};

// Set the interaction target.
Props.prototype.setTarget = function(sprite) {
	if (!sprite) {
		if (this.markerTarget) {
			this.markerSprite.kill();
			this.markerTarget = null;
			this.markerTween.stop();
			this.markerTween = null;
		}
		return;
	}
	var obj = this.objs[sprite.name];
	if (!obj) {
		console.log(this.objs);
		console.error('Invalid interaction target:', sprite);
		return;
	}
	if (this.markerTarget == obj) {
		return;
	}
	this.markerTarget = obj;
	var tx = sprite.x;
	var ty0 = sprite.y - BOB_MAGNITUDE -obj.markerOffset;
	var ty1 = ty0 + BOB_MAGNITUDE * 2;
	if (!this.markerSprite) {
		this.markerSprite = this.group.create(tx, ty0, 'props', 6);
		this.markerSprite.anchor.setTo(0.5, 0.5);
	} else {
		this.markerSprite.reset(tx, ty0);
	}
	if (this.markerTween) {
		this.markerTween.stop();
		this.markerTween = null;
	}
	this.markerTween = game.add.tween(this.markerSprite);
	this.markerTween.to(
		{x: tx, y: ty1}, BOB_TIME * 500, Phaser.Easing.Sinusoidal.InOut,
		true, 0, -1, true);
};

// Try to interact with something, as the player.
Props.prototype.interact = function() {
	if (!this.markerTarget) {
		console.log('Cannot interact');
	} else {
		this.markerTarget.interact(this.level);
	}
};

////////////////////////////////////////////////////////////////////////
// Exports

module.exports = {
	Props: Props,
};
<|endoftext|>


<commit_before>import { PropTypes } from 'react'

export const propTypes = {
  url: PropTypes.string,
  playing: PropTypes.bool,
  loop: PropTypes.bool,
  controls: PropTypes.bool,
  volume: PropTypes.number,
  width: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
  height: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
  hidden: PropTypes.bool,
  className: PropTypes.string,
  style: PropTypes.object,
  progressFrequency: PropTypes.number,
  soundcloudConfig: PropTypes.shape({
    clientId: PropTypes.string
  }),
  youtubeConfig: PropTypes.shape({
    playerVars: PropTypes.object,
    preload: PropTypes.bool
  }),
  vimeoConfig: PropTypes.shape({
    iframeParams: PropTypes.object,
    preload: PropTypes.bool
  }),
  fileConfig: PropTypes.shape({
    attributes: PropTypes.object
  }),
  onStart: PropTypes.func,
  onPlay: PropTypes.func,
  onPause: PropTypes.func,
  onBuffer: PropTypes.func,
  onEnded: PropTypes.func,
  onError: PropTypes.func,
  onDuration: PropTypes.func,
  onProgress: PropTypes.func
}

export const defaultProps = {
  playing: false,
  loop: false,
  controls: false,
  volume: 0.8,
  width: 640,
  height: 360,
  progressFrequency: 1000,
  soundcloudConfig: {
    clientId: 'e8b6f84fbcad14c301ca1355cae1dea2'
  },
  youtubeConfig: {
    playerVars: {},
    preload: false
  },
  vimeoConfig: {
    iframeParams: {},
    preload: false
  },
  fileConfig: {
    attributes: {}
  },
  onStart: function () {},
  onPlay: function () {},
  onPause: function () {},
  onBuffer: function () {},
  onEnded: function () {},
  onError: function () {},
  onDuration: function () {},
  onProgress: function () {}
}
<commit_msg>Set default value for hidden prop to false<commit_after>import { PropTypes } from 'react'

export const propTypes = {
  url: PropTypes.string,
  playing: PropTypes.bool,
  loop: PropTypes.bool,
  controls: PropTypes.bool,
  volume: PropTypes.number,
  width: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
  height: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
  hidden: PropTypes.bool,
  className: PropTypes.string,
  style: PropTypes.object,
  progressFrequency: PropTypes.number,
  soundcloudConfig: PropTypes.shape({
    clientId: PropTypes.string
  }),
  youtubeConfig: PropTypes.shape({
    playerVars: PropTypes.object,
    preload: PropTypes.bool
  }),
  vimeoConfig: PropTypes.shape({
    iframeParams: PropTypes.object,
    preload: PropTypes.bool
  }),
  fileConfig: PropTypes.shape({
    attributes: PropTypes.object
  }),
  onStart: PropTypes.func,
  onPlay: PropTypes.func,
  onPause: PropTypes.func,
  onBuffer: PropTypes.func,
  onEnded: PropTypes.func,
  onError: PropTypes.func,
  onDuration: PropTypes.func,
  onProgress: PropTypes.func
}

export const defaultProps = {
  playing: false,
  loop: false,
  controls: false,
  volume: 0.8,
  width: 640,
  height: 360,
  hidden: false,
  progressFrequency: 1000,
  soundcloudConfig: {
    clientId: 'e8b6f84fbcad14c301ca1355cae1dea2'
  },
  youtubeConfig: {
    playerVars: {},
    preload: false
  },
  vimeoConfig: {
    iframeParams: {},
    preload: false
  },
  fileConfig: {
    attributes: {}
  },
  onStart: function () {},
  onPlay: function () {},
  onPause: function () {},
  onBuffer: function () {},
  onEnded: function () {},
  onError: function () {},
  onDuration: function () {},
  onProgress: function () {}
}
<|endoftext|>


<commit_before>/*
 Inspired by pyson.js implementation in Sao.
 */
goog.provide('ng.tryton.PYSON');

goog.require('goog.object');
goog.require('goog.date.Interval');

goog.require('ng.tryton.fulfil');

goog.scope(function() {
  'use strict';

  var Fulfil = ng.tryton.fulfil;

  /**
   * Pyson Service.
   * @constructor
   */
  ng.tryton.PYSON = function() {};

  var PYSON = ng.tryton.PYSON;

  /**
   * This method accepts JSON parsed PYSON object.
   * Depending upon the class of the object, call relevant function.
   * @param pysonObj
   * @param context
   */
  PYSON.prototype.evaluate = function(pysonObj, context) {
    var cls = pysonObj.__class__;
    switch (cls) {
      case 'Eval':
        return PYSON.Eval.call(this, pysonObj, context);
      case 'Not':
        return PYSON.Not.call(this, pysonObj);
      case 'Bool':
        return PYSON.Bool.call(this, pysonObj);
      case 'And':
        return PYSON.And.call(this, pysonObj);
      case 'Or':
        return PYSON.Or.call(this, pysonObj);
      case 'Equal':
        return PYSON.Equal.call(this, pysonObj);
      case 'Greater':
        return PYSON.Greater.call(this, pysonObj);
      case 'Less':
        return PYSON.Less.call(this, pysonObj);
      case 'If':
        return PYSON.If.call(this, pysonObj);
      case 'Get':
        return PYSON.Get.call(this, pysonObj);
      case 'In':
        return PYSON.In.call(this, pysonObj);
      case 'Date':
        return PYSON.Date.call(this, pysonObj);
      case 'DateTime':
        return PYSON.DateTime.call(this, pysonObj);
      case 'Len':
        return PYSON.Len.call(this, pysonObj);
    }
  };

  /**
   * This method accept data object and convert that to pyson string
   * @param
   */
  PYSON.prototype.fromObject = function(dataObject) {
    return JSON.stringify(Fulfil.transformRequest(dataObject));
  };

  PYSON.Eval = function (value, context) {
    if (value.v in context) {
      return context[value.v];
    } else {
      return value.d;
    }
  };

  /**
   * @return {boolean}
   */
  PYSON.Not = function (value) {
    return !value.v;
  };

  /**
   * @return {boolean}
   */
  PYSON.Bool = function (value) {
    if (value.v instanceof Object) {
      return !goog.object.isEmpty(value.v);
    } else {
      return Boolean(value.v);
    }
  };

  PYSON.And = function (value) {
    var result = true;
    for (var i = 0, len = value.s.length; i < len; i++) {
      var statement = value.s[i];
      result = result && statement;
    }
    return result;
  };

  PYSON.Or = function (value) {
    var result = false;
    for (var i = 0, len = value.s.length; i < len; i++) {
      var statement = value.s[i];
      result = result || (
        goog.isObject(statement) ? !goog.object.isEmpty(statement) : !!statement
      );
    }
    return result;
  };

  /**
   * @return {boolean}
   */
  PYSON.Equal = function (value) {
    return value.s1 == value.s2;
  };

  /**
   * @return {boolean}
   */
  PYSON.Greater = function (v) {
    var value = {};
    goog.object.extend(value, v);
    value.s1 = Number(value.s1);
    value.s2 = Number(value.s2);
    if (value.e) {
      return value.s1 >= value.s2;
    } else {
      return value.s1 > value.s2;
    }
  };

  /**
   * @return {boolean}
   */
  PYSON.Less = function (v) {
    var value = {};
    goog.object.extend(value, v);
    value.s1 = Number(value.s1);
    value.s2 = Number(value.s2);
    if (value.e) {
      return value.s1 <= value.s2;
    } else {
      return value.s1 < value.s2;
    }
  };

  PYSON.If = function (value) {
    if (value.c) {
      return value.t;
    } else {
      return value.e;
    }
  };

  PYSON.Get = function (value) {
    if (value.k in value.v) {
      return value.v[value.k];
    } else {
      return value.d;
    }
  };

  PYSON.In = function (value) {
    if (goog.isArray(value.v)) {
      return goog.object.contains(value.v, value.k);
    } else {
      return goog.object.containsKey(value.v, value.k);
    }
  };

  PYSON.Date = function (value) {
    var interval = new goog.date.Interval();
    var date = new Fulfil.datatype.Date(
      value.y,
      value.M && value.M - 1,
      value.d
    );

    if (value.dy) interval.years = value.dy;
    if (value.dM) interval.months = value.dM;
    if (value.dd) interval.days = value.dd;
    date.add(interval)
    return date;
  };

  PYSON.DateTime = function (value) {
    var interval = new goog.date.Interval();
    var date = new Fulfil.datatype.DateTime(
      value.y,
      value.M && value.M - 1,
      value.d,
      value.h,
      value.m,
      value.s,
      value.ms && value.ms / 1000
    );

    if (value.dy) interval.years = value.dy;
    if (value.dM) interval.months = value.dM;
    if (value.dd) interval.days = value.dd;
    if (value.dh) interval.hours = value.dh;
    if (value.dm) interval.minutes = value.dm;
    if (value.ds) interval.seconds = value.ds;
    // TODO: Handle ms
    date.add(interval)
    return date;
  };

  PYSON.Len = function (value) {
    return goog.object.getCount(value.v);
  };
});   // goog.scope
<commit_msg>Add provision to parse and transform request<commit_after>/*
 Inspired by pyson.js implementation in Sao.
 */
goog.provide('ng.tryton.PYSON');

goog.require('goog.object');
goog.require('goog.date.Interval');

goog.require('ng.tryton.fulfil');

goog.scope(function() {
  'use strict';

  var Fulfil = ng.tryton.fulfil;

  /**
   * Pyson Service.
   * @constructor
   */
  ng.tryton.PYSON = function() {};

  var PYSON = ng.tryton.PYSON;

  /**
   * This method accepts JSON parsed PYSON object.
   * Depending upon the class of the object, call relevant function.
   * @param pysonObj
   * @param context
   */
  PYSON.prototype.evaluate = function(pysonObj, context) {
    var cls = pysonObj.__class__;
    switch (cls) {
      case 'Eval':
        return PYSON.Eval.call(this, pysonObj, context);
      case 'Not':
        return PYSON.Not.call(this, pysonObj);
      case 'Bool':
        return PYSON.Bool.call(this, pysonObj);
      case 'And':
        return PYSON.And.call(this, pysonObj);
      case 'Or':
        return PYSON.Or.call(this, pysonObj);
      case 'Equal':
        return PYSON.Equal.call(this, pysonObj);
      case 'Greater':
        return PYSON.Greater.call(this, pysonObj);
      case 'Less':
        return PYSON.Less.call(this, pysonObj);
      case 'If':
        return PYSON.If.call(this, pysonObj);
      case 'Get':
        return PYSON.Get.call(this, pysonObj);
      case 'In':
        return PYSON.In.call(this, pysonObj);
      case 'date':
      case 'Date':
        return PYSON.Date.call(this, pysonObj);
      case 'datetime':
      case 'DateTime':
        return PYSON.DateTime.call(this, pysonObj);
      case 'Len':
        return PYSON.Len.call(this, pysonObj);
    }
  };

  /**
   * This method accept data object and convert that to pyson string
   * @param
   */
  PYSON.prototype.fromObject = function(dataObject) {
    return JSON.stringify(Fulfil.transformRequest(dataObject));
  };

  PYSON.Eval = function (value, context) {
    if (value.v in context) {
      return context[value.v];
    } else {
      return value.d;
    }
  };

  /**
   * @return {boolean}
   */
  PYSON.Not = function (value) {
    return !value.v;
  };

  /**
   * @return {boolean}
   */
  PYSON.Bool = function (value) {
    if (value.v instanceof Object) {
      return !goog.object.isEmpty(value.v);
    } else {
      return Boolean(value.v);
    }
  };

  PYSON.And = function (value) {
    var result = true;
    for (var i = 0, len = value.s.length; i < len; i++) {
      var statement = value.s[i];
      result = result && statement;
    }
    return result;
  };

  PYSON.Or = function (value) {
    var result = false;
    for (var i = 0, len = value.s.length; i < len; i++) {
      var statement = value.s[i];
      result = result || (
        goog.isObject(statement) ? !goog.object.isEmpty(statement) : !!statement
      );
    }
    return result;
  };

  /**
   * @return {boolean}
   */
  PYSON.Equal = function (value) {
    return value.s1 == value.s2;
  };

  /**
   * @return {boolean}
   */
  PYSON.Greater = function (v) {
    var value = {};
    goog.object.extend(value, v);
    value.s1 = Number(value.s1);
    value.s2 = Number(value.s2);
    if (value.e) {
      return value.s1 >= value.s2;
    } else {
      return value.s1 > value.s2;
    }
  };

  /**
   * @return {boolean}
   */
  PYSON.Less = function (v) {
    var value = {};
    goog.object.extend(value, v);
    value.s1 = Number(value.s1);
    value.s2 = Number(value.s2);
    if (value.e) {
      return value.s1 <= value.s2;
    } else {
      return value.s1 < value.s2;
    }
  };

  PYSON.If = function (value) {
    if (value.c) {
      return value.t;
    } else {
      return value.e;
    }
  };

  PYSON.Get = function (value) {
    if (value.k in value.v) {
      return value.v[value.k];
    } else {
      return value.d;
    }
  };

  PYSON.In = function (value) {
    if (goog.isArray(value.v)) {
      return goog.object.contains(value.v, value.k);
    } else {
      return goog.object.containsKey(value.v, value.k);
    }
  };

  PYSON.Date = function (value) {
    let interval = new goog.date.Interval();
    let month = value.M || value.month;

    let date = new Fulfil.datatype.Date(
      value.y || value.year,
      month && month - 1,
      value.d || value.day
    );

    if (value.dy) interval.years = value.dy;
    if (value.dM) interval.months = value.dM;
    if (value.dd) interval.days = value.dd;
    date.add(interval)
    return date;
  };

  PYSON.DateTime = function (value) {
    var interval = new goog.date.Interval();
    let month = value.M || value.month;
    let ms = value.ms || value.microsecond;
    var date = new Fulfil.datatype.DateTime(
      value.y || value.year,
      month && month - 1,
      value.d || value.day,
      value.h || value.hour,
      value.m || value.minute,
      value.s || value.second,
      ms && ms / 1000
    );

    if (value.dy) interval.years = value.dy;
    if (value.dM) interval.months = value.dM;
    if (value.dd) interval.days = value.dd;
    if (value.dh) interval.hours = value.dh;
    if (value.dm) interval.minutes = value.dm;
    if (value.ds) interval.seconds = value.ds;
    // TODO: Handle ms
    date.add(interval)
    return date;
  };

  PYSON.Len = function (value) {
    return goog.object.getCount(value.v);
  };
});   // goog.scope
<|endoftext|>


<commit_before>var Batch = require('batch');

var redis = require('./redis');
var Job = require('./job');
var Workers = require('./workers');

var debug = require('debug')('qp:Queue');

var Queue = module.exports = function(qp, name, opts) {
  this.name = name;
  this.redis = redis.client();
  this.qp = qp;
  this.workers = [];
  this.opts = opts;
  this.states = ['active', 'inactive', 'completed', 'failed'];

  // add the queue name to the jobtypes set
  this.redis.sadd('qp:job:types', this.name);
  this.ttl();
};

/**
 * Remove jobs from state queues based on TTL settings
 */
Queue.prototype.ttl = function() {
  var self = this;

  var runFrequency = 1000;
  clearTimeout(self.ttlTimeout);

  var scheduleNext = function(){
    self.ttlTimeout = setTimeout(self.ttl.bind(self), runFrequency);
  };

  var getStateOption = function(state){
    return self.getOption(state+'TTL');
  };

  var ttlSet = false;
  for (var i = 0; i < this.states.length; i++) {
    var state = this.states[i];
    ttlSet = (typeof getStateOption(state) == 'number');
  }

  if (!ttlSet) return scheduleNext();

  var removeJobs = function(jobs, cb){
    var batch = new Batch();

    for (var i = 0; i < jobs.length; i++) {
      var job = jobs[i];
      batch.push(job.remove.bind(job));
    }

    batch.end(cb);
  };

  self.setLock(self.redis, Math.ceil(runFrequency / 1000), 'qp:' + self.name, 'ttl', function(err, lockAcquired){
    if (err){
      debug('Unable to set ttl check lock');
      return scheduleNext();
    }

    if (!lockAcquired) return scheduleNext();

    var batch = new Batch();

    self.states.forEach(function(state){
      var ttl = getStateOption(state);

      if (typeof ttl != 'number') return;

      batch.push(function(done){
        self.jobsByState(state, ttl, function(err, jobs){
          if (err || !jobs) return done();

          var numJobs = jobs.length;
          if (numJobs) debug('Removing %d jobs in %s state past ttl of %d', numJobs, state, ttl);
          removeJobs(jobs, done);
        });
      });
    });

    batch.end(function(err){
      if (err) debug(err);

      scheduleNext();
    });
  });
};

/**
 * Get array of jobs by their state
 * @param  {string}   state
 * @param  {integer}   ttl  in ms
 * @param  {Function} cb
 */
Queue.prototype.jobsByState = function(state, ttl, cb) {
  var self = this;

  if (!ttl) cb = ttl;
  if (!cb) cb = function(){};

  var key = 'qp:' + self.name + '.' + state;
  if (ttl) end = Date.now() - ttl;
  else end = -1;

  self.redis.zrangebyscore(key, 0, end, function(err, members){
    if (err) return cb(err);

    var jobs = [];
    for (var i = 0; i < members.length; i++) {
      var job = self.create();
      job.id = members[i];
      job.state = state;
      jobs.push(job);
    }

    cb(err, jobs);
  });
};

/**
 * Set a lock key
 * @param {object}   redis   node-redis client
 * @param {integer}  ttl     Time in seconds for the lock to live
 * @param {string}   suffix  Add uniqueness to the lock
 * @param {Function} cb
 */
Queue.prototype.setLock = function(redis, ttl, keyPrefix, suffix, cb) {
  var timestamp = ~~(new Date()/1000);
  timestamp -= timestamp % ttl;
  var checksum = require('crypto').createHash('md5').update(suffix + timestamp).digest('hex').substr(0, 10);
  var key = keyPrefix + 'lock:' + checksum;
  var m = redis.multi();
  m.setnx(key, timestamp, function(err, lockAcquired){
    if(err) return cb(err);

    return cb(err, +lockAcquired);
  });
  m.expire(key, ttl);
  m.exec();
};

Queue.prototype.create = Queue.prototype.createJob = function(data, opts) {
  var job = new Job(this, data, opts);
  return job;
};

// helper to set the job id as well as any data
Queue.prototype.job = function(id, data, opts) {
  var job = this.create(data, opts);
  job.id = id;
  return job;
};

Queue.prototype.multiSave = function(jobs, cb) {

  var self = this;

  for (var i = 0; i < jobs.length; i++) {
    if (!(jobs[i] instanceof Job)) {
      jobs[i] = self.create(jobs[i]);
    }
  }

  var r = this.redis.multi();

  var batch = new Batch();

  // stop redis storming if uniqueness is enabled or IDs arent set
  batch.concurrency(3);

  jobs.forEach(function(job) {
    batch.push(function(done) {
      job._save(r, done);
    });
  });

  batch.end(function() {
    // how is best to handle errors from _save here?
    // we probably still want to exec the rest otherwise
    // one bad job stops the entire batch from being saved
    r.exec(cb);
  });

};

Queue.prototype.process = function(opts, cb) {

  // allow concurrency not to be set
  if (typeof opts == 'function' && !cb) {
    cb = opts;
    opts = {};
  }

  if (typeof opts === 'number') {
    opts = { concurrency: opts };
  }

  var workers = new Workers(this, this.redis);
  this.workers.push(workers);

  workers.process(opts, cb);

};

Queue.prototype.numJobs = function(states, cb) {
  var self = this;

  if (typeof states === 'function' && !cb) {
    cb = states;
    states = self.states.concat('queued');
  }

  if (!Array.isArray(states)) states = [states];

  var data = {};

  debug('getting number of jobs');

  var batch = new Batch();

  states.forEach(function(state) {
    batch.push(function(done) {
      if (state === 'queued') {
        self.redis.llen('qp:' + self.name + ':jobs', function(e, r) {
          data[state] = r;
          done();
        });
      } else {
        self.redis.zcard('qp:' + self.name + '.' + state, function(e, r) {
          data[state] = r;
          done();
        });
      }
    });
  });

  batch.end(function() {
    cb(null, data);
  });

};

Queue.prototype.getOption = function(key) {
  var defaults = {
    noInfo: false,
    pubSub: true,
    noBlock: false,
    checkInterval: 200,
    unique: false,
    deleteOnFinish: false,
    zsets: true,
    inactiveTTL: false,
    activeTTL: false,
    completedTTL: false,
    failedTTL: false
  };

  // use queue opts first
  if (this.opts.hasOwnProperty(key)) return this.opts[key];

  // try QP opts
  if (this.qp.opts.hasOwnProperty(key)) return this.qp.opts[key];

  // return the default (or undefined)
  return defaults[key];
};

Queue.prototype.getJobs = function(state, from, to, cb) {
  var self = this;

  self.redis.zrange('qp:' + this.name + '.' + state, from, to, function(err, jobs) {

    var batch = new Batch();
    jobs.forEach(function(id) {

      batch.push(function(done) {
        var job = self.create();
        job.id = id;
        job.getInfo(function() {
          job.toJSON(true);
          done(null, job);
        });
      });

    });
    batch.end(cb);
  });
};

Queue.prototype.flush = function(cb) {
  var r = this.redis.multi();

  debug('flushing');

  r.srem('qp:job:types', this.name);
};

Queue.prototype.clear = function(type, cb) {
  var self = this;

  debug('clearing');

  if (!cb && typeof type === 'function') {
    cb = type;
    type = 'completed';
  }
  if (!type) type = 'completed';

  var r = self.redis.multi();
  self.redis.zrange('qp:' + self.name + '.' + type, 0, -1, function(e, members){
    for (var i = 0; i < members.length; i++) {
      var job = self.create();
      job.id = members[i];
      job.state = type;
      job._remove(r);
    }
    r.exec(cb);
  });
};

Queue.prototype.stop = function(cb) {
  debug('stopping queue');

  var batch = new Batch();
  for (var i = 0; i < this.workers.length; i++) {
    var w = this.workers[i];
    batch.push(w.stop.bind(w));
  }
  batch.end(cb);
};
<commit_msg>tidy everything up<commit_after>var Batch = require('batch');

var redis = require('./redis');
var Job = require('./job');
var Workers = require('./workers');

var debug = require('debug')('qp:Queue');

var Queue = module.exports = function(qp, name, opts) {
  this.name = name;
  this.redis = redis.client();
  this.qp = qp;
  this.workers = [];
  this.opts = opts;
  this.states = ['active', 'inactive', 'completed', 'failed'];

  // add the queue name to the jobtypes set
  this.redis.sadd('qp:job:types', this.name);
  this.ttl();
};

Queue.prototype.getOption = function(key) {
  var defaults = {
    noInfo: false,
    pubSub: true,
    noBlock: false,
    checkInterval: 200,
    unique: false,
    deleteOnFinish: false,
    zsets: true,
    inactiveTTL: false,
    activeTTL: false,
    completedTTL: false,
    failedTTL: false,
    ttlRunFrequency: 1000
  };

  // use queue opts first
  if (this.opts.hasOwnProperty(key)) return this.opts[key];

  // try QP opts
  if (this.qp.opts.hasOwnProperty(key)) return this.qp.opts[key];

  // return the default (or undefined)
  return defaults[key];
};

Queue.prototype.create = Queue.prototype.createJob = function(data, opts) {
  var job = new Job(this, data, opts);
  return job;
};

// helper to set the job id as well as any data
Queue.prototype.job = function(id, data, opts) {
  var job = this.create(data, opts);
  job.id = id;
  return job;
};

Queue.prototype.multiSave = function(jobs, cb) {

  var self = this;

  for (var i = 0; i < jobs.length; i++) {
    if (!(jobs[i] instanceof Job)) {
      jobs[i] = self.create(jobs[i]);
    }
  }

  var r = this.redis.multi();

  var batch = new Batch();

  // stop redis storming if uniqueness is enabled or IDs arent set
  batch.concurrency(3);

  jobs.forEach(function(job) {
    batch.push(function(done) {
      job._save(r, done);
    });
  });

  batch.end(function() {
    // how is best to handle errors from _save here?
    // we probably still want to exec the rest otherwise
    // one bad job stops the entire batch from being saved
    r.exec(cb);
  });

};

Queue.prototype.process = function(opts, cb) {

  // allow concurrency not to be set
  if (typeof opts == 'function' && !cb) {
    cb = opts;
    opts = {};
  }

  if (typeof opts === 'number') {
    opts = { concurrency: opts };
  }

  var workers = new Workers(this, this.redis);
  this.workers.push(workers);

  workers.process(opts, cb);

};

Queue.prototype.numJobs = function(states, cb) {
  var self = this;

  if (typeof states === 'function' && !cb) {
    cb = states;

    // default to all states, including the queued list
    states = self.states.concat('queued');
  }

  if (!Array.isArray(states)) states = [states];

  var data = {};

  debug('getting number of jobs');

  var batch = new Batch();

  states.forEach(function(state) {
    batch.push(function(done) {
      if (state === 'queued') {
        self.redis.llen('qp:' + self.name + ':jobs', function(e, r) {
          data[state] = r;
          done();
        });
      } else {
        self.redis.zcard('qp:' + self.name + '.' + state, function(e, r) {
          data[state] = r;
          done();
        });
      }
    });
  });

  batch.end(function() {
    cb(null, data);
  });

};

Queue.prototype.getJobs = function(state, from, to, cb) {
  var self = this;

  self.redis.zrange('qp:' + this.name + '.' + state, from, to, function(err, members) {
    if (err) return cb(err);

    var jobs = [];
    for (var i = 0; i < members.length; i++) {
      var job = self.create();
      job.id = members[i];
      job.state = state;
      jobs.push(job);
    }

    cb(err, jobs);
  });
};

// gets jobs by the time they were inserted into that state
Queue.prototype.getJobsByTime = function(state, from, to, cb) {
  var self = this;

  if (typeof to === 'function' && !cb) {
    // [state, to, cb] argument format
    cb = to;
    to = from;
    from = 0;
  }

  var key = 'qp:' + self.name + '.' + state;

  self.redis.zrangebyscore(key, from, to, function(err, members){
    if (err) return cb(err);

    var jobs = [];
    for (var i = 0; i < members.length; i++) {
      var job = self.create();
      job.id = members[i];
      job.state = state;
      jobs.push(job);
    }

    cb(err, jobs);
  });
};

Queue.prototype.setTTLLock = function(cb) {
  var self = this;

  var ttl = self.getOption('ttlRunFrequency');

  var timestamp = Date.now();

  // round the timestamp to the last run
  timestamp -= timestamp % ttl;

  var key = 'qp:' + self.name + ':lock.' + timestamp;

  var m = self.redis.multi();
  m.setnx(key, timestamp, function(err, lockAcquired){
    cb(err, +lockAcquired);
  });
  m.pexpire(key, ttl);
  m.exec();
};

Queue.prototype.ttl = function() {
  var self = this;

  clearTimeout(self.ttlTimeout);

  var scheduleNext = function(){
    self.ttlTimeout = setTimeout(self.ttl.bind(self), self.getOption('ttlRunFrequency'));
  };

  self.setTTLLock(function(err, lockAcquired){
    if (err){
      debug('Unable to set ttl check lock');
      return scheduleNext();
    }

    if (!lockAcquired) return scheduleNext();

    var batch = new Batch();
    batch.concurrency(1);

    self.states.forEach(function(state){
      var ttl = self.getOption(state+'TTL');

      // not set or invalid
      if (typeof ttl != 'number') return;

      batch.push(function(done){
        self.jobsByState(state, 0, Date.now() - ttl, function(err, jobs){
          if (err || !jobs || !jobs.length) return done();

          debug('Removing %d jobs in %s state past ttl of %d', jobs.length, state, ttl);
          removeJobs(jobs, done);
        });
      });
    });

    batch.end(function(err){
      if (err) debug(err);

      scheduleNext();
    });
  });
};

Queue.prototype.removeJobs = function(jobs, cb) {
  var batch = new Batch();

  debug('removing %d jobs', jobs.length);

  for (var i = 0; i < jobs.length; i++) {
    var job = jobs[i];

    // allow an array of job IDs
    if (!(job instanceof Job)) {
      job = self.job(job);
    }

    batch.push(job.remove.bind(job));
  }

  batch.end(cb);
};

Queue.prototype.clear = function(type, cb) {
  var self = this;

  debug('clearing');

  if (!cb && typeof type === 'function') {
    cb = type;
    type = 'completed';
  }

  if (!type) type = 'completed';

  var r = self.redis.multi();
  self.redis.zrange('qp:' + self.name + '.' + type, 0, -1, function(err, members) {
    self.removeJobs(members, cb);
  });
};

Queue.prototype.stop = function(cb) {
  debug('stopping queue');

  var batch = new Batch();
  for (var i = 0; i < this.workers.length; i++) {
    var w = this.workers[i];
    batch.push(w.stop.bind(w));
  }
  batch.end(cb);
};
<|endoftext|>


<commit_before>define([
  'vendor/eventEmitter/EventEmitter',
  'inlineMode',
  'richMode',
  'formatting/sanitizer',
  'selection',
  'history',
  'throttle'],
  function (EventEmitter, InlineMode, RichMode) {

  // Note: put default plugins last so they are included in the slice.
  var defaultPlugins = Array.prototype.slice.call(arguments, 3)

  function Quill (elem, opts) {
    if (!(this instanceof Quill))
      return new Quill(elem, opts)

    var Mode

    opts = opts || {}
    if (typeof elem === 'string')
      elem = document.querySelector(elem)

    if (!elem) throw new Error('Invalid element given.')

    this.elem = elem
    this._debug = opts.debug

    // Plugin names are kept in here:
    this.plugins = []

    elem.contentEditable = true

    defaultPlugins.forEach(function (Plugin) {
      this.use(Plugin)
    }.bind(this))

    // Establish the mode:
    Mode = opts.mode
    if (!Mode || Mode === 'rich') Mode = RichMode
    else if (Mode === 'inline') Mode = InlineMode

    this.use(Mode)

    // Use the mode's plugin name as Quill's mode property:
    this.mode = Mode.plugin
  }

  Quill.prototype = Object.create(EventEmitter.prototype)

  /**
   * Quill.use(Plugin, opts) adds a plugin to the Quill instance. Plugins
   * will be passed the Quill instance as a first parameter and opts as the
   * second.
   *
   * @param {Function} Plugin
   * @param {Any} opts
   * @return Context
   */
  Quill.prototype.use = function (Plugin, opts) {
    if (!Plugin) return

    // Plugins should be named via a 'plugin' property.
    var name = Plugin.plugin

    if (!name)
      throw new Error('Plugins should be named via a \'plugin\' property.')

    if (!(name in this)) {
      try {
        this[name] = new Plugin(this, opts)
        this.plugins.push(name)
      } catch (e) {
        if (this._debug) console.log(e)
      }
    } else throw new Error('Quill is already using a plugin ' + name)

    return this
  }

  /**
   * Quill.disable(name) disables the plugin with name 'name'.
   *
   * @param {String} name
   * @return Context
   */
  Quill.prototype.disable = function (name) {
    var i

    if (!name) return

    i = this.plugins.indexOf(name)
    if (i < 0)
      throw new Error('Quill is not using a plugin ' + name)

    if (typeof this[name].destroy === 'function')
      this[name].destroy()

    delete this[name]

    this.plugins.splice(i, 1)

    return this
  }

  /**
   * Quill.destroy() removes event listeners and deletes references
   * to elements etc.
   *
   * @return null
   */
  Quill.prototype.destroy = function () {
    if (this._destroyed) return

    this.plugins.forEach(function (name) {

      if (this[name] && typeof this[name].destroy === 'function')
        this[name].destroy()

      delete this[name]
    }.bind(this))
    delete this.plugins

    this.elem.contentEditable = false
    delete this.elem

    this._destroyed = true
    return null
  }

  Quill.addDefault = function (Plugin) {
    if (!Plugin) return false

    if (!defaultPlugins)
      defaultPlugins = [Plugin]
    else defaultPlugins.push(Plugin)

    return true
  }

  /**
   * Quill.getPlugin(name) gets the plugin with name 'name' from the
   * array of default plugins. Useful mainly for testing.
   *
   * @param {String} name
   * @return Function || false
   */
  Quill.getPlugin = function (name) {
    var i

    for (i = 0; i < defaultPlugins.length; i += 1)
      if (defaultPlugins[i].plugin === name) return defaultPlugins[i]

    return false
  }

  return Quill
})
<commit_msg>Remove plugins in reverse added order.<commit_after>define([
  'vendor/eventEmitter/EventEmitter',
  'inlineMode',
  'richMode',
  'formatting/sanitizer',
  'selection',
  'history',
  'throttle'],
  function (EventEmitter, InlineMode, RichMode) {

  // Note: put default plugins last so they are included in the slice.
  var defaultPlugins = Array.prototype.slice.call(arguments, 3)

  function Quill (elem, opts) {
    if (!(this instanceof Quill))
      return new Quill(elem, opts)

    var Mode

    opts = opts || {}
    if (typeof elem === 'string')
      elem = document.querySelector(elem)

    if (!elem) throw new Error('Invalid element given.')

    this.elem = elem
    this._debug = opts.debug

    // Plugin names are kept in here:
    this.plugins = []

    elem.contentEditable = true

    defaultPlugins.forEach(function (Plugin) {
      this.use(Plugin)
    }.bind(this))

    // Establish the mode:
    Mode = opts.mode
    if (!Mode || Mode === 'rich') Mode = RichMode
    else if (Mode === 'inline') Mode = InlineMode

    this.use(Mode)

    // Use the mode's plugin name as Quill's mode property:
    this.mode = Mode.plugin
  }

  Quill.prototype = Object.create(EventEmitter.prototype)

  /**
   * Quill.use(Plugin, opts) adds a plugin to the Quill instance. Plugins
   * will be passed the Quill instance as a first parameter and opts as the
   * second.
   *
   * @param {Function} Plugin
   * @param {Any} opts
   * @return Context
   */
  Quill.prototype.use = function (Plugin, opts) {
    if (!Plugin) return

    // Plugins should be named via a 'plugin' property.
    var name = Plugin.plugin

    if (!name)
      throw new Error('Plugins should be named via a \'plugin\' property.')

    if (!(name in this)) {
      try {
        this[name] = new Plugin(this, opts)
        this.plugins.push(name)
      } catch (e) {
        if (this._debug) console.log(e)
      }
    } else throw new Error('Quill is already using a plugin ' + name)

    return this
  }

  /**
   * Quill.disable(name) disables the plugin with name 'name'.
   *
   * @param {String} name
   * @return Context
   */
  Quill.prototype.disable = function (name) {
    var i

    if (!name) return

    i = this.plugins.indexOf(name)
    if (i < 0)
      throw new Error('Quill is not using a plugin ' + name)

    if (typeof this[name].destroy === 'function')
      this[name].destroy()

    delete this[name]

    this.plugins.splice(i, 1)

    return this
  }

  /**
   * Quill.destroy() removes event listeners and deletes references
   * to elements etc.
   *
   * @return null
   */
  Quill.prototype.destroy = function () {
    if (this._destroyed) return

    var i = this.plugins.length

    // We disable plugin in the reverse order they were added.
    // (Mainly so the sanitizer gets removed last).
    while (i) {
      this.disable(this.plugins[i - 1])
      i -= 1
    }

    delete this.plugins

    this.elem.contentEditable = false
    delete this.elem

    this._destroyed = true
    return null
  }

  Quill.addDefault = function (Plugin) {
    if (!Plugin) return false

    if (!defaultPlugins)
      defaultPlugins = [Plugin]
    else defaultPlugins.push(Plugin)

    return true
  }

  /**
   * Quill.getPlugin(name) gets the plugin with name 'name' from the
   * array of default plugins. Useful mainly for testing.
   *
   * @param {String} name
   * @return Function || false
   */
  Quill.getPlugin = function (name) {
    var i

    for (i = 0; i < defaultPlugins.length; i += 1)
      if (defaultPlugins[i].plugin === name) return defaultPlugins[i]

    return false
  }

  return Quill
})
<|endoftext|>


<commit_before>jQuery(function ($) {
    var csrf_token = $('meta[name=csrf-token]').attr('content'),
        csrf_param = $('meta[name=csrf-param]').attr('content');

    $.fn.extend({
        /**
         * Triggers a custom event on an element and returns the event result
         * this is used to get around not being able to ensure callbacks are placed
         * at the end of the chain.
         *
         * TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our
         *       own events and placing ourselves at the end of the chain.
         */
        triggerAndReturn: function (name, data) {
            var event = new jQuery.Event(name);
            this.trigger(event, data);

            return event.result !== false;
        },

        /**
         * Handles execution of remote calls firing overridable events along the way
         */
        callRemote: function () {
            var el      = this,
                data    = el.is('form') ? el.serializeArray() : [],
                method  = el.attr('method') || el.attr('data-method') || 'GET',
                url     = el.attr('action') || el.attr('href');

            if (url === undefined) {
              throw "No URL specified for remote call (action or href must be present).";
            } else {
                if (el.triggerAndReturn('ajax:before')) {
                    $.ajax({
                        url: url,
                        data: data,
                        type: method.toUpperCase(),
                        beforeSend: function (xhr) {
                            xhr.setRequestHeader("Accept", "text/javascript");
                            el.trigger('ajax:loading', xhr);
                        },
                        success: function (data, status, xhr) {
                            el.trigger('ajax:success', [data, status, xhr]);
                        },
                        complete: function (xhr) {
                            el.trigger('ajax:complete', xhr);
                        },
                        error: function (xhr, status, error) {
                            el.trigger('ajax:failure', [xhr, status, error]);
                        }
                    });
                }

                el.trigger('ajax:after');
            }
        }
    });

    /**
     *  confirmation handler
     */
    $('a[data-confirm],input[data-confirm]').live('click', function () {
        var el = $(this);
        if (el.triggerAndReturn('confirm')) {
            if (!confirm(el.attr('data-confirm'))) {
                return false;
            }
        }
    });

    /**
     * remote handlers
     */
    $('form[data-remote="true"]').live('submit', function (e) {
        $(this).callRemote();
        e.preventDefault();
    });

    $('a[data-remote="true"],input[data-remote="true"]').live('click', function (e) {
        $(this).callRemote();
        e.preventDefault();
    });

    $('a[data-method][data-remote!=true]').live('click',function(e){
        var link = $(this),
            href = link.attr('href'),
            method = link.attr('data-method'),
            form = $('<form method="post" action="'+href+'">'),
            input = $('<input name="_method" value="'+method+'" type="hidden" />'),
            csrf_input = $('<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />');

        form.hide()
            .append(input)
            .append(csrf_input)
            .appendTo('body'); // redundant?

        e.preventDefault();
        form.submit();
    });

    /**
     * disable_with handlers
     */
    $('form[data-remote="true"]').live('ajax:before', function () {
        $(this).children('input[data-disable-with]').each(function () {
            var input = $(this);
            input.data('enable_with', input.val())
                 .attr('value', input.attr('data-disable-with'))
                 .attr('disabled', 'disabled');
        });
    });

    $('form[data-remote="true"]').live('ajax:after', function () {
        $(this).children('input[data-disable-with]').each(function () {
            var input = $(this);
            input.removeAttr('disabled')
                 .val(input.data('enable_with'));
        });
    });
});

<commit_msg>Utilize dataType option to manage Accept header<commit_after>jQuery(function ($) {
    var csrf_token = $('meta[name=csrf-token]').attr('content'),
        csrf_param = $('meta[name=csrf-param]').attr('content');

    $.fn.extend({
        /**
         * Triggers a custom event on an element and returns the event result
         * this is used to get around not being able to ensure callbacks are placed
         * at the end of the chain.
         *
         * TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our
         *       own events and placing ourselves at the end of the chain.
         */
        triggerAndReturn: function (name, data) {
            var event = new jQuery.Event(name);
            this.trigger(event, data);

            return event.result !== false;
        },

        /**
         * Handles execution of remote calls firing overridable events along the way
         */
        callRemote: function () {
            var el      = this,
                data    = el.is('form') ? el.serializeArray() : [],
                method  = el.attr('method') || el.attr('data-method') || 'GET',
                url     = el.attr('action') || el.attr('href');

            if (url === undefined) {
              throw "No URL specified for remote call (action or href must be present).";
            } else {
                if (el.triggerAndReturn('ajax:before')) {
                    $.ajax({
                        url: url,
                        data: data,
                        dataType: 'script',
                        type: method.toUpperCase(),
                        beforeSend: function (xhr) {
                            el.trigger('ajax:loading', xhr);
                        },
                        success: function (data, status, xhr) {
                            el.trigger('ajax:success', [data, status, xhr]);
                        },
                        complete: function (xhr) {
                            el.trigger('ajax:complete', xhr);
                        },
                        error: function (xhr, status, error) {
                            el.trigger('ajax:failure', [xhr, status, error]);
                        }
                    });
                }

                el.trigger('ajax:after');
            }
        }
    });

    /**
     *  confirmation handler
     */
    $('a[data-confirm],input[data-confirm]').live('click', function () {
        var el = $(this);
        if (el.triggerAndReturn('confirm')) {
            if (!confirm(el.attr('data-confirm'))) {
                return false;
            }
        }
    });

    /**
     * remote handlers
     */
    $('form[data-remote="true"]').live('submit', function (e) {
        $(this).callRemote();
        e.preventDefault();
    });

    $('a[data-remote="true"],input[data-remote="true"]').live('click', function (e) {
        $(this).callRemote();
        e.preventDefault();
    });

    $('a[data-method][data-remote!=true]').live('click',function(e){
        var link = $(this),
            href = link.attr('href'),
            method = link.attr('data-method'),
            form = $('<form method="post" action="'+href+'">'),
            input = $('<input name="_method" value="'+method+'" type="hidden" />'),
            csrf_input = $('<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />');

        form.hide()
            .append(input)
            .append(csrf_input)
            .appendTo('body'); // redundant?

        e.preventDefault();
        form.submit();
    });

    /**
     * disable_with handlers
     */
    $('form[data-remote="true"]').live('ajax:before', function () {
        $(this).children('input[data-disable-with]').each(function () {
            var input = $(this);
            input.data('enable_with', input.val())
                 .attr('value', input.attr('data-disable-with'))
                 .attr('disabled', 'disabled');
        });
    });

    $('form[data-remote="true"]').live('ajax:after', function () {
        $(this).children('input[data-disable-with]').each(function () {
            var input = $(this);
            input.removeAttr('disabled')
                 .val(input.data('enable_with'));
        });
    });
});

<|endoftext|>


<commit_before>var readyCallbacks = [],
	readyListenedTo = FALSE,
	readyAcknowledged = FALSE,
	readyFireing = FALSE;

function fireReady() {

	while ( readyCallbacks[ STR_LENGTH ] ) {
			args = readyCallbacks.shift();
			args[0][ STR_APPLY ]( document , slice[ STR_CALL ]( args , 1 ) );
	}

	readyFireing = FALSE;

}

function testReady() {

	if ( document[ STR_GET_ELEMENTS_BY_TAG_NAME ]
		&& document.body
		&& document[ STR_GET_ELEMENTS_BY_TAG_NAME ]("body")[ STR_LENGTH ] ) {

		readyAcknowledged = readyFireing = TRUE;
		later( fireReady );

		return TRUE;
	}

}

function ready( func ) {

	if ( isFunction ( func ) ) {

		readyCallbacks[ STR_PUSH ]( arguments );

		if ( ! readyListenedTo ) {

			readyListenedTo = TRUE;

			if ( ! testReady() ) {
				poll( testReady );
			}

		} else if ( readyAcknowledged && ! readyFireing ) {

			readyFireing = TRUE
			fireReady();

		}

	}

	return FALSE;
}

<commit_msg>Re-ordered tests in testReady (should be faster). Need to check if polling and waiting for body to pop out is a valid approach.<commit_after>var readyCallbacks = [],
	readyListenedTo = FALSE,
	readyAcknowledged = FALSE,
	readyFireing = FALSE;

function fireReady() {

	while ( readyCallbacks[ STR_LENGTH ] ) {
			args = readyCallbacks.shift();
			args[0][ STR_APPLY ]( document , slice[ STR_CALL ]( args , 1 ) );
	}

	readyFireing = FALSE;

}

function testReady() {

	if ( document.body
		&& document[ STR_GET_ELEMENTS_BY_TAG_NAME ]
		&& document[ STR_GET_ELEMENTS_BY_TAG_NAME ]("body")[ STR_LENGTH ] ) {

		readyAcknowledged = readyFireing = TRUE;
		later( fireReady );

		return TRUE;
	}

}

function ready( func ) {

	if ( isFunction ( func ) ) {

		readyCallbacks[ STR_PUSH ]( arguments );

		if ( ! readyListenedTo ) {

			readyListenedTo = TRUE;

			if ( ! testReady() ) {
				poll( testReady );
			}

		} else if ( readyAcknowledged && ! readyFireing ) {

			readyFireing = TRUE
			fireReady();

		}

	}

	return FALSE;
}

<|endoftext|>


<commit_before>/**
 * @module Keo
 * @submodule Redux
 * @author Adam Timberlake
 * @link https://github.com/Wildhoney/Keo
 */
import {createWithCompose, wrap} from './keo';
import {connect} from 'react-redux';
export {memoize, trace, partial, compose, composeDeferred} from 'funkel';
export {default as objectAssign} from 'object-assign';
export {pipe, pipeDeferred, resolutionMap} from './keo';

/**
 * @method stitch
 * @param {Object|Function} component
 * @param {Function} [mapStateToProps]
 * @return {React.createClass}
 */
export const stitch = (component, mapStateToProps) => {
    return connect(mapStateToProps)(createWithCompose(wrap(component)));
};
<commit_msg>Added default Redux mapStateToProps function<commit_after>/**
 * @module Keo
 * @submodule Redux
 * @author Adam Timberlake
 * @link https://github.com/Wildhoney/Keo
 */
import {createWithCompose, wrap} from './keo';
import {connect} from 'react-redux';
export {memoize, trace, partial, compose, composeDeferred} from 'funkel';
export {default as objectAssign} from 'object-assign';
export {pipe, pipeDeferred, resolutionMap} from './keo';

/**
 * @method stitch
 * @param {Object|Function} component
 * @param {Function} [mapStateToProps = state => state]
 * @return {React.createClass}
 */
export const stitch = (component, mapStateToProps = state => state) => {
    return connect(mapStateToProps)(createWithCompose(wrap(component)));
};
<|endoftext|>