<commit_before>const xlsx = require('node-xlsx');
const fs = require('fs');
const path = require('path');
// const moment = require('moment');

let arraySeparator;

/**
 * sheet(table) 的类型
 * 影响输出json的类型
 * 当有#id类型的时候  表输出json的是map形式(id:{xx:1})
 * 当没有#id类型的时候  表输出json的是数组类型 没有id索引
 */
const SheetType = {
  /**
   * 普通表
   */
  NORMAL: 0,

  /**
   * 有主外键关系的主表
   * primary key
   */
  PRIMARY: 1,

  /**
   * 有主外键关系的附表
   * foreign key
   */
  FOREIGN: 2
};

/**
 * 支持的数据类型
 */
const DataType = {
  NUMBER: 'number',
  STRING: 'string',
  BOOL: 'bool',
  DATE: 'date',
  ID: 'id',
  ARRAY: '[]',
  OBJECT: '{}',
  OBJECT_ARRAY: '[{}]',
  UNKOWN: 'unkown'
};

module.exports = {

  /**
   * convert xlsx file to json and save it to file system.
   * @param  {String} src path of .xlsx files.
   * @param  {String} dest       directory for exported json files.
   * @param  {Number} headIndex      index of head line.
   * @param  {String} separator      array separator.
   *
   * excel structure
   * workbook > worksheet > table(row column)
   */
  toJson: function(src, dest, config) {

    let headIndex = config.xlsx.head - 1;
    arraySeparator = config.xlsx.arraySeparator;
    let uglifyJson = config.json.uglify;

    if (!fs.existsSync(dest)) {
      fs.mkdirSync(dest);
    }

    console.log("parsing excel:", src);

    let workbook = xlsx.parse(src);
    parseWorkbook(workbook, dest, headIndex, uglifyJson);
  }
};

/**
 * convert worksheet in workbook and save to file for each.
 * @param       {[Object]} workbook json object of excel's workbook.
 * @param       {[String]} dest     directory for exported json files.
 * @param       {[Number]} headIndex     index of head line.
 */
function parseWorkbook(workbook, dest, headIndex, uglifyJson) {

  workbook.forEach(sheet => {

    // ignore sheet with external keys only, or start with a '#'
    if (sheet.name.indexOf('@') === -1 && sheet.name[0] !== "#") {
      let parsedSheet = parseSheet(sheet, headIndex);

      let dest_file = path.resolve(dest, sheet.name + ".json");
      let formatedJson = JSON.stringify(parsedSheet, null, uglifyJson ? 0 : 2); //, null, 2
      fs.writeFile(dest_file, formatedJson, err => {
        if (err) {
          console.error("error：", err);
          throw err;
        }
        console.log('exported successfully  -->  ', path.basename(dest_file));
      });
    }
  });
}

/**
 * parse one sheet and return the result as a json object or array
 *
 * @param sheet
 * @param headIndex
 * @private
 */
function parseSheet(sheet, headIndex) {

  console.log('\t parsing sheet', sheet.name);

  if (sheet && sheet.data) {

    let head = parseHead(sheet, headIndex);

    let result;

    if (head.sheetType === SheetType.NORMAL) {
      result = [];
    } else if (head.sheetType === SheetType.PRIMARY) {
      result = {};
    }

    for (let i_row = headIndex + 1; i_row < sheet.data.length; i_row++) {

      let row = sheet.data[i_row];

      let parsedRow = parseRow(row, i_row, head);
      if (head.sheetType === SheetType.NORMAL) { ////json以数组的格式输出
        result.push(parsedRow);
      } else if (head.sheetType === SheetType.PRIMARY) { //json以map的格式输出
        let id = parsedRow[head.getIdKey()];
        result[id] = parsedRow;
      } else {
        throw '无法识别表格类型!';
      }
    }
    return result;
  }
}

function parseHead(sheet, headIndex) {

  let headRow = sheet.data[headIndex];

  // console.log("\t\t parsing head", headIndex, headRow);

  let head = {
    //所有名字 json的key
    names: [],

    //所有列的数据类型
    types: [],

    //表头所在的行索引
    index: headIndex,

    //表类型 普通表  主表 引用表
    sheetType: SheetType.NORMAL,

    getIdKey:function(){
      let id_col_index = this.types.indexOf(DataType.ID);
      if(id_col_index < 0){
        throw '获取不到id列的名字';
      }
      return this.names[id_col_index];
    }
  };

  headRow.forEach(cell => {
    let type = DataType.UNKOWN;
    let name = cell;

    if ((cell + '').indexOf('#') !== -1) {
      let pair = cell.split('#');
      name = pair[0].trim();
      type = pair[1].toLowerCase().trim();
      if (type === DataType.ID) {
        head.sheetType = SheetType.PRIMARY;
      }
    }

    head.types.push(type);
    head.names.push(name);
  });

  return head;
}

function parseRow(row, rowIndex, head) {

  let result = {};
  let id;

  row.forEach((cell, index) => {

    if (cell) {

      let name = head.names[index];
      let type = head.types[index];

      switch (type) {
        case DataType.ID: // number string boolean
          if (isNumber(cell)) {
            id = Number(cell);
          } else {
            id = cell;
          }
          result[name] = id;
          break;
        case DataType.UNKOWN: // number string boolean
          if (isNumber(cell)) {
            result[name] = Number(cell);
          } else if (isBoolean(cell)) {
            result[name] = toBoolean(cell);
          } else {
            result[name] = cell;
          }
          break;
        case DataType.DATE:
          if (isNumber(cell)) {
            //xlsx's bug!!!
            result[name] = numdate(cell);
          } else {
            result[name] = cell.toString();
          }
          break;
        case DataType.STRING:
          result[name] = cell.toString();
          break;
        case DataType.NUMBER:
          //+xxx.toString() '+' means convert it to number
          if (isNumber(cell)) {
            result[name] = Number(cell);
          } else {
            console.warn("type error at [" + rowIndex + "," + index + "]," + cell + " is not a number");
          }
          break;
        case DataType.BOOL:
          result[name] = toBoolean(cell);
          break;
        case DataType.OBJECT: //support {number boolean string date} property type
          result[name] = array2object(cell.split(';'));
          break;
        case DataType.ARRAY: //[number] [boolean] [string]  todo:support [date] type
          result[name] = parseBasicArrayField(cell, arraySeparator);
          break;
        case DataType.OBJECT_ARRAY:
          result[name] = parseObjectArrayField(cell);
          break;
        default:
          // foo#[]| 处理自定义数组分隔符
          if (type.indexOf(DataType.ARRAY) !== -1) {
            // if (!type.endsWith(DataType.ARRAY)) {
            let separator = type.substr(-1, 1); //get the last character
            result[name] = parseBasicArrayField(cell, separator);
            // }
          } else {
            console.log('unrecognized type', '[' + rowIndex + ',' + index + ']', cell, typeof(cell));
          }
          break;
      }
    }
  });

  return result;

  // switch (head.sheetType) {
  //   case SheetType.NORMAL: //json以数组的格式输出
  //     return result;
  //   case SheetType.PRIMARY: //json以map的格式输出
  //     let map = {};
  //     map[id] = result;
  //     return map;
  //   default:
  //     throw '无法识别表格类型!';
  // }

  // return result;
}

/**
 * parse object array.
 */
function parseObjectArrayField(value) {

  let obj_array = [];

  if (value) {
    if (value.indexOf(',') !== -1) {
      obj_array = value.split(',');
    } else {
      obj_array.push(value.toString());
    }
  }

  // if (typeof(value) === 'string' && value.indexOf(',') !== -1) {
  //     obj_array = value.split(',');
  // } else {
  //     obj_array.push(value.toString());
  // };

  let result = [];

  obj_array.forEach(function(e) {
    if (e) {
      result.push(array2object(e.split(';')));
    }
  });

  // row[key] = result;
  return result;
}

/**
 * parse object from array.
 *  for example : [a:123,b:45] => {'a':123,'b':45}
 */
function array2object(array) {
  let result = {};
  array.forEach(function(e) {
    if (e) {
      let colonIndex = e.indexOf(':');
      let key = e.substring(0, colonIndex);
      let value = e.substring(colonIndex + 1);
      if (isNumber(value)) {
        value = Number(value);
      } else if (isBoolean(value)) {
        value = toBoolean(value);
      }
      result[key] = value;
    }
  });
  return result;
}

/**
 * parse simple array.
 */
function parseBasicArrayField(array, arraySeparator) {
  let basic_array;

  if (typeof array === "string") {
    basic_array = array.split(arraySeparator);
  } else {
    basic_array = [];
    basic_array.push(array);
  }

  let result = [];
  if (isNumberArray(basic_array)) {
    basic_array.forEach(function(element) {
      result.push(Number(element));
    });
  } else if (isBooleanArray(basic_array)) {
    basic_array.forEach(function(element) {
      result.push(toBoolean(element));
    });
  } else { //string array
    result = basic_array;
  }
  // console.log("basic_array", result + "|||" + cell.value);
  // field[key] = result;
  return result;
}

/**
 * convert value to boolean.
 */
function toBoolean(value) {
  return value.toString().toLowerCase() === 'true';
}

/**
 * is a boolean array.
 */
function isBooleanArray(arr) {
  return arr.every(function(element, index, array) {
    return isBoolean(element);
  });
}

/**
 * is a number array.
 */
function isNumberArray(arr) {
  return arr.every(function(element, index, array) {
    return isNumber(element);
  });
}

/**
 * is a number.
 */
function isNumber(value) {

  if (value) {
    if (typeof value === 'number') {
      return true;
    }
    return !isNaN(+value.toString());
  }

  return false;
}

/**
 * boolean type check.
 */
function isBoolean(value) {

  if (typeof(value) === "undefined") {
    return false;
  }

  if (typeof value === 'boolean') {
    return true;
  }

  let b = value.toString().trim().toLowerCase();

  return b === 'true' || b === 'false';
}

/**
 * date type check.
 */
// function isDateType(value) {
//   if (isNumber(value)) {
//     return false;
//   }
//   if (value) {
//     return moment(new Date(value), "YYYY-M-D", true).isValid() || moment(value, "YYYY-M-D H:m:s", true).isValid() || moment(value, "YYYY/M/D H:m:s", true).isValid() || moment(value, "YYYY/M/D", true).isValid();
//   }
//   return false;
// }

//fuck xlsx's bug
var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
// var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
// function datenum(v, date1904) {
// 	var epoch = v.getTime();
// 	if(date1904) epoch -= 1462*24*60*60*1000;
// 	return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
// }

function numdate(v) {
  var out = new Date();
  out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
  return out;
}
//fuck over
<commit_msg>bugfix:number 0 does not output<commit_after>const xlsx = require('node-xlsx');
const fs = require('fs');
const path = require('path');
// const moment = require('moment');

let arraySeparator;

/**
 * sheet(table) 的类型
 * 影响输出json的类型
 * 当有#id类型的时候  表输出json的是map形式(id:{xx:1})
 * 当没有#id类型的时候  表输出json的是数组类型 没有id索引
 */
const SheetType = {
  /**
   * 普通表
   */
  NORMAL: 0,

  /**
   * 有主外键关系的主表
   * primary key
   */
  PRIMARY: 1,

  /**
   * 有主外键关系的附表
   * foreign key
   */
  FOREIGN: 2
};

/**
 * 支持的数据类型
 */
