<commit_before>"use strict";

/**
 * lei-proto
 *
 * @author Zongmin Lei <leizongmin@gmail.com>
 */

const DATA_TYPES = ["int", "uint", "float", "double", "string", "buffer"];

function NotSupportDataTypeError(parameter, type) {
  const err = new Error("not support type `" + type + "`");
  err.code = "NOT_SUPPORT_TYPE";
  err.parameter = parameter;
  err.type = type;
  return err;
}

// eslint-disable-next-line
function InvalidDataTypeError(parameter, type) {
  const err = new Error("`" + parameter + "` is not a " + type);
  err.code = "INVALID_TYPE";
  err.parameter = parameter;
  err.type = type;
  return err;
}

function InvalidDataSizeError(parameter, size) {
  const err = new Error("invalid size for `" + parameter + "`");
  err.code = "INVALID_DATA_SIZE";
  err.parameter = parameter;
  err.size = size;
  return err;
}

function InvalidParameterNameFormatError(name) {
  const err = new Error("invalid parameter format `" + name + "`");
  err.code = "INVALID_PARAMETER_FORMAT";
  err.name = name;
  return err;
}

function InvalidProtocolInfoError(msg) {
  const err = new Error("invalid protocol info: " + msg);
  err.code = "INVALID_PROTOCOL_INFO";
  err.info = msg;
  return err;
}

function generateJsCodes(
  encodeSource,
  encodeExSource,
  encodeStrictSource,
  encodeExStrictSource,
  decodeSource,
  decodeStrictSource,
  offset,
) {
  return `(function () {
    var proto = {
      /** 编码器 */
      encode: ${encodeSource},
      /** 编码器，参数为一个对象 */
      encodeEx: ${encodeExSource},
      /** 严格模式的编码器 */
      encodeStrict: ${encodeStrictSource},
      /** 严格模式的编码器，参数为一个对象 */
      encodeExStrict: ${encodeExStrictSource},
      /** 解码器 */
      decode: ${decodeSource},
      /** 严格模式的解码器 */
      decodeStrict: ${decodeStrictSource},
      /** 数据包长度，如果最后一项是不定长的，则总长度为size+最后一项的长度 */
      size: offset,
    };
    return proto;
  })()`;
}

function parseProto(list, options) {
  options = options || {};

  const encodeArgs = [];
  const encodeCheck = [];
  const encodeBody = [];
  const decodeBody = [];
  let offset = 0;

  list.forEach(function(item, i) {
    if (!Array.isArray(item)) throw new InvalidProtocolInfoError("item must be an array");
    if (item.length < 2) throw new InvalidProtocolInfoError("missing `name` and `type`");

    const name = String(item[0]);
    const type = String(item[1]).toLowerCase();
    let size = Number(item[2]);
    let bytes = String(item[3]).toUpperCase();

    if (!(size > 0)) size = 0;
    if (bytes !== "LE") bytes = "BE";
    if (type === "float") size = 4;
    if (type === "double") size = 8;

    if (!/^[a-zA-Z_]/.test(name)) throw new InvalidParameterNameFormatError(name);
    if (encodeArgs.indexOf(name) !== -1) throw new InvalidParameterNameFormatError(name);

    if (DATA_TYPES.indexOf(type) === -1) throw new NotSupportDataTypeError(name, type);

    if (type === "string" || type === "buffer") {
      if (size < 1 && i < list.length - 1) {
        throw new InvalidDataSizeError(name, size);
      }
    } else if (size < 1) {
      throw new InvalidDataSizeError(name, size);
    }

    encodeArgs.push(name);
    switch (type) {
      case "int":
        encodeCheck.push(
          `if (typeof a !== "number" || isNaN(${name})) throw new InvalidDataTypeError("${name}", "${type}");`,
        );
        if (size === 1) {
          encodeBody.push(`$buf.writeUInt8(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readUInt8(${offset})`);
        } else if (size === 2) {
          encodeBody.push(`$buf.writeInt16${bytes}(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readInt16${bytes}(${offset})`);
        } else if (size === 4) {
          encodeBody.push(`$buf.writeInt32${bytes}(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readInt32${bytes}(${offset})`);
        } else {
          encodeBody.push(`$buf.writeInt${bytes}(${name}, ${offset}, ${size});`);
          decodeBody.push(`${name}: $buf.readInt${bytes}(${offset}, ${size})`);
        }
        break;
      case "uint":
        encodeCheck.push(
          `if (typeof a !== "number" || isNaN(${name})) throw new InvalidDataTypeError("${name}", "${type}");`,
        );
        if (size === 1) {
          encodeBody.push(`$buf.writeUInt8(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readUInt8(${offset})`);
        } else if (size === 2) {
          encodeBody.push(`$buf.writeUInt16${bytes}(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readUInt16${bytes}(${offset})`);
        } else if (size === 4) {
          encodeBody.push(`$buf.writeUInt32${bytes}(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readUInt32${bytes}(${offset})`);
        } else {
          encodeBody.push(`$buf.writeUInt${bytes}(${name}, ${offset}, ${size});`);
          decodeBody.push(`${name}: $buf.readUInt${bytes}(${offset}, ${size})`);
        }
        break;
      case "float":
        encodeCheck.push(
          `if (typeof a !== "number" || isNaN(${name})) throw new InvalidDataTypeError("${name}", "${type}");`,
        );
        encodeBody.push(`$buf.writeFloat${bytes}(${name}, ${offset});`);
        decodeBody.push(`${name}: $buf.readFloat${bytes}(${offset})`);
        break;
      case "double":
        encodeCheck.push(
          `if (typeof a !== "number" || isNaN(${name})) throw new InvalidDataTypeError("${name}", "${type}");`,
        );
        encodeBody.push(`$buf.writeDouble${bytes}(${name}, ${offset});`);
        decodeBody.push(`${name}: $buf.readDouble${bytes}(${offset})`);
        break;
      case "string":
        encodeCheck.push(`if (typeof ${name} !== "string") throw new InvalidDataTypeError("${name}", "${type}");`);
        if (size > 0) {
          encodeBody.push(`Buffer.from(${name}).copy($buf, ${offset}, 0, ${size})`);
          decodeBody.push(`${name}: $buf.slice(${offset}, ${offset + size}).toString()`);
        } else {
          encodeBody.push(`Buffer.from(${name}).copy($buf, ${offset}, 0)`);
          decodeBody.push(`${name}: $buf.slice(${offset}).toString()`);
        }
        break;
      case "buffer":
        encodeCheck.push(`if (!Buffer.isBuffer(${name})) throw new InvalidDataTypeError("${name}", "${type}");`);
        if (size > 0) {
          encodeBody.push(`${name}.copy($buf, ${offset}, 0, ${size})`);
          decodeBody.push(`${name}: $buf.slice(${offset}, ${offset + size})`);
        } else {
          encodeBody.push(`${name}.copy($buf, ${offset}, 0)`);
          decodeBody.push(`${name}: $buf.slice(${offset})`);
        }
        break;
      default:
        throw new NotSupportDataTypeError(name, type);
    }

    offset += size;
  });

  const lastItemType = String(list[list.length - 1][1]).toLowerCase();
  let lastItemSize = Number(list[list.length - 1][2]);
  if (lastItemType === "float") lastItemSize = 4;
  if (lastItemType === "double") lastItemSize = 8;
  const lastItemName = list[list.length - 1][0];
  const isDynamicSize = !(lastItemSize > 0);
  const argNames = encodeArgs.join(", ");
  const argNames2 = encodeArgs.map(n => `data.${n}`).join(", ");
  const encodeBodyLines = encodeBody.join("\n");
  const decodeBodyLines = decodeBody.join(",\n");
  const encodeCheckLines = encodeCheck.join("\n");
  const encodeSource = `(function (${argNames}) {
    ${isDynamicSize ? `${lastItemName} = Buffer.from(${lastItemName});` : ""}
    var $buf = Buffer.allocUnsafe(${lastItemSize > 0 ? offset : `${offset}+${lastItemName}.length`});
    ${encodeBodyLines}
    return $buf;
  })`;
  const encodeStrictSource = `(function (${argNames}) {
    ${encodeCheckLines}
    ${isDynamicSize ? `${lastItemName} = Buffer.from(${lastItemName});` : ""}
    var $buf = Buffer.allocUnsafe(${lastItemSize > 0 ? offset : `${offset}+${lastItemName}.length`});
    ${encodeBodyLines}
    return $buf;
    })`;
  const encodeExSource = `(function (data) { return proto.encode(${argNames2}); })`;
  const encodeExStrictSource = `(function (data) { return proto.encodeStrict(${argNames2}); })`;
  const decodeSource = `(function ($buf) { return { ${decodeBodyLines} }; })`;
  const decodeStrictSource = `(function ($buf) {
    if ($buf.length < ${offset}) throw new IncorrectBufferSizeError(${offset}, $buf.length);
    return { ${decodeBodyLines} };
    })`;

  const js = generateJsCodes(
    encodeSource,
    encodeExSource,
    encodeStrictSource,
    encodeExStrictSource,
    decodeSource,
    decodeStrictSource,
    offset,
  );
  if (options.sourceCode) {
    return js;
  }
  return eval(js);
}

module.exports = parseProto;
<commit_msg>style: 删除eslint注释<commit_after>"use strict";

/**
 * lei-proto
 *
 * @author Zongmin Lei <leizongmin@gmail.com>
 */

const DATA_TYPES = ["int", "uint", "float", "double", "string", "buffer"];

function NotSupportDataTypeError(parameter, type) {
  const err = new Error("not support type `" + type + "`");
  err.code = "NOT_SUPPORT_TYPE";
  err.parameter = parameter;
  err.type = type;
  return err;
}

function InvalidDataTypeError(parameter, type) {
  const err = new Error("`" + parameter + "` is not a " + type);
  err.code = "INVALID_TYPE";
  err.parameter = parameter;
  err.type = type;
  return err;
}

function InvalidDataSizeError(parameter, size) {
  const err = new Error("invalid size for `" + parameter + "`");
  err.code = "INVALID_DATA_SIZE";
  err.parameter = parameter;
  err.size = size;
  return err;
}

function InvalidParameterNameFormatError(name) {
  const err = new Error("invalid parameter format `" + name + "`");
  err.code = "INVALID_PARAMETER_FORMAT";
  err.name = name;
  return err;
}

function InvalidProtocolInfoError(msg) {
  const err = new Error("invalid protocol info: " + msg);
  err.code = "INVALID_PROTOCOL_INFO";
  err.info = msg;
  return err;
}

function generateJsCodes(
  encodeSource,
  encodeExSource,
  encodeStrictSource,
  encodeExStrictSource,
  decodeSource,
  decodeStrictSource,
  offset,
) {
  return `(function () {
    var proto = {
      /** 编码器 */
      encode: ${encodeSource},
      /** 编码器，参数为一个对象 */
      encodeEx: ${encodeExSource},
      /** 严格模式的编码器 */
      encodeStrict: ${encodeStrictSource},
      /** 严格模式的编码器，参数为一个对象 */
      encodeExStrict: ${encodeExStrictSource},
      /** 解码器 */
      decode: ${decodeSource},
      /** 严格模式的解码器 */
      decodeStrict: ${decodeStrictSource},
      /** 数据包长度，如果最后一项是不定长的，则总长度为size+最后一项的长度 */
      size: offset,
    };
    return proto;
  })()`;
}

