<commit_before>const i_common = require('../common');
const i_extractor = require('../extractor');
const i_decorator = require('../decorator');

const c_extract_feature = {
   '"': [extract_string],
   '\'': [extract_char],
   '/': [extract_line_comment, extract_multiline_comment]
};

function extract_string(env) {
   return i_extractor.extract_string(env, '"', '"', '\\');
}

function extract_char(env) {
   return i_extractor.extract_string(env, '\'', '\'', '\\');
}

function extract_line_comment(env) {
   return i_extractor.extract_comment(env, '//', '\n');
}

function extract_multiline_comment(env) {
   return i_extractor.extract_comment(env, '/*', '*/');
}

const c_keywords = [
   // ref:
   // - https://en.cppreference.com/w/c/keyword
   'auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', 'double',
   'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
   'return', 'short', 'signed', 'sizeof', 'static', 'struct', 'switch', 'typedef',
   'union', 'unsigned', 'void', 'volatile', 'while',
   /* C99 */ '_Bool', '_Complex', '_Imaginary', 'inline', 'restrict', '_Pragma',
   /* C11 */ '_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn', '_Static_assert',
   '_Thread_local',
   /* C extension */ 'asm', 'fortran',
   '#if', '#ifdef', '#ifndef', '#else', '#elif', '#endif', '#pragma', '#error',
   '#define', '#undef', '#line', 'defined', '#include',
];

const c_combinations = [
   '++', '--', '+=', '-=', '*=', '/=', '%=', '==',
   '!=', '>=', '<=', '->', '&&', '||', '<<', '>>',
   '&=', '|=', '^=', '<<=', '>>=', ['#', 'include'],
   ['#', 'if'], ['#', 'ifdef'], ['#', 'ifndef'],
   ['#', 'else'], ['#', 'elif'], ['#', 'endif'],
   ['#', 'pragma'], ['#', 'error'], ['#', 'define'],
   ['#', 'undef'], ['#', 'line'],
];

const c_decorate_precompile_feature = {
   '#include': [decorate_include],
   '#if': [decorate_precompile],
   '#ifdef': [decorate_precompile],
   '#ifndef': [decorate_precompile],
   '#elif': [decorate_precompile],
   '#else': [decorate_precompile],
   '#endif': [decorate_precompile],
   '#pragma': [decorate_precompile],
   '#error': [decorate_precompile],
   '#define': [decorate_precompile],
   '#undef': [decorate_precompile],
   '#line': [decorate_precompile],
   '{': [decorate_bracket],
   '[': [decorate_bracket],
   '(': [decorate_bracket],
   '}': [decorate_bracket],
   ']': [decorate_bracket],
   ')': [decorate_bracket],
   '\\\n': [decorate_combline],
};

const c_decorate_feature = {
   '#include': [skip_precompile],
   '#if': [skip_precompile],
   '#ifdef': [skip_precompile],
   '#ifndef': [skip_precompile],
   '#elif': [skip_precompile],
   '#else': [skip_precompile],
   '#endif': [skip_precompile],
   '#pragma': [skip_precompile],
   '#error': [skip_precompile],
   '#define': [skip_precompile],
   '#undef': [skip_precompile],
   '#line': [skip_precompile],
   '{': [
      decorate_function, decorate_struct, decorate_enum,
      decorate_union, enter_block_bracket,
   ],
   '}': [leave_block_bracket],
   ';': [decorate_function],
};

function enter_block_bracket(env) {
   if (!env.indefine_able) env.indefine_able = 0;
   env.indefine_able ++;
   return 1;
}

function leave_block_bracket(env) {
   if (env.indefine_able) {
      env.indefine_able --;
   }
   return 1;
}

function decorate_combline(env) {
   let token = env.tokens[env.cursor];
   token._token = token.token;
   token.token = '';
   return 1;
}

const return_type_prefix = ['struct', 'enum', 'union'];
const keyword_block = ['if', 'for', 'while', 'switch'];
function decorate_function(env) {
   let st = env.cursor;
   let token = env.tokens[st];
   // int main() {}
   // int main() ;
   let ed = token.endIndex || env.cursor;
   if (ed === env.cursor && env.indefine_able > 1) {
      return 0;
   }
   let parameter = [];
   st = i_common.search_prev_skip_spacen(env.tokens, st-1);
   token = env.tokens[st];
   if (token.token !== ')') return 0;
   parameter.push(st);
   st = i_common.search_prev(env.tokens, st-1, (x) => x.endIndex !== st+1);
   parameter.unshift(st);
   token = env.tokens[st];
   if (!token) return 0;
   st = i_common.search_prev_skip_spacen(env.tokens, st-1);
   token = env.tokens[st];
   if (!token) return 0;
   if (keyword_block.indexOf(token.token) >= 0) {
      // if/for/while/switch (...) {...}
      return 0;
   }
   let return_type = st;
   if (token.token === ')') {
      // return function pointer
      parameter = [];
      return_type = i_common.search_prev(env.tokens, st-1, (x) => x.endIndex !== st);
      st = i_common.search_prev_skip_spacen(env.tokens, st-1);
      token = env.tokens[st];
      if (!token) return 0;
      if (token.token !== ')') return 0;
      parameter.push(st);
      st = i_common.search_prev(env.tokens, st-1, (x) => x.endIndex !== st+1);
      parameter.unshift(st);
      st = i_common.search_prev_skip_spacen(env.tokens, st-1);
      token = env.tokens[st];
   }
   let name = [st, st+1];
   // search for heading type, e.g. int, struct name {int a;}**
   while (true) {
      return_type = i_common.search_prev_skip_spacen(env.tokens, return_type-1);
      token = env.tokens[return_type];
      if (!token) break;
      if (token.token === '*') continue;
      if (token.token === '}') {
         return_type = i_common.search_prev(
            env.tokens, return_type-1, (x) => x.endIndex !== return_type+1
         );
         return_type = i_common.search_prev_skip_spacen(env.tokens, return_type-1);
         token = env.tokens[return_type];
         if (!token) break;
      }
      //      m0() {}      m1() {}
      // void m0() {} void m1() {}
      if (token.token === ')') {
         break;
      }
      // name
      if (return_type_prefix.indexOf(token.token) < 0) {
         st = return_type;
         return_type = i_common.search_prev_skip_spacen(env.tokens, return_type-1);
         token = env.tokens[return_type];
         if (token && token.endIndex && return_type_prefix.indexOf(token.token) >= 0) {
            st = return_type;
         }
      } else {
         st = return_type;
      }
      // TODO: search for function attribute, e.g. extern, static
      break;
   }
   env.indefine_able = (env.indefine_able || 0) + 1;
   token = env.tokens[name[0]];
   token.startIndex = st;
   token.endIndex = ed;
   token.parameter = parameter;
   token.name = name;
   token.tag = i_common.TAG_FUNCTION;
   token = env.tokens[env.cursor];
   if (token.token === ';') env.indefine_able --;
   return 1;
}

function decorate_type(env, type) {
   let st = env.cursor;
   let token = env.tokens[st];
   let ed = token.endIndex;
   let name = null;
   st = i_common.search_prev_skip_spacen(env.tokens, st-1);
   token = env.tokens[st];
   if (!token) return 0;
   if (token.token !== type) {
      name = [st, st+1];
      st = i_common.search_prev_skip_spacen(env.tokens, st-1);
   }
   token = env.tokens[st];
   if (!token) return 0;
   if (token.token !== type) {
      return 0;
   }
   token.startIndex = st;
   token.endIndex = ed;
   token.tag = i_common.TAG_CLASS;
   if (name) token.name = name;
   return 1;
}

function decorate_struct(env) {
   return decorate_type(env, 'struct');
}

function decorate_enum(env) {
   return decorate_type(env, 'enum');
}

function decorate_union(env) {
   return decorate_type(env, 'union');
}

function skip_precompile(env) {
   let token = env.tokens[env.cursor];
   return token.endIndex - token.startIndex;
}

function decorate_include(env) {
   let st = env.cursor, ed = st;
   let start_token = env.tokens[st];
   ed = i_common.search_next(env.tokens, st+1, (x) => x.tag !== i_common.TAG_STRING && x.token !== '<');
   let token = env.tokens[ed];
   if (!token) return 1;
   start_token.startIndex = st;
   if (token.tag === i_common.TAG_STRING) {
      start_token.name = [ed, ed+1];
   } else {
      st = ed + 1;
      ed = i_common.search_next(env.tokens, st, (x) => x.token !== '>');
      start_token.name = [st, ed];
   }
   start_token.endIndex = ed + 1;
   return ed - st;
}

function decorate_precompile(env) {
   let st = env.cursor;
   let ed = i_common.search_next(env.tokens, st+1, (x) => x.token !== '\n');
   while (env.tokens[ed-1].token === '\\') {
      ed = i_common.search_next(env.tokens, ed+1, (x) => x.token !== '\n');
   }
   let start_token = env.tokens[st];
   start_token.startIndex = st;
   start_token.endIndex = ed;
   return ed - st;
}

function decorate_bracket(env) {
   if (!env.bracket_stack) {
      env.bracket_stack = [];
   }
   let bracket_token = env.tokens[env.cursor];
   switch (bracket_token.token) {
      case '{': case '[': case '(':
      bracket_token.tag = i_common.TAG_BRACKET[bracket_token.token];
      bracket_token.startIndex = env.cursor;
      env.bracket_stack.push(bracket_token);
      break;
      case '}': case ']': case ')':
      bracket_token = env.bracket_stack.pop();
      // TODO: deal with not pairing bracket
      bracket_token.endIndex = env.cursor + 1;
      break;
   }
   return 1;
}

function parse(env) {
   env.cursor = 0;
   i_extractor.extract_tokens(env, c_extract_feature);
   i_extractor.merge_tokens(env, c_combinations);
   env.cursor = 0;
   i_decorator.decorate_scope(env, c_decorate_precompile_feature);
   // TODO: simulate preprocess
   i_decorator.decorate_keywords(env, c_keywords);
   env.cursor = 0;
   i_decorator.decorate_scope(env, c_decorate_feature);
   return env.tokens;
}

const i_fs = require('fs');
let filename = process.argv[2];
let text = i_fs.readFileSync(filename).toString();
let tokens = parse({text: text});
console.log(JSON.stringify(tokens.map((x, i) => { x.id=i; return x; }), null, 3));
<commit_msg>[lazac] parser v2: improve c parser<commit_after>const i_common = require('../common');
const i_extractor = require('../extractor');
const i_decorator = require('../decorator');

const c_extract_feature = {
   '"': [extract_string],
   '\'': [extract_char],
   '/': [extract_line_comment, extract_multiline_comment]
};

function extract_string(env) {
   return i_extractor.extract_string(env, '"', '"', '\\');
}

function extract_char(env) {
   return i_extractor.extract_string(env, '\'', '\'', '\\');
}

function extract_line_comment(env) {
   return i_extractor.extract_comment(env, '//', '\n');
}

function extract_multiline_comment(env) {
   return i_extractor.extract_comment(env, '/*', '*/');
}

const c_keywords = [
   // ref:
   // - https://en.cppreference.com/w/c/keyword
   'auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', 'double',
   'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
   'return', 'short', 'signed', 'sizeof', 'static', 'struct', 'switch', 'typedef',
   'union', 'unsigned', 'void', 'volatile', 'while',
   /* C99 */ '_Bool', '_Complex', '_Imaginary', 'inline', 'restrict', '_Pragma',
   /* C11 */ '_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn', '_Static_assert',
   '_Thread_local',
   /* C extension */ 'asm', 'fortran',
   '#if', '#ifdef', '#ifndef', '#else', '#elif', '#endif', '#pragma', '#error',
   '#define', '#undef', '#line', 'defined', '#include',
];