const DataType = {
  NUMBER: 'number',
  STRING: 'string',
  BOOL: 'bool',
  DATE: 'date',
  ID: 'id',
  ARRAY: '[]',
  OBJECT: '{}',
  OBJECT_ARRAY: '[{}]',
  UNKOWN: 'unkown'
};

module.exports = {

  /**
   * convert xlsx file to json and save it to file system.
   * @param  {String} src path of .xlsx files.
   * @param  {String} dest       directory for exported json files.
   * @param  {Number} headIndex      index of head line.
   * @param  {String} separator      array separator.
   *
   * excel structure
   * workbook > worksheet > table(row column)
   */
  toJson: function(src, dest, config) {

    let headIndex = config.xlsx.head - 1;
    arraySeparator = config.xlsx.arraySeparator;
    let uglifyJson = config.json.uglify;

    if (!fs.existsSync(dest)) {
      fs.mkdirSync(dest);
    }

    console.log("parsing excel:", src);

    let workbook = xlsx.parse(src);
    parseWorkbook(workbook, dest, headIndex, uglifyJson);
  }
};

/**
 * convert worksheet in workbook and save to file for each.
 * @param       {[Object]} workbook json object of excel's workbook.
 * @param       {[String]} dest     directory for exported json files.
 * @param       {[Number]} headIndex     index of head line.
 */
function parseWorkbook(workbook, dest, headIndex, uglifyJson) {

  workbook.forEach(sheet => {

    // ignore sheet with external keys only, or start with a '#'
    if (sheet.name.indexOf('@') === -1 && sheet.name[0] !== "#") {
      let parsedSheet = parseSheet(sheet, headIndex);

      let dest_file = path.resolve(dest, sheet.name + ".json");
      let formatedJson = JSON.stringify(parsedSheet, null, uglifyJson ? 0 : 2); //, null, 2
      fs.writeFile(dest_file, formatedJson, err => {
        if (err) {
          console.error("error：", err);
          throw err;
        }
        console.log('exported successfully  -->  ', path.basename(dest_file));
      });
    }
  });
}

/**
 * parse one sheet and return the result as a json object or array
 *
 * @param sheet
 * @param headIndex
 * @private
 */
function parseSheet(sheet, headIndex) {

  console.log('\t parsing sheet', sheet.name);

  if (sheet && sheet.data) {

    let head = parseHead(sheet, headIndex);

    let result;

    if (head.sheetType === SheetType.NORMAL) {
      result = [];
    } else if (head.sheetType === SheetType.PRIMARY) {
      result = {};
    }

    for (let i_row = headIndex + 1; i_row < sheet.data.length; i_row++) {

      let row = sheet.data[i_row];

      let parsedRow = parseRow(row, i_row, head);
      if (head.sheetType === SheetType.NORMAL) { ////json以数组的格式输出
        result.push(parsedRow);
      } else if (head.sheetType === SheetType.PRIMARY) { //json以map的格式输出
        let id = parsedRow[head.getIdKey()];
        result[id] = parsedRow;
      } else {
        throw '无法识别表格类型!';
      }
    }
    return result;
  }
}

function parseHead(sheet, headIndex) {

  let headRow = sheet.data[headIndex];

  // console.log("\t\t parsing head", headIndex, headRow);

  let head = {
    //所有名字 json的key
    names: [],

    //所有列的数据类型
    types: [],

    //表头所在的行索引
    index: headIndex,

    //表类型 普通表  主表 引用表
    sheetType: SheetType.NORMAL,

    getIdKey: function() {
      let id_col_index = this.types.indexOf(DataType.ID);
      if (id_col_index < 0) {
        throw '获取不到id列的名字';
      }
      return this.names[id_col_index];
    }
  };

  headRow.forEach(cell => {
    let type = DataType.UNKOWN;
    let name = cell;

    if ((cell + '').indexOf('#') !== -1) {
      let pair = cell.split('#');
      name = pair[0].trim();
      type = pair[1].toLowerCase().trim();
      if (type === DataType.ID) {
        head.sheetType = SheetType.PRIMARY;
      }
    }

    head.types.push(type);
    head.names.push(name);
  });

  return head;
}

function parseRow(row, rowIndex, head) {

  let result = {};
  let id;

  console.log('parsing row', row);

  row.forEach((cell, index) => {

    // if (cell) {

    let name = head.names[index];
    let type = head.types[index];

    switch (type) {
      case DataType.ID: // number string boolean
        if (isNumber(cell)) {
          id = Number(cell);
        } else {
          id = cell;
        }
        result[name] = id;
        break;
      case DataType.UNKOWN: // number string boolean
        if (isNumber(cell)) {
          result[name] = Number(cell);
        } else if (isBoolean(cell)) {
          result[name] = toBoolean(cell);
        } else {
          if (cell) {
            result[name] = cell;
          }
        }
        break;
      case DataType.DATE:
        if (isNumber(cell)) {
          //xlsx's bug!!!
          result[name] = numdate(cell);
        } else {
          if (cell) {
            result[name] = cell.toString();
          }
        }
        break;
      case DataType.STRING:
        result[name] = cell.toString();
        break;
      case DataType.NUMBER:
        //+xxx.toString() '+' means convert it to number
        if (isNumber(cell)) {
          result[name] = Number(cell);
        } else {
          console.warn("type error at [" + rowIndex + "," + index + "]," + cell + " is not a number");
        }
        break;
      case DataType.BOOL:
        result[name] = toBoolean(cell);
        break;
      case DataType.OBJECT: //support {number boolean string date} property type
        if (cell) {
          result[name] = array2object(cell.split(';'));
        }
        break;
      case DataType.ARRAY: //[number] [boolean] [string]  todo:support [date] type
        result[name] = parseBasicArrayField(cell, arraySeparator);
        break;
      case DataType.OBJECT_ARRAY:
        result[name] = parseObjectArrayField(cell);
        break;
      default:
        // foo#[]| 处理自定义数组分隔符
        if (type.indexOf(DataType.ARRAY) !== -1) {
          // if (!type.endsWith(DataType.ARRAY)) {
          let separator = type.substr(-1, 1); //get the last character
          result[name] = parseBasicArrayField(cell, separator);
          // }
        } else {
          console.log('unrecognized type', '[' + rowIndex + ',' + index + ']', cell, typeof(cell));
        }
        break;
    }
    // }
  });

  return result;

  // switch (head.sheetType) {
  //   case SheetType.NORMAL: //json以数组的格式输出
  //     return result;
  //   case SheetType.PRIMARY: //json以map的格式输出
  //     let map = {};
  //     map[id] = result;
  //     return map;
  //   default:
  //     throw '无法识别表格类型!';
  // }

  // return result;
}

/**
 * parse object array.
 */
function parseObjectArrayField(value) {

  let obj_array = [];

  if (value) {
    if (value.indexOf(',') !== -1) {
      obj_array = value.split(',');
    } else {
      obj_array.push(value.toString());
    }
  }

  // if (typeof(value) === 'string' && value.indexOf(',') !== -1) {
  //     obj_array = value.split(',');
  // } else {
  //     obj_array.push(value.toString());
  // };

  let result = [];

  obj_array.forEach(function(e) {
    if (e) {
      result.push(array2object(e.split(';')));
    }
  });

  // row[key] = result;
  return result;
}

/**
 * parse object from array.
 *  for example : [a:123,b:45] => {'a':123,'b':45}
 */
function array2object(array) {
  let result = {};
  array.forEach(function(e) {
    if (e) {
      let colonIndex = e.indexOf(':');
      let key = e.substring(0, colonIndex);
      let value = e.substring(colonIndex + 1);
      if (isNumber(value)) {
        value = Number(value);
      } else if (isBoolean(value)) {
        value = toBoolean(value);
      }
      result[key] = value;
    }
  });
  return result;
}

/**
 * parse simple array.
 */
function parseBasicArrayField(array, arraySeparator) {
  let basic_array;

  if (typeof array === "string") {
    basic_array = array.split(arraySeparator);
  } else {
    basic_array = [];
    basic_array.push(array);
  }

  let result = [];
  if (isNumberArray(basic_array)) {
    basic_array.forEach(function(element) {
      result.push(Number(element));
    });
  } else if (isBooleanArray(basic_array)) {
    basic_array.forEach(function(element) {
      result.push(toBoolean(element));
    });
  } else { //string array
    result = basic_array;
  }
  // console.log("basic_array", result + "|||" + cell.value);
  // field[key] = result;
  return result;
}

/**
 * convert value to boolean.
 */
function toBoolean(value) {
  return value.toString().toLowerCase() === 'true';
}

/**
 * is a boolean array.
 */
function isBooleanArray(arr) {
  return arr.every(function(element, index, array) {
    return isBoolean(element);
  });
}

/**
 * is a number array.
 */
function isNumberArray(arr) {
  return arr.every(function(element, index, array) {
    return isNumber(element);
  });
}

/**
 * is a number.
 */
function isNumber(value) {

  if (typeof value === 'number') {
    return true;
  }

  if (value) {
    return !isNaN(+value.toString());
  }

  return false;
}

/**
 * boolean type check.
 */
function isBoolean(value) {

  if (typeof(value) === "undefined") {
    return false;
  }

  if (typeof value === 'boolean') {
    return true;
  }

  let b = value.toString().trim().toLowerCase();

  return b === 'true' || b === 'false';
}

/**
 * date type check.
 */
// function isDateType(value) {
//   if (isNumber(value)) {
//     return false;
//   }
//   if (value) {
//     return moment(new Date(value), "YYYY-M-D", true).isValid() || moment(value, "YYYY-M-D H:m:s", true).isValid() || moment(value, "YYYY/M/D H:m:s", true).isValid() || moment(value, "YYYY/M/D", true).isValid();
//   }
//   return false;
// }

//fuck xlsx's bug
var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
// var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
// function datenum(v, date1904) {
// 	var epoch = v.getTime();
// 	if(date1904) epoch -= 1462*24*60*60*1000;
// 	return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
// }

function numdate(v) {
  var out = new Date();
  out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
  return out;
}
//fuck over
<|endoftext|>


<commit_before>const httpServer = require('http');
const queryString = require('querystring');
/**
 * http请求
 */
class Http {
	/**
	 * 构造函数
	 */
	constructor() {
		this.params = {};
		this.isPost = false;
		this.req = null;
		this.hostname = '';
		this.port = 80;
		this.urlPath = '';
		this.protocol = 'http:';
		this.timeout = 10000;
		this.headers = {};
	}

	/**
	 * [setParams description]
	 * @param {Object} [params] {key:value}
	 */
	setParams(params) {
		this.params = params;
	}

	/**
	 * 设置主机名
	 * @param {String} hostname
	 */
	setHostName(hostname) {
		this.hostname = hostname;
	}

	/**
	 * 设置path
	 * @param {String} path
	 */
	setUrlPath(path) {
		this.urlPath = path;
	}
	/**
	 * 设置请求类型
	 * @param {Boolean} isPost
	 */
	setIsPost(isPost) {
		this.isPost = isPost;
	}

	/**
	 * 设置请求端口
	 * @param {Number} port
	 */
	setPort(port) {
		this.port = port;
	}

	/**
	 * 设置请求协议
	 * @param {String} protocol
	 */
	setProtocol(protocol) {
		this.protocol = protocol;
	}

	/**
	 * 设置请求超时时间
	 * @param {Number} timeout
	 */
	setTimeout(timeout) {
		this.timeout = timeout;
	}