function parseProto(list, options) {
  options = options || {};

  const encodeArgs = [];
  const encodeCheck = [];
  const encodeBody = [];
  const decodeBody = [];
  let offset = 0;

  list.forEach(function(item, i) {
    if (!Array.isArray(item)) throw new InvalidProtocolInfoError("item must be an array");
    if (item.length < 2) throw new InvalidProtocolInfoError("missing `name` and `type`");

    const name = String(item[0]);
    const type = String(item[1]).toLowerCase();
    let size = Number(item[2]);
    let bytes = String(item[3]).toUpperCase();

    if (!(size > 0)) size = 0;
    if (bytes !== "LE") bytes = "BE";
    if (type === "float") size = 4;
    if (type === "double") size = 8;

    if (!/^[a-zA-Z_]/.test(name)) throw new InvalidParameterNameFormatError(name);
    if (encodeArgs.indexOf(name) !== -1) throw new InvalidParameterNameFormatError(name);

    if (DATA_TYPES.indexOf(type) === -1) throw new NotSupportDataTypeError(name, type);

    if (type === "string" || type === "buffer") {
      if (size < 1 && i < list.length - 1) {
        throw new InvalidDataSizeError(name, size);
      }
    } else if (size < 1) {
      throw new InvalidDataSizeError(name, size);
    }

    encodeArgs.push(name);
    switch (type) {
      case "int":
        encodeCheck.push(
          `if (typeof a !== "number" || isNaN(${name})) throw new InvalidDataTypeError("${name}", "${type}");`,
        );
        if (size === 1) {
          encodeBody.push(`$buf.writeUInt8(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readUInt8(${offset})`);
        } else if (size === 2) {
          encodeBody.push(`$buf.writeInt16${bytes}(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readInt16${bytes}(${offset})`);
        } else if (size === 4) {
          encodeBody.push(`$buf.writeInt32${bytes}(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readInt32${bytes}(${offset})`);
        } else {
          encodeBody.push(`$buf.writeInt${bytes}(${name}, ${offset}, ${size});`);
          decodeBody.push(`${name}: $buf.readInt${bytes}(${offset}, ${size})`);
        }
        break;
      case "uint":
        encodeCheck.push(
          `if (typeof a !== "number" || isNaN(${name})) throw new InvalidDataTypeError("${name}", "${type}");`,
        );
        if (size === 1) {
          encodeBody.push(`$buf.writeUInt8(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readUInt8(${offset})`);
        } else if (size === 2) {
          encodeBody.push(`$buf.writeUInt16${bytes}(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readUInt16${bytes}(${offset})`);
        } else if (size === 4) {
          encodeBody.push(`$buf.writeUInt32${bytes}(${name}, ${offset});`);
          decodeBody.push(`${name}: $buf.readUInt32${bytes}(${offset})`);
        } else {
          encodeBody.push(`$buf.writeUInt${bytes}(${name}, ${offset}, ${size});`);
          decodeBody.push(`${name}: $buf.readUInt${bytes}(${offset}, ${size})`);
        }
        break;
      case "float":
        encodeCheck.push(
          `if (typeof a !== "number" || isNaN(${name})) throw new InvalidDataTypeError("${name}", "${type}");`,
        );
        encodeBody.push(`$buf.writeFloat${bytes}(${name}, ${offset});`);
        decodeBody.push(`${name}: $buf.readFloat${bytes}(${offset})`);
        break;
      case "double":
        encodeCheck.push(
          `if (typeof a !== "number" || isNaN(${name})) throw new InvalidDataTypeError("${name}", "${type}");`,
        );
        encodeBody.push(`$buf.writeDouble${bytes}(${name}, ${offset});`);
        decodeBody.push(`${name}: $buf.readDouble${bytes}(${offset})`);
        break;
      case "string":
        encodeCheck.push(`if (typeof ${name} !== "string") throw new InvalidDataTypeError("${name}", "${type}");`);
        if (size > 0) {
          encodeBody.push(`Buffer.from(${name}).copy($buf, ${offset}, 0, ${size})`);
          decodeBody.push(`${name}: $buf.slice(${offset}, ${offset + size}).toString()`);
        } else {
          encodeBody.push(`Buffer.from(${name}).copy($buf, ${offset}, 0)`);
          decodeBody.push(`${name}: $buf.slice(${offset}).toString()`);
        }
        break;
      case "buffer":
        encodeCheck.push(`if (!Buffer.isBuffer(${name})) throw new InvalidDataTypeError("${name}", "${type}");`);
        if (size > 0) {
          encodeBody.push(`${name}.copy($buf, ${offset}, 0, ${size})`);
          decodeBody.push(`${name}: $buf.slice(${offset}, ${offset + size})`);
        } else {
          encodeBody.push(`${name}.copy($buf, ${offset}, 0)`);
          decodeBody.push(`${name}: $buf.slice(${offset})`);
        }
        break;
      default:
        throw new NotSupportDataTypeError(name, type);
    }

    offset += size;
  });

  const lastItemType = String(list[list.length - 1][1]).toLowerCase();
  let lastItemSize = Number(list[list.length - 1][2]);
  if (lastItemType === "float") lastItemSize = 4;
  if (lastItemType === "double") lastItemSize = 8;
  const lastItemName = list[list.length - 1][0];
  const isDynamicSize = !(lastItemSize > 0);
  const argNames = encodeArgs.join(", ");
  const argNames2 = encodeArgs.map(n => `data.${n}`).join(", ");
  const encodeBodyLines = encodeBody.join("\n");
  const decodeBodyLines = decodeBody.join(",\n");
  const encodeCheckLines = encodeCheck.join("\n");
  const encodeSource = `(function (${argNames}) {
    ${isDynamicSize ? `${lastItemName} = Buffer.from(${lastItemName});` : ""}
    var $buf = Buffer.allocUnsafe(${lastItemSize > 0 ? offset : `${offset}+${lastItemName}.length`});
    ${encodeBodyLines}
    return $buf;
  })`;
  const encodeStrictSource = `(function (${argNames}) {
    ${encodeCheckLines}
    ${isDynamicSize ? `${lastItemName} = Buffer.from(${lastItemName});` : ""}
    var $buf = Buffer.allocUnsafe(${lastItemSize > 0 ? offset : `${offset}+${lastItemName}.length`});
    ${encodeBodyLines}
    return $buf;
    })`;
  const encodeExSource = `(function (data) { return proto.encode(${argNames2}); })`;
  const encodeExStrictSource = `(function (data) { return proto.encodeStrict(${argNames2}); })`;
  const decodeSource = `(function ($buf) { return { ${decodeBodyLines} }; })`;
  const decodeStrictSource = `(function ($buf) {
    if ($buf.length < ${offset}) throw new IncorrectBufferSizeError(${offset}, $buf.length);
    return { ${decodeBodyLines} };
    })`;

  const js = generateJsCodes(
    encodeSource,
    encodeExSource,
    encodeStrictSource,
    encodeExStrictSource,
    decodeSource,
    decodeStrictSource,
    offset,
  );
  if (options.sourceCode) {
    return js;
  }
  return eval(js);
}

module.exports = parseProto;
<|endoftext|>


<commit_before>var store  = window.localStorage;
var list   = JSON.parse(store.getItem("master") || "[]");
var sortBy = store.getItem("sortBy") || "date";
var master = document.getElementById("master");
var weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

var titleElem  = document.getElementById("title");
var courseElem = document.getElementById("course");
var dateElem   = document.getElementById("date");
var countElem  = document.getElementById("count");
var colorElem  = document.getElementById("color");
var nowElem    = document.getElementById("now");
dateElem.valueAsDate = new Date();
countElem.removeChild(countElem.firstChild);
countElem.appendChild(document.createTextNode(list.length));

var now = new Date(); var d = [now.getFullYear(), now.getMonth()+1, now.getDate()];
nowElem.appendChild(document.createTextNode(d.join("-") + " " + weekdays[now.getDay()]))

function datestrToWeekday(str) {
    var dates = str.split("-");
    var dateObj = new Date(dates[0], dates[1]-1, dates[2]);
    return weekdays[dateObj.getDay()];
}

function itemToElemInto(item, liElem) {
    var dateTxt = document.createTextNode(item.date + " " + datestrToWeekday(item.date));
    var dateElem = document.createElement("span");
    dateElem.className = "label label-default";
    dateElem.appendChild(dateTxt);
    var courseElem = document.createElement("span");
    var courseTxt = document.createTextNode(item.course);
    courseElem.className = "label " + item.color;
    courseElem.appendChild(courseTxt);
    var restTxt = document.createTextNode(" " + item.title + " ");
    liElem.appendChild(dateElem);
    liElem.appendChild(document.createTextNode(" "));
    liElem.appendChild(courseElem);
    liElem.appendChild(restTxt);
}

function update() {
    store.setItem("master", JSON.stringify(list));
    window.location.reload();
}

function renderItem(item, index) {
    var liElem = document.createElement("li");
    itemToElemInto(item, liElem);
    var btnElem = document.createElement("button");
    var btnTxt  = document.createTextNode("×");
    btnElem.appendChild(btnTxt);
    btnElem.addEventListener("click", function (event) {
        list.splice(index, 1); update();
    });
    btnElem.className = "btn btn-default btn-xs";
    liElem.appendChild(btnElem);
    liElem.className = "list-group-item";
    master.appendChild(liElem);
}

list.sort(function (a, b) {
    if (a[sortBy] > b[sortBy])
        return 1;
    else if (a[sortBy] < b[sortBy])
        return -1;
    else return 0;
})

for (var i = 0; i < list.length; i++) {
    renderItem(list[i], i);
}

document.getElementById("add").addEventListener("click", function (event) {
    if (!titleElem.value || !courseElem.value) return;
    list.push({ title: titleElem.value, date: dateElem.value, course: courseElem.value, color: colorElem.value }); update();
});

var sortByElems = document.getElementsByClassName("sort");
for (var i = 0; i < sortByElems.length; i++) {
    sortByElems[i].addEventListener("click", function (event) {
        store.setItem("sortBy", this.dataset.value); update();
    });
}
<commit_msg>[Tak] avoid null-date error<commit_after>var store  = window.localStorage;
var list   = JSON.parse(store.getItem("master") || "[]");
var sortBy = store.getItem("sortBy") || "date";
var master = document.getElementById("master");
var weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

var titleElem  = document.getElementById("title");
var courseElem = document.getElementById("course");
var dateElem   = document.getElementById("date");
var countElem  = document.getElementById("count");
var colorElem  = document.getElementById("color");
var nowElem    = document.getElementById("now");
dateElem.valueAsDate = new Date();
countElem.removeChild(countElem.firstChild);
countElem.appendChild(document.createTextNode(list.length));