const c_combinations = [
   '++', '--', '+=', '-=', '*=', '/=', '%=', '==',
   '!=', '>=', '<=', '->', '&&', '||', '<<', '>>',
   '&=', '|=', '^=', '<<=', '>>=', ['#', 'include'],
   ['#', 'if'], ['#', 'ifdef'], ['#', 'ifndef'],
   ['#', 'else'], ['#', 'elif'], ['#', 'endif'],
   ['#', 'pragma'], ['#', 'error'], ['#', 'define'],
   ['#', 'undef'], ['#', 'line'],
];

const c_decorate_precompile_feature = {
   '#include': [decorate_include],
   '#if': [decorate_precompile],
   '#ifdef': [decorate_precompile],
   '#ifndef': [decorate_precompile],
   '#elif': [decorate_precompile],
   '#else': [decorate_precompile],
   '#endif': [decorate_precompile],
   '#pragma': [decorate_precompile],
   '#error': [decorate_precompile],
   '#define': [decorate_precompile],
   '#undef': [decorate_precompile],
   '#line': [decorate_precompile],
   '{': [decorate_bracket],
   '[': [decorate_bracket],
   '(': [decorate_bracket],
   '}': [decorate_bracket],
   ']': [decorate_bracket],
   ')': [decorate_bracket],
   '\\\n': [decorate_combline],
};

const c_decorate_feature = {
   '#include': [skip_precompile],
   '#if': [skip_precompile],
   '#ifdef': [skip_precompile],
   '#ifndef': [skip_precompile],
   '#elif': [skip_precompile],
   '#else': [skip_precompile],
   '#endif': [skip_precompile],
   '#pragma': [skip_precompile],
   '#error': [skip_precompile],
   '#define': [skip_precompile],
   '#undef': [skip_precompile],
   '#line': [skip_precompile],
   '{': [
      decorate_function, decorate_struct, decorate_enum,
      decorate_union, enter_block_bracket,
   ],
   '}': [leave_block_bracket],
   ';': [decorate_function],
};

function enter_block_bracket(env) {
   if (!env.indefine_able) env.indefine_able = 0;
   env.indefine_able ++;
   return 1;
}

function leave_block_bracket(env) {
   if (env.indefine_able) {
      env.indefine_able --;
   }
   return 1;
}

function decorate_combline(env) {
   let token = env.tokens[env.cursor];
   token._token = token.token;
   token.token = '';
   return 1;
}

const return_type_prefix = ['struct', 'enum', 'union'];
const keyword_block = ['if', 'for', 'while', 'switch'];
function decorate_function(env) {
   let st = env.cursor;
   let token = env.tokens[st];
   // int main() {}
   // int main() ;
   let ed = token.endIndex || env.cursor;
   if (env.indefine_able >= 1) {
      return 0;
   }
   let parameter = [];
   st = i_common.search_prev_skip_spacen(env.tokens, st-1);
   token = env.tokens[st];
   if (token.token !== ')') return 0;
   parameter.push(st);
   st = i_common.search_prev(env.tokens, st-1, (x) => x.endIndex !== st+1);
   parameter.unshift(st);
   token = env.tokens[st];
   if (!token) return 0;
   st = i_common.search_prev_skip_spacen(env.tokens, st-1);
   token = env.tokens[st];
   if (!token) return 0;
   if (keyword_block.indexOf(token.token) >= 0) {
      // if/for/while/switch (...) {...}
      return 0;
   }
   let return_type = st;
   if (token.token === ')') {
      // return function pointer
      parameter = [];
      return_type = i_common.search_prev(env.tokens, st-1, (x) => x.endIndex !== st);
      st = i_common.search_prev_skip_spacen(env.tokens, st-1);
      token = env.tokens[st];
      if (!token) return 0;
      if (token.token !== ')') return 0;
      parameter.push(st);
      st = i_common.search_prev(env.tokens, st-1, (x) => x.endIndex !== st+1);
      parameter.unshift(st);
      st = i_common.search_prev_skip_spacen(env.tokens, st-1);
      token = env.tokens[st];
   }
   let name = [st, st+1];
   // search for heading type, e.g. int, struct name {int a;}**
   while (true) {
      return_type = i_common.search_prev_skip_spacen(env.tokens, return_type-1);
      token = env.tokens[return_type];
      if (!token) break;
      if (token.token === '*') continue;
      if (token.token === '}') {
         return_type = i_common.search_prev(
            env.tokens, return_type-1, (x) => x.endIndex !== return_type+1
         );
         return_type = i_common.search_prev_skip_spacen(env.tokens, return_type-1);
         token = env.tokens[return_type];
         if (!token) break;
      }
      //      m0() {}      m1() {}
      // void m0() {} void m1() {}
      if (token.token === ')') {
         break;
      }
      // name
      if (return_type_prefix.indexOf(token.token) < 0) {
         st = return_type;
         return_type = i_common.search_prev_skip_spacen(env.tokens, return_type-1);
         token = env.tokens[return_type];
         if (token && token.endIndex && return_type_prefix.indexOf(token.token) >= 0) {
            st = return_type;
         }
      } else {
         st = return_type;
      }
      // TODO: search for function attribute, e.g. extern, static
      break;
   }
   env.indefine_able = (env.indefine_able || 0) + 1;
   token = env.tokens[name[0]];
   token.startIndex = st;
   token.endIndex = ed;
   token.parameter = parameter;
   token.name = name;
   token.tag = i_common.TAG_FUNCTION;
   token = env.tokens[env.cursor];
   if (token.token === ';') env.indefine_able --;
   return 1;
}

function decorate_type(env, type) {
   let st = env.cursor;
   let token = env.tokens[st];
   let ed = token.endIndex;
   let name = null;
   st = i_common.search_prev_skip_spacen(env.tokens, st-1);
   token = env.tokens[st];
   if (!token) return 0;
   if (token.token !== type) {
      name = [st, st+1];
      st = i_common.search_prev_skip_spacen(env.tokens, st-1);
   }
   token = env.tokens[st];
   if (!token) return 0;
   if (token.token !== type) {
      return 0;
   }
   token.startIndex = st;
   token.endIndex = ed;
   token.tag = i_common.TAG_CLASS;
   if (name) token.name = name;
   return 1;
}

function decorate_struct(env) {
   return decorate_type(env, 'struct');
}

function decorate_enum(env) {
   return decorate_type(env, 'enum');
}

function decorate_union(env) {
   return decorate_type(env, 'union');
}

function skip_precompile(env) {
   let token = env.tokens[env.cursor];
   return token.endIndex - token.startIndex;
}

function decorate_include(env) {
   let st = env.cursor, ed = st;
   let start_token = env.tokens[st];
   ed = i_common.search_next(env.tokens, st+1, (x) => x.tag !== i_common.TAG_STRING && x.token !== '<');
   let token = env.tokens[ed];
   if (!token) return 1;
   start_token.startIndex = st;
   if (token.tag === i_common.TAG_STRING) {
      start_token.name = [ed, ed+1];
   } else {
      st = ed + 1;
      ed = i_common.search_next(env.tokens, st, (x) => x.token !== '>');
      start_token.name = [st, ed];
   }
   start_token.endIndex = ed + 1;
   return ed - st;
}

function decorate_precompile(env) {
   let st = env.cursor;
   let ed = i_common.search_next(env.tokens, st+1, (x) => x.token !== '\n');
   while (env.tokens[ed-1].token === '\\') {
      ed = i_common.search_next(env.tokens, ed+1, (x) => x.token !== '\n');
   }
   let start_token = env.tokens[st];
   start_token.startIndex = st;
   start_token.endIndex = ed;
   return ed - st;
}

function decorate_bracket(env) {
   if (!env.bracket_stack) {
      env.bracket_stack = [];
   }
   let bracket_token = env.tokens[env.cursor];
   switch (bracket_token.token) {
      case '{': case '[': case '(':
      bracket_token.tag = i_common.TAG_BRACKET[bracket_token.token];
      bracket_token.startIndex = env.cursor;
      env.bracket_stack.push(bracket_token);
      break;
      case '}': case ']': case ')':
      bracket_token = env.bracket_stack.pop();
      // TODO: deal with not pairing bracket
      bracket_token.endIndex = env.cursor + 1;
      break;
   }
   return 1;
}

function parse(env) {
   env.cursor = 0;
   i_extractor.extract_tokens(env, c_extract_feature);
   i_extractor.merge_tokens(env, c_combinations);
   env.cursor = 0;
   i_decorator.decorate_scope(env, c_decorate_precompile_feature);
   // TODO: simulate preprocess
   i_decorator.decorate_keywords(env, c_keywords);
   env.cursor = 0;
   i_decorator.decorate_scope(env, c_decorate_feature);
   return env.tokens;
}

const i_fs = require('fs');
let filename = process.argv[2];
let text = i_fs.readFileSync(filename).toString();
let tokens = parse({text: text});
console.log(JSON.stringify(tokens.map((x, i) => { x.id=i; return x; }), null, 3));
<|endoftext|>


<commit_before>/*
Name:             bolcom.js
Description:      Module for node.js to access Bol.com Open API service
Author:           Franklin (https://fvdm.com)
Source:           https://github.com/fvdm/nodejs-bolcom
License:          Unlicense
*/

const { doRequest } = require ('httpreq');