	/**
	 * [setHeader description]
	 * @param {[Object]} headers [description]
	 */
	setHeader(headers) {
		this.headers = headers;
	}
	/**
	 * sendRequest
	 * @return {object}
	 */
	sendRequest() {
		let options = {
			protocol: this.protocol,
			hostname: this.hostname,
			port: this.port,
			path: this.urlPath,
			method: 'GET',
			timeout: this.timeout,
			headers: this.headers
		};
		if (this.isPost) {
			options.method = 'POST';
			if (!options.headers['Content-Type']) {
				options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
			}
			options.path = this.urlPath;
			if (this.params instanceof Object && this.parseContentType(options.headers['Content-Type']) == 'json') {
				this.params = JSON.stringify(this.params);
			} else {
				this.params = queryString.stringify(this.params);
			}
			options.headers['Content-Length'] = Buffer.byteLength(this.params);
		} else {
			this.params = queryString.stringify(this.params);
			options.path = this.urlPath + '?' + this.params;
		}
		return new Promise((resolve, reject)=>{
			this._request(options).then((res)=>{
				this._getResponse(res).then((chunk)=>{
					resolve(chunk.toString());
				});
			}).catch((msg)=>{
				console.log(err);
				reject(msg);
			});
			this._requestStatus().then((err)=>{
				console.log(err);
				reject(err);
			});
		});
	}

	/**
	 * 解析请求头
	 * @param {String} contentType
	 * @return {String}
	 */
	parseContentType(contentType) {
		if (/(json)/.test(contentType)) {
			return 'json';
		} else if (/(x-www-form-urlencoded)/.test(contentType)) {
			return 'form';
		} else {
			return 'raw';
		}
	}
	/**
	 * 获取响应
	 * @param {Object} res
	 * @return {Promise}
	 */
	_getResponse(res) {
		return new Promise((resolve, reject)=>{
			// res.setEncoding('utf8');
			res.on('data', (chunk) => {
				resolve(chunk);
			});
		});
	}

	/**
	 * 获取请求状态
	 * @return {Promise}
	 */
	_requestStatus() {
		return new Promise((resolve, reject)=>{
			this.req.on('error', (e) => {
				resolve(e);
			});
			if (this.isPost) {
				this.req.write(this.params);
			}
			this.req.end();
		});
	}

	/**
	 * 请求
	 * @param {Object} options
	 * @return {Promise}
	 */
	_request(options) {
		return new Promise((resolve, reject)=>{
			this.req = httpServer.request(options, (res)=>{
				if (res) {
					resolve(res);
				} else {
					reject('请求失败');
				}
			});
		});
	}
}

module.exports = Http;
<commit_msg>update http.js<commit_after>const httpServer = require('http');
const queryString = require('querystring');
/**
 * http请求
 */
class Http {
	/**
	 * 构造函数
	 */
	constructor() {
		this.params = {};
		this.isPost = false;
		this.req = null;
		this.hostname = '';
		this.port = 80;
		this.urlPath = '';
		this.protocol = 'http:';
		this.timeout = 10000;
		this.headers = {};
	}

	/**
	 * [setParams description]
	 * @param {Object} [params] {key:value}
	 */
	setParams(params) {
		this.params = params;
	}

	/**
	 * 设置主机名
	 * @param {String} hostname
	 */
	setHostName(hostname) {
		this.hostname = hostname;
	}

	/**
	 * 设置path
	 * @param {String} path
	 */
	setUrlPath(path) {
		this.urlPath = path;
	}
	/**
	 * 设置请求类型
	 * @param {Boolean} isPost
	 */
	setIsPost(isPost) {
		this.isPost = isPost;
	}

	/**
	 * 设置请求端口
	 * @param {Number} port
	 */
	setPort(port) {
		this.port = port;
	}

	/**
	 * 设置请求协议
	 * @param {String} protocol
	 */
	setProtocol(protocol) {
		this.protocol = protocol;
	}

	/**
	 * 设置请求超时时间
	 * @param {Number} timeout
	 */
	setTimeout(timeout) {
		this.timeout = timeout;
	}

	/**
	 * [setHeader description]
	 * @param {[Object]} headers [description]
	 */
	setHeader(headers) {
		this.headers = headers;
	}
	/**
	 * sendRequest
	 * @return {object}
	 */
	sendRequest() {
		let options = {
			protocol: this.protocol,
			hostname: this.hostname,
			port: this.port,
			path: this.urlPath,
			method: 'GET',
			timeout: this.timeout,
			headers: this.headers
		};
		if (this.isPost) {
			options.method = 'POST';
			if (!options.headers['Content-Type']) {
				options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
			}
			options.path = this.urlPath;
			if (this.params instanceof Object && this.parseContentType(options.headers['Content-Type']) == 'json') {
				this.params = JSON.stringify(this.params);
			} else {
				this.params = queryString.stringify(this.params);
			}
			options.headers['Content-Length'] = Buffer.byteLength(this.params);
		} else {
			this.params = queryString.stringify(this.params);
			options.path = this.urlPath + '?' + this.params;
		}
		return new Promise((resolve, reject)=>{
			this._request(options).then((res)=>{
				this._getResponse(res).then((chunk)=>{
					resolve(chunk.toString());
				});
			}).catch((msg)=>{
				console.log(err);
				reject(msg);
			});
			this._requestStatus().then((err)=>{
				console.log(err);
				reject(err);
			});
		});
	}

	/**
	 * 解析请求头
	 * @param {String} contentType
	 * @return {String}
	 */
	parseContentType(contentType) {
		if (/(json)/.test(contentType)) {
			return 'json';
		} else if (/(x-www-form-urlencoded)/.test(contentType)) {
			return 'form';
		} else {
			return 'raw';
		}
	}
	/**
	 * 获取响应
	 * @param {Object} res
	 * @return {Promise}
	 */
	_getResponse(res) {
		return new Promise((resolve, reject)=>{
			// res.setEncoding('utf8');
			let rawData = '';
			res.on('data', (chunk) => {
				rawData += chunk;
			});
			res.on('end', () => {
				resolve(rawData);
			});
		});
	}

	/**
	 * 获取请求状态
	 * @return {Promise}
	 */
	_requestStatus() {
		return new Promise((resolve, reject)=>{
			this.req.on('error', (e) => {
				resolve(e);
			});
			if (this.isPost) {
				this.req.write(this.params);
			}
			this.req.end();
		});
	}

	/**
	 * 请求
	 * @param {Object} options
	 * @return {Promise}
	 */
	_request(options) {
		return new Promise((resolve, reject)=>{
			this.req = httpServer.request(options, (res)=>{
				if (res) {
					resolve(res);
				} else {
					reject('请求失败');
				}
			});
		});
	}
}

module.exports = Http;
<|endoftext|>


<commit_before>const path = require('path')
const pkg = require('./package.json')

const SRC = path.resolve(__dirname, './src')
const LIB = path.resolve(__dirname, './lib')
const ES = path.resolve(__dirname, './es')

const external = [
  ...Object.keys(pkg.peerDependencies),
  'history/createHashHistory',
  'history/createBrowserHistory',
]

module.exports = {
  external,
  context: SRC,
  extensions: ['.ts', '.tsx'],
  include: [
    'src/index.ts',
  ],
  output: [{
    filename: '[dir]/[name].js',
    dest: LIB,
    format: 'cjs',
    sourcemap: true,
  }, {
    filename: '[dir]/[name].js',
    dest: ES,
    format: 'es',
    sourcemap: true,
  }],
  namedExports: {
    '../../node_modules/react-hot-loader/index.js': ['AppContainer'],
  },
}
<commit_msg>fix(packages/appson): remove include<commit_after>const path = require('path')
const pkg = require('./package.json')

const SRC = path.resolve(__dirname, './src')
const LIB = path.resolve(__dirname, './lib')
const ES = path.resolve(__dirname, './es')

const external = [
  ...Object.keys(pkg.peerDependencies),
  'history/createHashHistory',
  'history/createBrowserHistory',
]

module.exports = {
  external,
  context: SRC,
  extensions: ['.ts', '.tsx'],
  output: [{
    filename: '[dir]/[name].js',
    dest: LIB,
    format: 'cjs',
    sourcemap: true,
  }, {
    filename: '[dir]/[name].js',
    dest: ES,
    format: 'es',
    sourcemap: true,
  }],
  namedExports: {
    '../../node_modules/react-hot-loader/index.js': ['AppContainer'],
  },
}
<|endoftext|>


<commit_before>"use strict";

module.class("Holder",
{
	init: function(data)
	{
		var self = this;
		this.element = document.createElement("div");
		this.element.setAttribute("class", "holder");
		this.element.addEventListener("dragover", function(event) { self.handleDragOver(event); }, false);
		this.element.addEventListener("drop", function(event) { self.handleFileSelect(event); }, false);

		this.removeItemFunc = function(data) {
			console.log(data);
		};

		this.data = data;
		this.items = [];
		this.freeItems = [];
		this.loadAssets();
	},

	loadAssets: function()
	{
		var item, itemInfo;
		var num = this.data.length;
		for(var n = 0; n < num; n++)
		{
			itemInfo = this.data[n];
			item = this.createItem();
			item.name = itemInfo.name;
			item.info = itemInfo;
			item.img = editor.dirPath + itemInfo.name + "." +
				itemInfo.type.substr(itemInfo.type.indexOf("/") + 1);
		}
	},

	createItem: function()
	{
		var item;

		if(this.freeItems.length > 0) {
			item = this.freeItems.pop();
		}
		else
		{
			var self = this;

			item = new module.exports.Item(self);
			item.element.setAttribute("data-id", this._uniqueItemId++);

			var removeButton = item.element.querySelector(".close");
			removeButton.addEventListener("click", function() {
				self.removeItem(item);
			});
		}

		this.items.push(item);
		this.element.appendChild(item.element);

		return item;
	},

	removeItem: function(item)
	{
		var num = this.items.length;
		for(var n = 0; n < num; n++)
		{
			if(this.items[n] === item)
			{
				this.freeItems.push(item);
				this.items[n] = this.items[num - 1];
				this.items.pop();

				this.element.removeChild(item.element);
				break;
			}
		}

		// Remove from the json data.
		num = this.data.length;
		for(n = 0; n < num; n++)
		{
			if(this.data[n] === item.info) {
				this.data.splice(n, 1);
				break;
			}
		}

		// Remove from the file system:
		var path = item.info.name + "." +
			item.info.type.substr(item.info.type.indexOf("/") + 1);
		editor.fileSystem.remove(path);
		editor.saveJSON();

		item.info = null;
	},

	handleDragOver: function(event)
	{
		event.stopPropagation();
		event.preventDefault();
		event.dataTransfer.dropEffect = "copy";
	},

	handleFileSelect: function(event)
	{
		event.stopPropagation();
		event.preventDefault();

		var self = this;

		var file, reader, item;
		var files = event.dataTransfer.files;
		var numFiles = files.length;
		this.numItemsLoading += numFiles;

		function createCb(path) {
			return function() { console.log(path); }
		}

		for(var n = 0; n < numFiles; n++)
		{
			file = files[n];
			if(!file.type.match("image.*")) {
				continue;
			}

			reader = new FileReader();
			reader.onload = (function(file) {
				return function(fileResult)
				{
					var name = encodeURIComponent(file.name);
					var wildcardIndex = name.indexOf(".");
					var idName = name.substr(0, wildcardIndex);
					var ext = name.substr(wildcardIndex);

					var blob = dataURItoBlob(fileResult.target.result, file.type);

					// TODO: Check if there is such name in the folder already.

					// Info:
					var info = {
						name: idName,
						path: "",
						type: file.type,
						lastModified: file.lastModified
					};
					self.data.push(info);

					item = self.createItem();
					item.name = idName;
					item.info = info;

					var cb = (function(item) {
						return function(path) {
							item.img = path;
						}
					}(item));

					editor.fileSystem.writeBlob(idName + ext, blob, cb);
					editor.saveJSON();
				}
			})(file);
			reader.readAsDataURL(file);
		}
	},

	//
	data: null,
	element: null,
	activeItem: null,

	items: null,
	freeItems: null,

	numItemsLoading: 0,

	_uniqueItemId: 0,
});