var now = new Date(); var d = [now.getFullYear(), now.getMonth()+1, now.getDate()];
nowElem.appendChild(document.createTextNode(d.join("-") + " " + weekdays[now.getDay()]))

function datestrToWeekday(str) {
    var dates = str.split("-");
    var dateObj = new Date(dates[0], dates[1]-1, dates[2]);
    return weekdays[dateObj.getDay()];
}

function itemToElemInto(item, liElem) {
    var dateTxt = document.createTextNode(item.date + " " + datestrToWeekday(item.date));
    var dateElem = document.createElement("span");
    dateElem.className = "label label-default";
    dateElem.appendChild(dateTxt);
    var courseElem = document.createElement("span");
    var courseTxt = document.createTextNode(item.course);
    courseElem.className = "label " + item.color;
    courseElem.appendChild(courseTxt);
    var restTxt = document.createTextNode(" " + item.title + " ");
    liElem.appendChild(dateElem);
    liElem.appendChild(document.createTextNode(" "));
    liElem.appendChild(courseElem);
    liElem.appendChild(restTxt);
}

function update() {
    store.setItem("master", JSON.stringify(list));
    window.location.reload();
}

function renderItem(item, index) {
    var liElem = document.createElement("li");
    itemToElemInto(item, liElem);
    var btnElem = document.createElement("button");
    var btnTxt  = document.createTextNode("×");
    btnElem.appendChild(btnTxt);
    btnElem.addEventListener("click", function (event) {
        list.splice(index, 1); update();
    });
    btnElem.className = "btn btn-default btn-xs";
    liElem.appendChild(btnElem);
    liElem.className = "list-group-item";
    master.appendChild(liElem);
}

list.sort(function (a, b) {
    if (a[sortBy] > b[sortBy])
        return 1;
    else if (a[sortBy] < b[sortBy])
        return -1;
    else return 0;
})

for (var i = 0; i < list.length; i++) {
    renderItem(list[i], i);
}

document.getElementById("add").addEventListener("click", function (event) {
    if (!titleElem.value || !courseElem.value || !dateElem.value || !colorElem.value) return;
    list.push({ title: titleElem.value, date: dateElem.value, course: courseElem.value, color: colorElem.value }); update();
});

var sortByElems = document.getElementsByClassName("sort");
for (var i = 0; i < sortByElems.length; i++) {
    sortByElems[i].addEventListener("click", function (event) {
        store.setItem("sortBy", this.dataset.value); update();
    });
}
<|endoftext|>


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

var mergeTrees = require( 'broccoli-merge-trees' ),
    pickFiles  = require( 'broccoli-static-compiler' );

module.exports = {
    name: 'sl-ember-components',

    included: function( app ) {
        this._super.included( app );

        app.import({
            development : 'bower_components/sl-bootstrap/dist/js/sl-bootstrap.js',
            production  : 'bower_components/sl-bootstrap/dist/js/sl-bootstrap.min.js'
        });

        app.import( 'bower_components/sl-bootstrap/dist/css/sl-bootstrap-theme.css.map' );

        app.import( 'bower_components/bootstrap-datepicker/js/bootstrap-datepicker.js' );

        app.import( 'bower_components/fontawesome/css/font-awesome.min.css' );

        app.import({
            development : 'bower_components/highcharts/highcharts.src.js',
            production  : 'bower_components/highcharts/highcharts.js'
        });

        app.import({
            development : 'bower_components/moment/min/moment-with-locales.js',
            production  : 'bower_components/moment/min/moment-with-locales.min.js'
        });

        app.import({
            development : 'bower_components/moment-timezone/builds/moment-timezone-with-data.js',
            production  : 'bower_components/moment-timezone/builds/moment-timezone-with-data.min.js'
        });

        app.import({
            development : 'bower_components/select2/select2.js',
            production  : 'bower_components/select2/select2.min.js'
        });

        app.import({
            development : 'bower_components/typeahead.js/dist/typeahead.bundle.js',
            production  : 'bower_components/typeahead.js/dist/typeahead.bundle.min.js'
        });
    },

    postprocessTree: function( type, tree ) {
        return mergeTrees([ tree,
            pickFiles( 'bower_components/sl-bootstrap/fonts', {
                srcDir  : '/',
                files   : [ 'benton-sans-*' ],
                destDir : '/fonts'
            }),

            pickFiles( 'bower_components/fontawesome/fonts', {
                srcDir  : '/',
                files   : [ 'fontawesome-webfont.woff' ],
                destDir : '/fonts'
            }),

            pickFiles( 'public/assets/images', {
                srcDir  : '/',
                files   : [ 'spinner-dark.png', 'spinner-light.png' ],
                destDir : '/assets/images'
            })
        ]);
    }
};
<commit_msg>Add select2's spinner gif to images include<commit_after>/* jshint node: true */
'use strict';

var mergeTrees = require( 'broccoli-merge-trees' ),
    pickFiles  = require( 'broccoli-static-compiler' );

module.exports = {
    name: 'sl-ember-components',

    included: function( app ) {
        this._super.included( app );

        app.import({
            development : 'bower_components/sl-bootstrap/dist/js/sl-bootstrap.js',
            production  : 'bower_components/sl-bootstrap/dist/js/sl-bootstrap.min.js'
        });

        app.import( 'bower_components/sl-bootstrap/dist/css/sl-bootstrap-theme.css.map' );

        app.import( 'bower_components/bootstrap-datepicker/js/bootstrap-datepicker.js' );

        app.import( 'bower_components/fontawesome/css/font-awesome.min.css' );

        app.import({
            development : 'bower_components/highcharts/highcharts.src.js',
            production  : 'bower_components/highcharts/highcharts.js'
        });

        app.import({
            development : 'bower_components/moment/min/moment-with-locales.js',
            production  : 'bower_components/moment/min/moment-with-locales.min.js'
        });

        app.import({
            development : 'bower_components/moment-timezone/builds/moment-timezone-with-data.js',
            production  : 'bower_components/moment-timezone/builds/moment-timezone-with-data.min.js'
        });

        app.import({
            development : 'bower_components/select2/select2.js',
            production  : 'bower_components/select2/select2.min.js'
        });

        app.import({
            development : 'bower_components/typeahead.js/dist/typeahead.bundle.js',
            production  : 'bower_components/typeahead.js/dist/typeahead.bundle.min.js'
        });
    },

    postprocessTree: function( type, tree ) {
        return mergeTrees([ tree,
            pickFiles( 'bower_components/sl-bootstrap/fonts', {
                srcDir  : '/',
                files   : [ 'benton-sans-*' ],
                destDir : '/fonts'
            }),

            pickFiles( 'bower_components/fontawesome/fonts', {
                srcDir  : '/',
                files   : [ 'fontawesome-webfont.woff' ],
                destDir : '/fonts'
            }),

            pickFiles( 'public/assets', {
                srcDir  : '/',
                files   : [
                    'select2-spinner.gif',
                    'images/spinner-dark.png',
                    'images/spinner-light.png'
                ],
                destDir : '/assets'
            })
        ]);
    }
};
<|endoftext|>


<commit_before>var express = require('express'),
    serveStatic = require('serve-static'),
    fs = require('fs'),
    http = require('http'),
    https = require('https'),
    bodyParser = require('body-parser'),
    ipn = require('paypal-ipn'),
    ParseServer = require('parse-server').ParseServer;

var app = express()
var settings = {
  "appId": process.env.APPLICATION_ID || "APPLICATION_ID",
  "appName": process.env.APPLICATION_NAME || "Yorick",
  "masterKey": process.env.MASTER_KEY || "MASTER_KEY",
  "databaseURI": process.env.DATABASE_URI || "mongodb://localhost:27017/anotherstore",
  "mountPath": process.env.MOUNT_PATH || "/parse/1",
  "cloud": process.env.CLOUD_CODE_MAIN || "/home/ubuntu/workspace/cloud/main.js",
  "verbose": true,
  "publicServerURL": process.env.PUBLIC_SERVER_URL || "https://yorick-latest-parse-server-gnu-lorien.c9users.io/parse/1",
  "serverURL": process.env.SERVER_URL || "http://0.0.0.0/parse/1"
}

var api = new ParseServer(settings);
app.use('/parse/1', api);

app.get('/deez', function (req, res) {
    new Parse.Query("Vampire").first({useMasterKey: true}).then(function (v) {
        res.send("I got something named what exactly? " + v.get("name"));
    }).fail(function (error) {
        res.send(error.message);
    });
});

app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

app.post('/deez', function (req, res) {
    console.log(JSON.stringify(req.body));
    ipn.verify(req.body, {allow_sandbox: true}, function (err, msg) {
        if (err) {
            console.error(err);
        } else {
            console.log("I verified it");
            var PaymentPaypal = Parse.Object.extend("PaymentPaypal");
            var p = new PaymentPaypal;
            p.save(req.body, {useMasterKey: true}).then(function (newpaymente) {
                console.log("Boom new payment");
            }).fail(function (error) {
                console.error(error.message);
            })
        }
    })
    res.send("I found something");
})

http.createServer(app).listen(80, '0.0.0.0');<commit_msg>Corrected mongodb env variable reference<commit_after>var express = require('express'),
    serveStatic = require('serve-static'),
    fs = require('fs'),
    http = require('http'),
    https = require('https'),
    bodyParser = require('body-parser'),
    ipn = require('paypal-ipn'),
    ParseServer = require('parse-server').ParseServer;

var app = express()
var settings = {
  "appId": process.env.APPLICATION_ID || "APPLICATION_ID",
  "appName": process.env.APPLICATION_NAME || "Yorick",
  "masterKey": process.env.MASTER_KEY || "MASTER_KEY",
  "databaseURI": process.env.MONGODB_URI || "mongodb://localhost:27017/anotherstore",
  "mountPath": process.env.MOUNT_PATH || "/parse/1",
  "cloud": process.env.CLOUD_CODE_MAIN || "/home/ubuntu/workspace/cloud/main.js",
  "verbose": true,
  "publicServerURL": process.env.PUBLIC_SERVER_URL || "https://yorick-latest-parse-server-gnu-lorien.c9users.io/parse/1",
  "serverURL": process.env.SERVER_URL || "http://0.0.0.0/parse/1"
}

var api = new ParseServer(settings);
app.use('/parse/1', api);

app.get('/deez', function (req, res) {
    new Parse.Query("Vampire").first({useMasterKey: true}).then(function (v) {
        res.send("I got something named what exactly? " + v.get("name"));
    }).fail(function (error) {
        res.send(error.message);
    });
});

app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

app.post('/deez', function (req, res) {
    console.log(JSON.stringify(req.body));
    ipn.verify(req.body, {allow_sandbox: true}, function (err, msg) {
        if (err) {
            console.error(err);
        } else {
            console.log("I verified it");
            var PaymentPaypal = Parse.Object.extend("PaymentPaypal");
            var p = new PaymentPaypal;
            p.save(req.body, {useMasterKey: true}).then(function (newpaymente) {
                console.log("Boom new payment");
            }).fail(function (error) {
                console.error(error.message);
            })
        }
    })
    res.send("I found something");
})