module.exports = class BolcomAPI {

  constructor ({
    apikey,
    sessionId = null,
    timeout = 5000,
  }) {
    this._config = {
      apikey,
      sessionId,
      timeout,
    };
  }

  /**
   * Clean up product URLs
   *
   * @param   {object}  product  Product to clean
   * @return  {object}           Cleaned product
   */

  async _cleanProductUrls (product) {
    let urls = {};
    let url;

    for (let i = 0; i < product.urls.length; i++) {
      url = product.urls[i];
      urls[url.key] = url;
    }

    product.urls = urls;
    return product;
  }

  /**
   * Clean up product images
   *
   * @param   {object}  product  Product to clean
   * @return  {object}           Cleaned product
   */

  async _cleanProductImages (product) {
    let imgs = {};
    let image;

    for (let i = 0; i < product.images.length; i++) {
      image = product.images[i];
      imgs[image.key] = product.images[i];
    }

    product.images = imgs;
    return product;
  }

  /**
   * Clean up product attributeGroups
   *
   * @param   {object}  product  Product to clean
   * @return  {object}           Cleaned product
   */

  async _cleanProductAttrGroups (product) {
    let groups = {};
    let group;
    let attrib;

    if (product.attributeGroups) {
      for (let i = 0; i < product.attributeGroups.length; i++) {
        group = product.attributeGroups[i];
        groups[group.title] = {
          title: group.title,
        };

        if (group.attributes) {
          groups[group.title].attributes = {};

          for (let a = 0; a < group.attributes.length; a++) {
            attrib = group.attributes[a];
            groups[group.title].attributes[attrib.key] = attrib;
          }
        }
      }

      product.attributeGroups = groups;
    }

    return product;
  }

  /**
   * Clean up product data
   *
   * @param   {object}  product  Object to clean
   * @return  {object}           Cleaned object
   */

  async _cleanProduct (product) {
    return this._cleanProductUrls (product)
      .then (this._cleanProductImages)
      .then (this._cleanProductAttrGroups)
    ;
  }

  /**
   * Communication with API
   *
   * @param     {string}    cat       api.bol.com/:CAT/v4/method
   * @param     {string}    method    api.bol.com/cat/v4/:METHOD
   * @param     {object}    [params]  Request paramaters
   *
   * @return    {Promise<object>}
   */

  async _talk (cat, method, params = {}) {
    const options = {
      url: `https://api.bol.com/${cat}/v4/${method}`,
      method: 'GET',
      timeout: this._config.timeout,
      parameters: params,
      headers: {
        'Accept': 'application/json',
        'User-Agent': 'bolcom.js (https://www.npmjs.com/package/bolcom)',
      },
    };

    options.parameters.apikey = this._config.apikey;
    options.parameters.format = 'json';

    // check session ID
    if (this._config.sessionId) {
      options.headers['X-OpenAPI-Session-ID'] = this._config.sessionId;
    }

    // send request
    const data = await doRequest (options)
      .then (res => JSON.parse (res.body)
    ;

    if (data.status) {
      const error = new Error (data.title);

      error.status = data.status;
      error.detail = data.detail;

      throw error;
    }

    return data;
  }

  /**
   * Method: ping
   *
   * @return    {Promise<object>}
   */

  async ping () {
    return this._talk ('utils', 'ping');
  }

  /**
   * Method: account.sessions
   *
   * @return    {Promise<object>}
   */

  async accountSessions () {
    return this._talk ('accounts', 'sessions');
  }

  /**
   * Generic catalog request handler
   *
   * @param     {string}    name      Catalog method name
   * @param     {object}    props     Request parameters
   *
   * @return    {Promise<object>}
   */

  async _catalogTalk (name, props) {
    const data = await this._talk ('catalog', name, props);

    if (data.products && Array.isArray (data.products)) {
      for (let i = 0; i < data.products.length; i++) {
        data.products[i] = this._cleanProduct (data.products[i]);
      }
    }

    return data;
  }

  /**
   * Method: catalog.search
   *
   * @param     {object}    props     Method parameters
   *
   * @return    {Promise<object>}
   */

  async catalogSearch (props) {
    return this._catalogTalk ('search', props);
  }

  /**
   * Method: catalog.lists
   *
   * @param     {object}    props     Method parameters
   *
   * @return    {Promise<object>}
   */

  async catalogLists (props) {
    return this._catalogTalk ('lists', props);
  }

  /**
   * Method: catalog.products
   *
   * @param     {string}    productId  Product ID
   * @param     {object}    [props]    Method parameters
   *
   * @return    {Promise<object>}
   */

  async catalogProducts (productId, props) {
    return this._catalogTalk (`products/${productId}`, props);
  }

  /**
   * Method: catalog.offers
   *
   * @param     {string}    productId  Product ID
   * @param     {object}    [props]    Method parameters
   *
   * @return    {Promise<object>}
   */

  async catalogOffers (productId, props) {
    const data = await this._talk ('catalog', `offers/${productId}`, props);

    if (data.offerData) {
      data = data.offerData;
    }

    return data;
  }

  /**
   * Method: catalog.recommendations
   *
   * @return    {Promise<object>}
   *
   * @param     {string}    productId  Product ID
   * @param     {object}    [props]    Method parameters
   */

  async catalogRecommendations (productId, props) {
    return this._catalogTalk (`recommendations/${productId}`, props);
  }

  /**
   * Method: catalog.relatedproducts
   *
   * @return    {Promise<object>}
   *
   * @param     {string}    productId  Product ID
   * @param     {object}    [props]    Method parameters
   */

  async catalogRelatedProducts (productId, props) {
    let data = await this._talk ('catalog', `relatedproducts/${productId}`, props);
    let tmp = {};
    let tmp2 = {};

    if (data.productFamilies) {
      data = data.productFamilies;

      if (!Array.isArray (data) && !data.length && !data[0].key) {
        return data;
      }

      for (let i = 0; i < data.length; i++) {
        tmp[data[i].key] = data[i];

        if (Array.isArray (data[i].productFamilyMembers)) {
          tmp2 = {};

          for (let m = 0; m < data[i].productFamilyMembers.length; m++) {
            tmp2[data[i].productFamilyMembers[m].label] = data[i].productFamilyMembers[m];
          }

          tmp[data[i].key].productFamilyMembers = tmp2;
        }

        data = tmp;
      }
    }

    return data;
  }

  /**
   * Method: account.wishlists
   *
   * @return    {Promise<object>}
   */

  async accountWishlists () {
    return this._talk ('accounts', 'wishlists');
  }

};
<commit_msg>Fix: Syntax typo<commit_after>/*
Name:             bolcom.js
Description:      Module for node.js to access Bol.com Open API service
Author:           Franklin (https://fvdm.com)
Source:           https://github.com/fvdm/nodejs-bolcom
License:          Unlicense
*/

const { doRequest } = require ('httpreq');

module.exports = class BolcomAPI {

  constructor ({
    apikey,
    sessionId = null,
    timeout = 5000,
  }) {
    this._config = {
      apikey,
      sessionId,
      timeout,
    };
  }

  /**
   * Clean up product URLs
   *
   * @param   {object}  product  Product to clean
   * @return  {object}           Cleaned product
   */

  async _cleanProductUrls (product) {
    let urls = {};
    let url;

    for (let i = 0; i < product.urls.length; i++) {
      url = product.urls[i];
      urls[url.key] = url;
    }

    product.urls = urls;
    return product;
  }

  /**
   * Clean up product images
   *
   * @param   {object}  product  Product to clean
   * @return  {object}           Cleaned product
   */

  async _cleanProductImages (product) {
    let imgs = {};
    let image;

    for (let i = 0; i < product.images.length; i++) {
      image = product.images[i];
      imgs[image.key] = product.images[i];
    }

    product.images = imgs;
    return product;
  }

  /**
   * Clean up product attributeGroups
   *
   * @param   {object}  product  Product to clean
   * @return  {object}           Cleaned product
   */

  async _cleanProductAttrGroups (product) {
    let groups = {};
    let group;
    let attrib;

    if (product.attributeGroups) {
      for (let i = 0; i < product.attributeGroups.length; i++) {
        group = product.attributeGroups[i];
        groups[group.title] = {
          title: group.title,
        };

        if (group.attributes) {
          groups[group.title].attributes = {};

          for (let a = 0; a < group.attributes.length; a++) {
            attrib = group.attributes[a];
            groups[group.title].attributes[attrib.key] = attrib;
          }
        }
      }

      product.attributeGroups = groups;
    }

    return product;
  }

  /**
   * Clean up product data
   *
   * @param   {object}  product  Object to clean
   * @return  {object}           Cleaned object
   */

  async _cleanProduct (product) {
    return this._cleanProductUrls (product)
      .then (this._cleanProductImages)
      .then (this._cleanProductAttrGroups)
    ;
  }

  /**
   * Communication with API
   *
   * @param     {string}    cat       api.bol.com/:CAT/v4/method
   * @param     {string}    method    api.bol.com/cat/v4/:METHOD
   * @param     {object}    [params]  Request paramaters
   *
   * @return    {Promise<object>}
   */

  async _talk (cat, method, params = {}) {
    const options = {
      url: `https://api.bol.com/${cat}/v4/${method}`,
      method: 'GET',
      timeout: this._config.timeout,
      parameters: params,
      headers: {
        'Accept': 'application/json',
        'User-Agent': 'bolcom.js (https://www.npmjs.com/package/bolcom)',
      },
    };

    options.parameters.apikey = this._config.apikey;
    options.parameters.format = 'json';

    // check session ID
    if (this._config.sessionId) {
      options.headers['X-OpenAPI-Session-ID'] = this._config.sessionId;
    }

    // send request
    const data = await doRequest (options)
      .then (res => JSON.parse (res.body))
    ;

    if (data.status) {
      const error = new Error (data.title);

      error.status = data.status;
      error.detail = data.detail;

      throw error;
    }

    return data;
  }

  /**
   * Method: ping
   *
   * @return    {Promise<object>}
   */

  async ping () {
    return this._talk ('utils', 'ping');
  }

  /**
   * Method: account.sessions
   *
   * @return    {Promise<object>}
   */

  async accountSessions () {
    return this._talk ('accounts', 'sessions');
  }

  /**
   * Generic catalog request handler
   *
   * @param     {string}    name      Catalog method name
   * @param     {object}    props     Request parameters
   *
   * @return    {Promise<object>}
   */

  async _catalogTalk (name, props) {
    const data = await this._talk ('catalog', name, props);

    if (data.products && Array.isArray (data.products)) {
      for (let i = 0; i < data.products.length; i++) {
        data.products[i] = this._cleanProduct (data.products[i]);
      }
    }

    return data;
  }

  /**
   * Method: catalog.search
   *
   * @param     {object}    props     Method parameters
   *
   * @return    {Promise<object>}
   */

  async catalogSearch (props) {
    return this._catalogTalk ('search', props);
  }

  /**
   * Method: catalog.lists
   *
   * @param     {object}    props     Method parameters
   *
   * @return    {Promise<object>}
   */

  async catalogLists (props) {
    return this._catalogTalk ('lists', props);
  }

  /**
   * Method: catalog.products
   *
   * @param     {string}    productId  Product ID
   * @param     {object}    [props]    Method parameters
   *
   * @return    {Promise<object>}
   */

  async catalogProducts (productId, props) {
    return this._catalogTalk (`products/${productId}`, props);
  }

  /**
   * Method: catalog.offers
   *
   * @param     {string}    productId  Product ID
   * @param     {object}    [props]    Method parameters
   *
   * @return    {Promise<object>}
   */

  async catalogOffers (productId, props) {
    const data = await this._talk ('catalog', `offers/${productId}`, props);

    if (data.offerData) {
      data = data.offerData;
    }

    return data;
  }

  /**
   * Method: catalog.recommendations
   *
   * @return    {Promise<object>}
   *
   * @param     {string}    productId  Product ID
   * @param     {object}    [props]    Method parameters
   */

  async catalogRecommendations (productId, props) {
    return this._catalogTalk (`recommendations/${productId}`, props);
  }

  /**
   * Method: catalog.relatedproducts
   *
   * @return    {Promise<object>}
   *
   * @param     {string}    productId  Product ID
   * @param     {object}    [props]    Method parameters
   */

  async catalogRelatedProducts (productId, props) {
    let data = await this._talk ('catalog', `relatedproducts/${productId}`, props);
    let tmp = {};
    let tmp2 = {};

    if (data.productFamilies) {
      data = data.productFamilies;

      if (!Array.isArray (data) && !data.length && !data[0].key) {
        return data;
      }

      for (let i = 0; i < data.length; i++) {
        tmp[data[i].key] = data[i];

        if (Array.isArray (data[i].productFamilyMembers)) {
          tmp2 = {};

          for (let m = 0; m < data[i].productFamilyMembers.length; m++) {
            tmp2[data[i].productFamilyMembers[m].label] = data[i].productFamilyMembers[m];
          }

          tmp[data[i].key].productFamilyMembers = tmp2;
        }

        data = tmp;
      }
    }

    return data;
  }

  /**
   * Method: account.wishlists
   *
   * @return    {Promise<object>}
   */

  async accountWishlists () {
    return this._talk ('accounts', 'wishlists');
  }

};
<|endoftext|>


<commit_before>import posed from "react-pose";
import React from "react";
import styled, { keyframes } from "styled-components";

const jump = keyframes({
  from: { transform: "translateY(-50%)" },
  to: { transform: "translateY(50%)" }
});

const Ball1 = styled.div({
  animation: `${jump.getName()} 500ms ease-in-out forwards alternate infinite`,
  backgroundColor: "rgba(0, 0, 0, 0.4)",
  borderRadius: "50%",
  display: "block",
  height: "0.5rem",
  position: "absolute",
  transform: "translateY(-50%)",
  width: "0.5rem"
});

const Ball2 = styled(Ball1)({
  animationDelay: "100ms",
  left: "1rem"
});

const Ball3 = styled(Ball1)({
  animationDelay: "200ms",
  left: "2rem"
});

const fadeIn = keyframes({
  from: { opacity: 0 },
  to: { opacity: 1 }
});

const Container = styled.i({
  animation: `${fadeIn.getName()} 125ms ease-in-out`,
  display: "block",
  height: "0.5rem",
  position: "relative",
  width: "2.5rem"
});

const Typing = React.forwardRef((props, ref) => (

    <Container aria-live="polite">
      <Ball1 />
      <Ball2 />
      <Ball3 />
    </Container>

));

export default posed(Typing)({
  enter: { opacity: 1 },
  exit: { opacity: 0 }
});
<commit_msg>fix: workaround for keyframes not working inside object styles<commit_after>import posed from "react-pose";
import React from "react";
import styled, { keyframes } from "styled-components";

const jump = keyframes({
  from: { transform: "translateY(-50%)" },
  to: { transform: "translateY(50%)" }
});

const Ball1 = styled.div`
  animation: ${jump} 500ms ease-in-out forwards alternate infinite;
  background-color: rgba(0, 0, 0, 0.4);
  border-radius: 50%;
  display: block;
  height: 0.5rem;
  position: absolute;
  transform: translateY(-50%);
  width: 0.5rem;
`;

const Ball2 = styled(Ball1)({
  animationDelay: "100ms",
  left: "1rem"
});

const Ball3 = styled(Ball1)({
  animationDelay: "200ms",
  left: "2rem"
});

const fadeIn = keyframes({
  from: { opacity: 0 },
  to: { opacity: 1 }
});

const Container = styled.i`
  animation: ${fadeIn} 125ms ease-in-out;
  display: block;
  height: 0.5rem;
  position: relative;
  width: 2.5rem;
`;

const Typing = React.forwardRef((props, ref) => (

    <Container aria-live="polite">
      <Ball1 />
      <Ball2 />
      <Ball3 />
    </Container>

));

export default posed(Typing)({
  enter: { opacity: 1 },
  exit: { opacity: 0 }
});
<|endoftext|>


<commit_before>/**
 * Copyright 2022 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* eslint-env node */
const contributors = {
  allanl: {
    // Unique per author, contribid
    name: {
      given: 'Allan',
      family: 'Livingston', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Chrome OS', // Optional
      title: 'Product Management Director', // Optional
    },
  },
  bgable: {
    // Unique per author, contribid
    name: {
      given: 'Ben',
      family: 'Gable', // Optional
    },
    work: {
      company: 'Google', // Optional
      title: 'Partner Developer Advocate', // Optional
    },
  },
  nataliagvak: {
    // Unique per author, contribid
    name: {
      given: 'Natalia',
      family: 'Gvak', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Chrome OS', // Optional
      title: 'Head of Chrome OS Apps Ecosystem Product Marketing', // Optional
    },
  },
  samrichard: {
    // Unique per author, contribid
    name: {
      given: 'Sam',
      family: 'Richard', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Chrome OS', // Optional
      title: 'Developer Advocate', // Optional
    },
  },
  ssamat: {
    // Unique per author, contribid
    name: {
      given: 'Sameer',
      family: 'Samat', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Platforms & Ecosystems', // Optional
      title: 'Vice President', // Optional
    },
  },
  kennethford: {
    // Unique per author, contribid
    name: {
      given: 'Kenneth',
      family: 'Ford', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Chrome OS', // Optional
      title: 'Developer Advocate', // Optional
    },
  },
  csells: {
    // Unique per author, contribid
    name: {
      given: 'Chris',
      family: 'Sells', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Flutter', // Optional
      title: 'Product Manager', // Optional
    },
  },
  ieinvaldez: {
    name: {
      given: 'Iein',
      family: 'Valdez',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Head of Developer Relations',
    },
  },
  pjmclachlan: {
    name: {
      given: 'Penny',
      family: 'McLachlan',
    },
    work: {
      company: 'Google',
      org: 'Web Platform',
      title: 'Product Manager',
    },
  },
  tbuckley: {
    name: {
      given: 'Tom',
      family: 'Buckley',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Product Manager',
    },
  },
  mmonasch: {
    name: {
      given: 'Matt',
      family: 'Monasch',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Lead Games Developer Advocate',
    },
  },
  pfuentes: {
    name: {
      given: 'Patrick',
      family: 'Fuentes',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Developer Relations Engineering Manager',
    },
  },
  fahdi: {
    name: {
      given: 'Fahd',
      family: 'Imtiaz',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Product Manager',
    },
  },
  ikarahan: {
    name: {
      given: 'Ibrahim',
      family: 'Karahan',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Developer Advocate',
    },
  },
  sanjn: {
    name: {
      given: 'Sanj',
      family: 'Nathwani',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Product Manager',
    },
  },
  nohe: {
    name: {
      given: 'Alexander',
      family: 'Nohe',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Developer Relations Engineer',
    },
  },
  vivekmistry: {
    name: {
      given: 'Vivek',
      family: 'Mistry',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Program Manager',
    },
  },
  joycetoh: {
    name: {
      given: 'Joyce',
      family: 'Toh',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Developer Relations Engineer',
    },
  },
  hadrosaur: {
    name: {
      given: 'Emilie',
      family: 'Roberts',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Developer Relations Engineer',
    },
  },
  bgeffon: {
    name: {
      given: 'Brian',
      family: 'Geffon',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  joelaf: {
    name: {
      given: 'Joel',
      family: 'Fernandes',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  jsbarnes: {
    name: {
      given: 'Jesse',
      family: 'Barnes',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Engineering Manager',
    },
  },
  dstockwell: {
    name: {
      given: 'Douglas',
      family: 'Stockwell',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  edwintay: {
    name: {
      given: 'Edwin',
      family: 'Tay',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  hikalium: {
    name: {
      given: 'Hikaru',
      family: 'Nishida',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  suleiman: {
    name: {
      given: 'Suleiman',
      family: 'Souhlal',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  sxm: {
    name: {
      given: 'Sangwhan',
      family: 'Moon',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineering Manager',
    },
  },
  kenh: {
    name: {
      given: 'Ken',
      family: 'Hoetmer',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Product Lead, Apps Platforms',
    },
  },
  davidriley: {
    name: {
      given: 'David',
      family: 'Riley',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Softare Engineer',
    },
  },
  cpelling: {
    name: {
      given: 'Chloe',
      family: 'Pelling',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  marcheu: {
    name: {
      given: 'Stéphane',
      family: 'Marchesin',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
};

module.exports = () => contributors; // By making this a function, it'll force Eleventy to reevaluate it every time it gets recompiled
<commit_msg>📝(content) Fix title.  (#415)<commit_after>/**
 * Copyright 2022 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* eslint-env node */
const contributors = {
  allanl: {
    // Unique per author, contribid
    name: {
      given: 'Allan',
      family: 'Livingston', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Chrome OS', // Optional
      title: 'Product Management Director', // Optional
    },
  },
  bgable: {
    // Unique per author, contribid
    name: {
      given: 'Ben',
      family: 'Gable', // Optional
    },
    work: {
      company: 'Google', // Optional
      title: 'Partner Developer Advocate', // Optional
    },
  },
  nataliagvak: {
    // Unique per author, contribid
    name: {
      given: 'Natalia',
      family: 'Gvak', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Chrome OS', // Optional
      title: 'Head of Chrome OS Apps Ecosystem Product Marketing', // Optional
    },
  },
  samrichard: {
    // Unique per author, contribid
    name: {
      given: 'Sam',
      family: 'Richard', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Chrome OS', // Optional
      title: 'Developer Advocate', // Optional
    },
  },
  ssamat: {
    // Unique per author, contribid
    name: {
      given: 'Sameer',
      family: 'Samat', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Platforms & Ecosystems', // Optional
      title: 'Vice President', // Optional
    },
  },
  kennethford: {
    // Unique per author, contribid
    name: {
      given: 'Kenneth',
      family: 'Ford', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Chrome OS', // Optional
      title: 'Developer Advocate', // Optional
    },
  },
  csells: {
    // Unique per author, contribid
    name: {
      given: 'Chris',
      family: 'Sells', // Optional
    },
    work: {
      company: 'Google', // Optional
      org: 'Flutter', // Optional
      title: 'Product Manager', // Optional
    },
  },
  ieinvaldez: {
    name: {
      given: 'Iein',
      family: 'Valdez',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Head of Developer Relations',
    },
  },
  pjmclachlan: {
    name: {
      given: 'Penny',
      family: 'McLachlan',
    },
    work: {
      company: 'Google',
      org: 'Web Platform',
      title: 'Product Manager',
    },
  },
  tbuckley: {
    name: {
      given: 'Tom',
      family: 'Buckley',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Product Manager',
    },
  },
  mmonasch: {
    name: {
      given: 'Matt',
      family: 'Monasch',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Lead Games Developer Advocate',
    },
  },
  pfuentes: {
    name: {
      given: 'Patrick',
      family: 'Fuentes',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Developer Relations Engineering Manager',
    },
  },
  fahdi: {
    name: {
      given: 'Fahd',
      family: 'Imtiaz',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Product Manager',
    },
  },
  ikarahan: {
    name: {
      given: 'Ibrahim',
      family: 'Karahan',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Developer Advocate',
    },
  },
  sanjn: {
    name: {
      given: 'Sanj',
      family: 'Nathwani',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Product Manager',
    },
  },
  nohe: {
    name: {
      given: 'Alexander',
      family: 'Nohe',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Developer Relations Engineer',
    },
  },
  vivekmistry: {
    name: {
      given: 'Vivek',
      family: 'Mistry',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Program Manager',
    },
  },
  joycetoh: {
    name: {
      given: 'Joyce',
      family: 'Toh',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Developer Relations Engineer',
    },
  },
  hadrosaur: {
    name: {
      given: 'Emilie',
      family: 'Roberts',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Developer Relations Engineer',
    },
  },
  bgeffon: {
    name: {
      given: 'Brian',
      family: 'Geffon',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  joelaf: {
    name: {
      given: 'Joel',
      family: 'Fernandes',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  jsbarnes: {
    name: {
      given: 'Jesse',
      family: 'Barnes',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Engineering Manager',
    },
  },
  dstockwell: {
    name: {
      given: 'Douglas',
      family: 'Stockwell',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  edwintay: {
    name: {
      given: 'Edwin',
      family: 'Tay',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  hikalium: {
    name: {
      given: 'Hikaru',
      family: 'Nishida',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  suleiman: {
    name: {
      given: 'Suleiman',
      family: 'Souhlal',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  sxm: {
    name: {
      given: 'Sangwhan',
      family: 'Moon',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineering Manager',
    },
  },
  kenh: {
    name: {
      given: 'Ken',
      family: 'Hoetmer',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Product Lead, Apps Platforms',
    },
  },
  davidriley: {
    name: {
      given: 'David',
      family: 'Riley',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  cpelling: {
    name: {
      given: 'Chloe',
      family: 'Pelling',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
  marcheu: {
    name: {
      given: 'Stéphane',
      family: 'Marchesin',
    },
    work: {
      company: 'Google',
      org: 'Chrome OS',
      title: 'Software Engineer',
    },
  },
};

module.exports = () => contributors; // By making this a function, it'll force Eleventy to reevaluate it every time it gets recompiled
<|endoftext|>


<commit_before>import { PropTypes } from 'react';
import favicon from './favicon.png';
import { getAsset } from '../../shared_state/asset_store';
import { PopupBackdrop } from '../../shared_state/popup/components';
import './default.styl';

const getCssFile = (name) => getAsset(`${name}.css`);
const getJsFile = (name) => getAsset(`${name}.js`);

const DefaultLayout = ({ children, title, name }) => (
  /* eslint-disable max-len */

      <title>{title}</title>
      <base href='https://myimpactpledge.com' />
      <link
        type='text/css'
        rel='stylesheet'
        href='https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css'
      />
      <link
        type='text/css'
        rel='stylesheet'
        href='https://fonts.googleapis.com/css?family=Lato:400,700'
      />
      <link
        type='text/css'
        rel='stylesheet'
        href='https://fonts.googleapis.com/css?family=Droid+Sans:400,700'
      />
      <link
        type='text/css'
        rel='stylesheet'
        href='https://fonts.googleapis.com/css?family=Merriweather:400,700'
      />
      <link
        rel='stylesheet'
        href='https://cdn.linearicons.com/free/1.0.0/icon-font.min.css'
      />
      <link rel='stylesheet' href={`/${getCssFile(name)}`} />
      <link rel='icon' href={favicon} />
      <meta name='viewport' content='width=device-width, user-scalable=no' />
      <meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />

      {children}

<PopupBackdrop />


<commit_before>// @flow
import React from 'react'
import {FlatList} from 'react-native'
import delay from 'delay'
import {reportNetworkProblem} from '../../lib/report-network-problem'
import {TabBarIcon} from '../components/tabbar-icon'
import type {OtherModeType} from './types'
import * as defaultData from '../../../docs/transportation.json'
import * as c from '../components/colors'
import {Button} from '../components/button'
import {trackedOpenUrl} from '../components/open-url'
import {Markdown} from '../components/markdown'
import glamorous from 'glamorous-native'

const Title = glamorous.text({
  fontSize: 30,
  alignSelf: 'center',
  marginTop: 10,
})

const Container = glamorous.view({
  backgroundColor: c.white,
  paddingHorizontal: 10,

  borderWidth: 5,
  borderTopWidth: 1,
  borderColor: c.iosLightBackground,
})

const GITHUB_URL =
  'https://stodevx.github.io/AAO-React-Native/transportation.json'

class OtherModeCard extends React.PureComponent {
  props: {
    data: OtherModeType,
  }

  onPress = () => {
    const {data} = this.props
    const modeName = data.name.replace(' ', '')
    return trackedOpenUrl({
      url: data.url,
      id: `Transportation_OtherModes_${modeName}View`,
    })
  }

  render() {
    const {data} = this.props
    return (
      <Container>
        <Title selectable={true}>{data.name}</Title>
        <Markdown source={data.description} />
        <Button onPress={this.onPress} title="More Info" />
      </Container>
    )
  }
}

export default class OtherModesView extends React.PureComponent {
  static navigationOptions = {
    tabBarLabel: 'Other Modes',
    tabBarIcon: TabBarIcon('boat'),
  }

  state = {
    modes: defaultData.data,
    loading: false,
  }

  componentWillMount() {
    this.fetchData()
  }

  fetchData = async () => {
    const start = Date.now()
    this.setState(() => ({loading: true}))

    let {data: modes} = await fetchJson(GITHUB_URL).catch(err => {
      reportNetworkProblem(err)
      return defaultData
    })

    if (process.env.NODE_ENV === 'development') {
      modes = defaultData.data
    }

    // wait 0.5 seconds – if we let it go at normal speed, it feels broken.
    const elapsed = Date.now() - start
    if (elapsed < 500) {
      await delay(500 - elapsed)
    }

    this.setState(() => ({modes, loading: false}))
  }

  renderItem = ({item}: {item: OtherModeType}) => <OtherModeCard data={item} />

  keyExtractor = (item: OtherModeType) => item.name

  render() {
    return (
      <FlatList
        keyExtractor={this.keyExtractor}
        renderItem={this.renderItem}
        refreshing={this.state.loading}
        onRefresh={this.fetchData}
        data={this.state.modes}
      />
    )
  }
}
<commit_msg>remove artificial delay in OtherModes view<commit_after>// @flow
import React from 'react'
import {FlatList} from 'react-native'
import delay from 'delay'
import {reportNetworkProblem} from '../../lib/report-network-problem'
import {TabBarIcon} from '../components/tabbar-icon'
import type {OtherModeType} from './types'
import * as defaultData from '../../../docs/transportation.json'
import * as c from '../components/colors'
import {Button} from '../components/button'
import {trackedOpenUrl} from '../components/open-url'
import {Markdown} from '../components/markdown'
import glamorous from 'glamorous-native'

const Title = glamorous.text({
  fontSize: 30,
  alignSelf: 'center',
  marginTop: 10,
})

const Container = glamorous.view({
  backgroundColor: c.white,
  paddingHorizontal: 10,

  borderWidth: 5,
  borderTopWidth: 1,
  borderColor: c.iosLightBackground,
})

const GITHUB_URL =
  'https://stodevx.github.io/AAO-React-Native/transportation.json'

class OtherModeCard extends React.PureComponent {
  props: {
    data: OtherModeType,
  }

  onPress = () => {
    const {data} = this.props
    const modeName = data.name.replace(' ', '')
    return trackedOpenUrl({
      url: data.url,
      id: `Transportation_OtherModes_${modeName}View`,
    })
  }

  render() {
    const {data} = this.props
    return (
      <Container>
        <Title selectable={true}>{data.name}</Title>
        <Markdown source={data.description} />
        <Button onPress={this.onPress} title="More Info" />
      </Container>
    )
  }
}

export default class OtherModesView extends React.PureComponent {
  static navigationOptions = {
    tabBarLabel: 'Other Modes',
    tabBarIcon: TabBarIcon('boat'),
  }

  state = {
    modes: defaultData.data,
    loading: false,
  }

  componentWillMount() {
    this.fetchData()
  }

  refresh = async () => {
    const start = Date.now()
    this.setState(() => ({refreshing: true}))

    await this.fetchData()

    // wait 0.5 seconds – if we let it go at normal speed, it feels broken.
    const elapsed = Date.now() - start
    if (elapsed < 500) {
      await delay(500 - elapsed)
    }

    this.setState(() => ({refreshing: false}))
  }

  fetchData = async () => {
    this.setState(() => ({loading: true}))

    let {data: modes} = await fetchJson(GITHUB_URL).catch(err => {
      reportNetworkProblem(err)
      return defaultData
    })

    if (process.env.NODE_ENV === 'development') {
      modes = defaultData.data
    }

    this.setState(() => ({modes, loading: false}))
  }

  renderItem = ({item}: {item: OtherModeType}) => <OtherModeCard data={item} />

  keyExtractor = (item: OtherModeType) => item.name

  render() {
    return (
      <FlatList
        keyExtractor={this.keyExtractor}
        renderItem={this.renderItem}
        refreshing={this.state.refreshing}
        onRefresh={this.refreshing}
        data={this.state.modes}
      />
    )
  }
}
<|endoftext|>


<commit_before>
/**
 * Core Javascript Bindings that apply
 * to the entirety of the site.
 */

(function( yourcode ) {

	yourcode( window.jQuery, window, document );

} (function( $, window, document ) {

	Dropzone.autoDiscover = false;
	var baseURL = $("head base").attr( "href" );
	var expDropzone;

	$(function( ) {

		addFileValidator( );
		initializeDropzone( );
		initializeDatePicker( );
		initializeUploadFormValidation( );

	});

	function initializeDatePicker( ) {

		$("input#experimentDate").datepicker({
			format: 'yyyy-mm-dd',
			todayHighlight: true,
			forceParse: true
		}).on( 'changeDate', function( e ) {
			$("#uploadForm").formValidation( 'revalidateField', 'experimentDate' );
		});

	}

	function initializeDropzone( ) {

		expDropzone = new Dropzone( "div#dropzoneBox", {
			url: baseURL + "/scripts/uploadExperiment.php",
			parallelUploads: 3,
			addRemoveLinks: true,
			sending: function( file, xhr, formData ) {
				formData.append( 'experimentCode', $("#experimentCode").val( ) );
			},
			success: function( file, response ) {

				// Set to a value, to allow for validation
				// of form submission
				$("#experimentHasFile").val( "true" );

				// Test to see if we are still validated
				$("#uploadForm").formValidation( 'revalidateField', 'experimentHasFile' );

			},
			canceled: function( file ) {
				$("#uploadForm").formValidation( 'revalidateField', 'experimentHasFile' );
			},
			error: function( file, message ) {
				$("#uploadForm").formValidation( 'revalidateField', 'experimentHasFile' );
			}
		});

		expDropzone.on( "addedfile", function( file ) {

			// Use a fancy text type icon to represent
			// non-image type files
			if (!file.type.match(/image.*/)) {
				expDropzone.emit( "thumbnail", file, baseURL + "/img/text-icon.png" );
			}

			// Check for duplicates and ignore them if they
			// are already uploaded
			if( this.files.length ) {
				var i, len;
				for( i = 0, len = this.files.length; i < len - 1; i++ ) {
					if( this.files[i].name == file.name && this.files[i].size == file.size ) {
						this.removeFile( file );
					}
				}
			}

		});

		expDropzone.on( "removedfile", function( file ) {

			if( !this.files.length ) {
				// Empty out to prevent form submission
				$("#experimentHasFile").val( "" );
			} else {

				// Check to see if there are any successfully
				// uploaded files remaining and set the validation
				// flag if not
				var hasFile = false;
				var i, len;
				for( i = 0, len = this.files.length; i < len; i++ ) {
					if( this.files[i].status == "success" ) {
						hasFile = true;
						break;
					}
				}

				if( !hasFile ) {
					$("#experimentHasFile").val( "" );
				}
			}

			$("#uploadForm").formValidation( 'revalidateField', 'experimentHasFile' );

		});

	}

	function initializeUploadFormValidation( ) {

		var fieldVals = { };

		fieldVals['experimentName'] = {
			validators: {
				notEmpty: {
					message: 'An Experiment Name is Required'
				}
			}
		};

		fieldVals['experimentDate'] = {
			validators: {
				notEmpty: {
					message: 'An Experiment Date is Required'
				},
				date: {
					format: 'YYYY-MM-DD',
					message: 'The Experiment Date is not formatted correctly. Should be YYYY-MM-DD'
				}
			}
		};

		fieldVals['experimentDesc'] = {
			validators: {
				notEmpty: {
					message: 'An Experiment Description is Required'
				}
			}
		};

		fieldVals['experimentHasFile'] = {
			excluded: false,
			validators: {
				notEmpty: {
					message: 'An Uploaded Experiment File is Required'
				},
				hasFiles: {
					message: 'You must upload at least one valid file AND have no files still processing...'
				}
			}
		};

		fieldVals['experimentBG'] = {
			validators: {
				notEmpty: {
					message: 'You must select at least one valid background file'
				}
			}
		}

		$("#uploadForm").formValidation({
			framework: 'bootstrap',
			fields: fieldVals
		}).on( 'success.form.fv', function( e ) {
			e.preventDefault( );

			var $form = $(e.target),
				fv = $(e.target).data( 'formValidation' );

			submitExperiment( );

		});
	}

	function submitExperiment( ) {

		var formData = $("#uploadForm").serializeArray( );
		var submitSet = { };

		// Get main form data
		$.each( formData, function( ) {
			submitSet[this.name] = this.value;
		});

		// Get successful files only
		submitSet['experimentFiles'] = [];
		$.each( expDropzone.files, function( ) {
			if( this.status == "success" ) {
				submitSet['experimentFiles'].push( this.name );
			}
		});

		// Convert to JSON
		submitSet = JSON.stringify( submitSet );

		// Send via AJAX for submission to
		// database and placement of files
		$.ajax({
			url: baseURL + "/scripts/submitExperiment.php",
			type: "POST",
			data: {"expData" : submitSet},
			dataType: 'json',
			beforeSend: function( ) {
				$("#messages").html( "" );
			}
		}).done( function( data, textStatus, jqXHR ) {

			var alertType = "success";
			var alertIcon = "fa-check";
			if( data["STATUS"] == "error" ) {
				alertType = "danger";
				alertIcon = "fa-warning";
				$("#uploadForm").formValidation( 'disableSubmitButtons', false );
			}

			$("#messages").html( '
 ' + data['MESSAGE'] + '

' );

			if( data["STATUS"] == "success" ) {
				window.location = baseURL + "/FileProgress?expID=" + data["ID"];
			}

		}).fail( function( jqXHR, textStatus, errorThrown ) {
			console.log( jqXHR );
			console.log( textStatus );
			$("#uploadForm").formValidation( 'disableSubmitButtons', false );
		});

	}

	function addFileValidator( ) {

		FormValidation.Validator.hasFiles = {
			validate: function( validator, $field, options ) {

				var files = expDropzone.files;
				var filesLength = files.length;
				var hasSuccess = false;
				var stillProcessing = false;

				if( filesLength ) {
					var i, len;
					for( i = 0; i < filesLength; i++ ) {
						// Ensure at least 1 successful file
						if( files[i].status == "success" ) {
							hasSuccess = true;
						// Ensure no files are still queued or uploading
						} else if( files[i].status == "queued" || files[i].status == "uploading" ) {
							stillProcessing = true;
						}
					}
				}

				// If at least one successful and none
				// still processing, we are valid
				if( hasSuccess && !stillProcessing ) {
					return true;
				}

				return false;

			}
		};

	}

}));<commit_msg>Added Population of Background Selector by File Upload<commit_after>
/**
 * Core Javascript Bindings that apply
 * to the entirety of the site.
 */

(function( yourcode ) {

	yourcode( window.jQuery, window, document );

} (function( $, window, document ) {

	Dropzone.autoDiscover = false;
	var baseURL = $("head base").attr( "href" );
	var expDropzone;

	$(function( ) {

		addFileValidator( );
		initializeDropzone( );
		initializeDatePicker( );
		initializeUploadFormValidation( );

	});

	function initializeDatePicker( ) {

		$("input#experimentDate").datepicker({
			format: 'yyyy-mm-dd',
			todayHighlight: true,
			forceParse: true
		}).on( 'changeDate', function( e ) {
			$("#uploadForm").formValidation( 'revalidateField', 'experimentDate' );
		});

	}

	function initializeDropzone( ) {

		expDropzone = new Dropzone( "div#dropzoneBox", {
			url: baseURL + "/scripts/uploadExperiment.php",
			parallelUploads: 3,
			addRemoveLinks: true,
			sending: function( file, xhr, formData ) {
				formData.append( 'experimentCode', $("#experimentCode").val( ) );
			},
			success: function( file, response ) {

				// Set to a value, to allow for validation
				// of form submission
				$("#experimentHasFile").val( "true" );

				// Test to see if we are still validated
				$("#uploadForm").formValidation( 'revalidateField', 'experimentHasFile' );
				$("#experimentBG").append( "<option value='" + file.name + "'>" + file.name + "</option>" ).prop( 'disabled', false );

			},
			canceled: function( file ) {
				$("#uploadForm").formValidation( 'revalidateField', 'experimentHasFile' );
				removeBackgroundOption( file );
			},
			error: function( file, message ) {
				$("#uploadForm").formValidation( 'revalidateField', 'experimentHasFile' );
				removeBackgroundOption( file );
			}
		});

		expDropzone.on( "addedfile", function( file ) {

			// Use a fancy text type icon to represent
			// non-image type files
			if (!file.type.match(/image.*/)) {
				expDropzone.emit( "thumbnail", file, baseURL + "/img/text-icon.png" );
			}

			// Check for duplicates and ignore them if they
			// are already uploaded
			if( this.files.length ) {
				var i, len;
				for( i = 0, len = this.files.length; i < len - 1; i++ ) {
					if( this.files[i].name == file.name && this.files[i].size == file.size ) {
						this.removeFile( file );
					}
				}
			}

		});

		expDropzone.on( "removedfile", function( file ) {

			removeBackgroundOption( file );

			if( !this.files.length ) {
				// Empty out to prevent form submission
				$("#experimentHasFile").val( "" );
			} else {

				// Check to see if there are any successfully
				// uploaded files remaining and set the validation
				// flag if not
				var hasFile = false;
				var i, len;
				for( i = 0, len = this.files.length; i < len; i++ ) {
					if( this.files[i].status == "success" ) {
						hasFile = true;
						break;
					}
				}

				if( !hasFile ) {
					$("#experimentHasFile").val( "" );
				}
			}

			$("#uploadForm").formValidation( 'revalidateField', 'experimentHasFile' );

		});

	}

	function removeBackgroundOption( file ) {

		$("#experimentBG option[value='" + file.name + "']").remove( );
		if( $("#experimentBG option").length <= 0 ) {
			$("#experimentBG").prop( "disabled", true );
		}

	}

	function initializeUploadFormValidation( ) {

		var fieldVals = { };

		fieldVals['experimentName'] = {
			validators: {
				notEmpty: {
					message: 'An Experiment Name is Required'
				}
			}
		};

		fieldVals['experimentDate'] = {
			validators: {
				notEmpty: {
					message: 'An Experiment Date is Required'
				},
				date: {
					format: 'YYYY-MM-DD',
					message: 'The Experiment Date is not formatted correctly. Should be YYYY-MM-DD'
				}
			}
		};

		fieldVals['experimentDesc'] = {
			validators: {
				notEmpty: {
					message: 'An Experiment Description is Required'
				}
			}
		};

		fieldVals['experimentHasFile'] = {
			excluded: false,
			validators: {
				notEmpty: {
					message: 'An Uploaded Experiment File is Required'
				},
				hasFiles: {
					message: 'You must upload at least one valid file AND have no files still processing...'
				}
			}
		};

		fieldVals['experimentBG'] = {
			validators: {
				notEmpty: {
					message: 'You must select at least one valid background file'
				}
			}
		}

		$("#uploadForm").formValidation({
			framework: 'bootstrap',
			fields: fieldVals
		}).on( 'success.form.fv', function( e ) {
			e.preventDefault( );

			var $form = $(e.target),
				fv = $(e.target).data( 'formValidation' );

			submitExperiment( );

		});
	}

	function submitExperiment( ) {

		var formData = $("#uploadForm").serializeArray( );
		var submitSet = { };

		// Get main form data
		$.each( formData, function( ) {
			submitSet[this.name] = this.value;
		});

		// Get successful files only
		submitSet['experimentFiles'] = [];
		$.each( expDropzone.files, function( ) {
			if( this.status == "success" ) {
				submitSet['experimentFiles'].push( this.name );
			}
		});

		// Convert to JSON
		submitSet = JSON.stringify( submitSet );

		// Send via AJAX for submission to
		// database and placement of files
		$.ajax({
			url: baseURL + "/scripts/submitExperiment.php",
			type: "POST",
			data: {"expData" : submitSet},
			dataType: 'json',
			beforeSend: function( ) {
				$("#messages").html( "" );
			}
		}).done( function( data, textStatus, jqXHR ) {

			var alertType = "success";
			var alertIcon = "fa-check";
			if( data["STATUS"] == "error" ) {
				alertType = "danger";
				alertIcon = "fa-warning";
				$("#uploadForm").formValidation( 'disableSubmitButtons', false );
			}

			$("#messages").html( '
 ' + data['MESSAGE'] + '

' );

			if( data["STATUS"] == "success" ) {
				window.location = baseURL + "/FileProgress?expID=" + data["ID"];
			}

		}).fail( function( jqXHR, textStatus, errorThrown ) {
			console.log( jqXHR );
			console.log( textStatus );
			$("#uploadForm").formValidation( 'disableSubmitButtons', false );
		});

	}

	function addFileValidator( ) {

		FormValidation.Validator.hasFiles = {
			validate: function( validator, $field, options ) {

				var files = expDropzone.files;
				var filesLength = files.length;
				var hasSuccess = false;
				var stillProcessing = false;

				if( filesLength ) {
					var i, len;
					for( i = 0; i < filesLength; i++ ) {
						// Ensure at least 1 successful file
						if( files[i].status == "success" ) {
							hasSuccess = true;
						// Ensure no files are still queued or uploading
						} else if( files[i].status == "queued" || files[i].status == "uploading" ) {
							stillProcessing = true;
						}
					}
				}

				// If at least one successful and none
				// still processing, we are valid
				if( hasSuccess && !stillProcessing ) {
					return true;
				}

				return false;

			}
		};

	}

}));<|endoftext|>


<commit_before>'use strict'

module.exports = {
  env: {
    browser: true,
    node: false
  },

  plugins: [
    'babel',
    'react'
  ],

  extends: [
    '@strv/javascript/environments/react/latest',
    '@strv/javascript/environments/react/best-practices',
    '@strv/javascript/environments/react/optional',
    '@strv/javascript/coding-styles/base'
  ],

  rules: {
    'class-methods-use-this': 0
  }
}
<commit_msg>Do not warn on @TODOs etc.<commit_after>'use strict'

module.exports = {
  env: {
    browser: true,
    node: false
  },

  plugins: [
    'babel',
    'react'
  ],

  extends: [
    '@strv/javascript/environments/react/latest',
    '@strv/javascript/environments/react/best-practices',
    '@strv/javascript/environments/react/optional',
    '@strv/javascript/coding-styles/base'
  ],

  rules: {
    'class-methods-use-this': 0,
    'no-warning-comments': 0
  }
}
<|endoftext|>


<commit_before>/* jshint node:true */
'use strict';

var fs = require('fs');
var rm = require('rimraf');

function jsFiles(file) {
    return file.slice(-3) === '.js';
}

function build(path) {
    var indexImports = [];
    var indexExports = [];
    var indexSrc = '';

    fs.readdir(path, function(err, files) {
        files.filter(jsFiles).forEach(function(file) {
            var srcPath = path + '/' + file;
            var varName = file.replace('.js', '');

            indexImports.push(
                'import ' + varName + ' from ' + '\'./' + file + '\';'
            );
            indexExports.push('\t' + varName);

            fs.readFile(srcPath, {encoding: 'utf-8'}, function(err, content) {
                fs.writeFile(file, content, {encoding: 'utf-8'});
            });
        });

        indexSrc =
            indexImports.join('\n') + '\n' + '\n' + '\n' +
            'export default {\n' + indexExports.join(',\n') + '\n};\n';

        fs.writeFile('index.js', indexSrc, {encoding: 'utf-8'});
    });
}

function clean(path) {
    fs.readdir(path, function(err, files) {
        files.filter(jsFiles).filter(function(file) {
            return file !== 'make.js';
        }).forEach(function(file) {
            rm(file);
        });
    });

    rm('.coverage', function() {});
}

if (process.argv[2] === 'build') {
    clean('.');
    build('src');
} else if (process.argv[2] === 'clean') {
    clean('.');
}
<commit_msg>fix make<commit_after>/* jshint node:true */
'use strict';

var fs = require('fs');
var rm = require('rimraf');

function jsFiles(file) {
    return file.slice(-3) === '.js';
}

function build(path) {
    var indexImports = [];
    var indexExports = [];
    var indexSrc = '';

    fs.readdir(path, function(err, files) {
        files.filter(jsFiles).forEach(function(file) {
            var srcPath = path + '/' + file;
            var varName = file.replace('.js', '');

            indexImports.push(
                'import ' + varName + ' from ' + '\'./' + file + '\';'
            );
            indexExports.push('\t' + varName);

            fs.readFile(srcPath, {encoding: 'utf-8'}, function(err, content) {
                fs.writeFile(file, content, {encoding: 'utf-8'});
            });
        });

        indexSrc =
            indexImports.join('\n') + '\n' + '\n' + '\n' +
            'export default {\n' + indexExports.join(',\n') + '\n};\n';

        fs.writeFile('index.js', indexSrc, {encoding: 'utf-8'});
    });
}

function clean(path) {
    fs.readdir(path, function(err, files) {
        files.filter(jsFiles).filter(function(file) {
            return file !== 'make.js';
        }).forEach(function(file) {
            rm(file, function() {});
        });
    });

    rm('.coverage', function() {});
}

if (process.argv[2] === 'build') {
    clean('.');
    build('src');
} else if (process.argv[2] === 'clean') {
    clean('.');
}
<|endoftext|>


<commit_before>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var Playback = require('playback')
var JST = require('../../base/jst')
var Styler = require('../../base/styler')
var Browser = require('browser')
var Mousetrap = require('mousetrap')
var seekStringToSeconds = require('../../base/utils').seekStringToSeconds

var _ = require('underscore')

class HTML5Video extends Playback {
  get name() { return 'html5_video' }
  get tagName() { return 'video' }
  get template() { return JST.html5_video }

  get attributes() {
    return {
      'data-html5-video': ''
    }
  }

  get events() {
    return {
      'timeupdate': 'timeUpdated',
      'progress': 'progress',
      'ended': 'ended',
      'stalled': 'stalled',
      'waiting': 'waiting',
      'canplaythrough': 'bufferFull',
      'loadedmetadata': 'loadedMetadata'
    }
  }

  constructor(options) {
    super(options)
    this.options = options
    this.src = options.src
    this.el.src = options.src
    this.el.loop = options.loop
    this.isHLS = (this.src.indexOf('m3u8') > -1)
    this.settings = {default: ['seekbar']}
    if (this.isHLS) {
      this.settings.left = ["playstop"]
      this.settings.right = ["fullscreen", "volume"]
    } else {
      this.settings.left = ["playpause", "position", "duration"]
      this.settings.right = ["fullscreen", "volume"]
      this.settings.seekEnabled = true
    }
    this.bindEvents()
  }

  bindEvents() {
    _.each(_.range(1,10), function (i) { Mousetrap.bind([i.toString()], () => this.seek(i * 10)) }.bind(this))
  }

  loadedMetadata(e) {
    this.trigger('playback:loadedmetadata', e.target.duration)
    this.trigger('playback:settingsupdate')
    this.checkInitialSeek()
  }

  getPlaybackType() {
    return this.isHLS && _.contains([0, undefined, Infinity], this.el.duration) ? 'live' : 'vod'
  }

  isHighDefinitionInUse() {
    return false
  }

  play() {
    this.el.play()
    this.trigger('playback:play');
    if (this.isHLS) {
      this.trigger('playback:timeupdate', 1, 1, this.name)
    }
  }

  pause() {
    this.el.pause()
  }

  stop() {
    this.pause()
    if (this.el.readyState !== 0) {
      this.el.currentTime = 0
    }
  }

  volume(value) {
    this.el.volume = value / 100
  }

  mute() {
    this.el.volume = 0
  }

  unmute() {
    this.el.volume = 1
  }

  isMuted() {
    return !!this.el.volume
  }

  isPlaying() {
    return !this.el.paused && !this.el.ended
  }

  ended() {
    this.trigger('playback:ended', this.name)
    this.trigger('playback:timeupdate', 0, this.el.duration, this.name)
  }

  stalled() {
    if (this.getPlaybackType() === 'vod' && this.el.readyState < this.el.HAVE_FUTURE_DATA) {
      this.trigger('playback:buffering', this.name)
    }
  }

  waiting() {
    if(this.el.readyState < this.el.HAVE_FUTURE_DATA) {
      this.trigger('playback:buffering', this.name)
    }
  }

  bufferFull() {
    if (this.getPlaybackType() === 'vod' && this.options.poster) {
      this.el.poster = this.options.poster
    }
    this.trigger('playback:bufferfull', this.name)
  }

  destroy() {
    this.stop()
    this.el.src = ''
    this.$el.remove()
  }

  seek(seekBarValue) {
    var time = this.el.duration * (seekBarValue / 100)
    this.seekSeconds(time)
  }

  seekSeconds(time) {
    this.el.currentTime = time
  }

  checkInitialSeek() {
    var seekTime = seekStringToSeconds(window.location.href)
    this.seekSeconds(seekTime)
  }

  getCurrentTime() {
    return this.el.currentTime
  }

  getDuration() {
    return this.el.duration
  }

  timeUpdated() {
    if (this.getPlaybackType() !== 'live') {
      this.trigger('playback:timeupdate', this.el.currentTime, this.el.duration, this.name)
    }
  }

  progress() {
    if (!this.el.buffered.length) return
    var bufferedPos = 0
    for (var i = 0;  i < this.el.buffered.length; i++) {
      if (this.el.currentTime >= this.el.buffered.start(i) && this.el.currentTime <= this.el.buffered.end(i)) {
        bufferedPos = i
        break
      }
    }
    this.trigger('playback:progress', this.el.buffered.start(bufferedPos), this.el.buffered.end(bufferedPos), this.el.duration, this.name)
  }

  typeFor(src) {
    return (src.indexOf('.m3u8') > 0) ? 'application/vnd.apple.mpegurl' : 'video/mp4'
  }

  render() {
    var style = Styler.getStyleFor(this.name)
    this.$el.html(this.template({ src: this.src, type: this.typeFor(this.src) }))
    this.$el.append(style)
    this.trigger('playback:ready', this.name)
    process.nextTick(() => this.options.autoPlay && this.play())
    return this
  }
}

HTML5Video.canPlay = function(resource) {
    return (!!resource.match(/(.*).mp4/) || Browser.isSafari || Browser.isMobile || Browser.isWin8App)
}

module.exports = HTML5Video
<commit_msg>poster: avoid adding poster on every buferfull event<commit_after>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var Playback = require('playback')
var JST = require('../../base/jst')
var Styler = require('../../base/styler')
var Browser = require('browser')
var Mousetrap = require('mousetrap')
var seekStringToSeconds = require('../../base/utils').seekStringToSeconds

var _ = require('underscore')

class HTML5Video extends Playback {
  get name() { return 'html5_video' }
  get tagName() { return 'video' }
  get template() { return JST.html5_video }

  get attributes() {
    return {
      'data-html5-video': ''
    }
  }

  get events() {
    return {
      'timeupdate': 'timeUpdated',
      'progress': 'progress',
      'ended': 'ended',
      'stalled': 'stalled',
      'waiting': 'waiting',
      'canplaythrough': 'bufferFull',
      'loadedmetadata': 'loadedMetadata'
    }
  }

  constructor(options) {
    super(options)
    this.options = options
    this.src = options.src
    this.el.src = options.src
    this.el.loop = options.loop
    this.firstBuffer = true
    this.isHLS = (this.src.indexOf('m3u8') > -1)
    this.settings = {default: ['seekbar']}
    if (this.isHLS) {
      this.settings.left = ["playstop"]
      this.settings.right = ["fullscreen", "volume"]
    } else {
      this.settings.left = ["playpause", "position", "duration"]
      this.settings.right = ["fullscreen", "volume"]
      this.settings.seekEnabled = true
    }
    this.bindEvents()
  }

  bindEvents() {
    _.each(_.range(1,10), function (i) { Mousetrap.bind([i.toString()], () => this.seek(i * 10)) }.bind(this))
  }

  loadedMetadata(e) {
    this.trigger('playback:loadedmetadata', e.target.duration)
    this.trigger('playback:settingsupdate')
    this.checkInitialSeek()
  }

  getPlaybackType() {
    return this.isHLS && _.contains([0, undefined, Infinity], this.el.duration) ? 'live' : 'vod'
  }

  isHighDefinitionInUse() {
    return false
  }

  play() {
    this.el.play()
    this.trigger('playback:play');
    if (this.isHLS) {
      this.trigger('playback:timeupdate', 1, 1, this.name)
    }
  }

  pause() {
    this.el.pause()
  }

  stop() {
    this.pause()
    if (this.el.readyState !== 0) {
      this.el.currentTime = 0
    }
  }

  volume(value) {
    this.el.volume = value / 100
  }

  mute() {
    this.el.volume = 0
  }

  unmute() {
    this.el.volume = 1
  }

  isMuted() {
    return !!this.el.volume
  }

  isPlaying() {
    return !this.el.paused && !this.el.ended
  }

  ended() {
    this.trigger('playback:ended', this.name)
    this.trigger('playback:timeupdate', 0, this.el.duration, this.name)
  }

  stalled() {
    if (this.getPlaybackType() === 'vod' && this.el.readyState < this.el.HAVE_FUTURE_DATA) {
      this.trigger('playback:buffering', this.name)
    }
  }

  waiting() {
    if(this.el.readyState < this.el.HAVE_FUTURE_DATA) {
      this.trigger('playback:buffering', this.name)
    }
  }

  bufferFull() {
    if (this.getPlaybackType() === 'vod' && this.options.poster && this.firstBuffer) {
      this.firstBuffer = false
      this.el.poster = this.options.poster
    } else {
      this.el.poster = ''
    }
    this.trigger('playback:bufferfull', this.name)
  }

  destroy() {
    this.stop()
    this.el.src = ''
    this.$el.remove()
  }

  seek(seekBarValue) {
    var time = this.el.duration * (seekBarValue / 100)
    this.seekSeconds(time)
  }

  seekSeconds(time) {
    this.el.currentTime = time
  }

  checkInitialSeek() {
    var seekTime = seekStringToSeconds(window.location.href)
    this.seekSeconds(seekTime)
  }

  getCurrentTime() {
    return this.el.currentTime
  }

  getDuration() {
    return this.el.duration
  }

  timeUpdated() {
    if (this.getPlaybackType() !== 'live') {
      this.trigger('playback:timeupdate', this.el.currentTime, this.el.duration, this.name)
    }
  }

  progress() {
    if (!this.el.buffered.length) return
    var bufferedPos = 0
    for (var i = 0;  i < this.el.buffered.length; i++) {
      if (this.el.currentTime >= this.el.buffered.start(i) && this.el.currentTime <= this.el.buffered.end(i)) {
        bufferedPos = i
        break
      }
    }
    this.trigger('playback:progress', this.el.buffered.start(bufferedPos), this.el.buffered.end(bufferedPos), this.el.duration, this.name)
  }

  typeFor(src) {
    return (src.indexOf('.m3u8') > 0) ? 'application/vnd.apple.mpegurl' : 'video/mp4'
  }

  render() {
    var style = Styler.getStyleFor(this.name)
    this.$el.html(this.template({ src: this.src, type: this.typeFor(this.src) }))
    this.$el.append(style)
    this.trigger('playback:ready', this.name)
    process.nextTick(() => this.options.autoPlay && this.play())
    return this
  }
}

HTML5Video.canPlay = function(resource) {
    return (!!resource.match(/(.*).mp4/) || Browser.isSafari || Browser.isMobile || Browser.isWin8App)
}

module.exports = HTML5Video
<|endoftext|>


<commit_before>/**
 * @file Require javascript resource handling
 * @since 0.2.2
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GPF_HOST*/ // Host types
/*global _gpfErrorDeclare*/ // Declare new gpf.Error names
/*global _gpfFunc*/ // Create a new function using the source
/*global _gpfHost*/ // Host type
/*global _gpfIgnore*/ // Helper to remove unused parameter warning
/*global _gpfPathJoin*/ // Join all arguments together and normalize the resulting path
/*global _gpfPathParent*/ // Get the parent of a path
/*global _gpfRegExpForEach*/ // Executes the callback for each match of the regular expression
/*global _gpfRequireProcessor*/ // Mapping of resource extension to processor function
/*global _gpfRequireWrapGpf*/ // Wrap gpf to fit the new context and give access to gpf.require.define promise
/*#endif*/

_gpfErrorDeclare("require/javascript", {

    /**
     * ### Summary
     *
     * Dynamic require not supported
     *
     * ### Description
     *
     * When loading a [CommonJS](http://www.commonjs.org/) module, a first pass is done to extract all requires being
     * called. If the require is based on a complex parameter (variable or string manipulation), the loader won't be
     * able to understand the require. No fallback mechanism is implemented yet
     * @since 0.2.2
     */
    noCommonJSDynamicRequire:
        "Dynamic require not supported"

});

var _gpfRequireJsModuleRegEx = /[^.]\brequire\b\s*\(\s*(?:['|"]([^"']+)['|"]|[^)]+)\s*\)/g;

function _gpfRequireJSGetStaticDependencies (resourceName, content) {
    /*jshint validthis:true*/
    var requires = _gpfRegExpForEach(_gpfRequireJsModuleRegEx, content);
    if (requires.length) {
        return _gpfRequireWrapGpf(this, resourceName).gpf.require.define(requires //eslint-disable-line no-invalid-this
            .map(function (match) {
                return match[1]; // may be undefined if dynamic
            })
            .filter(function (require) {
                return require;
            })
            .reduce(function (dictionary, name) {
                dictionary[name] = name;
                return dictionary;
            }, {}),
        function (require) {
            return require;
        });
    }
    return Promise.resolve({}); // No static dependencies
}

//region AMD define wrapper

function _gpfRequireAmdDefineParamsFactoryOnly (factory) {
    return {
        dependencies: [],
        factory: factory
    };
}

function _gpfRequireAmdDefineParamsDependenciesAndFactory (dependencies, factory) {
    return {
        dependencies: dependencies,
        factory: factory
    };
}

function _gpfRequireAmdDefineParamsAll (any, dependencies, factory) {
    return {
        dependencies: dependencies,
        factory: factory
    };
}

var
    /**
     * Mapping of define parameter count to dependencies / factory
     *
     * @type {Function[]}
     * @since 0.2.2
     */
    _gpfRequireAmdDefineParamsMapping = [
        null,
        _gpfRequireAmdDefineParamsFactoryOnly,
        _gpfRequireAmdDefineParamsDependenciesAndFactory,
        _gpfRequireAmdDefineParamsAll
    ];

function _gpfRequireAmdDefine (name, dependencies, factory) {
    /*jshint validthis:true*/
    _gpfIgnore(name, dependencies, factory);
    var myGpf = this, //eslint-disable-line
        params = _gpfRequireAmdDefineParamsMapping[arguments.length].apply(null, arguments);
    myGpf.require.define(params.dependencies, function (require) {
        require.length = params.dependencies.length;
        return params.factory.apply(null, [].slice.call(require));
    });
}

function _gpfRequireJS (myGpf, content, staticDependencies) {
    var module = {};
    _gpfFunc(["gpf", "define", "module", "require"], content)(
        myGpf,
        _gpfRequireAmdDefine.bind(myGpf),
        module,
        function (name) {
            return staticDependencies[name] || gpf.Error.noCommonJSDynamicRequire();
        }
    );
    return module.exports;
}

/*global location*/

function _gpfRequireSourceMapBrowswer (name, content) {
    var parentPath = location.pathname.toString();
    /* istanbul ignore else */ // sourceURL.1
    if (!parentPath.endsWith("/")) {
        parentPath = _gpfPathParent(parentPath);
    }
    return "//# sourceURL=" + location.origin + _gpfPathJoin(parentPath, name) + "?gpf.require\n" + content;
}

function _gpfRequireSourceMapNone (name, content) {
    return content;
}

var _gpfRequireSourceMapImpl;
if (_GPF_HOST.BROWSER === _gpfHost) {
    _gpfRequireSourceMapImpl = _gpfRequireSourceMapBrowswer;

} else {
    _gpfRequireSourceMapImpl = _gpfRequireSourceMapNone;

}

_gpfRequireProcessor[".js"] = function (resourceName, content) {
    var wrapper = _gpfRequireWrapGpf(this, resourceName);
    return _gpfRequireJSGetStaticDependencies.call(this, resourceName, content)
        .then(function (staticDependencies) {
            var exports = _gpfRequireJS(wrapper.gpf, _gpfRequireSourceMapImpl(resourceName, content),
                staticDependencies);
            if (undefined === exports) {
                return wrapper.promise;
            }
            return exports;
        });
};
<commit_msg>no-magic-numbers (#280)<commit_after>/**
 * @file Require javascript resource handling
 * @since 0.2.2
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GPF_HOST*/ // Host types
/*global _gpfArraySlice*/ // [].slice.call
/*global _gpfErrorDeclare*/ // Declare new gpf.Error names
/*global _gpfFunc*/ // Create a new function using the source
/*global _gpfHost*/ // Host type
/*global _gpfIgnore*/ // Helper to remove unused parameter warning
/*global _gpfPathJoin*/ // Join all arguments together and normalize the resulting path
/*global _gpfPathParent*/ // Get the parent of a path
/*global _gpfRegExpForEach*/ // Executes the callback for each match of the regular expression
/*global _gpfRequireProcessor*/ // Mapping of resource extension to processor function
/*global _gpfRequireWrapGpf*/ // Wrap gpf to fit the new context and give access to gpf.require.define promise
/*#endif*/

_gpfErrorDeclare("require/javascript", {

    /**
     * ### Summary
     *
     * Dynamic require not supported
     *
     * ### Description
     *
     * When loading a [CommonJS](http://www.commonjs.org/) module, a first pass is done to extract all requires being
     * called. If the require is based on a complex parameter (variable or string manipulation), the loader won't be
     * able to understand the require. No fallback mechanism is implemented yet
     * @since 0.2.2
     */
    noCommonJSDynamicRequire:
        "Dynamic require not supported"

});

var _gpfRequireJsModuleRegEx = /[^.]\brequire\b\s*\(\s*(?:['|"]([^"']+)['|"]|[^)]+)\s*\)/g;

function _gpfRequireJSGetStaticDependencies (resourceName, content) {
    /*jshint validthis:true*/
    var requires = _gpfRegExpForEach(_gpfRequireJsModuleRegEx, content);
    if (requires.length) {
        return _gpfRequireWrapGpf(this, resourceName).gpf.require.define(requires //eslint-disable-line no-invalid-this
            .map(function (match) {
                return match[1]; // may be undefined if dynamic
            })
            .filter(function (require) {
                return require;
            })
            .reduce(function (dictionary, name) {
                dictionary[name] = name;
                return dictionary;
            }, {}),
        function (require) {
            return require;
        });
    }
    return Promise.resolve({}); // No static dependencies
}

//region AMD define wrapper

function _gpfRequireAmdDefineParamsFactoryOnly (factory) {
    return {
        dependencies: [],
        factory: factory
    };
}

function _gpfRequireAmdDefineParamsDependenciesAndFactory (dependencies, factory) {
    return {
        dependencies: dependencies,
        factory: factory
    };
}

function _gpfRequireAmdDefineParamsAll (any, dependencies, factory) {
    return {
        dependencies: dependencies,
        factory: factory
    };
}

var
    /**
     * Mapping of define parameter count to dependencies / factory
     *
     * @type {Function[]}
     * @since 0.2.2
     */
    _gpfRequireAmdDefineParamsMapping = [
        null,
        _gpfRequireAmdDefineParamsFactoryOnly,
        _gpfRequireAmdDefineParamsDependenciesAndFactory,
        _gpfRequireAmdDefineParamsAll
    ];

function _gpfRequireAmdDefine (name, dependencies, factory) {
    /*jshint validthis:true*/
    _gpfIgnore(name, dependencies, factory);
    var myGpf = this, //eslint-disable-line
        params = _gpfRequireAmdDefineParamsMapping[arguments.length].apply(null, arguments);
    myGpf.require.define(params.dependencies, function (require) {
        require.length = params.dependencies.length;
        return params.factory.apply(null, _gpfArraySlice(require));
    });
}

function _gpfRequireJS (myGpf, content, staticDependencies) {
    var module = {};
    _gpfFunc(["gpf", "define", "module", "require"], content)(
        myGpf,
        _gpfRequireAmdDefine.bind(myGpf),
        module,
        function (name) {
            return staticDependencies[name] || gpf.Error.noCommonJSDynamicRequire();
        }
    );
    return module.exports;
}

/*global location*/

function _gpfRequireSourceMapBrowswer (name, content) {
    var parentPath = location.pathname.toString();
    /* istanbul ignore else */ // sourceURL.1
    if (!parentPath.endsWith("/")) {
        parentPath = _gpfPathParent(parentPath);
    }
    return "//# sourceURL=" + location.origin + _gpfPathJoin(parentPath, name) + "?gpf.require\n" + content;
}

function _gpfRequireSourceMapNone (name, content) {
    return content;
}

var _gpfRequireSourceMapImpl;
if (_GPF_HOST.BROWSER === _gpfHost) {
    _gpfRequireSourceMapImpl = _gpfRequireSourceMapBrowswer;

} else {
    _gpfRequireSourceMapImpl = _gpfRequireSourceMapNone;

}

_gpfRequireProcessor[".js"] = function (resourceName, content) {
    var wrapper = _gpfRequireWrapGpf(this, resourceName);
    return _gpfRequireJSGetStaticDependencies.call(this, resourceName, content)
        .then(function (staticDependencies) {
            var exports = _gpfRequireJS(wrapper.gpf, _gpfRequireSourceMapImpl(resourceName, content),
                staticDependencies);
            if (undefined === exports) {
                return wrapper.promise;
            }
            return exports;
        });
};
<|endoftext|>