<commit_msg>Optimized item saving.<commit_after>"use strict";

module.class("Holder",
{
	init: function(data)
	{
		var self = this;
		this.element = document.createElement("div");
		this.element.setAttribute("class", "holder");
		this.element.addEventListener("dragover", function(event) { self.handleDragOver(event); }, false);
		this.element.addEventListener("drop", function(event) { self.handleFileSelect(event); }, false);

		this.removeItemFunc = function(data) {
			console.log(data);
		};

		this.data = data;
		this.items = [];
		this.freeItems = [];
		this.loadAssets();
	},

	loadAssets: function()
	{
		var item, itemInfo;
		var num = this.data.length;
		for(var n = 0; n < num; n++)
		{
			itemInfo = this.data[n];
			item = this.createItem();
			item.name = itemInfo.name;
			item.info = itemInfo;
			item.img = editor.dirPath + itemInfo.name + "." +
				itemInfo.type.substr(itemInfo.type.indexOf("/") + 1);
		}
	},

	createItem: function()
	{
		var item;

		if(this.freeItems.length > 0) {
			item = this.freeItems.pop();
		}
		else
		{
			var self = this;

			item = new module.exports.Item(self);
			item.element.setAttribute("data-id", this._uniqueItemId++);

			var removeButton = item.element.querySelector(".close");
			removeButton.addEventListener("click", function() {
				self.removeItem(item);
			});
		}

		this.items.push(item);
		this.element.appendChild(item.element);

		return item;
	},

	removeItem: function(item)
	{
		var num = this.items.length;
		for(var n = 0; n < num; n++)
		{
			if(this.items[n] === item)
			{
				this.freeItems.push(item);
				this.items[n] = this.items[num - 1];
				this.items.pop();

				this.element.removeChild(item.element);
				break;
			}
		}

		// Remove from the json data.
		num = this.data.length;
		for(n = 0; n < num; n++)
		{
			if(this.data[n] === item.info) {
				this.data.splice(n, 1);
				break;
			}
		}

		// Remove from the file system:
		var path = item.info.name + "." +
			item.info.type.substr(item.info.type.indexOf("/") + 1);
		editor.fileSystem.remove(path);
		editor.saveJSON();

		item.info = null;
	},

	handleDragOver: function(event)
	{
		event.stopPropagation();
		event.preventDefault();
		event.dataTransfer.dropEffect = "copy";
	},

	handleFileSelect: function(event)
	{
		event.stopPropagation();
		event.preventDefault();

		var self = this;

		var file, reader, item;
		var files = event.dataTransfer.files;
		var numFiles = files.length;
		this.numItemsLoading += numFiles;

		function createCb(path) {
			return function() { console.log(path); }
		}

		for(var n = 0; n < numFiles; n++)
		{
			file = files[n];
			if(!file.type.match("image.*")) {
				continue;
			}

			reader = new FileReader();
			reader.onload = (function(file) {
				return function(fileResult)
				{
					var name = encodeURIComponent(file.name);
					var wildcardIndex = name.indexOf(".");
					var idName = name.substr(0, wildcardIndex);
					var ext = name.substr(wildcardIndex);

					var blob = dataURItoBlob(fileResult.target.result, file.type);

					// TODO: Check if there is such name in the folder already.

					// Info:
					var info = {
						name: idName,
						path: "",
						type: file.type,
						lastModified: file.lastModified
					};
					self.data.push(info);

					item = self.createItem();
					item.name = idName;
					item.info = info;

					var cb = (function(item) {
						return function(path)
						{
							item.img = path;
							self.numItemsLoading--;
							if(self.numItemsLoading === 0) {
								editor.saveJSON();
							}
						}
					}(item));

					editor.fileSystem.writeBlob(idName + ext, blob, cb);
				}
			})(file);
			reader.readAsDataURL(file);
		}
	},

	//
	data: null,
	element: null,
	activeItem: null,

	items: null,
	freeItems: null,

	numItemsLoading: 0,

	_uniqueItemId: 0,
});

<|endoftext|>


<commit_before>/*
    Copyright 2015 IBM Corp.
    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
        http://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.
*/
var exec = require("cordova/exec");

var MFPAnalytics = {
    /**
     * Turns on the global setting for persisting of the analytics data.
     */
    enable: function () {
        cordova.exec(success , failure, "MFPAnalytics", "enable", []);
    },
    /**
     * Turns off the global setting for persisting of the analytics data.
     */
    disable: function () {
        cordova.exec(success , failure, "MFPAnalytics", "disable", []);
    },
    /**
     * Gets the current setting for determining if log data should be saved persistently.
     * @param success recieves {boolean}
     * @param failure
     */
    isEnabled: function (success, failure) {
        cordova.exec(success , failure, "MFPAnalytics", "isEnabled", []);
    },
    /**
     * Sends the analytics log file when the log store exists and is not empty
     * If the send fails, the local store is preserved. If the send succeeds, the local store is deleted.
     * @param success callback (android only)
     * @param failure  callback (android only)
     */
    send: function (success, failure) {
        cordova.exec(success , failure, "MFPAnalytics", "send", []);
    }
};

module.exports = MFPAnalytics;<commit_msg>adding success and failure callbacks<commit_after>/*
    Copyright 2015 IBM Corp.
    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
        http://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.
*/
var exec = require("cordova/exec");

var success = function(message) {
    console.log("Success");
    console.log(message);
};
var failure = function(message) {
    console.log("Failure");
    console.log(message);
};

var MFPAnalytics = {
    /**
     * Turns on the global setting for persisting of the analytics data.
     */
    enable: function () {
        cordova.exec(success , failure, "MFPAnalytics", "enable", []);
    },
    /**
     * Turns off the global setting for persisting of the analytics data.
     */
    disable: function () {
        cordova.exec(success , failure, "MFPAnalytics", "disable", []);
    },
    /**
     * Gets the current setting for determining if log data should be saved persistently.
     * @param success recieves {boolean}
     * @param failure
     */
    isEnabled: function (success, failure) {
        cordova.exec(success , failure, "MFPAnalytics", "isEnabled", []);
    },
    /**
     * Sends the analytics log file when the log store exists and is not empty
     * If the send fails, the local store is preserved. If the send succeeds, the local store is deleted.
     * @param success callback (android only)
     * @param failure  callback (android only)
     */
    send: function (success, failure) {
        cordova.exec(success , failure, "MFPAnalytics", "send", []);
    }
};

module.exports = MFPAnalytics;<|endoftext|>


<commit_before>var exec = require('cordova/exec');

var defaultThumbnailWidth = 512; // optimal for android
var defaultThumbnailHeight = 384; // optimal for android

var defaultQuality = 0.5;

var isBrowser = cordova.platformId == 'browser';

var photoLibrary = {};

// Will start caching for specified size
photoLibrary.getLibrary = function (success, error, options) {

  if (!options) {
    options = {};
  }

  options = {
    thumbnailWidth: options.thumbnailWidth ? options.thumbnailWidth : defaultThumbnailWidth,
    thumbnailHeight: options.thumbnailHeight ? options.thumbnailHeight : defaultThumbnailHeight,
  };

  cordova.exec(
    function (library) {
      addUrlsToLibrary(library, success, options);
    },
    error,
    'PhotoLibrary',
    'getLibrary', [options]
  );

};

// Generates url that can be accessed directly, so it will work more efficiently than getThumbnail, which does base64 encode/decode.
// If success callback not provided, will return value immediately, but use overload with success as it browser-friendly
photoLibrary.getThumbnailURL = function (photoIdOrLibraryItem, success, error, options) {

  var photoId = typeof photoIdOrLibraryItem.id !== 'undefined' ? photoIdOrLibraryItem.id : photoIdOrLibraryItem;

  if (typeof success !== 'function' && typeof options === 'undefined') {
    options = success;
    success = undefined;
  }

  options = getThumbnailOptionsWithDefaults(options);

  var thumbnailURL = 'cdvphotolibrary://thumbnail?photoId=' + encodeURIComponent(photoId) +
      '&width=' + encodeURIComponent(options.thumbnailWidth) +
      '&height=' + encodeURIComponent(options.thumbnailHeight) +
      '&quality=' + encodeURIComponent(options.quality);

  if (success) {
    if (isBrowser) {
      cordova.exec(success, success, 'PhotoLibrary', '_getThumbnailURLBrowser', [photoId, options]);
    } else {
      success(thumbnailURL);
    }
  } else {
    return thumbnailURL;
  }

};

// Generates url that can be accessed directly, so it will work more efficiently than getPhoto, which does base64 encode/decode.
// If success callback not provided, will return value immediately, but use overload with success as it browser-friendly
photoLibrary.getPhotoURL = function (photoIdOrLibraryItem, success, error, options) {

  var photoId = typeof photoIdOrLibraryItem.id !== 'undefined' ? photoIdOrLibraryItem.id : photoIdOrLibraryItem;

  if (typeof success !== 'function' && typeof options === 'undefined') {
    options = success;
    success = undefined;
  }

  if (!options) {
    options = {};
  }

  var photoURL = 'cdvphotolibrary://photo?photoId=' + encodeURIComponent(photoId);

  if (success) {
    if (isBrowser) {
      cordova.exec(success, success, 'PhotoLibrary', '_getPhotoURLBrowser', [photoId, options]);
    } else {
      success(photoURL);
    }
  } else {
    return photoURL;
  }

};

// Provide same size as when calling getLibrary for better performance
photoLibrary.getThumbnail = function (photoIdOrLibraryItem, success, error, options) {

  var photoId = typeof photoIdOrLibraryItem.id !== 'undefined' ? photoIdOrLibraryItem.id : photoIdOrLibraryItem;

  options = getThumbnailOptionsWithDefaults(options);

  cordova.exec(
    function (data, mimeType) {
      if (!mimeType && data.data && data.mimeType) {
        // workaround for browser platform cannot return multipart result
        mimeType = data.mimeType;
        data = data.data;
      }
      var blob = new Blob([data], {
        type: mimeType
      });
      success(blob);
    },
    error,
    'PhotoLibrary',
    'getThumbnail', [photoId, options]
  );

};

photoLibrary.getPhoto = function (photoIdOrLibraryItem, success, error, options) {

  var photoId = typeof photoIdOrLibraryItem.id !== 'undefined' ? photoIdOrLibraryItem.id : photoIdOrLibraryItem;

  if (!options) {
    options = {};
  }

  cordova.exec(
    function (data, mimeType) {
      if (!mimeType && data.data && data.mimeType) {
        // workaround for browser platform cannot return multipart result
        mimeType = data.mimeType;
        data = data.data;
      }
      var blob = new Blob([data], {
        type: mimeType
      });
      success(blob);
    },
    error,
    'PhotoLibrary',
    'getPhoto', [photoId, options]
  );

};