http.createServer(app).listen(80, '0.0.0.0');<|endoftext|>


<commit_before>'use strict';
var fs = require('fs'),
    chokidar = require('chokidar'),
    winston = require('winston'),
    mongoose = require('mongoose'),
    junk = require('junk'),
    path = require('path'),
    validate = require('json-schema').validate,
    ObjectId = require('mongodb').ObjectID;

/*
    ---------------------
       Winston Logger
    ---------------------

    Instances of winston are event emitters and winston transports
    are lazy-loaded getters. Each log message will output into a log file
    and/or the console as a stream. There are different log levels you can use,
    where the levels are prioritized from 0 to 7 (highest to lowest). You can
    colorize them as well as define your own levels.

    Default:
    { emerg: 0, alert: 1, crit: 2, error: 3, warning: 4, notice: 5, info: 6, debug: 7 }

    The use cases look like:
    logger.warn('message'),
    logger.emerg('message'),
    logger.info('message'),
    or (generically) logger.log('%level', 'message').
*/

var logger = new winston.Logger({
    transports: [
        new(winston.transports.Console)({
            levels: {
                crit: 0,
                error: 1,
                warning: 2,
                notice: 3,
                info: 4,
                debug: 5
            },
            colors: {
                crit: 'magenta',
                error: 'red',
                warning: 'yellow',
                notice: 'grey',
                info: 'green',
                debug: 'blue',
            },
            colorize: true,
            prettyPrint: true,
        }),
        new winston.transports.File({ filename: './logs/all-logs.log' })
    ],
    exceptionHandlers: [
        new winston.transports.File({ filename: './logs/exceptions.log' })
    ],
    exitOnError: false // winston will *not* exit after logging an uncaught
        // exception. We should change this to true when not
        // in a development environment.
});

/*
    -----------------------------
        Main PSPublisher Class
    -----------------------------
*/

function PSPublisher(directory) {
    this.directory = directory;
}

PSPublisher.prototype.start = function() {
    logger.log('info', "PSPublisher is starting...");
    this.watch();
}

PSPublisher.prototype.connect = function(uri) {
    mongoose.connect(uri);

    // Confirms successful database connection
    mongoose.connection.once('connected', function(err) {
        if (err) {
            next(err);
            logger.log('error', "Couldn't connect to " + uri + ".");
        }
        logger.log('info', "Connected to " + uri);
    });
}

/*
    ----------------------------------------------------------------------------
        Registers Schemas in order to interface with Database using Mongoose
    ----------------------------------------------------------------------------

    We opt here to have user defined models passed in as an array.

    Example:

        PSPublisher.models([{
            name: 'Posts',
            schema: {
                'title': title,
                'body': body
            }
        }, {
            name: 'Comments',
            schema: {
                'name': name,
                'comment': comment
            }
        ]);

    Currently does not have support for subdocuments.
*/

// This is simply to make the name of the models available to this script.
var modelNames = [];

PSPublisher.prototype.models = function(models) {
    if (!models) {
        logger.log('error', "Invalid model. Please use proper formatting" + " or a valid schema.");
    }

    if (!Array.isArray(models)) {
        logger.log('error', "Invalid model. Please use proper formatting" + " or a valid schema.");
    }

    for (var i = 0; i < models.length; i++) {
        var Schema = new mongoose.Schema(models[i].schema, { timestamps: true });
        mongoose.model(models[i].name, Schema);
        modelNames.push(models[i].name);
    }
}

/*
    --------------------
        Main Watcher
    --------------------
*/

PSPublisher.prototype.watch = function() {
    var dir = this.directory;

    // Trim off the end of the path since chokidar have absolute directory
    // paths without a trailing backslash. This will protect users.
    if (dir[dir.length - 1] === '/') {
        dir = dir.substring(0, dir.length - 1);
    }

    // This will initialize the watcher, i.e. the main event emitter. We will
    // be calling watch() on an instance of PSPublish to use it as a wrapper
    // around chokidar with preconfigured events.
    var watcher = chokidar.watch(dir, {
        ignored: [
            /[\/\\]\./,
        ],
        persistent: true
    });

    watcher.on('ready', function() {
        logger.log('info', "Began watching " + dir);

        /*
            Checks and sees what files are currently being watched. Chokidar also
            tracks the directory itself so it's necessary to grab the property that
            only has the files. Our file listings is going to be our canonical record.
            Our "tracked files" in trackedFiles.json holds the id of the documents in
            our database when they were first added. When the file is no longer in the
            directory, we will remove the document from the database and then untrack it.
        */

        var Watched = watcher.getWatched();
        var fileListings = Watched[path.join(__dirname, dir)].sort();

        // Reconcile the file listings with the record of tracked files. This
        // will be used to update the database on this script's startup.
        fs.readFile('./lib/trackedFiles.json', 'utf8', function(err, data) {
            if (err) {
                logger.log('error', "An error occurred with trackedFiles file." + " Please resolve before continuing.");
            }

            if (data) {
                var trackedFiles = JSON.parse(data),
                    trackedKeys = Object.keys(trackedFiles).sort();
            } else {
                var trackedKeys = [];
            }

            /*
                trackedFiles[trackedKeys[i]] will give us the ids, if we need them.
                We can also do:
                Object.keys(trackedFiles).forEach(function (key) {
                    let value = trackedFiles[key];
                    logger.log('info', value);
                });
            */

            if (arrayEquals(fileListings, trackedKeys)) {
                logger.log('info', "Files are in sync. Will be listening for changes.");
            } else {
                if (fileListings) {
                    logger.log('info', "There are currently no files in " + dir + ".");
                } else {
                    logger.log('info', "Files in " + dir + " are not in sync.");
                    syncFiles(fileListings, trackedKeys);
                }
            }
        });
    });

    watcher.on('add', function(file) {
        logger.log('info', file + " was added to " + dir + ".");
        insertFile(file);
    });

    watcher.on('change', function(file, stats) {
        logger.log('info', file + " was modified at " + stats.mtime + ".");
        updateFile(file);
    });

    watcher.on('unlink', function(file) {
        logger.log('info', file + " was removed from " + dir + ".");
        removeFile(file);
    });
}

/*
    ----------------------------------
        Watcher Helper Functions
    ----------------------------------
*/

function syncFiles(listing, tracked) {
    logger.log('info', "Syncing files...");
    if (listing.length > tracked.length) {
        /*
            If the number of files in the directory is larger than the number
            of files in trackedFiles.json, we have documents not yet added
            to the database. We will also need to insert those files into
            trackedFiles after finding them. For each element in listing,
            we test to see if it is in tracked. If it isn't, then we call
            the insertFile method and insert it into our database. This search
            is costly (O(n^2)), but we can improve it later with a binary
            search since the arrays are already sorted.
        */
        listing.forEach(function(file) {
            if (!(file in tracked)) {
                insertFile(file);
            }
        });
    } else if (listing.length < tracked.length) {
        /*
            If the number of files in the directory is less than the number
            of files in trackedFiles.json, we want to remove documents from
            the database. We find each element in tracked and not in the
            directory and remove it from the database and then
            trackedFiles.json.
        */
        tracked.forEach(function(file) {
            if (!(file in listing)) {
                removeFile(file);
            }
        });
    }
}

function insertFile(file) {
    var file = file;
    fs.readFile(path.join(__dirname, file), 'utf8', function(err, content) {
        if (err) {
            logger.log('error', "Was not able to read the file.");
        }

        var model = mongoose.model(modelNames[0]);
        if (model) {
            var obj = JSON.parse(content);
            model.create(obj, function(err, doc) {
                if (err) {
                    logger.log('error', "An error occurred. " + file + " was not inserted into database.");
                }

                logger.log('info', file + " was successfully inserted. id: " + doc._id);
                addToTrackedFiles(file, doc._id);
            });
        } else {
            logger.log('error', "Could not insert " + file + " into database.");
        }
    });
}

function updateFile(file) {
    var file = file;
    fs.readFile(path.join(__dirname, file), 'utf8', function(err, content) {
        if (err) {
            logger.log('error', "Was not able to update " + file + ".");
        }

        if (!content) {
            logger.log('error', file + " cannot be empty.");
        }

        var model = mongoose.model(modelNames[0]);
        if (model) {
            var updatedDoc = JSON.parse(content);
            fs.readFile(path.join(__dirname, './lib/trackedFiles.json'), 'utf8',
                function(err, data) {
                    var fileObj = JSON.parse(data);
                    if (fileObj[file]) {
                        model.findOneAndUpdate({ _id: ObjectId(fileObj[file]) }, updatedDoc,
                            function(err, doc) {
                                if (err) {
                                    logger.log('error', "An error occurred. Was not" + " able to update " + file + ".");
                                }

                                logger.log('info', file + " was successfully updated.");
                            }
                        );
                    } else {
                        logger.log('error', "Could not find " + file + " in the tracked files.");
                    }
                }
            );
        } else {
            logger.log('error', "Was not able to update" + file + ".");
        }
    });
}

function removeFile(file) {
    var file = file;
    fs.readFile(path.join(__dirname, './lib/trackedFiles.json'), 'utf8', function(err, content) {
        if (err) {
            logger.log('error', "Was not able to read trackedFiles.json.");
        }

        var model = mongoose.model(modelNames[0]);
        if (model) {
            var fileObj = JSON.parse(content);
            model.remove({ _id: ObjectId(fileObj[file]) }, function(err) {
                if (err) {
                    logger.log('error', "Could not find document in collection.");
                }

                logger.log('info', "Successfully removed " + file + " from collection.");

                // Simply delete the key-value pair and overwrites the
                // original file with one less element.
                delete fileObj[file];

                if (fileObj) {
                    removeFromTrackedFiles(file, fileObj);
                } else {
                    removeFromTrackedFiles(file, {});
                }
            });
        } else {
            logger.log('error', "Could not delete " + file + " from database.");
        }
    });
}

/*
    -----------------------------
        CRUD Helper Functions
    -----------------------------
*/

function findAndValidateModel(file) {
    /*
        This helper function will check if the file has a valid schema.
        It will return a model if it does. If not, it will throw an
        exception. The user must create a schema before moving any files
        into the directory.
    */
    fs.readFile(path.join(__dirname, file), 'utf8', function(err, data) {
        var obj = JSON.parse(data);
        // Validates the file. If there are no errors,
        // we can return the correct model.
        modelNames.forEach(function(name) {
            var schema = mongoose.model(name).schema;
            if ((validate(obj, schema).valid)) {
                logger.log('info', "Schema found!");
                return mongoose.model(name);
            }
        });
    });
    logger.log('error', "File does not have a valid schema." + " Please recheck your document.");
}

function addToTrackedFiles(file, id) {
    /*
        This helper function will write into trackedFiles.json a key-value
        pair of the form:

            file: id

        This will allow quick and easy access to finding the document in
        the database by using Obj.file as the query condition. The id can
        only be added after an insert into the database so in order to
        remove a document from the database, the id must first exist in
        the trackedFiles.json file.
    */
    fs.readFile(path.join(__dirname, './lib/trackedFiles.json'), 'utf8', function(err, data) {
        // If trackedFiles.json is not empty then...
        if (data) {
            var fileObj = JSON.parse(data);
            fileObj[file] = id;

            /*
                trackedFiles.json must be opened synchronously or else we
                have the problem of one I/O operation overwriting one
                another. Mongoose, however, handles asynchrously operations
                perfectly so we don't have to worry about the database.
            */
            fs.openSync(path.join(__dirname, './lib/trackedFiles.json'), 'w', 'utf8',
                function(err, fd) {
                    if (err) {
                        logger.log('error', "There was a problem. " + file + " was not added to tracked files.");
                    }

                    var writeBuf = new Buffer(JSON.stringify(fileObj));
                    fs.writeSync(fd, writeBuf, 0, writeBuf.length, 0);
                    logger.log('info', "Successfully added " + file + " to tracked files.");
                    logger.log('info', 'Original tracked files has been updated.');

                    fs.closeSync(fd);
                }
            );
        } else {
            // else do...
            var trackObject = {};
            trackObject[file] = id;
            fs.openSync(path.join(__dirname, './lib/trackedFiles.json'), 'w', 'utf8',
                function(err, fd) {
                    if (err) {
                        logger.log('error', "There was a problem. " + file + " was not added to tracked files.");
                    }

                    var writeBuf = new Buffer(JSON.stringify(trackObject));
                    fs.writeSync(fd, writeBuf, 0, writeBuf.length, 0);
                    logger.log('info', "Successfully added " + file + " to tracked files.");
                    logger.log('info', 'Original tracked files has been updated.');

                    fs.closeSync(fd);
                }
            );
        }
    });
}

function removeFromTrackedFiles(file, obj) {
    fs.openSync(path.join(__dirname, './lib/trackedFiles.json'), 'w',
        function(err, fd) {
            if (err) {
                logger.log('error', "There was a problem. Could not" + " write into tracked files.");
            }

            var writeBuf = new Buffer(JSON.stringify(obj));
            fs.writeSync(fd, writeBuf, 0, writeBuf.length, 0);
            logger.log('info', "Successfully removed " + file + " from tracked files.");
            logger.log('info', 'Original tracked files has been updated.');

            fs.closeSync(fd);
        }
    );
}

/*
    -------------------------------
        Common Helper Functions
    -------------------------------
*/

function arrayEquals(arr1, arr2) {
    if (arr1.length === 0 || arr2.length === 0) {
        return false;
    } else if (arr1.length === arr2.length) {
        for (var i = 0; i < arr1.length; i++) {
            if (arr1[i] !== arr2[i]) {
                return false;
            }
        }
        return true;
    } else {
        return false;
    }
}

/*
    ---------------
        Exports
    ---------------
*/

module.exports = {
    PSPublisher: PSPublisher,
    logger: logger
};
<commit_msg>I did this already... must've been undo accident<commit_after>'use strict';
var fs = require('fs'),
    chokidar = require('chokidar'),
    winston = require('winston'),
    mongoose = require('mongoose'),
    junk = require('junk'),
    path = require('path'),
    validate = require('json-schema').validate,
    ObjectId = require('mongodb').ObjectID;

/*
    ---------------------
       Winston Logger
    ---------------------

    Instances of winston are event emitters and winston transports
    are lazy-loaded getters. Each log message will output into a log file
    and/or the console as a stream. There are different log levels you can use,
    where the levels are prioritized from 0 to 7 (highest to lowest). You can
    colorize them as well as define your own levels.

    Default:
    { emerg: 0, alert: 1, crit: 2, error: 3, warning: 4, notice: 5, info: 6, debug: 7 }

    The use cases look like:
    logger.warn('message'),
    logger.emerg('message'),
    logger.info('message'),
    or (generically) logger.log('%level', 'message').
*/

var logger = new winston.Logger({
    transports: [
        new(winston.transports.Console)({
            levels: {
                crit: 0,
                error: 1,
                warning: 2,
                notice: 3,
                info: 4,
                debug: 5
            },
            colors: {
                crit: 'magenta',
                error: 'red',
                warning: 'yellow',
                notice: 'grey',
                info: 'green',
                debug: 'blue',
            },
            colorize: true,
            prettyPrint: true,
        }),
        new winston.transports.File({ filename: './logs/all-logs.log' })
    ],
    exceptionHandlers: [
        new winston.transports.File({ filename: './logs/exceptions.log' })
    ],
    exitOnError: false // winston will *not* exit after logging an uncaught
        // exception. We should change this to true when not
        // in a development environment.
});

/*
    -----------------------------
        Main PSPublisher Class
    -----------------------------
*/

function PSPublisher(directory) {
    this.directory = directory;
}

PSPublisher.prototype.start = function() {
    logger.log('info', "PSPublisher is starting...");
    this.watch();
}

PSPublisher.prototype.connect = function(uri) {
    mongoose.connect(uri);

    // Confirms successful database connection
    mongoose.connection.once('connected', function(err) {
        if (err) {
            next(err);
            logger.log('error', "Couldn't connect to " + uri + ".");
        }
        logger.log('info', "Connected to " + uri);
    });
}

/*
    ----------------------------------------------------------------------------
        Registers Schemas in order to interface with Database using Mongoose
    ----------------------------------------------------------------------------

    We opt here to have user defined models passed in as an array.

    Example:

        PSPublisher.models([{
            name: 'Posts',
            schema: {
                'title': title,
                'body': body
            }
        }, {
            name: 'Comments',
            schema: {
                'name': name,
                'comment': comment
            }
        ]);

    Currently does not have support for subdocuments.
*/

// This is simply to make the name of the models available to this script.
var modelNames = [];

PSPublisher.prototype.models = function(models) {
    if (!models) {
        logger.log('error', "Invalid model. Please use proper formatting" + " or a valid schema.");
    }

    if (!Array.isArray(models)) {
        logger.log('error', "Invalid model. Please use proper formatting" + " or a valid schema.");
    }

    for (var i = 0; i < models.length; i++) {
        var Schema = new mongoose.Schema(models[i].schema, { timestamps: true });
        mongoose.model(models[i].name, Schema);
        modelNames.push(models[i].name);
    }
}

/*
    --------------------
        Main Watcher
    --------------------
*/

PSPublisher.prototype.watch = function() {
    var dir = this.directory;

    // Trim off the end of the path since chokidar have absolute directory
    // paths without a trailing backslash. This will protect users.
    if (dir[dir.length - 1] === '/') {
        dir = dir.substring(0, dir.length - 1);
    }

    // This will initialize the watcher, i.e. the main event emitter. We will
    // be calling watch() on an instance of PSPublish to use it as a wrapper
    // around chokidar with preconfigured events.
    var watcher = chokidar.watch(dir, {
        ignored: [
            /[\/\\]\./,
        ],
        persistent: true
    });

    watcher.on('ready', function() {
        logger.log('info', "Began watching " + dir);

        /*
            Checks and sees what files are currently being watched. Chokidar also
            tracks the directory itself so it's necessary to grab the property that
            only has the files. Our file listings is going to be our canonical record.
            Our "tracked files" in trackedFiles.json holds the id of the documents in
            our database when they were first added. When the file is no longer in the
            directory, we will remove the document from the database and then untrack it.
        */

        var Watched = watcher.getWatched();
        var fileListings = Watched[path.join(__dirname, dir)].sort();

        // Reconcile the file listings with the record of tracked files. This
        // will be used to update the database on this script's startup.
        fs.readFile('./lib/trackedFiles.json', 'utf8', function(err, data) {
            if (err) {
                logger.log('error', "An error occurred with trackedFiles file." + " Please resolve before continuing.");
            }

            if (data) {
                var trackedFiles = JSON.parse(data),
                    trackedKeys = Object.keys(trackedFiles).sort();
            } else {
                var trackedKeys = [];
            }

            /*
                trackedFiles[trackedKeys[i]] will give us the ids, if we need them.
                We can also do:
                Object.keys(trackedFiles).forEach(function (key) {
                    let value = trackedFiles[key];
                    logger.log('info', value);
                });
            */

            if (arrayEquals(fileListings, trackedKeys)) {
                logger.log('info', "Files are in sync. Will be listening for changes.");
            } else {
                if (!fileListings) {
                    logger.log('info', "There are currently no files in " + dir + ".");
                } else {
                    logger.log('info', "Files in " + dir + " are not in sync.");
                    syncFiles(fileListings, trackedKeys);
                }
            }
        });
    });

    watcher.on('add', function(file) {
        logger.log('info', file + " was added to " + dir + ".");
        insertFile(file);
    });

    watcher.on('change', function(file, stats) {
        logger.log('info', file + " was modified at " + stats.mtime + ".");
        updateFile(file);
    });

    watcher.on('unlink', function(file) {
        logger.log('info', file + " was removed from " + dir + ".");
        removeFile(file);
    });
}

/*
    ----------------------------------
        Watcher Helper Functions
    ----------------------------------
*/

function syncFiles(listing, tracked) {
    logger.log('info', "Syncing files...");
    if (listing.length > tracked.length) {
        /*
            If the number of files in the directory is larger than the number
            of files in trackedFiles.json, we have documents not yet added
            to the database. We will also need to insert those files into
            trackedFiles after finding them. For each element in listing,
            we test to see if it is in tracked. If it isn't, then we call
            the insertFile method and insert it into our database. This search
            is costly (O(n^2)), but we can improve it later with a binary
            search since the arrays are already sorted.
        */
        listing.forEach(function(file) {
            if (!(file in tracked)) {
                insertFile(file);
            }
        });
    } else if (listing.length < tracked.length) {
        /*
            If the number of files in the directory is less than the number
            of files in trackedFiles.json, we want to remove documents from
            the database. We find each element in tracked and not in the
            directory and remove it from the database and then
            trackedFiles.json.
        */
        tracked.forEach(function(file) {
            if (!(file in listing)) {
                removeFile(file);
            }
        });
    }
}

function insertFile(file) {
    var file = file;
    fs.readFile(path.join(__dirname, file), 'utf8', function(err, content) {
        if (err) {
            logger.log('error', "Was not able to read the file.");
        }

        var model = mongoose.model(modelNames[0]);
        if (model) {
            var obj = JSON.parse(content);
            model.create(obj, function(err, doc) {
                if (err) {
                    logger.log('error', "An error occurred. " + file + " was not inserted into database.");
                }

                logger.log('info', file + " was successfully inserted. id: " + doc._id);
                addToTrackedFiles(file, doc._id);
            });
        } else {
            logger.log('error', "Could not insert " + file + " into database.");
        }
    });
}