// Call when thumbnails are not longer needed for better performance
photoLibrary.stopCaching = function (success, error) {

  cordova.exec(
    success,
    error,
    'PhotoLibrary',
    'stopCaching', []
  );

};

module.exports = photoLibrary;

var getThumbnailOptionsWithDefaults = function (options) {

  if (!options) {
    options = {};
  }

  options = {
    thumbnailWidth: options.thumbnailWidth ? options.thumbnailWidth : defaultThumbnailWidth,
    thumbnailHeight: options.thumbnailHeight ? options.thumbnailHeight : defaultThumbnailHeight,
    quality: options.quality ? options.quality : defaultQuality,
  };

  return options;

};

var addUrlsToLibrary = function(library, success, options) {

  var urlsLeft = library.length;

  var handlePhotoURL = function (libraryItem, photoURL) {
    libraryItem.photoURL = photoURL;
    urlsLeft -= 1;
    if (urlsLeft === 0) {
      success(library);
    }
  };

  var handleThumbnailURL = function (libraryItem, thumbnailURL) {
    libraryItem.thumbnailURL = thumbnailURL;
    photoLibrary.getPhotoURL(libraryItem, handlePhotoURL.bind(null, libraryItem), handleUrlError);
  };

  var handleUrlError = function () {}; // Should never happen

  var i;
  for (i = 0; i<library.length; i++) {
    var libraryItem = library[i];
    photoLibrary.getThumbnailURL(libraryItem, handleThumbnailURL.bind(null, libraryItem), handleUrlError, options);
  }

};
<commit_msg>fixed issue with uri encoding<commit_after>var exec = require('cordova/exec');

var defaultThumbnailWidth = 512; // optimal for android
var defaultThumbnailHeight = 384; // optimal for android

var defaultQuality = 0.5;

var isBrowser = cordova.platformId == 'browser';

var photoLibrary = {};

// Will start caching for specified size
photoLibrary.getLibrary = function (success, error, options) {

  if (!options) {
    options = {};
  }

  options = {
    thumbnailWidth: options.thumbnailWidth ? options.thumbnailWidth : defaultThumbnailWidth,
    thumbnailHeight: options.thumbnailHeight ? options.thumbnailHeight : defaultThumbnailHeight,
  };

  cordova.exec(
    function (library) {
      addUrlsToLibrary(library, success, options);
    },
    error,
    'PhotoLibrary',
    'getLibrary', [options]
  );

};

// Generates url that can be accessed directly, so it will work more efficiently than getThumbnail, which does base64 encode/decode.
// If success callback not provided, will return value immediately, but use overload with success as it browser-friendly
photoLibrary.getThumbnailURL = function (photoIdOrLibraryItem, success, error, options) {

  var photoId = typeof photoIdOrLibraryItem.id !== 'undefined' ? photoIdOrLibraryItem.id : photoIdOrLibraryItem;

  if (typeof success !== 'function' && typeof options === 'undefined') {
    options = success;
    success = undefined;
  }

  options = getThumbnailOptionsWithDefaults(options);

  var thumbnailURL = 'cdvphotolibrary://thumbnail?photoId=' + fixedEncodeURIComponent(photoId) +
      '&width=' + fixedEncodeURIComponent(options.thumbnailWidth) +
      '&height=' + fixedEncodeURIComponent(options.thumbnailHeight) +
      '&quality=' + fixedEncodeURIComponent(options.quality);

  if (success) {
    if (isBrowser) {
      cordova.exec(success, success, 'PhotoLibrary', '_getThumbnailURLBrowser', [photoId, options]);
    } else {
      success(thumbnailURL);
    }
  } else {
    return thumbnailURL;
  }

};

// Generates url that can be accessed directly, so it will work more efficiently than getPhoto, which does base64 encode/decode.
// If success callback not provided, will return value immediately, but use overload with success as it browser-friendly
photoLibrary.getPhotoURL = function (photoIdOrLibraryItem, success, error, options) {

  var photoId = typeof photoIdOrLibraryItem.id !== 'undefined' ? photoIdOrLibraryItem.id : photoIdOrLibraryItem;

  if (typeof success !== 'function' && typeof options === 'undefined') {
    options = success;
    success = undefined;
  }

  if (!options) {
    options = {};
  }

  var photoURL = 'cdvphotolibrary://photo?photoId=' + fixedEncodeURIComponent(photoId);

  if (success) {
    if (isBrowser) {
      cordova.exec(success, success, 'PhotoLibrary', '_getPhotoURLBrowser', [photoId, options]);
    } else {
      success(photoURL);
    }
  } else {
    return photoURL;
  }

};

// Provide same size as when calling getLibrary for better performance
photoLibrary.getThumbnail = function (photoIdOrLibraryItem, success, error, options) {

  var photoId = typeof photoIdOrLibraryItem.id !== 'undefined' ? photoIdOrLibraryItem.id : photoIdOrLibraryItem;

  options = getThumbnailOptionsWithDefaults(options);

  cordova.exec(
    function (data, mimeType) {
      if (!mimeType && data.data && data.mimeType) {
        // workaround for browser platform cannot return multipart result
        mimeType = data.mimeType;
        data = data.data;
      }
      var blob = new Blob([data], {
        type: mimeType
      });
      success(blob);
    },
    error,
    'PhotoLibrary',
    'getThumbnail', [photoId, options]
  );

};

photoLibrary.getPhoto = function (photoIdOrLibraryItem, success, error, options) {

  var photoId = typeof photoIdOrLibraryItem.id !== 'undefined' ? photoIdOrLibraryItem.id : photoIdOrLibraryItem;

  if (!options) {
    options = {};
  }

  cordova.exec(
    function (data, mimeType) {
      if (!mimeType && data.data && data.mimeType) {
        // workaround for browser platform cannot return multipart result
        mimeType = data.mimeType;
        data = data.data;
      }
      var blob = new Blob([data], {
        type: mimeType
      });
      success(blob);
    },
    error,
    'PhotoLibrary',
    'getPhoto', [photoId, options]
  );

};

// Call when thumbnails are not longer needed for better performance
photoLibrary.stopCaching = function (success, error) {

  cordova.exec(
    success,
    error,
    'PhotoLibrary',
    'stopCaching', []
  );

};

module.exports = photoLibrary;

var getThumbnailOptionsWithDefaults = function (options) {

  if (!options) {
    options = {};
  }

  options = {
    thumbnailWidth: options.thumbnailWidth ? options.thumbnailWidth : defaultThumbnailWidth,
    thumbnailHeight: options.thumbnailHeight ? options.thumbnailHeight : defaultThumbnailHeight,
    quality: options.quality ? options.quality : defaultQuality,
  };

  return options;

};

var addUrlsToLibrary = function(library, success, options) {

  var urlsLeft = library.length;

  var handlePhotoURL = function (libraryItem, photoURL) {
    libraryItem.photoURL = photoURL;
    urlsLeft -= 1;
    if (urlsLeft === 0) {
      success(library);
    }
  };

  var handleThumbnailURL = function (libraryItem, thumbnailURL) {
    libraryItem.thumbnailURL = thumbnailURL;
    photoLibrary.getPhotoURL(libraryItem, handlePhotoURL.bind(null, libraryItem), handleUrlError);
  };

  var handleUrlError = function () {}; // Should never happen

  var i;
  for (i = 0; i<library.length; i++) {
    var libraryItem = library[i];
    photoLibrary.getThumbnailURL(libraryItem, handleThumbnailURL.bind(null, libraryItem), handleUrlError, options);
  }

};

// from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
function fixedEncodeURIComponent (str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}
<|endoftext|>


<commit_before>
/**
 * generate ab formulas
 */
App.AB = {
	options: {
		tagline: [
			{
				name: 'tagline-for-free',
				tagline: 'Order the top food %s. For free.
 After you order, everything is saved for future 1 click ordering.
Choose a restaurant:'
			},
			{
				name: 'tagline-no-free',
				tagline: 'Order the top food %s.
 After you order, everything is saved for future 1 click ordering.
Choose a restaurant:'
			}
		],
		slogan: [
			{
				name: 'slogan-push-food',
				slogan: 'Push a button. Get Food.'
			}
		],
		nothingInTheCartMobile: [
			{
				name: 'empty-cart-mobile-begin',
				line: 'Begin by tapping on anything from our curated menu below!'
			},
			{
				name: 'empty-cart-mobile-food',
				line: 'Choose food below!',
				disabled: true
			}
		],
		nothingInTheCartDesktop: [
			{
				name: 'empty-cart-desktop-begin',
				line: 'Begin by clicking on anything from our curated menu on the left!'
			},
			{
				name: 'empty-cart-desktop-food',
				line: 'Choose Food!'
			}
		],
		restaurantPage: [
			{
				name: 'restaurant-page-noimage'
			},
			{
				name: 'restaurant-page-image',
				disabled: true
			}
		],
		dollarSign: [
			{
				name : 'show'
			},
			{
				name : 'hide'
			}
		]
	},
	init: function() {
		// we dont have ab variables. generate them
		App.AB.create(false);
		App.AB.load();
	},
	create: function(clear) {
		if (clear) {
			App.config.ab = {};
		}

		// Creates the ab object case it don't exist
		if( App.config && !App.config.ab ){
			App.config.ab = {};
		}

		// loop through each option type
		for (var key in App.AB.options) {
			if (App.config.ab[key]) {
				return;
			}
			var optionType = App.AB.options[key];
			var opts = [];

			// loop through all of the options for the specific ab option type
			for (var x in optionType) {
				// remove disabled ones
				if (!optionType[x].disabled || optionType[x].disabled == false) {
					opts[opts.length] = optionType[x];
				}
			}
			var opt = opts[Math.floor(Math.random()*opts.length)];
			App.config.ab[key] = opt.name
		}
		App.AB.save();
	},
	load: function() {
		App.slogan = App.AB.pluck('slogan', App.config.ab.slogan);
		App.tagline = App.AB.pluck('tagline', App.config.ab.tagline);

		if (!App.slogan || !App.tagline) {
			App.AB.create(true);
			App.AB.load(true);
		}
	},
	pluck: function(option, name) {
		for (var x in App.AB.options[option]) {
			if (App.AB.options[option][x].name == name) {
				return App.AB.options[option][x];
			}
		}
		return null;
	},
	save: function() {
		$.ajax({
			url: App.service + 'config',
			data: {ab: App.config.ab},
			dataType: 'json',
			type: 'POST',
			complete: function(json) {

			}
		});
	}
};
<commit_msg>set 'App.AB.create(true);' at App.AB.init() - it will force create AB test<commit_after>
/**
 * generate ab formulas
 */
App.AB = {
	options: {
		tagline: [
			{
				name: 'tagline-for-free',
				tagline: 'Order the top food %s. For free.
 After you order, everything is saved for future 1 click ordering.
Choose a restaurant:'
			},
			{
				name: 'tagline-no-free',
				tagline: 'Order the top food %s.
 After you order, everything is saved for future 1 click ordering.
Choose a restaurant:'
			}
		],
		slogan: [
			{
				name: 'slogan-push-food',
				slogan: 'Push a button. Get Food.'
			}
		],
		nothingInTheCartMobile: [
			{
				name: 'empty-cart-mobile-begin',
				line: 'Begin by tapping on anything from our curated menu below!'
			},
			{
				name: 'empty-cart-mobile-food',
				line: 'Choose food below!',
				disabled: true
			}
		],
		nothingInTheCartDesktop: [
			{
				name: 'empty-cart-desktop-begin',
				line: 'Begin by clicking on anything from our curated menu on the left!'
			},
			{
				name: 'empty-cart-desktop-food',
				line: 'Choose Food!'
			}
		],
		restaurantPage: [
			{
				name: 'restaurant-page-noimage'
			},
			{
				name: 'restaurant-page-image',
				disabled: true
			}
		],
		dollarSign: [
			{
				name : 'show'
			},
			{
				name : 'hide'
			}
		]
	},
	init: function() {
		// we dont have ab variables. generate them
		App.AB.create(true);
		App.AB.load();
	},
	create: function(clear) {
		if (clear) {
			App.config.ab = {};
		}

		// Creates the ab object case it don't exist
		if( App.config && !App.config.ab ){
			App.config.ab = {};
		}

		// loop through each option type
		for (var key in App.AB.options) {
			if (App.config.ab[key]) {
				return;
			}
			var optionType = App.AB.options[key];
			var opts = [];

			// loop through all of the options for the specific ab option type
			for (var x in optionType) {
				// remove disabled ones
				if (!optionType[x].disabled || optionType[x].disabled == false) {
					opts[opts.length] = optionType[x];
				}
			}
			var opt = opts[Math.floor(Math.random()*opts.length)];
			App.config.ab[key] = opt.name
		}
		App.AB.save();
	},
	load: function() {
		App.slogan = App.AB.pluck('slogan', App.config.ab.slogan);
		App.tagline = App.AB.pluck('tagline', App.config.ab.tagline);
		if (!App.slogan || !App.tagline) {
			App.AB.create(true);
			App.AB.load(true);
		}
	},
	pluck: function(option, name) {
		for (var x in App.AB.options[option]) {
			if (App.AB.options[option][x].name == name) {
				return App.AB.options[option][x];
			}
		}
		return null;
	},
	save: function() {
		$.ajax({
			url: App.service + 'config',
			data: {ab: App.config.ab},
			dataType: 'json',
			type: 'POST',
			complete: function(json) {}
		});
	}
};
<|endoftext|>


<commit_before>/* global cordova:false */
/* globals window, document, navigator */

/*!
 * Module dependencies.
 */

var exec = cordova.require('cordova/exec');

/**
 * PushNotification constructor.
 *
 * @param {Object} options to initiate Push Notifications.
 * @return {PushNotification} instance that can be monitored and cancelled.
 */
var serviceWorker, subscription;
var notificationCanceled = false;
var keepChannelAliveTimeout = null;
var PushNotification = function(options) {
    this._handlers = {
        'registration': [],
        'notification': [],
        'notificationclick': [],
        'error': []
    };

    // require options parameter
    if (typeof options === 'undefined') {
        throw new Error('The options argument is required.');
    }

    // store the options to this object instance
    this.options = options;

    // triggered on registration and notification
    var that = this;
    var windowGuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });

    // Add manifest.json to main HTML file
    var linkElement = document.createElement('link');
    linkElement.rel = 'manifest';
    linkElement.href = 'manifest.json';
    document.getElementsByTagName('head')[0].appendChild(linkElement);

    var MAX_RETRIES = 3;

    function installServiceWorker(retry) {
        if ('serviceWorker' in navigator && 'MessageChannel' in window) {
            var result;

            navigator.serviceWorker.register('ServiceWorker.js').then(function(reg) {
                var serviceWorker;
                if (reg.installing) {
                    serviceWorker = reg.installing;
                } else if (reg.waiting) {
                    serviceWorker = reg.waiting;
                } else if (reg.active) {
                    serviceWorker = reg.active;
                }
                serviceWorker.addEventListener('statechange', function(event) {
                    if (event.target.state === "redundant") {
                        if (retry < MAX_RETRIES) {
                            navigator.serviceWorker.getRegistrations().then(function(registrations) {
                                for (var i=0; i<registrations.length; i++) {
                                    registrations[i].unregister();
                                }
                                installServiceWorker(retry + 1);
                            });
                        }
                    }
                });
                return navigator.serviceWorker.ready;
            })
            .then(function(reg) {
                reg.pushManager.subscribe({userVisibleOnly: true}).then(function(sub) {
                    subscription = sub;
                    var jsonSub = JSON.parse(JSON.stringify(subscription));
                    var result = {
                        endpoint: sub.endpoint,
                        key: jsonSub.keys['p256dh'],
                        auth: jsonSub.keys['auth']
                    };
                    var registrationId = JSON.stringify(result);
                    result['registrationId'] = registrationId;
                    that.emit('registration', result);
                }).catch(function(error) {
                    if (navigator.serviceWorker.controller === null) {
                        // When you first register a SW, need a page reload to handle network operations
                        window.location.reload();
                        return;
                    }

                    //throw new Error('Error subscribing for Push notifications.');
                    throw error;
                });
                var serviceWorker;
                if (reg.installing) {
                    serviceWorker = reg.installing;
                } else if (reg.waiting) {
                    serviceWorker = reg.waiting;
                } else if (reg.active) {
                    serviceWorker = reg.active;
                }
                if (keepChannelAliveTimeout != null) {
                    window.clearTimeout(keepChannelAliveTimeout);
                }
                keepChannelAliveTimeout = window.setInterval(function(){
                    console.log("SW: Interval");
                    var channel = new MessageChannel();
                    serviceWorker.postMessage({cmd: 'init', windowid: windowGuid}, [channel.port2]);
                    channel.port1.onmessage = function(e) {
                        var cmd = e.data.cmd;
                        var data = e.data.data;
                        if (cmd == 'notification') {
                            if (typeof(data.sound) !== "undefined" && !data["content_available"]) {
                                try {
                                    var audio = new Audio(data.sound);
                                    audio.play();
                                } catch (e) {
                                    console.error(e);
                                }
                            }
                            var channel = new MessageChannel();
                            notificationCanceled = false;
                            that.emit('notification', data);
                            if (notificationCanceled) {
                                serviceWorker.postMessage({cmd: 'received', pushId: data.pushId}, [channel.port2]);
                            }
                        } else if (cmd == 'notificationclick') {
                            that.emit('notificationclick', data);
                        }
                    }
                },5000);
            }).catch(function(error) {
                console.log(error);
                throw new Error('Error registering Service Worker');
            });
        } else {
            throw new Error('Service Workers are not supported on your browser.');
        }
    }

    installServiceWorker(1);
};

/**
 * Cancel showing current notification
 */

PushNotification.prototype.cancelNotification = function() {
    notificationCanceled = true;
}

/**
 * Unregister from push notifications
 */

PushNotification.prototype.unregister = function(successCallback, errorCallback, options) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.unregister failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.unregister failure: success callback parameter must be a function');
        return;
    }

    var that = this;
    if (!options) {
        that._handlers = {
            'registration': [],
            'notification': [],
            'notificationclick': [],
            'error': []
        };
    }

    if (serviceWorker) {
        serviceWorker.unregister().then(function(isSuccess) {
            if (isSuccess) {
                successCallback();
            } else {
                errorCallback();
            }
        });
    }
};

/**
 * subscribe to a topic
 * @param   {String}      topic               topic to subscribe
 * @param   {Function}    successCallback     success callback
 * @param   {Function}    errorCallback       error callback
 * @return  {void}
 */
PushNotification.prototype.subscribe = function(topic, successCallback, errorCallback) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.subscribe failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.subscribe failure: success callback parameter must be a function');
        return;
    }

    successCallback();
};

/**
 * unsubscribe to a topic
 * @param   {String}      topic               topic to unsubscribe
 * @param   {Function}    successCallback     success callback
 * @param   {Function}    errorCallback       error callback
 * @return  {void}
 */
PushNotification.prototype.unsubscribe = function(topic, successCallback, errorCallback) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.unsubscribe failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.unsubscribe failure: success callback parameter must be a function');
        return;
    }

    successCallback();
};

/**
 * Call this to set the application icon badge
 */

PushNotification.prototype.setApplicationIconBadgeNumber = function(successCallback, errorCallback, badge) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.setApplicationIconBadgeNumber failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.setApplicationIconBadgeNumber failure: success callback parameter must be a function');
        return;
    }

    successCallback();
};

/**
 * Get the application icon badge
 */

PushNotification.prototype.getApplicationIconBadgeNumber = function(successCallback, errorCallback) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.getApplicationIconBadgeNumber failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.getApplicationIconBadgeNumber failure: success callback parameter must be a function');
        return;
    }

    successCallback();
};

/**
 * Get the application icon badge
 */

PushNotification.prototype.clearAllNotifications = function(successCallback, errorCallback) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.clearAllNotifications failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.clearAllNotifications failure: success callback parameter must be a function');
        return;
    }

    successCallback();
};

/**
 * Listen for an event.
 *
 * The following events are supported:
 *
 *   - registration
 *   - notification
 *   - error
 *
 * @param {String} eventName to subscribe to.
 * @param {Function} callback triggered on the event.
 */

PushNotification.prototype.on = function(eventName, callback) {
    if (this._handlers.hasOwnProperty(eventName)) {
        this._handlers[eventName].push(callback);
    }
};

/**
 * Remove event listener.
 *
 * @param {String} eventName to match subscription.
 * @param {Function} handle function associated with event.
 */

PushNotification.prototype.off = function (eventName, handle) {
    if (this._handlers.hasOwnProperty(eventName)) {
        var handleIndex = this._handlers[eventName].indexOf(handle);
        if (handleIndex >= 0) {
            this._handlers[eventName].splice(handleIndex, 1);
        }
    }
};

/**
 * Emit an event.
 *
 * This is intended for internal use only.
 *
 * @param {String} eventName is the event to trigger.
 * @param {*} all arguments are passed to the event listeners.
 *
 * @return {Boolean} is true when the event is triggered otherwise false.
 */

PushNotification.prototype.emit = function() {
    var args = Array.prototype.slice.call(arguments);
    var eventName = args.shift();

    if (!this._handlers.hasOwnProperty(eventName)) {
        return false;
    }

    for (var i = 0, length = this._handlers[eventName].length; i < length; i++) {
        var callback = this._handlers[eventName][i];
        if (typeof callback === 'function') {
            callback.apply(undefined,args);
        } else {
            console.log('event handler: ' + eventName + ' must be a function');
        }
    }

    return true;
};

PushNotification.prototype.finish = function(successCallback, errorCallback, id) {
    if (!successCallback) { successCallback = function() {}; }
    if (!errorCallback) { errorCallback = function() {}; }
    if (!id) { id = 'handler'; }

    if (typeof successCallback !== 'function') {
        console.log('finish failure: success callback parameter must be a function');
        return;
    }

    if (typeof errorCallback !== 'function')  {
        console.log('finish failure: failure parameter not a function');
        return;
    }

    successCallback();
};

/*!
 * Push Notification Plugin.
 */

module.exports = {
    /**
     * Register for Push Notifications.
     *
     * This method will instantiate a new copy of the PushNotification object
     * and start the registration process.
     *
     * @param {Object} options
     * @return {PushNotification} instance
     */

    init: function(options) {
        return new PushNotification(options);
    },

    hasPermission: function(successCallback, errorCallback) {
        successCallback(true);
    },

    unregister: function(successCallback, errorCallback, options) {
        PushNotification.unregister(successCallback, errorCallback, options);
    },

    /**
     * PushNotification Object.
     *
     * Expose the PushNotification object for direct use
     * and testing. Typically, you should use the
     * .init helper method.
     */

    PushNotification: PushNotification
};
<commit_msg>Removed console.log<commit_after>/* global cordova:false */
/* globals window, document, navigator */