function updateFile(file) {
    var file = file;
    fs.readFile(path.join(__dirname, file), 'utf8', function(err, content) {
        if (err) {
            logger.log('error', "Was not able to update " + file + ".");
        }

        if (!content) {
            logger.log('error', file + " cannot be empty.");
        }

        var model = mongoose.model(modelNames[0]);
        if (model) {
            var updatedDoc = JSON.parse(content);
            fs.readFile(path.join(__dirname, './lib/trackedFiles.json'), 'utf8',
                function(err, data) {
                    var fileObj = JSON.parse(data);
                    if (fileObj[file]) {
                        model.findOneAndUpdate({ _id: ObjectId(fileObj[file]) }, updatedDoc,
                            function(err, doc) {
                                if (err) {
                                    logger.log('error', "An error occurred. Was not" + " able to update " + file + ".");
                                }

                                logger.log('info', file + " was successfully updated.");
                            }
                        );
                    } else {
                        logger.log('error', "Could not find " + file + " in the tracked files.");
                    }
                }
            );
        } else {
            logger.log('error', "Was not able to update" + file + ".");
        }
    });
}

function removeFile(file) {
    var file = file;
    fs.readFile(path.join(__dirname, './lib/trackedFiles.json'), 'utf8', function(err, content) {
        if (err) {
            logger.log('error', "Was not able to read trackedFiles.json.");
        }

        var model = mongoose.model(modelNames[0]);
        if (model) {
            var fileObj = JSON.parse(content);
            model.remove({ _id: ObjectId(fileObj[file]) }, function(err) {
                if (err) {
                    logger.log('error', "Could not find document in collection.");
                }

                logger.log('info', "Successfully removed " + file + " from collection.");

                // Simply delete the key-value pair and overwrites the
                // original file with one less element.
                delete fileObj[file];

                if (fileObj) {
                    removeFromTrackedFiles(file, fileObj);
                } else {
                    removeFromTrackedFiles(file, {});
                }
            });
        } else {
            logger.log('error', "Could not delete " + file + " from database.");
        }
    });
}

/*
    -----------------------------
        CRUD Helper Functions
    -----------------------------
*/

function findAndValidateModel(file) {
    /*
        This helper function will check if the file has a valid schema.
        It will return a model if it does. If not, it will throw an
        exception. The user must create a schema before moving any files
        into the directory.
    */
    fs.readFile(path.join(__dirname, file), 'utf8', function(err, data) {
        var obj = JSON.parse(data);
        // Validates the file. If there are no errors,
        // we can return the correct model.
        modelNames.forEach(function(name) {
            var schema = mongoose.model(name).schema;
            if ((validate(obj, schema).valid)) {
                logger.log('info', "Schema found!");
                return mongoose.model(name);
            }
        });
    });
    logger.log('error', "File does not have a valid schema." + " Please recheck your document.");
}

function addToTrackedFiles(file, id) {
    /*
        This helper function will write into trackedFiles.json a key-value
        pair of the form:

            file: id

        This will allow quick and easy access to finding the document in
        the database by using Obj.file as the query condition. The id can
        only be added after an insert into the database so in order to
        remove a document from the database, the id must first exist in
        the trackedFiles.json file.
    */
    fs.readFile(path.join(__dirname, './lib/trackedFiles.json'), 'utf8', function(err, data) {
        // If trackedFiles.json is not empty then...
        if (data) {
            var fileObj = JSON.parse(data);
            fileObj[file] = id;

            /*
                trackedFiles.json must be opened synchronously or else we
                have the problem of one I/O operation overwriting one
                another. Mongoose, however, handles asynchrously operations
                perfectly so we don't have to worry about the database.
            */
            fs.openSync(path.join(__dirname, './lib/trackedFiles.json'), 'w', 'utf8',
                function(err, fd) {
                    if (err) {
                        logger.log('error', "There was a problem. " + file + " was not added to tracked files.");
                    }

                    var writeBuf = new Buffer(JSON.stringify(fileObj));
                    fs.writeSync(fd, writeBuf, 0, writeBuf.length, 0);
                    logger.log('info', "Successfully added " + file + " to tracked files.");
                    logger.log('info', 'Original tracked files has been updated.');

                    fs.closeSync(fd);
                }
            );
        } else {
            // else do...
            var trackObject = {};
            trackObject[file] = id;
            fs.openSync(path.join(__dirname, './lib/trackedFiles.json'), 'w', 'utf8',
                function(err, fd) {
                    if (err) {
                        logger.log('error', "There was a problem. " + file + " was not added to tracked files.");
                    }

                    var writeBuf = new Buffer(JSON.stringify(trackObject));
                    fs.writeSync(fd, writeBuf, 0, writeBuf.length, 0);
                    logger.log('info', "Successfully added " + file + " to tracked files.");
                    logger.log('info', 'Original tracked files has been updated.');

                    fs.closeSync(fd);
                }
            );
        }
    });
}

function removeFromTrackedFiles(file, obj) {
    fs.openSync(path.join(__dirname, './lib/trackedFiles.json'), 'w',
        function(err, fd) {
            if (err) {
                logger.log('error', "There was a problem. Could not" + " write into tracked files.");
            }

            var writeBuf = new Buffer(JSON.stringify(obj));
            fs.writeSync(fd, writeBuf, 0, writeBuf.length, 0);
            logger.log('info', "Successfully removed " + file + " from tracked files.");
            logger.log('info', 'Original tracked files has been updated.');

            fs.closeSync(fd);
        }
    );
}

/*
    -------------------------------
        Common Helper Functions
    -------------------------------
*/

function arrayEquals(arr1, arr2) {
    if (arr1.length === 0 || arr2.length === 0) {
        return false;
    } else if (arr1.length === arr2.length) {
        for (var i = 0; i < arr1.length; i++) {
            if (arr1[i] !== arr2[i]) {
                return false;
            }
        }
        return true;
    } else {
        return false;
    }
}

/*
    ---------------
        Exports
    ---------------
*/

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


<commit_before>function ContentLoader(){
  var constructor = function(){
    setInterval(function(){checkValidation(navigator.connection);},30000);
    loadShopInfo();
  }

  function checkValidation(connection){
    if($(connection).type != "none" && $(connection).type != "unknown" && !isUndefined(connection)){
      console.log("refreshato");
      window.location.href = 'index.html';
    }
  }
  function loadShopInfo(){
    $.get('local/shop/contacts.html', function(data){
      if($(data).length > 0){
        $(data).appendTo($('#mainLogo'))
      }
    });
  }
  constructor();

  function isUndefined(obj){
    return typeof $(connection) === "undefined";
  }
}
(function () {
  var c_loader = new ContentLoader();
});<commit_msg>sadasd<commit_after>function ContentLoader(){
  var constructor = function(){
    setInterval(function(){checkValidation(navigator.connection);},30000);
    loadShopInfo();
  }

  function checkValidation(connection){
    if($(connection).type != "none" && $(connection).type != "unknown" && !isUndefined(connection)){
      console.log("refreshato");
      window.location.href = 'index.html';
    }
  }
  function loadShopInfo(){
    $.get('local/shop/contacts.html', function(data){
      if($(data).length > 0){
        $(data).appendTo($('#mainLogo'))
      }
    });
  }
  constructor();

  function isUndefined(obj){
    return typeof $(connection) === "undefined";
  }
}
(function () {
  var c_loader = new ContentLoader();
}());<|endoftext|>


<commit_before>const _ = require('lodash');
const cheerio = require('cheerio');
const express = require('express');
const bodyParser = require('body-parser');
const Promise = require('bluebird');
const Trello = require('node-trello');
const rp = require('request-promise');

require('dotenv').config();
Promise.promisifyAll(Trello.prototype);

const TRELLO_MAX_RATE = 300; // max one request every x milliseconds
const conferences = require('./conferences.json');

const getConference = (name) =>
  (conferences[name] != null) ? _.extend(conferences[name], { name }) : null;

const labelColors = ['green', 'yellow', 'orange', 'red', 'purple', 'blue',
 'sky', 'lime', 'pink', 'black'];

const app = express();
app.set('view engine', 'pug');
app.use(bodyParser.urlencoded({ extended: true }));

app.use(express.static('public'));

app.get('/:conference?', function(req, res) {
  const conference = getConference(req.query.conference || req.params.conference);

  if (conference == null) {
    if (req.params.conference != null) {
      res.redirect('/');
    } else {
      res.render('select_conference', {
        conferences
      });
    }
  } else {
    res.render('index', {
      appKey: process.env.TRELLO_KEY,
      conference: conference,
    });
  }
})

app.post('/', function(req, res){
  const { board_idOrg, token } = req.body;

  const board_name = req.body.board_name.trim()

  const conference = getConference(req.body.conference);

  if (conference == null) {
    res.redirect(303, '/');
    return;
  }

  conference.name = req.body.conference;

  const fetcher = require(`./conferences/${conference.name}.js`);

  try {
    if (!board_name) {
      throw new Error('You need to specify a board name');
    }
    if (!token) {
      throw new Error('You need to pass a Trello token');
    }
  }
  catch (err) {
    res.status(400).send(err.message);
    return;
  }

  const trello = new Trello(process.env.TRELLO_KEY, token);

  let lastTrelloRequest = null
  // rate limited Trello API requests
  const trelloPost = (path, params) => {
    const now = Date.now();
    const delta = now - lastTrelloRequest;
    lastTrelloRequest = now;
    const doThePost = () => trello.postAsync(path, params)

    if (delta < TRELLO_MAX_RATE) {
      return Promise.delay(TRELLO_MAX_RATE - delta).then(doThePost)
    } else {
      return doThePost();
    }
  }

  const write = (s, newLine = true) => res.write(s + (newLine ? "

" : ''));
  const willWrite = (s, newLine = true) => () => write(s, newLine)

  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf8' });

  write('<title>Creating conference board</title>\
    <link rel="stylesheet" href="/style.css" />\
    \

');

  write(`Downloading ${conference.scheduleUrl}... `, false)

  fetcher(conference.scheduleUrl)
  .then(({ days, labels }) => {
    const labelIds = {};

    write("done")

    write(`Creating "${board_name}" board... `, false)

    return trelloPost('/1/boards', {
      name: board_name,
      idOrganization: board_idOrg,
      defaultLabels: false,
      defaultLists: false,
    })
    .tap(board => write(`done — <a href="${board.url}" target="_blank">watch it grow!</a><p>(if this page stops updating, check the Trello board as the server may still be working on it)</p>`))
    // add 'how to use' list
    .then(board =>
      trelloPost('/1/lists', {
        idBoard: board.id,
        name: 'How to use this board',
      })
      .tap(willWrite("Setting up the board... "))
      .tap(willWrite("  - instruction cards", false))
      .then(list =>
        Promise.each([
            '** BEFORE THE CONFERENCE **',
            'Add all your team mates that are going the conference to this board.',
            'Choose which sessions you\'re going to in each slot by adding yourself to those cards. (Press `space` when the card is open or under your cursor).',
            '** DURING THE CONFERENCE **',
            'Use this board on your laptop, iPhone, iPad or Android device with Trello\'s mobile apps.',
            'You can write notes as comments on the session\'s card, and attach any photos or links to elsewhere to the card too.',
            'Press `q` to see your personal schedule.',
            'Press `f` to filter by a label or some text.',
            '** AFTER THE CONFERENCE **',
            'You have a central resource with all the details of the conference, including your whole team\'s notes, photos and links.',
            'When the conference videos are released, link to each one on its card.',
            'Share the board with everyone else at your company so they can learn too, including your notes on how this can apply to your situation!',
          ],
          name =>
            trelloPost('/1/cards', { name, idList: list.id })
            .tap(willWrite('.', false))
        )
        .tap(willWrite(' ✓'))
        .then(() => board)
      )
    )
    .tap(willWrite(`  - ${labels.length} labels`, false))
    // create labels
    .tap(board =>
      Promise.each(labels, (name, index) =>
        trelloPost(`/1/boards/${board.id}/labels`, {
          name,
          color: labelColors[index % labelColors.length+1]
        })
        .then(label =>
          labelIds[name] = label.id
        )
        .tap(willWrite('.', false))
      )
    )
    .tap(willWrite(' ✓'))
    .tap(willWrite('Creating lists and cards for each day... '))
    // add each day's slots and sessions
    .tap(board =>
      Promise.each(days, day =>
        trelloPost('/1/lists', {
          idBoard: board.id,
          name: day.title,
          pos: 'bottom',
        })
        .tap(dayList => trelloPost('/1/cards', { name: 'Goals for this day', idList: dayList.id }))
        .tap(dayList => trelloPost('/1/cards', { name: 'Key takeaways', idList: dayList.id }))
        .tap(willWrite(`  ${day.title}`))
        .then(() =>
          Promise.each(day.slots, slot =>
            trelloPost('/1/lists', {
              idBoard: board.id,
              name: slot.time,
              pos: 'bottom',
            })
            .tap(willWrite(`    ${slot.time}`, false))
            .then(list =>
              Promise.each(slot.sessions, session =>
                trelloPost('/1/cards', {
                  name: `${session.title} — ${session.speakers}`,
                  desc: session.blurb,
                  idLabels: session.labels.map(label => labelIds[label]).join(','),
                  idList: list.id
                })
                .then(card =>
                  Promise.each(session.avatars.reverse(), avatarUrl =>
                    trelloPost(`/1/cards/${card.id}/attachments`, { url: avatarUrl })
                  ) // Promise.each
                ) // then card
                .tap(willWrite('.', false))
              ) // each session
            ) // then list
            .tap(willWrite(' ✓'))
          ) // each slot
        ) // then dayList
      ) // each day
    )
    .then(board => {
      res.write(`\n\nAll Done! <a href="${board.url}">${board.url}</a></p></article></body></html>`)
      res.end();
    })
  })
  .catch(err => {
    console.error(err);
    res.write(`</p><p style="color: red">Error: ${err.message}</p><p>You might want to close the board in Trello and refresh this page to try again.</p></article></body></html>`);
    res.end()
    throw err;
  })
});

const port = process.env.PORT || 3002;
app.listen(port);

console.log(`listening on ${port}`)
<commit_msg>Add a list for people you meet<commit_after>const _ = require('lodash');
const cheerio = require('cheerio');
const express = require('express');
const bodyParser = require('body-parser');
const Promise = require('bluebird');
const Trello = require('node-trello');
const rp = require('request-promise');

require('dotenv').config();
Promise.promisifyAll(Trello.prototype);

const TRELLO_MAX_RATE = 300; // max one request every x milliseconds
const conferences = require('./conferences.json');

const getConference = (name) =>
  (conferences[name] != null) ? _.extend(conferences[name], { name }) : null;

const labelColors = ['green', 'yellow', 'orange', 'red', 'purple', 'blue',
 'sky', 'lime', 'pink', 'black'];

const app = express();
app.set('view engine', 'pug');
app.use(bodyParser.urlencoded({ extended: true }));

app.use(express.static('public'));

app.get('/:conference?', function(req, res) {
  const conference = getConference(req.query.conference || req.params.conference);

  if (conference == null) {
    if (req.params.conference != null) {
      res.redirect('/');
    } else {
      res.render('select_conference', {
        conferences
      });
    }
  } else {
    res.render('index', {
      appKey: process.env.TRELLO_KEY,
      conference: conference,
    });
  }
})

app.post('/', function(req, res){
  const { board_idOrg, token } = req.body;

  const board_name = req.body.board_name.trim()

  const conference = getConference(req.body.conference);

  if (conference == null) {
    res.redirect(303, '/');
    return;
  }

  conference.name = req.body.conference;

  const fetcher = require(`./conferences/${conference.name}.js`);

  try {
    if (!board_name) {
      throw new Error('You need to specify a board name');
    }
    if (!token) {
      throw new Error('You need to pass a Trello token');
    }
  }
  catch (err) {
    res.status(400).send(err.message);
    return;
  }

  const trello = new Trello(process.env.TRELLO_KEY, token);

  let lastTrelloRequest = null
  // rate limited Trello API requests
  const trelloPost = (path, params) => {
    const now = Date.now();
    const delta = now - lastTrelloRequest;
    lastTrelloRequest = now;
    const doThePost = () => trello.postAsync(path, params)

    if (delta < TRELLO_MAX_RATE) {
      return Promise.delay(TRELLO_MAX_RATE - delta).then(doThePost)
    } else {
      return doThePost();
    }
  }

  const write = (s, newLine = true) => res.write(s + (newLine ? "

" : ''));
  const willWrite = (s, newLine = true) => () => write(s, newLine)

  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf8' });

  write('<title>Creating conference board</title>\
    <link rel="stylesheet" href="/style.css" />\
    \

');

  write(`Downloading ${conference.scheduleUrl}... `, false)

  fetcher(conference.scheduleUrl)
  .then(({ days, labels }) => {
    const labelIds = {};

    write("done")

    write(`Creating "${board_name}" board... `, false)

    return trelloPost('/1/boards', {
      name: board_name,
      idOrganization: board_idOrg,
      defaultLabels: false,
      defaultLists: false,
    })
    .tap(board => write(`done — <a href="${board.url}" target="_blank">watch it grow!</a><p>(if this page stops updating, check the Trello board as the server may still be working on it)</p>`))
    // add 'how to use' list
    .then(board =>
      trelloPost('/1/lists', {
        idBoard: board.id,
        name: 'How to use this board',
      })
      .tap(willWrite("Setting up the board... "))
      .tap(willWrite("  - instruction cards", false))
      .then(list =>
        Promise.each([
            '** BEFORE THE CONFERENCE **',
            'Add all your team mates that are going the conference to this board.',
            'Choose which sessions you\'re going to in each slot by adding yourself to those cards. (Press `space` when the card is open or under your cursor).',
            '** DURING THE CONFERENCE **',
            'Use this board on your laptop, iPhone, iPad or Android device with Trello\'s mobile apps.',
            'You can write notes as comments on the session\'s card, and attach any photos or links to elsewhere to the card too.',
            'Press `q` to see your personal schedule.',
            'Press `f` to filter by a label or some text.',
            '** AFTER THE CONFERENCE **',
            'You have a central resource with all the details of the conference, including your whole team\'s notes, photos and links.',
            'When the conference videos are released, link to each one on its card.',
            'Share the board with everyone else at your company so they can learn too, including your notes on how this can apply to your situation!',
          ],
          name =>
            trelloPost('/1/cards', { name, idList: list.id })
            .tap(willWrite('.', false))
        )
        .tap(willWrite(' ✓'))
        .then(() => board)
      )
    )
    .tap(willWrite('  - people list...', false))
    .tap(board =>
      trelloPost('/1/lists', {
        idBoard: board.id,
        name: 'People',
        pos: 'bottom',
      })
      .then(list =>
        trelloPost('/1/cards', {
          idList: list.id,
          name: 'Record details of the interesting people you meet here'
        })
      )
    )
    .tap(willWrite(' ✓'))
    .tap(willWrite(`  - ${labels.length} labels`, false))
    // create labels
    .tap(board =>
      Promise.each(labels, (name, index) =>
        trelloPost(`/1/boards/${board.id}/labels`, {
          name,
          color: labelColors[index % labelColors.length+1]
        })
        .then(label =>
          labelIds[name] = label.id
        )
        .tap(willWrite('.', false))
      )
    )
    .tap(willWrite(' ✓'))
    .tap(willWrite('Creating lists and cards for each day... '))
    // add each day's slots and sessions
    .tap(board =>
      Promise.each(days, day =>
        trelloPost('/1/lists', {
          idBoard: board.id,
          name: day.title,
          pos: 'bottom',
        })
        .tap(dayList => trelloPost('/1/cards', { name: 'Goals for this day', idList: dayList.id }))
        .tap(dayList => trelloPost('/1/cards', { name: 'Key takeaways', idList: dayList.id }))
        .tap(willWrite(`  ${day.title}`))
        .then(() =>
          Promise.each(day.slots, slot =>
            trelloPost('/1/lists', {
              idBoard: board.id,
              name: slot.time,
              pos: 'bottom',
            })
            .tap(willWrite(`    ${slot.time}`, false))
            .then(list =>
              Promise.each(slot.sessions, session =>
                trelloPost('/1/cards', {
                  name: `${session.title} — ${session.speakers}`,
                  desc: session.blurb,
                  idLabels: session.labels.map(label => labelIds[label]).join(','),
                  idList: list.id
                })
                .then(card =>
                  Promise.each(session.avatars.reverse(), avatarUrl =>
                    trelloPost(`/1/cards/${card.id}/attachments`, { url: avatarUrl })
                  ) // Promise.each
                ) // then card
                .tap(willWrite('.', false))
              ) // each session
            ) // then list
            .tap(willWrite(' ✓'))
          ) // each slot
        ) // then dayList
      ) // each day
    )
    .then(board => {
      res.write(`\n\nAll Done! <a href="${board.url}">${board.url}</a></p></article></body></html>`)
      res.end();
    })
  })
  .catch(err => {
    console.error(err);
    res.write(`</p><p style="color: red">Error: ${err.message}</p><p>You might want to close the board in Trello and refresh this page to try again.</p></article></body></html>`);
    res.end()
    throw err;
  })
});

const port = process.env.PORT || 3002;
app.listen(port);

console.log(`listening on ${port}`)
<|endoftext|>


<commit_before>var crypto = require('crypto');

/**
 * This module provides native bindings to ecdsa [secp256k1](https://github.com/bitcoin/secp256k1) functions
 * @module secp256k1
 */

var secpNode = require('bindings')('secp256k1');

/**
 * Verify an ECDSA secret key.
 * @method verifySecetKey
 * @param {Buffer} sercetKey the sercet Key to verify
 * @return {Boolean}  `true` if sercet key is valid, `false` sercet key is invalid
 */
exports.verifySecretKey = function(sercetKey){
  return Boolean(secpNode.secKeyVerify(sercetKey));
};

/**
 * Verify an ECDSA public key.
 * @method verifyPublicKey
 * @param {Buffer} publicKey the public Key to verify
 * @return {Boolean} `true` if public key is valid, `false` sercet key is invalid
 */
exports.verifyPublicKey = function(publicKey){
  return Boolean(secpNode.pubKeyVerify(publicKey));
};

/**
 * Create an ECDSA signature.
 * @method sign
 * @param  {Buffer} secretkey a 32-byte secret key (assumed to be valid)
 * @param {Buffer} msg he message being signed
 * @param {Function} cb the callback given. The callback is given the signature
 * @returns {Buffer} if no callback is given a 72-byte signature is returned
 */
exports.sign = function(secretKey, msg, cb){
  if(cb){
    secpNode.signAsync(secretKey, msg, cb);
  }else{
    return secpNode.sign(secretKey, msg);
  }
};

/**
 * Create a compact ECDSA signature (64 byte + recovery id). Runs asyncously
 * if given a callback
 * @method signCompact
 * @param {Buffer} sercetKey a 32-byte secret key (assumed to be valid)
 * @param {Buffer} msg the message being signed
 * @param {Function} [cb] the callback which is give `err`, `sig` the
 *    - param {Buffer} sig  a 64-byte buffer repersenting the signature
 *    - param {Number} recid an int which is the recovery id.
 * @return {Object} result only if no callback is given will the result be returned
 *    - result.sigature
 *    - result.r
 *    - result.s
 *    - result.recoveryID
 */
exports.signCompact = function(secretKey, msg, cb){

  if(cb){
    secpNode.signCompactAsync(secretKey, msg, cb);
  }else{
    var array = secpNode.signCompact(secretKey, msg);
    return {
      recoveryId: array[1],
      signature: array[2],
      r: array[2].slice(0, 32),
      s: array[2].slice(32, 64)
    };
  }
};

/**
 * Verify an ECDSA signature.
 * @method verify
 * @param {Buffer} pubKey the public key
 * @param {Buffer} mgs the message
 * @param {Buffer} sig the signature
 * @return {Integer}
 *
 *    - 1: correct signature
 *    - 0: incorrect signature
 *    - -1: invalid public key
 *    - -2: invalid signature
 */
exports.verify = function(pubKey, msg, sig, cb){
  if(cb){
    secpNode.verifyAsync(pubKey, msg, sig, cb);
  }else{
    return secpNode.verify(pubKey, msg, sig);
  }
};

/**
 * Recover an ECDSA public key from a compact signature. In the process also verifing it.
 * @method recoverCompact
 * @param {Buffer} msg the message assumed to be signed
 * @param {Buffer} sig the signature as 64 byte buffer
 * @param {Integer} recid the recovery id (as returned by ecdsa_sign_compact)
 * @param {Boolean} compressed whether to recover a compressed or uncompressed pubkey
 * @param {Function} [cb]
 * @return {Buffer} the pubkey, a 33 or 65 byte buffer
 */
exports.recoverCompact = function(msg, sig, recid, compressed, cb){

  compressed = compressed ? 1 : 0;

  if (recid < 0 || recid > 3) {
    if (!cb) {
      return null;
    } else {
      return cb('recovery id must be >= 0 && recid <= 3');
    }
  }

  if(!cb){
    return secpNode.recoverCompact(msg, sig, compressed, recid);
  }else{
    secpNode.recoverCompactAsync(msg, sig, compressed, recid, cb);
  }
};

/**
 * Compute the public key for a secret key.
 * @method createPubKey
 * @param {Buffer} secKey a 32-byte private key.
 * @param {Boolean} [compressed=0] whether the computed public key should be compressed
 * @return {Buffer} a 33-byte (if compressed) or 65-byte (if uncompressed) area to store the public key.
 */
exports.createPublicKey = function(secKey, compressed){
  compressed = compressed ? 1 : 0;
  return secpNode.pubKeyCreate(secKey, compressed);
};

/**
 * @method exportPrivateKey
 * @param {Buffer} secertKey
 * @param {Boolean} compressed
 * @return {Buffer} privateKey
 */
exports.exportPrivateKey = secpNode.privKeyExport;

/**
 * @method importPrivateKey
 * @param {Buffer} privateKey
 * @return {Buffer} secertKey
 */
exports.importPrivateKey = secpNode.privKeyImport;

/**
 * @method decompressPublickey
 * @param {Buffer} secretKey
 * @return {Buffer}
 */
exports.decompressPublicKey = secpNode.pubKeyDecompress;

/**
 * @method privKeyTweakAdd
 * @param {Buffer} privateKey
 * @param {Buffer} tweak
 * @return {Buffer}
 */
exports.privKeyTweakAdd = secpNode.privKeyTweakAdd;

/**
 * @method privKeyTweakMul
 * @param {Buffer} privateKey
 * @param {Buffer} tweak
 * @return {Buffer}
 */
exports.privKeyTweakMul = secpNode.privKeyTweakMul;

/**
 * @method pubKeyTweakAdd
 * @param {Buffer} publicKey
 * @param {Buffer} tweak
 * @return {Buffer}
 */
exports.pubKeyTweakAdd = secpNode.pubKeyTweakAdd;

/**
 * @method pubKeyTweakMul
 * @param {Buffer} publicKey
 * @param {Buffer} tweak
 * @return {Buffer}
 */
exports.pubKeyTweakMul = secpNode.pubKeyTweakMul;
<commit_msg>use acctully Error<commit_after>var crypto = require('crypto');

/**
 * This module provides native bindings to ecdsa [secp256k1](https://github.com/bitcoin/secp256k1) functions
 * @module secp256k1
 */

var secpNode = require('bindings')('secp256k1');

/**
 * Verify an ECDSA secret key.
 * @method verifySecetKey
 * @param {Buffer} sercetKey the sercet Key to verify
 * @return {Boolean}  `true` if sercet key is valid, `false` sercet key is invalid
 */
exports.verifySecretKey = function(sercetKey){
  return Boolean(secpNode.secKeyVerify(sercetKey));
};

/**
 * Verify an ECDSA public key.
 * @method verifyPublicKey
 * @param {Buffer} publicKey the public Key to verify
 * @return {Boolean} `true` if public key is valid, `false` sercet key is invalid
 */
exports.verifyPublicKey = function(publicKey){
  return Boolean(secpNode.pubKeyVerify(publicKey));
};

/**
 * Create an ECDSA signature.
 * @method sign
 * @param  {Buffer} secretkey a 32-byte secret key (assumed to be valid)
 * @param {Buffer} msg he message being signed
 * @param {Function} cb the callback given. The callback is given the signature
 * @returns {Buffer} if no callback is given a 72-byte signature is returned
 */
exports.sign = function(secretKey, msg, cb){
  if(cb){
    secpNode.signAsync(secretKey, msg, cb);
  }else{
    return secpNode.sign(secretKey, msg);
  }
};

/**
 * Create a compact ECDSA signature (64 byte + recovery id). Runs asyncously
 * if given a callback
 * @method signCompact
 * @param {Buffer} sercetKey a 32-byte secret key (assumed to be valid)
 * @param {Buffer} msg the message being signed
 * @param {Function} [cb] the callback which is give `err`, `sig` the
 *    - param {Buffer} sig  a 64-byte buffer repersenting the signature
 *    - param {Number} recid an int which is the recovery id.
 * @return {Object} result only if no callback is given will the result be returned
 *    - result.sigature
 *    - result.r
 *    - result.s
 *    - result.recoveryID
 */
exports.signCompact = function(secretKey, msg, cb){
  if(cb){
    secpNode.signCompactAsync(secretKey, msg, cb);
  }else{
    var array = secpNode.signCompact(secretKey, msg);
    return {
      recoveryId: array[1],
      signature: array[2],
      r: array[2].slice(0, 32),
      s: array[2].slice(32, 64)
    };
  }
};

/**
 * Verify an ECDSA signature.
 * @method verify
 * @param {Buffer} pubKey the public key
 * @param {Buffer} mgs the message
 * @param {Buffer} sig the signature
 * @return {Integer}
 *
 *    - 1: correct signature
 *    - 0: incorrect signature
 *    - -1: invalid public key
 *    - -2: invalid signature
 */
exports.verify = function(pubKey, msg, sig, cb){
  if(cb){
    secpNode.verifyAsync(pubKey, msg, sig, cb);
  }else{
    return secpNode.verify(pubKey, msg, sig);
  }
};

/**
 * Recover an ECDSA public key from a compact signature. In the process also verifing it.
 * @method recoverCompact
 * @param {Buffer} msg the message assumed to be signed
 * @param {Buffer} sig the signature as 64 byte buffer
 * @param {Integer} recid the recovery id (as returned by ecdsa_sign_compact)
 * @param {Boolean} compressed whether to recover a compressed or uncompressed pubkey
 * @param {Function} [cb]
 * @return {Buffer} the pubkey, a 33 or 65 byte buffer
 */
exports.recoverCompact = function(msg, sig, recid, compressed, cb){

  compressed = compressed ? 1 : 0;

  if (recid < 0 || recid > 3) {
    if (!cb) {
      return null;
    } else {
      return cb(new Error('recovery id must be >= 0 && recid <= 3'));
    }
  }

  if(!cb){
    return secpNode.recoverCompact(msg, sig, compressed, recid);
  }else{
    secpNode.recoverCompactAsync(msg, sig, compressed, recid, cb);
  }
};

/**
 * Compute the public key for a secret key.
 * @method createPubKey
 * @param {Buffer} secKey a 32-byte private key.
 * @param {Boolean} [compressed=0] whether the computed public key should be compressed
 * @return {Buffer} a 33-byte (if compressed) or 65-byte (if uncompressed) area to store the public key.
 */
exports.createPublicKey = function(secKey, compressed){
  compressed = compressed ? 1 : 0;
  return secpNode.pubKeyCreate(secKey, compressed);
};

/**
 * @method exportPrivateKey
 * @param {Buffer} secertKey
 * @param {Boolean} compressed
 * @return {Buffer} privateKey
 */
exports.exportPrivateKey = secpNode.privKeyExport;

/**
 * @method importPrivateKey
 * @param {Buffer} privateKey
 * @return {Buffer} secertKey
 */
exports.importPrivateKey = secpNode.privKeyImport;

/**
 * @method decompressPublickey
 * @param {Buffer} secretKey
 * @return {Buffer}
 */
exports.decompressPublicKey = secpNode.pubKeyDecompress;

/**
 * @method privKeyTweakAdd
 * @param {Buffer} privateKey
 * @param {Buffer} tweak
 * @return {Buffer}
 */
exports.privKeyTweakAdd = secpNode.privKeyTweakAdd;

/**
 * @method privKeyTweakMul
 * @param {Buffer} privateKey
 * @param {Buffer} tweak
 * @return {Buffer}
 */
exports.privKeyTweakMul = secpNode.privKeyTweakMul;

/**
 * @method pubKeyTweakAdd
 * @param {Buffer} publicKey
 * @param {Buffer} tweak
 * @return {Buffer}
 */
exports.pubKeyTweakAdd = secpNode.pubKeyTweakAdd;

/**
 * @method pubKeyTweakMul
 * @param {Buffer} publicKey
 * @param {Buffer} tweak
 * @return {Buffer}
 */
exports.pubKeyTweakMul = secpNode.pubKeyTweakMul;
<|endoftext|>