/*!
 * Module dependencies.
 */

var exec = cordova.require('cordova/exec');

/**
 * PushNotification constructor.
 *
 * @param {Object} options to initiate Push Notifications.
 * @return {PushNotification} instance that can be monitored and cancelled.
 */
var serviceWorker, subscription;
var notificationCanceled = false;
var keepChannelAliveTimeout = null;
var PushNotification = function(options) {
    this._handlers = {
        'registration': [],
        'notification': [],
        'notificationclick': [],
        'error': []
    };

    // require options parameter
    if (typeof options === 'undefined') {
        throw new Error('The options argument is required.');
    }

    // store the options to this object instance
    this.options = options;

    // triggered on registration and notification
    var that = this;
    var windowGuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });

    // Add manifest.json to main HTML file
    var linkElement = document.createElement('link');
    linkElement.rel = 'manifest';
    linkElement.href = 'manifest.json';
    document.getElementsByTagName('head')[0].appendChild(linkElement);

    var MAX_RETRIES = 3;

    function installServiceWorker(retry) {
        if ('serviceWorker' in navigator && 'MessageChannel' in window) {
            var result;

            navigator.serviceWorker.register('ServiceWorker.js').then(function(reg) {
                var serviceWorker;
                if (reg.installing) {
                    serviceWorker = reg.installing;
                } else if (reg.waiting) {
                    serviceWorker = reg.waiting;
                } else if (reg.active) {
                    serviceWorker = reg.active;
                }
                serviceWorker.addEventListener('statechange', function(event) {
                    if (event.target.state === "redundant") {
                        if (retry < MAX_RETRIES) {
                            navigator.serviceWorker.getRegistrations().then(function(registrations) {
                                for (var i=0; i<registrations.length; i++) {
                                    registrations[i].unregister();
                                }
                                installServiceWorker(retry + 1);
                            });
                        }
                    }
                });
                return navigator.serviceWorker.ready;
            })
            .then(function(reg) {
                reg.pushManager.subscribe({userVisibleOnly: true}).then(function(sub) {
                    subscription = sub;
                    var jsonSub = JSON.parse(JSON.stringify(subscription));
                    var result = {
                        endpoint: sub.endpoint,
                        key: jsonSub.keys['p256dh'],
                        auth: jsonSub.keys['auth']
                    };
                    var registrationId = JSON.stringify(result);
                    result['registrationId'] = registrationId;
                    that.emit('registration', result);
                }).catch(function(error) {
                    if (navigator.serviceWorker.controller === null) {
                        // When you first register a SW, need a page reload to handle network operations
                        window.location.reload();
                        return;
                    }

                    //throw new Error('Error subscribing for Push notifications.');
                    throw error;
                });
                var serviceWorker;
                if (reg.installing) {
                    serviceWorker = reg.installing;
                } else if (reg.waiting) {
                    serviceWorker = reg.waiting;
                } else if (reg.active) {
                    serviceWorker = reg.active;
                }
                if (keepChannelAliveTimeout != null) {
                    window.clearTimeout(keepChannelAliveTimeout);
                }
                keepChannelAliveTimeout = window.setInterval(function(){
                    var channel = new MessageChannel();
                    serviceWorker.postMessage({cmd: 'init', windowid: windowGuid}, [channel.port2]);
                    channel.port1.onmessage = function(e) {
                        var cmd = e.data.cmd;
                        var data = e.data.data;
                        if (cmd == 'notification') {
                            if (typeof(data.sound) !== "undefined" && !data["content_available"]) {
                                try {
                                    var audio = new Audio(data.sound);
                                    audio.play();
                                } catch (e) {
                                    console.error(e);
                                }
                            }
                            var channel = new MessageChannel();
                            notificationCanceled = false;
                            that.emit('notification', data);
                            if (notificationCanceled) {
                                serviceWorker.postMessage({cmd: 'received', pushId: data.pushId}, [channel.port2]);
                            }
                        } else if (cmd == 'notificationclick') {
                            that.emit('notificationclick', data);
                        }
                    }
                },5000);
            }).catch(function(error) {
                console.log(error);
                throw new Error('Error registering Service Worker');
            });
        } else {
            throw new Error('Service Workers are not supported on your browser.');
        }
    }

    installServiceWorker(1);
};

/**
 * Cancel showing current notification
 */

PushNotification.prototype.cancelNotification = function() {
    notificationCanceled = true;
}

/**
 * Unregister from push notifications
 */

PushNotification.prototype.unregister = function(successCallback, errorCallback, options) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.unregister failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.unregister failure: success callback parameter must be a function');
        return;
    }

    var that = this;
    if (!options) {
        that._handlers = {
            'registration': [],
            'notification': [],
            'notificationclick': [],
            'error': []
        };
    }

    if (serviceWorker) {
        serviceWorker.unregister().then(function(isSuccess) {
            if (isSuccess) {
                successCallback();
            } else {
                errorCallback();
            }
        });
    }
};

/**
 * subscribe to a topic
 * @param   {String}      topic               topic to subscribe
 * @param   {Function}    successCallback     success callback
 * @param   {Function}    errorCallback       error callback
 * @return  {void}
 */
PushNotification.prototype.subscribe = function(topic, successCallback, errorCallback) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.subscribe failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.subscribe failure: success callback parameter must be a function');
        return;
    }

    successCallback();
};

/**
 * unsubscribe to a topic
 * @param   {String}      topic               topic to unsubscribe
 * @param   {Function}    successCallback     success callback
 * @param   {Function}    errorCallback       error callback
 * @return  {void}
 */
PushNotification.prototype.unsubscribe = function(topic, successCallback, errorCallback) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.unsubscribe failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.unsubscribe failure: success callback parameter must be a function');
        return;
    }

    successCallback();
};

/**
 * Call this to set the application icon badge
 */

PushNotification.prototype.setApplicationIconBadgeNumber = function(successCallback, errorCallback, badge) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.setApplicationIconBadgeNumber failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.setApplicationIconBadgeNumber failure: success callback parameter must be a function');
        return;
    }

    successCallback();
};

/**
 * Get the application icon badge
 */

PushNotification.prototype.getApplicationIconBadgeNumber = function(successCallback, errorCallback) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.getApplicationIconBadgeNumber failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.getApplicationIconBadgeNumber failure: success callback parameter must be a function');
        return;
    }

    successCallback();
};

/**
 * Get the application icon badge
 */

PushNotification.prototype.clearAllNotifications = function(successCallback, errorCallback) {
    if (!errorCallback) { errorCallback = function() {}; }

    if (typeof errorCallback !== 'function')  {
        console.log('PushNotification.clearAllNotifications failure: failure parameter not a function');
        return;
    }

    if (typeof successCallback !== 'function') {
        console.log('PushNotification.clearAllNotifications failure: success callback parameter must be a function');
        return;
    }

    successCallback();
};

/**
 * Listen for an event.
 *
 * The following events are supported:
 *
 *   - registration
 *   - notification
 *   - error
 *
 * @param {String} eventName to subscribe to.
 * @param {Function} callback triggered on the event.
 */

PushNotification.prototype.on = function(eventName, callback) {
    if (this._handlers.hasOwnProperty(eventName)) {
        this._handlers[eventName].push(callback);
    }
};

/**
 * Remove event listener.
 *
 * @param {String} eventName to match subscription.
 * @param {Function} handle function associated with event.
 */

PushNotification.prototype.off = function (eventName, handle) {
    if (this._handlers.hasOwnProperty(eventName)) {
        var handleIndex = this._handlers[eventName].indexOf(handle);
        if (handleIndex >= 0) {
            this._handlers[eventName].splice(handleIndex, 1);
        }
    }
};

/**
 * Emit an event.
 *
 * This is intended for internal use only.
 *
 * @param {String} eventName is the event to trigger.
 * @param {*} all arguments are passed to the event listeners.
 *
 * @return {Boolean} is true when the event is triggered otherwise false.
 */

PushNotification.prototype.emit = function() {
    var args = Array.prototype.slice.call(arguments);
    var eventName = args.shift();

    if (!this._handlers.hasOwnProperty(eventName)) {
        return false;
    }

    for (var i = 0, length = this._handlers[eventName].length; i < length; i++) {
        var callback = this._handlers[eventName][i];
        if (typeof callback === 'function') {
            callback.apply(undefined,args);
        } else {
            console.log('event handler: ' + eventName + ' must be a function');
        }
    }

    return true;
};

PushNotification.prototype.finish = function(successCallback, errorCallback, id) {
    if (!successCallback) { successCallback = function() {}; }
    if (!errorCallback) { errorCallback = function() {}; }
    if (!id) { id = 'handler'; }

    if (typeof successCallback !== 'function') {
        console.log('finish failure: success callback parameter must be a function');
        return;
    }

    if (typeof errorCallback !== 'function')  {
        console.log('finish failure: failure parameter not a function');
        return;
    }

    successCallback();
};

/*!
 * Push Notification Plugin.
 */

module.exports = {
    /**
     * Register for Push Notifications.
     *
     * This method will instantiate a new copy of the PushNotification object
     * and start the registration process.
     *
     * @param {Object} options
     * @return {PushNotification} instance
     */

    init: function(options) {
        return new PushNotification(options);
    },

    hasPermission: function(successCallback, errorCallback) {
        successCallback(true);
    },

    unregister: function(successCallback, errorCallback, options) {
        PushNotification.unregister(successCallback, errorCallback, options);
    },

    /**
     * PushNotification Object.
     *
     * Expose the PushNotification object for direct use
     * and testing. Typically, you should use the
     * .init helper method.
     */

    PushNotification: PushNotification
};
<|endoftext|>


<commit_before>var debug = require('debug')('freecc:user:remote');
var blacklistedUsernames =
  require('../../server/utils/constants').blacklistedUsernames;

module.exports = function(User) {
  // NOTE(berks): user email validation currently not needed but build in. This
  // work around should let us sneak by
  // see:
  // https://github.com/strongloop/loopback/issues/1137#issuecomment-109200135
  delete User.validations.email;
  // set salt factor for passwords
  User.settings.saltWorkFactor = 5;

  // username should not be in blacklist
  User.validatesExclusionOf('username', {
    'in': blacklistedUsernames,
    message: 'is taken'
  });

  // username should be unique
  User.validatesUniquenessOf('username');

  debug('setting up user hooks');
  User.afterRemote('confirm', function(ctx) {
    ctx.req.flash('success', {
      msg: [
        'You\'re email has been confirmed!'
      ]
    });
    ctx.res.redirect('/email-signin');
  });

  User.afterRemote('login', function(ctx, user, next) {
    var res = ctx.res;
    var req = ctx.req;
    // var args = ctx.args;

    var accessToken = {};
    var config = {
      signed: !!req.signedCookies,
      maxAge: accessToken.ttl
    };
    if (accessToken && accessToken.id) {
      res.cookie('access_token', accessToken.id, config);
      res.cookie('userId', accessToken.userId, config);
    }

    return req.logIn(user, function(err) {
      if (err) {
        return next(err);
      }
      req.flash('success', { msg: 'Success! You are logged in.' });
      return res.redirect('/');
    });
  });

  User.afterRemote('logout', function(ctx, result, next) {
    var res = ctx.result;
    res.clearCookie('access_token');
    res.clearCookie('userId');
    next();
  });

  User.doesExist = function doesExist(username, email, cb) {
    if (!username && !email) {
      return process.nextTick(function() {
        cb(null, false);
      });
    }
    debug('checking existence');

    // check to see if username is on blacklist
    if (username && blacklistedUsernames.indexOf(username) !== -1) {
      return cb(null, true);
    }

    var where = {};
    if (username) {
      where.username = username.toLowerCase();
    } else {
      where.email = email ? email.toLowerCase() : email;
    }
    debug('where', where);
    User.count(
      where,
      function (err, count) {
        if (err) {
          debug('err checking existance: ', err);
          return cb(err);
        }
        if (count > 0) {
          return cb(null, true);
        }
        return cb(null, false);
      }
    );
  };

  User.remoteMethod(
    'doesExist',
    {
      description: 'checks whether a user exists using email or username',
      accepts: [
        {
          arg: 'username',
          type: 'string'
        },
        {
          arg: 'email',
          type: 'string'
        }
      ],
      returns: [
        {
          arg: 'exists',
          type: 'boolean'
        }
      ],
      http: {
        path: '/exists',
        verb: 'get'
      }
    }
  );
};
<commit_msg>Handle invalid login<commit_after>var debug = require('debug')('freecc:user:remote');
var blacklistedUsernames =
  require('../../server/utils/constants').blacklistedUsernames;

module.exports = function(User) {
  // NOTE(berks): user email validation currently not needed but build in. This
  // work around should let us sneak by
  // see:
  // https://github.com/strongloop/loopback/issues/1137#issuecomment-109200135
  delete User.validations.email;
  // set salt factor for passwords
  User.settings.saltWorkFactor = 5;

  // username should not be in blacklist
  User.validatesExclusionOf('username', {
    'in': blacklistedUsernames,
    message: 'is taken'
  });

  // username should be unique
  User.validatesUniquenessOf('username');

  debug('setting up user hooks');
  User.afterRemote('confirm', function(ctx) {
    ctx.req.flash('success', {
      msg: [
        'You\'re email has been confirmed!'
      ]
    });
    ctx.res.redirect('/email-signin');
  });

  User.afterRemote('login', function(ctx, user, next) {
    var res = ctx.res;
    var req = ctx.req;
    // var args = ctx.args;

    var accessToken = {};
    var config = {
      signed: !!req.signedCookies,
      maxAge: accessToken.ttl
    };
    if (accessToken && accessToken.id) {
      res.cookie('access_token', accessToken.id, config);
      res.cookie('userId', accessToken.userId, config);
    }
    debug('before pass login');
    return req.logIn(user, function(err) {
      if (err) {
        return next(err);
      }
      req.flash('success', { msg: 'Success! You are logged in.' });
      return res.redirect('/');
    });
  });

  User.afterRemoteError('login', function(ctx, usr, next) {
    var res = ctx.res;
    var req = ctx.req;
    // var args = ctx.args;

    debug('after pass lgin');
    req.flash('errors', {
      msg: 'Invalid username or password.'
    });
    return res.redirect('/');
  });

  User.afterRemote('logout', function(ctx, result, next) {
    var res = ctx.result;
    res.clearCookie('access_token');
    res.clearCookie('userId');
    next();
  });

  User.doesExist = function doesExist(username, email, cb) {
    if (!username && !email) {
      return process.nextTick(function() {
        cb(null, false);
      });
    }
    debug('checking existence');

    // check to see if username is on blacklist
    if (username && blacklistedUsernames.indexOf(username) !== -1) {
      return cb(null, true);
    }

    var where = {};
    if (username) {
      where.username = username.toLowerCase();
    } else {
      where.email = email ? email.toLowerCase() : email;
    }
    debug('where', where);
    User.count(
      where,
      function (err, count) {
        if (err) {
          debug('err checking existance: ', err);
          return cb(err);
        }
        if (count > 0) {
          return cb(null, true);
        }
        return cb(null, false);
      }
    );
  };

  User.remoteMethod(
    'doesExist',
    {
      description: 'checks whether a user exists using email or username',
      accepts: [
        {
          arg: 'username',
          type: 'string'
        },
        {
          arg: 'email',
          type: 'string'
        }
      ],
      returns: [
        {
          arg: 'exists',
          type: 'boolean'
        }
      ],
      http: {
        path: '/exists',
        verb: 'get'
      }
    }
  );
};
<|endoftext|>


<commit_before>/**
 * Aifang Javascript Framework.
 * Copyright 2012 ANJUKE Inc. All rights reserved.
 *
 * @path: event/event.js
 * @author: Jock
 * @version: 1.0.0
 * @date: 2012/08/29
 *
 *
 *
 *
 */

/**
 *
KEY_BACKSPACE:8,
KEY_TAB:9,
KEY_RETURN:13,
KEY_ESC:27,
KEY_LEFT:37,
KEY_UP:38,
KEY_RIGHT:39,
KEY_DOWN:40,
KEY_DELETE:46,
KEY_HOME:36,
KEY_END:35,
KEY_PAGEUP:33,
KEY_PAGEDOWN:34,
KEY_INSERT:45,
 */

(function (J, W, D) {

    J.add('event', {
        DA:'dataavailable',
        LO:'losecapture',
        ME:'mouseenter',
        ML:'mouseleave',
        CACHE:[],
        fix:getResponder,
        fixName:fixEventName,
        getKeyCode:function (event) {
            return event.which || event.keyCode;
        },
        g:function(element){
            return J.isString(element) ? D.getElementById(element) : (element.length && element.get) ? element.get(0) : element;
        }
    });

    var E = J.event, dom = J.dom, ME = E.ME, ML = E.ML, U= 'unload', docEl = D.documentElement, isIE = J.ua.ie;
    E.MMES = 'on'+ ME in docEl && 'on'+ ML in docEl;

    dom && dom.fn && J.each('on un once fire'.split(' '), function(i, v){
        dom.fn[v] = function(){
            E[v].apply(null, [this.get()].concat(J.slice.call(arguments)));
            return this;
        }
    });

    function extend(event, element, data, preventDefault, stopPropagation) {
        if (!event) return false;
        var d = 'preventDefault',p = 'stopPropagation',c = 'currentTarget';

        event[c] || (event[c] = element);
        event[d] || (event[d] = function () {
            event.returnValue = false;
        });
        event[p] || (event[p] = function () {
            event.cancelBubble = true;
        });
        event.stop = function () {
            event[d]();
            event[p]()
        };

        if (preventDefault) event[d]();
        if (stopPropagation) event[p]();

        return event;
    }

    function getResponder(element, type, handler, data, preventDefault, stopPropagation) {
        return function (event) {
            if (type.indexOf(':') > -1 && event && event.eventName !== type) return false;
            if (!E.MMES && (type === ME || type === ML)) {
                var a = event.currentTarget || element, b = event.relatedTarget;
                //火狐支持compareDocumentPosition(), 其他浏览器支持 contains();
                if (!(a != b && !(a.contains ? a.contains(b) : !!(a.compareDocumentPosition(b) & 16) ))) return false;
            }
            extend(event, element, data, preventDefault, stopPropagation);
            handler.call(element, event, data);
        };
    }

    function fixEventName(e) {
        var translations = { mouseenter:"mouseover", mouseleave:"mouseout" };
        return (translations[e] || e);
    }

    // 释放内存，防止造成内存泄漏
    if (isIE)
        W.attachEvent('on'+U, function(){
            var e, E = J.event, a = E.CACHE, l = a.length, dE = 'detachEvent';
            while (l--) {
                e = a[l];
                e.e[dE]('on' + e.t, e.r, false);
                if (e.t.indexOf(':') > -1) {
                    e.e[dE]("on"+ E.DA, e.r);
                    e.e[dE]("on"+ E.LO, e.r);
                }
                a.splice(l, 1);
            }
        });
    else
        W.addEventListener(U, function () {}, false);

})(J, window, document);<commit_msg>modify event<commit_after>/**
 * Aifang Javascript Framework.
 * Copyright 2012 ANJUKE Inc. All rights reserved.
 *
 * @path: event/event.js
 * @author: Jock
 * @version: 1.0.0
 * @date: 2012/08/29
 *
 *
 *
 *
 */

/**
 *
KEY_BACKSPACE:8,
KEY_TAB:9,
KEY_RETURN:13,
KEY_ESC:27,
KEY_LEFT:37,
KEY_UP:38,
KEY_RIGHT:39,
KEY_DOWN:40,
KEY_DELETE:46,
KEY_HOME:36,
KEY_END:35,
KEY_PAGEUP:33,
KEY_PAGEDOWN:34,
KEY_INSERT:45,
 */

(function (J, W, D) {

    J.add('event', {
        DA:'dataavailable',
        LO:'losecapture',
        ME:'mouseenter',
        ML:'mouseleave',
        CACHE:[],
        fix:getResponder,
        fixName:fixEventName,
        getKeyCode:function (event) {
            return event.which || event.keyCode;
        },
        g:function(element){
            return (!element) ? '' : J.isString(element) ? D.getElementById(element) : (element.length && element.get) ? element.get(0) : element;
        }
    });

    var E = J.event, dom = J.dom, ME = E.ME, ML = E.ML, U= 'unload', docEl = D.documentElement, isIE = J.ua.ie;
    E.MMES = 'on'+ ME in docEl && 'on'+ ML in docEl;

    dom && dom.fn && J.each('on un once fire'.split(' '), function(i, v){
        dom.fn[v] = function(){
            E[v].apply(null, [this.get()].concat(J.slice.call(arguments)));
            return this;
        }
    });

    function extend(event, element, data, preventDefault, stopPropagation) {
        if (!event) return false;
        var d = 'preventDefault',p = 'stopPropagation',c = 'currentTarget';

        event[c] || (event[c] = element);
        event[d] || (event[d] = function () {
            event.returnValue = false;
        });
        event[p] || (event[p] = function () {
            event.cancelBubble = true;
        });
        event.stop = function () {
            event[d]();
            event[p]()
        };

        if (preventDefault) event[d]();
        if (stopPropagation) event[p]();

        return event;
    }

    function getResponder(element, type, handler, data, preventDefault, stopPropagation) {
        return function (event) {
            if (type.indexOf(':') > -1 && event && event.eventName !== type) return false;
            if (!E.MMES && (type === ME || type === ML)) {
                var a = event.currentTarget || element, b = event.relatedTarget;
                //火狐支持compareDocumentPosition(), 其他浏览器支持 contains();
                if (!(a != b && !(a.contains ? a.contains(b) : !!(a.compareDocumentPosition(b) & 16) ))) return false;
            }
            extend(event, element, data, preventDefault, stopPropagation);
            handler.call(element, event, data);
        };
    }

    function fixEventName(e) {
        var translations = { mouseenter:"mouseover", mouseleave:"mouseout" };
        return (translations[e] || e);
    }

    // 释放内存，防止造成内存泄漏
    if (isIE)
        W.attachEvent('on'+U, function(){
            var e, E = J.event, a = E.CACHE, l = a.length, dE = 'detachEvent';
            while (l--) {
                e = a[l];
                e.e[dE]('on' + e.t, e.r, false);
                if (e.t.indexOf(':') > -1) {
                    e.e[dE]("on"+ E.DA, e.r);
                    e.e[dE]("on"+ E.LO, e.r);
                }
                a.splice(l, 1);
            }
        });
    else
        W.addEventListener(U, function () {}, false);

})(J, window, document);<|endoftext|>