<commit_before>/**
 * @class
 */
sahagin.TestDocResolver = function() {};

/**
 * @private
 * @type {string}
 */
sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER
= 'TestDoc of "{0}" contains invalid keyword "{1}"';

/**
 * @private
 * @type {string}
 */
sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER_POS
= 'TestDoc of "{0}" contains invalid position keyword {1}';

/**
 * @private
 * @type {string}
 */
sahagin.TestDocResolver.MSG_STATEMENT_NOT_CLOSED
= '{end} keyword not found in TestDoc of "{0}"';

/**
 * exposed to other class.
 * TODO this is temporal logic..
 * @type {string}
 */
sahagin.TestDocResolver.LOCAL_VAR = null;

/**
 * exposed to other class.
 * TODO this is temporal logic..
 * @type {string}
 */
sahagin.TestDocResolver.LOCAL_VAR_ASSIGN = null;

/**
 * @private
 * @returns {RegExp}
 */
sahagin.TestDocResolver.generatePlaceHolderRegExp = function() {
  return new RegExp(/{[^{}]+}/g);
};

/**
 * Returns invalid placeholder keyword in the specified TestMethod if exists.
 * Returns null if invalid keyword is not found.
 * @param {sahagin.TestMethod} method
 * @returns {string}
 */
sahagin.TestDocResolver.searchInvalidPlaceholder = function(method) {
  if (method == null || method == undefined) {
    throw new Error(method);
  }
  if (method.getTestDoc() == null) {
    return null; // no TestDoc
  }

  // replace all placeholders by RegExp
  var matched;
  var testDoc = method.getTestDoc();
  var regexp = sahagin.TestDocResolver.generatePlaceHolderRegExp();
  var conditionalFound = false;
  while ((matched = regexp.exec(testDoc)) != null) {
    var variable = matched[0];
    variable = variable.substring(1, variable.length - 1); // trim head and tail braces
    var varIndex = parseInt(variable, 10);
    if (isNaN(varIndex)) {
      // not index pattern
      if (matched == "this") {
        continue;
      } else if (sahagin.CommonUtils.startsWith(matched, "if:")) {
        conditionalFound = true;
        continue;
      } else if (conditionalFound && matched == "end") {
        continue;
      } else if (method.getArgVariables().indexOf(variable) == -1) {
        return variable;
      }
    } else {
      // TODO index check
    }
  }
  return null;
};

/**
 * @param {sahagin.SubMethodInvoke} methodInvoke
 * @param {string} variable
 * @return {Object} object with property "codes" and "empty".
 * "empty" is whether argument for variable is actually specified.
 * {this} and variable length argument can be empty
 */
sahagin.TestDocResolver.methodInvokeNormalVariableCodes = function(methodInvoke, variable) {
  var method = methodInvoke.getSubMethod();

  if (variable == "this") {
    var variableCode = methodInvoke.getThisInstance();
    var empty = false;
    if (variableCode == null) {
      // When called inside the class on which this method is defined,
      // set the class name for {this} keyword
      variableCode = new UnknownCode();
      variableCode.setOriginal(methodInvoke.getSubMethod().getTestClass().getSimpleName());
      empty = true;
    }
    return {codes: [variableCode], empty: empty};
  }

  var varIndex = parseInt(variable, 10);
  if (isNaN(varIndex)) {
    // not index pattern
    varIndex = method.getArgVariables().indexOf(variable);
  }

  if (varIndex < 0) {
    // maybe fails to calculate varIndex from variable
    throw new Error(sahagin.CommonUtils.strFormat(
        sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER, method.getQualifiedName(), variable));
  }

  // TODO maybe should check that varIndex >= method.getArgVariables().length
  // only when method actually has argument variable information

  if (!method.hasVariableLengthArg()) {
    if (varIndex >= methodInvoke.getArgs().length) {
      throw new Error(sahagin.CommonUtils.strFormat(
          sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER, method.getQualifiedName(), variable));
    }
    return {codes: [methodInvoke.getArgs()[varIndex]], empty: false};
  }

  if (varIndex == method.getVariableLengthArgIndex()) {
    // variable length argument.
    // - TestDoc for variable length argument
    //   is the comma connected string of all rest arguments.
    // - TestDoc for variable length argument
    //   is empty string if no rest arguments exist.
    var variableCodes = new Array();
    for (var i = varIndex; i < methodInvoke.getArgs().length; i++) {
      variableCodes.push(methodInvoke.getArgs()[i]);
    }
    return {codes: variableCodes, empty: (variableCodes.length == 0)};
  }

  if (varIndex > method.getVariableLengthArgIndex()) {
    throw new Error(sahagin.CommonUtils.strFormat(
        sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER, method.getQualifiedName(), variable));
  }

  return {codes: [methodInvoke.getArgs()[varIndex]], empty: false};
};

/**
 * @param {sahagin.SubMethodInvoke} methodInvoke
 * @param {string} variable
 * @param {Array.<string>} placeholderResolvedParentMethodArgTestDocs
 * @returns {string}
 */
sahagin.TestDocResolver.methodInvokeNormalVariableTestDoc
= function(methodInvoke, variable, placeholderResolvedParentMethodArgTestDocs) {
  var variableCodes
  = sahagin.TestDocResolver.methodInvokeNormalVariableCodes(methodInvoke, variable).codes;
  var testDoc = "";
  for (var i = 0; i < variableCodes.length; i++) {
    if (i != 0) {
      testDoc = testDoc + ", ";
    }
    testDoc = testDoc + sahagin.TestDocResolver.methodTestDocSub(
        variableCodes[i], placeholderResolvedParentMethodArgTestDocs);
  }
  return testDoc;
};

/**
 * @param {sahagin.SubMethodInvoke} methodInvoke
 * @param {string} condVariable
 * @param {Array.<string>} placeholderResolvedParentMethodArgTestDocs
 * @returns {boolean}
 */
sahagin.TestDocResolver.validateCondVariable = function(
    methodInvoke, condVariable, placeholderResolvedParentMethodArgTestDocs) {
  var splitted = condVariable.split(":");
  if (splitted.length != 2) {
    throw new Error(sahagin.CommonUtils.strFormat(
        sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER,
        methodInvoke.getSubMethod().getQualifiedName(), condVariable));
  }
  var expressionVariable = splitted[1];
  // returns true if argument for expressionVariable is not empty
  return !sahagin.TestDocResolver.methodInvokeNormalVariableCodes(
      methodInvoke, expressionVariable).empty;
};

sahagin.TestDocResolver.methodInvokeTestDoc = function(
    methodInvoke, placeholderResolvedParentMethodArgTestDocs) {
  var method = methodInvoke.getSubMethod();
  if (method.getTestDoc() == null) {
    return methodInvoke.getOriginal();
  }

  // replace all placeholders by RegExp
  var matched;
  var buf = '';
  var dummyBuf = '';
  var prevEnd = 0;
  var testDoc = method.getTestDoc();
  var regexp = sahagin.TestDocResolver.generatePlaceHolderRegExp();
  var ifFound = false;
  var insideIf = false;
  var skip = false;
  while ((matched = regexp.exec(testDoc)) !== null) {
    var variable = matched[0];
    var matchStart = matched.index;
    var matchEnd = matchStart + variable.length;
    variable = variable.substring(1, variable.length - 1); // trim head and tail braces

    if (sahagin.CommonUtils.startsWith(variable, "if:")) {
      if (insideIf) {
        // nested if is not supported yet
        throw new Error(sahagin.CommonUtils.strFormat(
            sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER_POS,
            method.getQualifiedName(), variable));
      }
      buf = buf + testDoc.substring(prevEnd, matchStart);
      ifFound = true;
      insideIf = true;
      skip = !sahagin.TestDocResolver.validateCondVariable(
          methodInvoke, variable, placeholderResolvedParentMethodArgTestDocs);
    } else if (variable == "end" && ifFound) {
      if (!insideIf) {
        throw new Error(sahagin.CommonUtils.strFormat(
            sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER_POS,
            method.getQualifiedName(), variable));
      }
      // abort matched data if skip flag is true
      if (!skip) {
        buf = buf + testDoc.substring(prevEnd, matchStart);
      }
      insideIf = false;
      skip = false;
    } else if (skip) {
      // abort matched data
    } else {
      var variableTestDoc = sahagin.TestDocResolver.methodInvokeNormalVariableTestDoc(
            methodInvoke, variable, placeholderResolvedParentMethodArgTestDocs);
      buf = buf + testDoc.substring(prevEnd, matchStart) + variableTestDoc;
    }
    prevEnd = matchEnd;
  }
  if (insideIf) {
    throw new Error(sahagin.CommonUtils.strFormat(
        sahagin.TestDocResolver.MSG_STATEMENT_NOT_CLOSED,
        method.getQualifiedName()));
  }
  buf = buf + testDoc.substring(prevEnd, testDoc.length);
  return buf.toString();
};

/**
 * Returns original source code if TestDoc is not found
 * @private
 * @param {sahagin.Code} code
 * @param {Array.<string>} placeholderResolvedParentMethodArgTestDocs
 * @returns {string}
 */
sahagin.TestDocResolver.methodTestDocSub = function(
    code, placeholderResolvedParentMethodArgTestDocs) {
  if (code instanceof sahagin.StringCode) {
    return code.getValue();
  } else if (code instanceof sahagin.MethodArgument) {
    var methodArg = code;
    return placeholderResolvedParentMethodArgTestDocs[methodArg.getArgIndex()];
  } else if (code instanceof sahagin.SubMethodInvoke) {
    var methodInvoke = code;
    return sahagin.TestDocResolver.methodInvokeTestDoc(
        methodInvoke, placeholderResolvedParentMethodArgTestDocs);
  } else if (code instanceof sahagin.LocalVar) {
    var localVar = code;
    // TODO implement locale handling logic.. very poor logic..
    return sahagin.CommonUtils.strFormat(sahagin.TestDocResolver.LOCAL_VAR,
        localVar.getName());
  } else if (code instanceof sahagin.LocalVarAssign) {
    var assign = code;
    var valueTestDoc = sahagin.TestDocResolver.methodTestDocSub(
        assign.getValue(), placeholderResolvedParentMethodArgTestDocs);
    // TODO implement locale handling logic.. very poor logic..
    return sahagin.CommonUtils.strFormat(sahagin.TestDocResolver.LOCAL_VAR_ASSIGN,
        assign.getName(), valueTestDoc);
  } else {
    return code.getOriginal();
  }
};

/**
 * @param {sahagin.Code} code
 * @param {Array.<string>} placeholderResolvedParentMethodArgTestDocs
 * @returns {Array.<string>}
 */
sahagin.TestDocResolver.placeholderResolvedMethodArgTestDocs = function(
    code, placeholderResolvedParentMethodArgTestDocs) {
  if (!(code instanceof sahagin.SubMethodInvoke)) {
    return new Array();
  }
  var methodInvoke = code;
  var result = new Array();
  for (var i = 0; i < methodInvoke.getArgs().length; i++) {
    var code = methodInvoke.getArgs()[i];
    var argStr = sahagin.TestDocResolver.methodTestDocSub(
        code, placeholderResolvedParentMethodArgTestDocs);
    result.push(argStr);
  }
  return result;
};

/**
 * @param {sahagin.Code} code
 * @param {Array.<string>} placeholderResolvedParentMethodArgTestDocs
 * @returns {string}
 */
sahagin.TestDocResolver.placeholderResolvedMethodTestDoc = function(
    code, placeholderResolvedParentMethodArgTestDocs) {
  if (code instanceof sahagin.UnknownCode) {
    return null; // TestDoc for UnknownCode is null
  } else {
    return sahagin.TestDocResolver.methodTestDocSub(
        code, placeholderResolvedParentMethodArgTestDocs);
  }
};

/**
 * returns null if Page not found
 * @private
 * @param {sahagin.SubMethodInvoke} methodInvoke
 * @returns {string}
 */
sahagin.TestDocResolver.methodInvokePageTestDocNoRecursive = function(methodInvoke) {
  if (!(methodInvoke.getSubMethod().getTestClass() instanceof sahagin.PageClass)) {
    return null;
  }
  var page = methodInvoke.getSubMethod().getTestClass();
  return page.getTestDoc();
};

/**
 * Returns first found page testDoc.
 * returns null if page testDoc not found
 * @private
 * @param {sahagin.SubMethodInvoke} methodInvoke
 * @returns {string}
 */
sahagin.TestDocResolver.methodInvokePageTestDocRecursive = function(methodInvoke) {
  var pageTestDoc = sahagin.TestDocResolver.methodInvokePageTestDocNoRecursive(methodInvoke);
  if (pageTestDoc != null) {
    return pageTestDoc;
  }
  for (var i = 0; i < methodInvoke.getArgs().length; i++) {
    var code = methodInvoke.getArgs()[i];
    if (code && code instanceof sahagin.SubMethodInvoke) {
      var codeLinePageTestDoc
      = sahagin.TestDocResolver.methodInvokePageTestDocRecursive(code);
      if (codeLinePageTestDoc != null) {
        return codeLinePageTestDoc;
      }
    }
  }
  return null;
};

/**
 * Returns first found page testDoc.
 * returns null if page testDoc not found
 * @param {sahagin.Code} code
 * @returns {string}
 */
sahagin.TestDocResolver.pageTestDoc = function(code) {
  if (!(code instanceof sahagin.SubMethodInvoke)) {
    return null;
  }
  var invoke = code;
  return sahagin.TestDocResolver.methodInvokePageTestDocRecursive(invoke);
};<commit_msg>LocalVar and LocalVarAssign support<commit_after>/**
 * @class
 */
sahagin.TestDocResolver = function() {};

/**
 * @private
 * @type {string}
 */
sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER
= 'TestDoc of "{0}" contains invalid keyword "{1}"';

/**
 * @private
 * @type {string}
 */
sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER_POS
= 'TestDoc of "{0}" contains invalid position keyword {1}';

/**
 * @private
 * @type {string}
 */
sahagin.TestDocResolver.MSG_STATEMENT_NOT_CLOSED
= '{end} keyword not found in TestDoc of "{0}"';

/**
 * exposed to other class.
 * TODO this is temporal logic..
 * @type {string}
 */
sahagin.TestDocResolver.JS_LOCAL_VAR = null;

/**
 * exposed to other class.
 * TODO this is temporal logic..
 * @type {string}
 */
sahagin.TestDocResolver.JS_LOCAL_VAR_ASSIGN = null;

/**
 * @private
 * @returns {RegExp}
 */
sahagin.TestDocResolver.generatePlaceHolderRegExp = function() {
  return new RegExp(/{[^{}]+}/g);
};

/**
 * Returns invalid placeholder keyword in the specified TestMethod if exists.
 * Returns null if invalid keyword is not found.
 * @param {sahagin.TestMethod} method
 * @returns {string}
 */
sahagin.TestDocResolver.searchInvalidPlaceholder = function(method) {
  if (method == null || method == undefined) {
    throw new Error(method);
  }
  if (method.getTestDoc() == null) {
    return null; // no TestDoc
  }

  // replace all placeholders by RegExp
  var matched;
  var testDoc = method.getTestDoc();
  var regexp = sahagin.TestDocResolver.generatePlaceHolderRegExp();
  var conditionalFound = false;
  while ((matched = regexp.exec(testDoc)) != null) {
    var variable = matched[0];
    variable = variable.substring(1, variable.length - 1); // trim head and tail braces
    var varIndex = parseInt(variable, 10);
    if (isNaN(varIndex)) {
      // not index pattern
      if (matched == "this") {
        continue;
      } else if (sahagin.CommonUtils.startsWith(matched, "if:")) {
        conditionalFound = true;
        continue;
      } else if (conditionalFound && matched == "end") {
        continue;
      } else if (method.getArgVariables().indexOf(variable) == -1) {
        return variable;
      }
    } else {
      // TODO index check
    }
  }
  return null;
};

/**
 * @param {sahagin.SubMethodInvoke} methodInvoke
 * @param {string} variable
 * @return {Object} object with property "codes" and "empty".
 * "empty" is whether argument for variable is actually specified.
 * {this} and variable length argument can be empty
 */
sahagin.TestDocResolver.methodInvokeNormalVariableCodes = function(methodInvoke, variable) {
  var method = methodInvoke.getSubMethod();

  if (variable == "this") {
    var variableCode = methodInvoke.getThisInstance();
    var empty = false;
    if (variableCode == null) {
      // When called inside the class on which this method is defined,
      // set the class name for {this} keyword
      variableCode = new UnknownCode();
      variableCode.setOriginal(methodInvoke.getSubMethod().getTestClass().getSimpleName());
      empty = true;
    }
    return {codes: [variableCode], empty: empty};
  }

  var varIndex = parseInt(variable, 10);
  if (isNaN(varIndex)) {
    // not index pattern
    varIndex = method.getArgVariables().indexOf(variable);
  }

  if (varIndex < 0) {
    // maybe fails to calculate varIndex from variable
    throw new Error(sahagin.CommonUtils.strFormat(
        sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER, method.getQualifiedName(), variable));
  }

  // TODO maybe should check that varIndex >= method.getArgVariables().length
  // only when method actually has argument variable information

  if (!method.hasVariableLengthArg()) {
    if (varIndex >= methodInvoke.getArgs().length) {
      throw new Error(sahagin.CommonUtils.strFormat(
          sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER, method.getQualifiedName(), variable));
    }
    return {codes: [methodInvoke.getArgs()[varIndex]], empty: false};
  }

  if (varIndex == method.getVariableLengthArgIndex()) {
    // variable length argument.
    // - TestDoc for variable length argument
    //   is the comma connected string of all rest arguments.
    // - TestDoc for variable length argument
    //   is empty string if no rest arguments exist.
    var variableCodes = new Array();
    for (var i = varIndex; i < methodInvoke.getArgs().length; i++) {
      variableCodes.push(methodInvoke.getArgs()[i]);
    }
    return {codes: variableCodes, empty: (variableCodes.length == 0)};
  }

  if (varIndex > method.getVariableLengthArgIndex()) {
    throw new Error(sahagin.CommonUtils.strFormat(
        sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER, method.getQualifiedName(), variable));
  }

  return {codes: [methodInvoke.getArgs()[varIndex]], empty: false};
};

/**
 * @param {sahagin.SubMethodInvoke} methodInvoke
 * @param {string} variable
 * @param {Array.<string>} placeholderResolvedParentMethodArgTestDocs
 * @returns {string}
 */
sahagin.TestDocResolver.methodInvokeNormalVariableTestDoc
= function(methodInvoke, variable, placeholderResolvedParentMethodArgTestDocs) {
  var variableCodes
  = sahagin.TestDocResolver.methodInvokeNormalVariableCodes(methodInvoke, variable).codes;
  var testDoc = "";
  for (var i = 0; i < variableCodes.length; i++) {
    if (i != 0) {
      testDoc = testDoc + ", ";
    }
    testDoc = testDoc + sahagin.TestDocResolver.methodTestDocSub(
        variableCodes[i], placeholderResolvedParentMethodArgTestDocs);
  }
  return testDoc;
};

/**
 * @param {sahagin.SubMethodInvoke} methodInvoke
 * @param {string} condVariable
 * @param {Array.<string>} placeholderResolvedParentMethodArgTestDocs
 * @returns {boolean}
 */
sahagin.TestDocResolver.validateCondVariable = function(
    methodInvoke, condVariable, placeholderResolvedParentMethodArgTestDocs) {
  var splitted = condVariable.split(":");
  if (splitted.length != 2) {
    throw new Error(sahagin.CommonUtils.strFormat(
        sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER,
        methodInvoke.getSubMethod().getQualifiedName(), condVariable));
  }
  var expressionVariable = splitted[1];
  // returns true if argument for expressionVariable is not empty
  return !sahagin.TestDocResolver.methodInvokeNormalVariableCodes(
      methodInvoke, expressionVariable).empty;
};

sahagin.TestDocResolver.methodInvokeTestDoc = function(
    methodInvoke, placeholderResolvedParentMethodArgTestDocs) {
  var method = methodInvoke.getSubMethod();
  if (method.getTestDoc() == null) {
    return methodInvoke.getOriginal();
  }

  // replace all placeholders by RegExp
  var matched;
  var buf = '';
  var dummyBuf = '';
  var prevEnd = 0;
  var testDoc = method.getTestDoc();
  var regexp = sahagin.TestDocResolver.generatePlaceHolderRegExp();
  var ifFound = false;
  var insideIf = false;
  var skip = false;
  while ((matched = regexp.exec(testDoc)) !== null) {
    var variable = matched[0];
    var matchStart = matched.index;
    var matchEnd = matchStart + variable.length;
    variable = variable.substring(1, variable.length - 1); // trim head and tail braces

    if (sahagin.CommonUtils.startsWith(variable, "if:")) {
      if (insideIf) {
        // nested if is not supported yet
        throw new Error(sahagin.CommonUtils.strFormat(
            sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER_POS,
            method.getQualifiedName(), variable));
      }
      buf = buf + testDoc.substring(prevEnd, matchStart);
      ifFound = true;
      insideIf = true;
      skip = !sahagin.TestDocResolver.validateCondVariable(
          methodInvoke, variable, placeholderResolvedParentMethodArgTestDocs);
    } else if (variable == "end" && ifFound) {
      if (!insideIf) {
        throw new Error(sahagin.CommonUtils.strFormat(
            sahagin.TestDocResolver.MSG_INVALID_PLACEHOLDER_POS,
            method.getQualifiedName(), variable));
      }
      // abort matched data if skip flag is true
      if (!skip) {
        buf = buf + testDoc.substring(prevEnd, matchStart);
      }
      insideIf = false;
      skip = false;
    } else if (skip) {
      // abort matched data
    } else {
      var variableTestDoc = sahagin.TestDocResolver.methodInvokeNormalVariableTestDoc(
            methodInvoke, variable, placeholderResolvedParentMethodArgTestDocs);
      buf = buf + testDoc.substring(prevEnd, matchStart) + variableTestDoc;
    }
    prevEnd = matchEnd;
  }
  if (insideIf) {
    throw new Error(sahagin.CommonUtils.strFormat(
        sahagin.TestDocResolver.MSG_STATEMENT_NOT_CLOSED,
        method.getQualifiedName()));
  }
  buf = buf + testDoc.substring(prevEnd, testDoc.length);
  return buf.toString();
};

/**
 * Returns original source code if TestDoc is not found
 * @private
 * @param {sahagin.Code} code
 * @param {Array.<string>} placeholderResolvedParentMethodArgTestDocs
 * @returns {string}
 */
sahagin.TestDocResolver.methodTestDocSub = function(
    code, placeholderResolvedParentMethodArgTestDocs) {
  if (code instanceof sahagin.StringCode) {
    return code.getValue();
  } else if (code instanceof sahagin.MethodArgument) {
    var methodArg = code;
    return placeholderResolvedParentMethodArgTestDocs[methodArg.getArgIndex()];
  } else if (code instanceof sahagin.SubMethodInvoke) {
    var methodInvoke = code;
    return sahagin.TestDocResolver.methodInvokeTestDoc(
        methodInvoke, placeholderResolvedParentMethodArgTestDocs);
  } else if (code instanceof sahagin.LocalVar) {
    var localVar = code;
    // TODO implement locale handling logic.. very poor logic..
    return sahagin.CommonUtils.strFormat(sahagin.TestDocResolver.JS_LOCAL_VAR,
        localVar.getName());
  } else if (code instanceof sahagin.LocalVarAssign) {
    var assign = code;
    var valueTestDoc = sahagin.TestDocResolver.methodTestDocSub(
        assign.getValue(), placeholderResolvedParentMethodArgTestDocs);
    // TODO implement locale handling logic.. very poor logic..
    return sahagin.CommonUtils.strFormat(sahagin.TestDocResolver.JS_LOCAL_VAR_ASSIGN,
        assign.getName(), valueTestDoc);
  } else {
    return code.getOriginal();
  }
};

/**
 * @param {sahagin.Code} code
 * @param {Array.<string>} placeholderResolvedParentMethodArgTestDocs
 * @returns {Array.<string>}
 */
sahagin.TestDocResolver.placeholderResolvedMethodArgTestDocs = function(
    code, placeholderResolvedParentMethodArgTestDocs) {
  if (!(code instanceof sahagin.SubMethodInvoke)) {
    return new Array();
  }
  var methodInvoke = code;
  var result = new Array();
  for (var i = 0; i < methodInvoke.getArgs().length; i++) {
    var code = methodInvoke.getArgs()[i];
    var argStr = sahagin.TestDocResolver.methodTestDocSub(
        code, placeholderResolvedParentMethodArgTestDocs);
    result.push(argStr);
  }
  return result;
};

/**
 * @param {sahagin.Code} code
 * @param {Array.<string>} placeholderResolvedParentMethodArgTestDocs
 * @returns {string}
 */
sahagin.TestDocResolver.placeholderResolvedMethodTestDoc = function(
    code, placeholderResolvedParentMethodArgTestDocs) {
  if (code instanceof sahagin.UnknownCode) {
    return null; // TestDoc for UnknownCode is null
  } else {
    return sahagin.TestDocResolver.methodTestDocSub(
        code, placeholderResolvedParentMethodArgTestDocs);
  }
};

/**
 * returns null if Page not found
 * @private
 * @param {sahagin.SubMethodInvoke} methodInvoke
 * @returns {string}
 */
sahagin.TestDocResolver.methodInvokePageTestDocNoRecursive = function(methodInvoke) {
  if (!(methodInvoke.getSubMethod().getTestClass() instanceof sahagin.PageClass)) {
    return null;
  }
  var page = methodInvoke.getSubMethod().getTestClass();
  return page.getTestDoc();
};

/**
 * Returns first found page testDoc.
 * returns null if page testDoc not found
 * @private
 * @param {sahagin.SubMethodInvoke} methodInvoke
 * @returns {string}
 */
sahagin.TestDocResolver.methodInvokePageTestDocRecursive = function(methodInvoke) {
  var pageTestDoc = sahagin.TestDocResolver.methodInvokePageTestDocNoRecursive(methodInvoke);
  if (pageTestDoc != null) {
    return pageTestDoc;
  }
  for (var i = 0; i < methodInvoke.getArgs().length; i++) {
    var code = methodInvoke.getArgs()[i];
    if (code && code instanceof sahagin.SubMethodInvoke) {
      var codeLinePageTestDoc
      = sahagin.TestDocResolver.methodInvokePageTestDocRecursive(code);
      if (codeLinePageTestDoc != null) {
        return codeLinePageTestDoc;
      }
    }
  }
  return null;
};

/**
 * Returns first found page testDoc.
 * returns null if page testDoc not found
 * @param {sahagin.Code} code
 * @returns {string}
 */
sahagin.TestDocResolver.pageTestDoc = function(code) {
  if (!(code instanceof sahagin.SubMethodInvoke)) {
    return null;
  }
  var invoke = code;
  return sahagin.TestDocResolver.methodInvokePageTestDocRecursive(invoke);
};<|endoftext|>


<commit_before>#!/usr/bin/env node
const _ = require('lodash')
const historyData = require('./historyData')
const DateTime = require('dateutils').DateTime
var DateFormat = require('dateutils').DateFormat
var DateLocale = require('dateutils').DateLocale
const format = require('../format')
const rates = require('../rates')
var historyHtml = require('./history.html')
const times = _.range(60, 230, 5).map(format.formatIsoTime)

module.exports = {
    historyResponse:    historyResponse,
    availabilityByDate: availabilityByDate,
    weeklyAvailability: getWeeklyAvailability,
    getRates:           getRates
}

function historyResponse(req, res) {
    const location = req.query.location
    var historyData = availabilityByDate()
    var today = new DateTime()
    const days = 70
    var firstDate = today.minusDays(days)
    var dates = _.range(1, days).map(num=>firstDate.plusDays(num)).map(date=>({
        dateTime:      date,
        formattedDate: DateFormat.format(date, 'D j.n', DateLocale.FI)
    }))
    const weeklyAvailability = getWeeklyAvailability()
    const rates = getRates()
    res.send(historyHtml({
        times:                   times,
        dates:                   dates,
        weeklyAvailability:      weeklyAvailability,
        rates:                   rates,
        location:                location,
        _:                       _,
        findAvailabilityForDate: findAvailabilityForDate
    }))

    function findAvailabilityForDate(date, time) {
        return _.get(_.find(historyData, row=> row.dateTime === date.toISODateString() + 'T' + time), 'available', [])
    }
}

function availabilityByDate() {
    return groupByDate(historyData)
}

function groupByDate(data) {
    return _.map(_.groupBy(data.map(mapData), 'dateTime'), (v, k) => ({
        dateTime:  k,
        available: _.map(_.groupBy(v, 'location'), (v, k)=>({location: k, available: v.length}))
    })).sort((a, b) => a.dateTime > b.dateTime ? 1 : -1)
}

function mapData(res) {
    const dateTimeStr = res.date + 'T' + res.time
    const dateTime = DateTime.fromIsoDateTime(dateTimeStr)
    return {
        dateTime:    dateTimeStr,
        time:        res.time, //'22:00',
        date:        res.date,// '2015-12-08',
        location:    res.location,//'taivallahti',
        type:        res.type,//'indoor',
        price:       res.price,//24,
        dateTimeObj: dateTime,
        weekDay:     dateTime.getDay()
    }
}

var timesObj = {}
times.forEach(time=>timesObj[time] = 0)

function getWeeklyAvailability() {
    return _.map(_.groupBy(historyData.map(mapData), 'weekDay'), (availableForWeekday) => {
        const dates = Object.keys(_.groupBy(availableForWeekday, 'date'))
        const availablePerTime = _.groupBy(availableForWeekday, 'time')
        return times.map(time=> time in availablePerTime ? availablePerTime[time].length / dates.length : 0)
    })
}

function getRates() {
    return {
        locations: _.map(rates, (ratesPerTime, location) => location),
        prices:    _.map(rates, ratesPerTime => _.flatten(_.zip.apply(_, _.map(_.get(ratesPerTime, 'indoor', ratesPerTime)))))
    }
}
<commit_msg>Count number of date rows dynamically<commit_after>#!/usr/bin/env node
const _ = require('lodash')
const historyData = require('./historyData')
const DateTime = require('dateutils').DateTime
var DateFormat = require('dateutils').DateFormat
var DateLocale = require('dateutils').DateLocale
const format = require('../format')
const rates = require('../rates')
var historyHtml = require('./history.html')
const times = _.range(60, 230, 5).map(format.formatIsoTime)

module.exports = {
    historyResponse:    historyResponse,
    availabilityByDate: availabilityByDate,
    weeklyAvailability: getWeeklyAvailability,
    getRates:           getRates
}

function historyResponse(req, res) {
    const location = req.query.location
    var historyData = availabilityByDate()
    const sortedDates = historyData.map(x=>x.dateTime)
    const firstDate = DateTime.fromIsoDateTime(_.first(sortedDates))
    const lastDate = DateTime.fromIsoDateTime(_.last(sortedDates))
    var days = firstDate.distanceInDays(lastDate)
    var dates = _.range(0, days + 1).map(num=>firstDate.plusDays(num)).map(date=>({
        dateTime:      date,
        formattedDate: DateFormat.format(date, 'D j.n', DateLocale.FI)
    }))
    const weeklyAvailability = getWeeklyAvailability()
    const rates = getRates()
    res.send(historyHtml({
        times:                   times,
        dates:                   dates,
        weeklyAvailability:      weeklyAvailability,
        rates:                   rates,
        location:                location,
        _:                       _,
        findAvailabilityForDate: findAvailabilityForDate
    }))

    function findAvailabilityForDate(date, time) {
        return _.get(_.find(historyData, row=> row.dateTime === date.toISODateString() + 'T' + time), 'available', [])
    }
}

function availabilityByDate() {
    return groupByDate(historyData)
}

function groupByDate(data) {
    return _.map(_.groupBy(data.map(mapData), 'dateTime'), (v, k) => ({
        dateTime:  k,
        available: _.map(_.groupBy(v, 'location'), (v, k)=>({location: k, available: v.length}))
    })).sort((a, b) => a.dateTime > b.dateTime ? 1 : -1)
}

function mapData(res) {
    const dateTimeStr = res.date + 'T' + res.time
    const dateTime = DateTime.fromIsoDateTime(dateTimeStr)
    return {
        dateTime:    dateTimeStr,
        time:        res.time, //'22:00',
        date:        res.date,// '2015-12-08',
        location:    res.location,//'taivallahti',
        type:        res.type,//'indoor',
        price:       res.price,//24,
        dateTimeObj: dateTime,
        weekDay:     dateTime.getDay()
    }
}

var timesObj = {}
times.forEach(time=>timesObj[time] = 0)

function getWeeklyAvailability() {
    return _.map(_.groupBy(historyData.map(mapData), 'weekDay'), (availableForWeekday) => {
        const dates = Object.keys(_.groupBy(availableForWeekday, 'date'))
        const availablePerTime = _.groupBy(availableForWeekday, 'time')
        return times.map(time=> time in availablePerTime ? availablePerTime[time].length / dates.length : 0)
    })
}

function getRates() {
    return {
        locations: _.map(rates, (ratesPerTime, location) => location),
        prices:    _.map(rates, ratesPerTime => _.flatten(_.zip.apply(_, _.map(_.get(ratesPerTime, 'indoor', ratesPerTime)))))
    }
}
<|endoftext|>


<commit_before>import { getInheritedDescriptor } from 'lowclass/utils'
import { dashCase, empty, keys, unique, pick } from './utils'

export function normalizeAttributeDefinition(name, prop) {
    const { attribute } = prop
    const obj =
        typeof attribute === 'object'
            ? { ...attribute }
            : { source: attribute, target: attribute }
    if (obj.source === true) {
        obj.source = dashCase(name)
    }
    if (obj.target === true) {
        obj.target = dashCase(name)
    }
    return obj
}

function identity(v) {
    return v
}

export function normalizePropertyDefinition(name, prop) {
    const { coerce, default: def, deserialize, serialize } = prop
    return {
        attribute: normalizeAttributeDefinition(name, prop),
        coerce: coerce || identity,
        default: typeof def === 'function' ? def : () => def,
        deserialize: deserialize || identity,
        serialize: serialize || identity
    }
}

const defaultTypesMap = new Map()

function defineProps(constructor) {
    if (constructor.hasOwnProperty('_propsNormalized')) return
    const { props } = constructor
    constructor._propsList = []
    keys(props).forEach(name => {
        let func = props[name] || props.any
        if (defaultTypesMap.has(func)) func = defaultTypesMap.get(func)
        if (typeof func !== 'function') func = prop(func)
        func({ constructor }, name)
        constructor._propsList.push(name)
    })
}

function delay(fn) {
    if (window.Promise) {
        Promise.resolve().then(fn)
    } else {
        setTimeout(fn)
    }
}

export function prop(definition) {
    const propertyDefinition = definition || {}

    // Allows decorators, or imperative definitions.
    const func = function({ constructor }, name) {
        const normalized = normalizePropertyDefinition(name, propertyDefinition)

        // Ensure that we can cache properties. We have to do this so the _props object literal doesn't modify parent
        // classes or share the instance anywhere where it's not intended to be shared explicitly in userland code.
        if (!constructor.hasOwnProperty('_propsNormalized')) {
            constructor._propsNormalized = {}
        }

        // Cache the value so we can reference when syncing the attribute to the property.
        constructor._propsNormalized[name] = normalized
        const {
            attribute: { source, target }
        } = normalized

        if (source) {
            constructor._observedAttributes.push(source)
            constructor._attributeToPropertyMap[source] = name
            if (source !== target) {
                constructor._attributeToAttributeMap[source] = target
            }
        }

        // the returned descriptor contains an "owner" property which is the
        // prototype object on which the descriptor was found.
        const existingDescriptor = getInheritedDescriptor(
            constructor.prototype,
            name
        )

        let existingDescriptorType
        let existingGetter
        let existingSetter

        // if the current constructor already inherits the prop accessor, we
        // don't need to re-define it.
        if (
            existingDescriptor &&
            existingDescriptor.owner.constructor &&
            existingDescriptor.owner.constructor._propsNormalized &&
            existingDescriptor.owner.constructor._propsNormalized[name]
        )
            return

        if (existingDescriptor) {
            if (!existingDescriptor.configurable) {
                console.error(
                    `Unable to create reactivity for prop "${name}" because existing descriptor is non-configurable.`
                )
                return
            }

            existingDescriptorType =
                'value' in existingDescriptor ? 'data' : 'accessor'

            if (existingDescriptorType === 'data') {
                // in case there's existing properties on a contructor's prototype
                // before we overwrite the descriptor. we store those values in this
                // cache so we can use them as initial values.
                if (!constructor.__existingPrototypeValues)
                    constructor.__existingPrototypeValues = {}

                constructor.__existingPrototypeValues[name] =
                    existingDescriptor.value
            } else if (existingDescriptorType === 'accessor') {
                existingGetter = existingDescriptor.get
                existingSetter = existingDescriptor.set
            }
        } else {
            // if there's no descriptor, we want to use the logic associaated
            // with data descriptors
            existingDescriptorType = 'data'
        }

        const newDescriptor = {
            enumerable: existingDescriptor
                ? existingDescriptor.enumerable
                : undefined,
            configurable: true,
            get:
                existingDescriptorType === 'accessor' && !existingGetter
                    ? undefined
                    : newGetter,
            set:
                existingDescriptorType === 'accessor' && !existingSetter
                    ? undefined
                    : newSetter
        }

        Object.defineProperty(constructor.prototype, name, newDescriptor)

        function newGetter() {
            let val

            if (existingDescriptorType === 'accessor' && existingGetter)
                val = existingGetter.call(this)
            else if (existingDescriptorType === 'data') val = this._props[name]

            if (val == null) {
                val = normalized.default.call(this, name)

                if (existingDescriptorType === 'accessor' && existingSetter)
                    existingSetter.call(this, val)
                else if (existingDescriptorType === 'data')
                    this._props[name] = val
            }

            return val
        }

        function newSetter(val) {
            const {
                attribute: { target },
                serialize,
                coerce
            } = normalized

            if (target) {
                const serializedVal = serialize.call(this, val, name)

                if (serializedVal == null) {
                    this.removeAttribute(target)
                } else {
                    this.setAttribute(target, serializedVal)
                }
            }

            val = coerce.call(this, val, name)

            if (existingDescriptorType === 'accessor' && existingSetter)
                existingSetter.call(this, val)
            else if (existingDescriptorType === 'data') this._props[name] = val

            this._modifiedProps[name] = true
            this.triggerUpdate()
        }
    }

    // Allows easy extension of pre-defined props, f.e. { ...props.number, default: 42 }.
    Object.keys(propertyDefinition).forEach(
        key => (func[key] = propertyDefinition[key])
    )

    return func
}

export const WithUpdate = (Base = HTMLElement) =>
    class WithUpdate extends Base {
        static get props() {
            if (!this._props) this._props = {}
            return this._props
        }

        static set props(props) {
            this._props = props
        }

        static get observedAttributes() {
            // make sure to create a new instance of these static props per constructor.
            if (!('_attributeToAttributeMap' in this))
                this._attributeToAttributeMap = {}
            if (!('_attributeToPropertyMap' in this))
                this._attributeToPropertyMap = {}
            if (!('_observedAttributes' in this)) this._observedAttributes = []

            // We have to define props here because observedAttributes are retrieved
            // only once when the custom element is defined. If we did this only in
            // the constructor, then props would not link to attributes.
            defineProps(this)
            return unique(
                this._observedAttributes.concat(super.observedAttributes || [])
            )
        }

        constructor(...args) {
            super(...args)

            this._prevProps = {}

            // this._props extends from __existingPrototypeValues in case we
            // overwrote a prototype property that had an existing value during
            // definition of the props. This ensures we get the original
            // prototype value when we read from a prop that we haven't set yet.
            this._props = {
                ...(this.constructor.__existingPrototypeValues || {})
            }

            this._modifiedProps = {}
        }

        get props() {
            return pick(this, keys(this.constructor.props))
        }

        set props(props) {
            const ctorProps = this.constructor.props
            keys(props).forEach(k => k in ctorProps && (this[k] = props[k]))
        }

        attributeChangedCallback(name, oldValue, newValue) {
            const {
                _attributeToAttributeMap,
                _attributeToPropertyMap,
                _propsNormalized
            } = this.constructor

            if (super.attributeChangedCallback) {
                super.attributeChangedCallback(name, oldValue, newValue)
            }

            const propertyName = _attributeToPropertyMap[name]
            if (propertyName) {
                const propertyDefinition = _propsNormalized[propertyName]
                if (propertyDefinition) {
                    const {
                        default: defaultValue,
                        deserialize
                    } = propertyDefinition
                    const propertyValue = deserialize
                        ? deserialize.call(this, newValue, propertyName)
                        : newValue
                    this._props[propertyName] =
                        propertyValue == null
                            ? defaultValue.call(this)
                            : propertyValue
                    this._modifiedProps[propertyName] = true
                    this.triggerUpdate()
                }
            }

            const targetAttributeName = _attributeToAttributeMap[name]
            if (targetAttributeName) {
                if (newValue == null) {
                    this.removeAttribute(targetAttributeName)
                } else {
                    this.setAttribute(targetAttributeName, newValue)
                }
            }
        }

        connectedCallback() {
            if (super.connectedCallback) {
                super.connectedCallback()
            }
            const propsList = this.constructor._propsList
            for (let i = 0, l = propsList.length; i < l; i += 1)
                this._modifiedProps[propsList[i]] = true
            this.triggerUpdate()
        }

        shouldUpdate() {
            return true
        }

        triggerUpdate() {
            if (this._updating) {
                return
            }
            this._updating = true
            delay(() => {
                const { _prevProps, _modifiedProps } = this
                if (this.updating) {
                    this.updating(_prevProps, _modifiedProps)
                }
                if (
                    this.updated &&
                    this.shouldUpdate(_prevProps, _modifiedProps)
                ) {
                    this.updated(_prevProps, _modifiedProps)
                }
                this._prevProps = this.props
                const propsList = this.constructor._propsList
                for (let i = 0, l = propsList.length; i < l; i += 1)
                    this._modifiedProps[propsList[i]] = false
                this._updating = false
            })
        }
    }

const { parse, stringify } = JSON
const attribute = Object.freeze({ source: true })
const zeroOrNumber = val => (empty(val) ? 0 : Number(val))

const any = prop({
    attribute
})

const array = prop({
    attribute,
    coerce: val => (Array.isArray(val) ? val : empty(val) ? null : [val]),
    default: Object.freeze([]),
    deserialize: parse,
    serialize: val => (val == null ? null : stringify(val))
})

const boolean = prop({
    attribute,
    coerce: Boolean,
    default: false,
    deserialize: val => !empty(val),
    serialize: val => (val ? '' : null)
})

const number = prop({
    attribute,
    default: 0,
    coerce: zeroOrNumber,
    deserialize: zeroOrNumber,
    serialize: val => (empty(val) ? null : String(Number(val)))
})

const object = prop({
    attribute,
    default: Object.freeze({}),
    deserialize: parse,
    serialize: val => (val == null ? null : stringify(val))
})

const string = prop({
    attribute,
    default: '',
    coerce: String,
    serialize: val => (empty(val) ? null : String(val))
})

defaultTypesMap.set(Array, array)
defaultTypesMap.set(Boolean, boolean)
defaultTypesMap.set(Number, number)
defaultTypesMap.set(Object, object)
defaultTypesMap.set(String, string)

export const props = {
    any,
    array,
    boolean,
    number,
    object,
    string
}
<commit_msg>allow WithUpdate.props setter to set any property on instances of WithUpdate. This fixes an issue where prop values passed into element constructors were not set onto the element instances, causing Behaviors not to see initial values of those props<commit_after>import { getInheritedDescriptor } from 'lowclass/utils'
import { dashCase, empty, keys, unique, pick } from './utils'

export function normalizeAttributeDefinition(name, prop) {
    const { attribute } = prop
    const obj =
        typeof attribute === 'object'
            ? { ...attribute }
            : { source: attribute, target: attribute }
    if (obj.source === true) {
        obj.source = dashCase(name)
    }
    if (obj.target === true) {
        obj.target = dashCase(name)
    }
    return obj
}

function identity(v) {
    return v
}

export function normalizePropertyDefinition(name, prop) {
    const { coerce, default: def, deserialize, serialize } = prop
    return {
        attribute: normalizeAttributeDefinition(name, prop),
        coerce: coerce || identity,
        default: typeof def === 'function' ? def : () => def,
        deserialize: deserialize || identity,
        serialize: serialize || identity
    }
}

const defaultTypesMap = new Map()

function defineProps(constructor) {
    if (constructor.hasOwnProperty('_propsNormalized')) return
    const { props } = constructor
    constructor._propsList = []
    keys(props).forEach(name => {
        let func = props[name] || props.any
        if (defaultTypesMap.has(func)) func = defaultTypesMap.get(func)
        if (typeof func !== 'function') func = prop(func)
        func({ constructor }, name)
        constructor._propsList.push(name)
    })
}

function delay(fn) {
    if (window.Promise) {
        Promise.resolve().then(fn)
    } else {
        setTimeout(fn)
    }
}

export function prop(definition) {
    const propertyDefinition = definition || {}

    // Allows decorators, or imperative definitions.
    const func = function({ constructor }, name) {
        const normalized = normalizePropertyDefinition(name, propertyDefinition)

        // Ensure that we can cache properties. We have to do this so the _props object literal doesn't modify parent
        // classes or share the instance anywhere where it's not intended to be shared explicitly in userland code.
        if (!constructor.hasOwnProperty('_propsNormalized')) {
            constructor._propsNormalized = {}
        }

        // Cache the value so we can reference when syncing the attribute to the property.
        constructor._propsNormalized[name] = normalized
        const {
            attribute: { source, target }
        } = normalized

        if (source) {
            constructor._observedAttributes.push(source)
            constructor._attributeToPropertyMap[source] = name
            if (source !== target) {
                constructor._attributeToAttributeMap[source] = target
            }
        }

        // the returned descriptor contains an "owner" property which is the
        // prototype object on which the descriptor was found.
        const existingDescriptor = getInheritedDescriptor(
            constructor.prototype,
            name
        )

        let existingDescriptorType
        let existingGetter
        let existingSetter

        // if the current constructor already inherits the prop accessor, we
        // don't need to re-define it.
        if (
            existingDescriptor &&
            existingDescriptor.owner.constructor &&
            existingDescriptor.owner.constructor._propsNormalized &&
            existingDescriptor.owner.constructor._propsNormalized[name]
        )
            return

        if (existingDescriptor) {
            if (!existingDescriptor.configurable) {
                console.error(
                    `Unable to create reactivity for prop "${name}" because existing descriptor is non-configurable.`
                )
                return
            }

            existingDescriptorType =
                'value' in existingDescriptor ? 'data' : 'accessor'

            if (existingDescriptorType === 'data') {
                // in case there's existing properties on a contructor's prototype
                // before we overwrite the descriptor. we store those values in this
                // cache so we can use them as initial values.
                if (!constructor.__existingPrototypeValues)
                    constructor.__existingPrototypeValues = {}

                constructor.__existingPrototypeValues[name] =
                    existingDescriptor.value
            } else if (existingDescriptorType === 'accessor') {
                existingGetter = existingDescriptor.get
                existingSetter = existingDescriptor.set
            }
        } else {
            // if there's no descriptor, we want to use the logic associaated
            // with data descriptors
            existingDescriptorType = 'data'
        }

        const newDescriptor = {
            enumerable: existingDescriptor
                ? existingDescriptor.enumerable
                : undefined,
            configurable: true,
            get:
                existingDescriptorType === 'accessor' && !existingGetter
                    ? undefined
                    : newGetter,
            set:
                existingDescriptorType === 'accessor' && !existingSetter
                    ? undefined
                    : newSetter
        }

        Object.defineProperty(constructor.prototype, name, newDescriptor)

        function newGetter() {
            let val

            if (existingDescriptorType === 'accessor' && existingGetter)
                val = existingGetter.call(this)
            else if (existingDescriptorType === 'data') val = this._props[name]

            if (val == null) {
                val = normalized.default.call(this, name)

                if (existingDescriptorType === 'accessor' && existingSetter)
                    existingSetter.call(this, val)
                else if (existingDescriptorType === 'data')
                    this._props[name] = val
            }

            return val
        }

        function newSetter(val) {
            const {
                attribute: { target },
                serialize,
                coerce
            } = normalized

            if (target) {
                const serializedVal = serialize.call(this, val, name)

                if (serializedVal == null) {
                    this.removeAttribute(target)
                } else {
                    this.setAttribute(target, serializedVal)
                }
            }

            val = coerce.call(this, val, name)

            if (existingDescriptorType === 'accessor' && existingSetter)
                existingSetter.call(this, val)
            else if (existingDescriptorType === 'data') this._props[name] = val

            this._modifiedProps[name] = true
            this.triggerUpdate()
        }
    }

    // Allows easy extension of pre-defined props, f.e. { ...props.number, default: 42 }.
    Object.keys(propertyDefinition).forEach(
        key => (func[key] = propertyDefinition[key])
    )

    return func
}

export const WithUpdate = (Base = HTMLElement) =>
    class WithUpdate extends Base {
        static get props() {
            if (!this._props) this._props = {}
            return this._props
        }

        static set props(props) {
            this._props = props
        }

        static get observedAttributes() {
            // make sure to create a new instance of these static props per constructor.
            if (!('_attributeToAttributeMap' in this))
                this._attributeToAttributeMap = {}
            if (!('_attributeToPropertyMap' in this))
                this._attributeToPropertyMap = {}
            if (!('_observedAttributes' in this)) this._observedAttributes = []

            // We have to define props here because observedAttributes are retrieved
            // only once when the custom element is defined. If we did this only in
            // the constructor, then props would not link to attributes.
            defineProps(this)
            return unique(
                this._observedAttributes.concat(super.observedAttributes || [])
            )
        }

        constructor(...args) {
            super(...args)

            this._prevProps = {}

            // this._props extends from __existingPrototypeValues in case we
            // overwrote a prototype property that had an existing value during
            // definition of the props. This ensures we get the original
            // prototype value when we read from a prop that we haven't set yet.
            this._props = {
                ...(this.constructor.__existingPrototypeValues || {})
            }

            this._modifiedProps = {}
        }

        get props() {
            return pick(this, keys(this.constructor.props))
        }

        set props(props) {
            const ctorProps = this.constructor.props
            keys(props).forEach(
                k => /*k in ctorProps && */ (this[k] = props[k])
            )
        }

        attributeChangedCallback(name, oldValue, newValue) {
            const {
                _attributeToAttributeMap,
                _attributeToPropertyMap,
                _propsNormalized
            } = this.constructor

            if (super.attributeChangedCallback) {
                super.attributeChangedCallback(name, oldValue, newValue)
            }

            const propertyName = _attributeToPropertyMap[name]
            if (propertyName) {
                const propertyDefinition = _propsNormalized[propertyName]
                if (propertyDefinition) {
                    const {
                        default: defaultValue,
                        deserialize
                    } = propertyDefinition
                    const propertyValue = deserialize
                        ? deserialize.call(this, newValue, propertyName)
                        : newValue
                    this._props[propertyName] =
                        propertyValue == null
                            ? defaultValue.call(this)
                            : propertyValue
                    this._modifiedProps[propertyName] = true
                    this.triggerUpdate()
                }
            }

            const targetAttributeName = _attributeToAttributeMap[name]
            if (targetAttributeName) {
                if (newValue == null) {
                    this.removeAttribute(targetAttributeName)
                } else {
                    this.setAttribute(targetAttributeName, newValue)
                }
            }
        }

        connectedCallback() {
            if (super.connectedCallback) {
                super.connectedCallback()
            }
            const propsList = this.constructor._propsList
            for (let i = 0, l = propsList.length; i < l; i += 1)
                this._modifiedProps[propsList[i]] = true
            this.triggerUpdate()
        }

        shouldUpdate() {
            return true
        }

        triggerUpdate() {
            if (this._updating) {
                return
            }
            this._updating = true
            delay(() => {
                const { _prevProps, _modifiedProps } = this
                if (this.updating) {
                    this.updating(_prevProps, _modifiedProps)
                }
                if (
                    this.updated &&
                    this.shouldUpdate(_prevProps, _modifiedProps)
                ) {
                    this.updated(_prevProps, _modifiedProps)
                }
                this._prevProps = this.props
                const propsList = this.constructor._propsList
                for (let i = 0, l = propsList.length; i < l; i += 1)
                    this._modifiedProps[propsList[i]] = false
                this._updating = false
            })
        }
    }

const { parse, stringify } = JSON
const attribute = Object.freeze({ source: true })
const zeroOrNumber = val => (empty(val) ? 0 : Number(val))

const any = prop({
    attribute
})

const array = prop({
    attribute,
    coerce: val => (Array.isArray(val) ? val : empty(val) ? null : [val]),
    default: Object.freeze([]),
    deserialize: parse,
    serialize: val => (val == null ? null : stringify(val))
})

const boolean = prop({
    attribute,
    coerce: Boolean,
    default: false,
    deserialize: val => !empty(val),
    serialize: val => (val ? '' : null)
})

const number = prop({
    attribute,
    default: 0,
    coerce: zeroOrNumber,
    deserialize: zeroOrNumber,
    serialize: val => (empty(val) ? null : String(Number(val)))
})

const object = prop({
    attribute,
    default: Object.freeze({}),
    deserialize: parse,
    serialize: val => (val == null ? null : stringify(val))
})

const string = prop({
    attribute,
    default: '',
    coerce: String,
    serialize: val => (empty(val) ? null : String(val))
})

defaultTypesMap.set(Array, array)
defaultTypesMap.set(Boolean, boolean)
defaultTypesMap.set(Number, number)
defaultTypesMap.set(Object, object)
defaultTypesMap.set(String, string)

export const props = {
    any,
    array,
    boolean,
    number,
    object,
    string
}
<|endoftext|>


<commit_before>import pageIcon from 'page-icon';
import path from 'path';
import fs from 'fs';
import tmp from 'tmp';
import gitCloud from 'gitcloud';
import helpers from './../helpers/helpers';

const {downloadFile, allowedIconFormats} = helpers;
tmp.setGracefulCleanup();

function inferIconFromStore(targetUrl, platform) {
    const allowedFormats = allowedIconFormats(platform);

    return gitCloud('http://jiahaog.com/nativefier-icons/')
        .then(fileIndex => {
            const matchingIcons = fileIndex
                .filter(item => {
                    // todo might have problems with matching length, e.g. `book` vs `facebook`
                    return targetUrl
                        .toLowerCase()
                        .includes(item.name);
                })
                .map(item => {
                    item.ext = path.extname(item.url);
                    return item;
                });

            let matchingUrl;
            for (let format of allowedFormats) {
                for (let icon of matchingIcons) {
                    if (icon.ext !== format) {
                        continue;
                    }
                    matchingUrl = icon.url;
                }
            }

            if (!matchingUrl) {
                return null;
            }
            return downloadFile(matchingUrl);
        });
}

function writeFilePromise(outPath, data) {
    return new Promise((resolve, reject) => {
        fs.writeFile(outPath, data, error => {
            if (error) {
                reject(error);
                return;
            }
            resolve(outPath);
        });
    });
}

function inferFromPage(targetUrl, platform, outDir) {
    let preferredExt = '.png';
    if (platform === 'win32') {
        preferredExt = '.ico';
    }

    // todo might want to pass list of preferences instead
    return pageIcon(targetUrl, {ext: preferredExt})
        .then(icon => {
            if (!icon) {
                return null;
            }

            const outfilePath = path.join(outDir, `/icon${icon.ext}`);
            return writeFilePromise(outfilePath, icon.data);
        });
}
/**
 *
 * @param {string} targetUrl
 * @param {string} platform
 * @param {string} outDir
 */
function inferIconFromUrlToPath(targetUrl, platform, outDir) {

    return inferIconFromStore(targetUrl, platform)
        .then(icon => {
            if (!icon) {
                return inferFromPage(targetUrl, platform, outDir);
            }

            const outfilePath = path.join(outDir, `/icon${icon.ext}`);
            return writeFilePromise(outfilePath, icon.data);
        });
}

/**
 * @param {string} targetUrl
 * @param {string} platform
 */
function inferIcon(targetUrl, platform) {
    const tmpObj = tmp.dirSync({unsafeCleanup: true});
    const tmpPath = tmpObj.name;
    return inferIconFromUrlToPath(targetUrl, platform, tmpPath);
}

export default inferIcon;
<commit_msg>Allow gitcloud matching of icons for multiple words<commit_after>import pageIcon from 'page-icon';
import path from 'path';
import fs from 'fs';
import tmp from 'tmp';
import gitCloud from 'gitcloud';
import helpers from './../helpers/helpers';

const {downloadFile, allowedIconFormats} = helpers;
tmp.setGracefulCleanup();

const GITCLOUD_SPACE_DELIMITER = '-';

function inferIconFromStore(targetUrl, platform) {
    const allowedFormats = allowedIconFormats(platform);

    return gitCloud('http://jiahaog.com/nativefier-icons/')
        .then(fileIndex => {
            const iconWithScores = mapIconWithMatchScore(fileIndex, targetUrl);
            const maxScore = getMaxMatchScore(iconWithScores);

            if (maxScore === 0) {
                return null;
            }

            const matchingIcons = getMatchingIcons(iconWithScores, maxScore);

            let matchingUrl;
            for (let format of allowedFormats) {
                for (let icon of matchingIcons) {
                    if (icon.ext !== format) {
                        continue;
                    }
                    matchingUrl = icon.url;
                }
            }

            if (!matchingUrl) {
                return null;
            }
            return downloadFile(matchingUrl);
        });
}

function mapIconWithMatchScore(fileIndex, targetUrl) {
    const normalisedTargetUrl = targetUrl.toLowerCase();
    return fileIndex
        .map(item => {
            const itemWords = item.name.split(GITCLOUD_SPACE_DELIMITER);
            const score = itemWords.reduce((currentScore, word) => {
                if (normalisedTargetUrl.includes(word)) {
                    return currentScore + 1;
                }
                return currentScore;
            }, 0);

            return Object.assign({},
                item,
                {score}
            );
        });
}

function getMaxMatchScore(iconWithScores) {
    return iconWithScores.reduce((maxScore, currentIcon) => {
        const currentScore = currentIcon.score;
        if (currentScore > maxScore) {
            return currentScore;
        }
        return maxScore;
    }, 0);
}

/**
 * also maps ext to icon object
 */
function getMatchingIcons(iconWithScores, maxScore) {
    return iconWithScores
        .filter(item => {
            return item.score === maxScore;
        })
        .map(item => {
            return Object.assign(
                {},
                item,
                {ext: path.extname(item.url)}
            );
        });
}

function writeFilePromise(outPath, data) {
    return new Promise((resolve, reject) => {
        fs.writeFile(outPath, data, error => {
            if (error) {
                reject(error);
                return;
            }
            resolve(outPath);
        });
    });
}

function inferFromPage(targetUrl, platform, outDir) {
    let preferredExt = '.png';
    if (platform === 'win32') {
        preferredExt = '.ico';
    }

    // todo might want to pass list of preferences instead
    return pageIcon(targetUrl, {ext: preferredExt})
        .then(icon => {
            if (!icon) {
                return null;
            }

            const outfilePath = path.join(outDir, `/icon${icon.ext}`);
            return writeFilePromise(outfilePath, icon.data);
        });
}
/**
 *
 * @param {string} targetUrl
 * @param {string} platform
 * @param {string} outDir
 */
function inferIconFromUrlToPath(targetUrl, platform, outDir) {

    return inferIconFromStore(targetUrl, platform)
        .then(icon => {
            if (!icon) {
                return inferFromPage(targetUrl, platform, outDir);
            }

            const outfilePath = path.join(outDir, `/icon${icon.ext}`);
            return writeFilePromise(outfilePath, icon.data);
        });
}

/**
 * @param {string} targetUrl
 * @param {string} platform
 */
function inferIcon(targetUrl, platform) {
    const tmpObj = tmp.dirSync({unsafeCleanup: true});
    const tmpPath = tmpObj.name;
    return inferIconFromUrlToPath(targetUrl, platform, tmpPath);
}

export default inferIcon;
<|endoftext|>


<commit_before>const config = {
  DEBUG: false,
  dimensions: {
    width: 3900,
    height: 4300,
    roofOffset: 0,
    wallHeight: 2400,
  },
  fin: {
    frameWidth: 150,
    pointDistance: 300,
    width: 250,
    grip: {
      width: 180,
      holeWidth: 60
    },
  },
  material: {
    thickness: 18,
    height: 2440,
    width: 1220
  },
  layers: {
    labels: false,
    sheets: false
  },
  svg: {
    padding: 400,
  }
}

module.exports = config
<commit_msg>updated defaults<commit_after>const config = {
  DEBUG: true,
  dimensions: {
    width: 3900,
    height: 4300,
    roofOffset: 0,
    wallHeight: 2400
  },
  fin: {
    frameWidth: 150,
    pointDistance: 300,
    width: 250,
    grip: {
      width: 180,
      holeWidth: 60
    }
  },
  material: {
    thickness: 18,
    height: 2440,
    width: 1220
  },
  layers: {
    labels: false,
    sheets: false
  },
  svg: {
    padding: 400
  }
};

module.exports = config;
<|endoftext|>


<commit_before>'use strict';

const { omit, deepMerge } = require('../../../utilities');

// Shallow copy nested models from the `model.id` they refer to
const mergeNestedModel = function (attr, { idl: { models } }) {
  if (!attr.model) { return; }

  const [, model] = Object.entries(models)
    .find(([name, mod]) => mod.model === attr.model || name === attr.model);
  const modelId = model.properties.id;

  const modelIdA = omit(modelId, metadataProps);
  const validate = omit(modelIdA.validate, ['required']);
  const modelIdB = { ...modelIdA, validate };

  const modelIdC = deepMerge(modelIdB, attr);
  return modelIdC;
};

const metadataProps = [
  'description',
  'deprecated',
  'examples',
];

module.exports = {
  mergeNestedModel,
};
<commit_msg>Improve model nesting<commit_after>'use strict';

const { omit, deepMerge } = require('../../../utilities');

// Shallow copy nested models from the `model.id` they refer to
const mergeNestedModel = function (attr, { idl: { models } }) {
  if (!attr.model) { return; }

  const [, model] = Object.entries(models)
    .find(([name, mod]) => mod.model === attr.model || name === attr.model);
  const modelId = model.properties.id;

  const modelIdA = omit(modelId, metadataProps);
  const validate = omit(modelIdA.validate, nestedValidateProps);
  const modelIdB = { ...modelIdA, validate };

  const modelIdC = deepMerge(modelIdB, attr);
  return modelIdC;
};

// Never using target model for those properties
const metadataProps = [
  'description',
  'deprecated',
  'examples',
];

const nestedValidateProps = [
  'required',
  'dependencies',
];

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


<commit_before>const ChampionSocket       = require('../../common/socket');
const Client               = require('../../common/client');
const Utility              = require('../../common/utility');
const default_redirect_url = require('../../common/url').default_redirect_url;
const Validation           = require('../../common/validation');

const ChampionNewVirtualAccount = (function() {
    'use strict';

    const form_selector = '#frm_new_account_virtual';

    let container,
        btn_submit;

    const fields = {
        txt_verification_code: '#txt_verification_code',
        txt_password         : '#txt_password',
        txt_re_password      : '#txt_re_password',
        ddl_residence        : '#ddl_residence',
        btn_submit           : '#btn_submit',
    };

    const load = () => {
        if (Client.redirect_if_login()) return;
        container  = $('#champion-container');
        btn_submit = container.find(fields.btn_submit);
        btn_submit.on('click dblclick', submit);

        Validation.init(form_selector, [
            { selector: fields.txt_verification_code, validations: ['req', 'email_token'] },
            { selector: fields.txt_password,          validations: ['req', 'password'] },
            { selector: fields.txt_re_password,       validations: ['req', ['compare', { to: fields.txt_password }]] },
            { selector: fields.ddl_residence,         validations: ['req'] },
        ]);

        populateResidence();
    };

    const populateResidence = () => {
        ChampionSocket.send({ residence_list: 1 }).then((response) => {
            const $ddl_residence = container.find(fields.ddl_residence);
            Utility.dropDownFromObject($ddl_residence, response.residence_list);
            container.find('#residence_loading').remove();
            $ddl_residence.removeClass('hidden');
        });
    };

    const unload = () => {
        if (btn_submit) {
            btn_submit.off('click', submit);
        }
    };

    const submit = (e) => {
        e.preventDefault();
        btn_submit.attr('disabled', 'disabled');
        if (Validation.validate(form_selector)) {
            const data = {
                new_account_virtual: 1,
                verification_code  : $(fields.txt_verification_code).val(),
                client_password    : $(fields.txt_password).val(),
                residence          : $(fields.ddl_residence).val(),
            };
            if (Client.get('affiliate_token')) {
                data.affiliate_token = Client.get('affiliate_token');
            }
            ChampionSocket.send(data).then((response) => {
                if (response.error) {
                    $('#msg_form').removeClass('hidden').text(response.error.message);
                    btn_submit.removeAttr('disabled');
                } else {
                    const acc_info = response.new_account_virtual;
                    Client.process_new_account(acc_info.email, acc_info.client_id, acc_info.oauth_token, true);
                    window.location.href = default_redirect_url();
                }
            });
        }
    };

    return {
        load  : load,
        unload: unload,
    };
})();

module.exports = ChampionNewVirtualAccount;
<commit_msg>Fix button remained disabled<commit_after>const ChampionSocket       = require('../../common/socket');
const Client               = require('../../common/client');
const Utility              = require('../../common/utility');
const default_redirect_url = require('../../common/url').default_redirect_url;
const Validation           = require('../../common/validation');

const ChampionNewVirtualAccount = (function() {
    'use strict';

    const form_selector = '#frm_new_account_virtual';

    let container,
        btn_submit;

    const fields = {
        txt_verification_code: '#txt_verification_code',
        txt_password         : '#txt_password',
        txt_re_password      : '#txt_re_password',
        ddl_residence        : '#ddl_residence',
        btn_submit           : '#btn_submit',
    };

    const load = () => {
        if (Client.redirect_if_login()) return;
        container  = $('#champion-container');
        btn_submit = container.find(fields.btn_submit);
        btn_submit.on('click dblclick', submit);

        Validation.init(form_selector, [
            { selector: fields.txt_verification_code, validations: ['req', 'email_token'] },
            { selector: fields.txt_password,          validations: ['req', 'password'] },
            { selector: fields.txt_re_password,       validations: ['req', ['compare', { to: fields.txt_password }]] },
            { selector: fields.ddl_residence,         validations: ['req'] },
        ]);

        populateResidence();
    };

    const populateResidence = () => {
        ChampionSocket.send({ residence_list: 1 }).then((response) => {
            const $ddl_residence = container.find(fields.ddl_residence);
            Utility.dropDownFromObject($ddl_residence, response.residence_list);
            container.find('#residence_loading').remove();
            $ddl_residence.removeClass('hidden');
        });
    };

    const unload = () => {
        if (btn_submit) {
            btn_submit.off('click', submit);
        }
    };

    const submit = (e) => {
        e.preventDefault();
        if (Validation.validate(form_selector)) {
            btn_submit.attr('disabled', 'disabled');
            const data = {
                new_account_virtual: 1,
                verification_code  : $(fields.txt_verification_code).val(),
                client_password    : $(fields.txt_password).val(),
                residence          : $(fields.ddl_residence).val(),
            };
            if (Client.get('affiliate_token')) {
                data.affiliate_token = Client.get('affiliate_token');
            }
            ChampionSocket.send(data).then((response) => {
                if (response.error) {
                    $('#msg_form').removeClass('hidden').text(response.error.message);
                    btn_submit.removeAttr('disabled');
                } else {
                    const acc_info = response.new_account_virtual;
                    Client.process_new_account(acc_info.email, acc_info.client_id, acc_info.oauth_token, true);
                    window.location.href = default_redirect_url();
                }
            });
        }
    };

    return {
        load  : load,
        unload: unload,
    };
})();

module.exports = ChampionNewVirtualAccount;
<|endoftext|>


<commit_before>/**
 * Image.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/**
@class moxie/runtime/html5/image/Image
@private
*/
define("moxie/runtime/html5/image/Image", [
	"moxie/runtime/html5/Runtime",
	"moxie/core/utils/Basic",
	"moxie/core/Exceptions",
	"moxie/core/utils/Encode",
	"moxie/file/Blob",
	"moxie/file/File",
	"moxie/runtime/html5/image/ImageInfo",
	"moxie/runtime/html5/image/MegaPixel",
	"moxie/runtime/html5/image/ResizerCanvas",
	"moxie/runtime/html5/image/ResizerWebGL",
	"moxie/core/utils/Mime",
	"moxie/core/utils/Env"
], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, MegaPixel, ResizerCanvas, ResizerWebGL, Mime, Env) {

	function HTML5Image() {
		var me = this
		, _img, _imgInfo, _canvas, _binStr, _blob
		, _modified = false // is set true whenever image is modified
		, _preserveHeaders = true
		;

		Basic.extend(this, {
			loadFromBlob: function(blob) {
				var comp = this, I = comp.getRuntime()
				, asBinary = arguments.length > 1 ? arguments[1] : true
				;

				if (!I.can('access_binary')) {
					throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
				}

				_blob = blob;

				if (blob.isDetached()) {
					_binStr = blob.getSource();
					_preload.call(this, _binStr);
					return;
				} else {
					_readAsDataUrl.call(this, blob.getSource(), function(dataUrl) {
						if (asBinary) {
							_binStr = _toBinary(dataUrl);
						}
						_preload.call(comp, dataUrl);
					});
				}
			},

			loadFromImage: function(img, exact) {
				this.meta = img.meta;

				_blob = new File(null, {
					name: img.name,
					size: img.size,
					type: img.type
				});

				_preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL());
			},

			getInfo: function() {
				var I = this.getRuntime(), info;

				if (!_imgInfo && _binStr && I.can('access_image_binary')) {
					_imgInfo = new ImageInfo(_binStr);
				}

				info = {
					width: _getImg().width || 0,
					height: _getImg().height || 0,
					type: _blob.type || Mime.getFileMime(_blob.name),
					size: _binStr && _binStr.length || _blob.size || 0,
					name: _blob.name || '',
					meta: null
				};

				if (_preserveHeaders) {
					info.meta = _imgInfo && _imgInfo.meta || this.meta || {};

					// store thumbnail data as blob
					if (info.meta && info.meta.thumb && !(info.meta.thumb.data instanceof Blob)) {
						info.meta.thumb.data = new Blob(null, {
							type: 'image/jpeg',
							data: info.meta.thumb.data
						});
					}
				}

				return info;
			},

			resize: function(rect, scale, options) {
				var canvas = document.createElement('canvas');
				canvas.width = rect.width;
				canvas.height = rect.height;

				canvas.getContext("2d").drawImage(_getImg(), rect.x, rect.y, rect.width, rect.height, 0, 0, canvas.width, canvas.height);

				try {
					_canvas = ResizerWebGL.scale(canvas, scale);
				} catch(ex) {
					_canvas = ResizerCanvas.scale(canvas, scale);
				}

				_preserveHeaders = options.preserveHeaders;

				// rotate if required, according to orientation tag
				if (!_preserveHeaders) {
					var orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;
					_rotateToOrientaion(_canvas.width, _canvas.height, orientation);
				}

				this.width = _canvas.width;
				this.height = _canvas.height;

				_modified = true;

				this.trigger('Resize');
			},

			getAsCanvas: function() {
				if (_canvas) {
					_canvas.id = this.uid + '_canvas';
				}
				return _canvas;
			},

			getAsBlob: function(type, quality) {
				if (type !== this.type) {
					// if different mime type requested prepare image for conversion
					_downsize.call(this, this.width, this.height, false);
				}
				return new File(null, {
					name: _blob.name || '',
					type: type,
					data: me.getAsBinaryString.call(this, type, quality)
				});
			},

			getAsDataURL: function(type) {
				var quality = arguments[1] || 90;

				// if image has not been modified, return the source right away
				if (!_modified) {
					return _img.src;
				}

				if ('image/jpeg' !== type) {
					return _canvas.toDataURL('image/png');
				} else {
					try {
						// older Geckos used to result in an exception on quality argument
						return _canvas.toDataURL('image/jpeg', quality/100);
					} catch (ex) {
						return _canvas.toDataURL('image/jpeg');
					}
				}
			},

			getAsBinaryString: function(type, quality) {
				// if image has not been modified, return the source right away
				if (!_modified) {
					// if image was not loaded from binary string
					if (!_binStr) {
						_binStr = _toBinary(me.getAsDataURL(type, quality));
					}
					return _binStr;
				}

				if ('image/jpeg' !== type) {
					_binStr = _toBinary(me.getAsDataURL(type, quality));
				} else {
					var dataUrl;

					// if jpeg
					if (!quality) {
						quality = 90;
					}

					try {
						// older Geckos used to result in an exception on quality argument
						dataUrl = _canvas.toDataURL('image/jpeg', quality/100);
					} catch (ex) {
						dataUrl = _canvas.toDataURL('image/jpeg');
					}

					_binStr = _toBinary(dataUrl);

					if (_imgInfo) {
						_binStr = _imgInfo.stripHeaders(_binStr);

						if (_preserveHeaders) {
							// update dimensions info in exif
							if (_imgInfo.meta && _imgInfo.meta.exif) {
								_imgInfo.setExif({
									PixelXDimension: this.width,
									PixelYDimension: this.height
								});
							}

							// re-inject the headers
							_binStr = _imgInfo.writeHeaders(_binStr);
						}

						// will be re-created from fresh on next getInfo call
						_imgInfo.purge();
						_imgInfo = null;
					}
				}

				_modified = false;

				return _binStr;
			},

			destroy: function() {
				me = null;
				_purge.call(this);
				this.getRuntime().getShim().removeInstance(this.uid);
			}
		});

		function _getImg() {
			if (!_canvas && !_img) {
				throw new x.ImageError(x.DOMException.INVALID_STATE_ERR);
			}
			return _canvas || _img;
		}

		function _toBinary(str) {
			return Encode.atob(str.substring(str.indexOf('base64,') + 7));
		}

		function _toDataUrl(str, type) {
			return 'data:' + (type || '') + ';base64,' + Encode.btoa(str);
		}

		function _preload(str) {
			var comp = this;

			_img = new Image();
			_img.onerror = function() {
				_purge.call(this);
				comp.trigger('error', x.ImageError.WRONG_FORMAT);
			};
			_img.onload = function() {
				comp.trigger('load');
			};

			_img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type);
		}

		function _readAsDataUrl(file, callback) {
			var comp = this, fr;

			// use FileReader if it's available
			if (window.FileReader) {
				fr = new FileReader();
				fr.onload = function() {
					callback(this.result);
				};
				fr.onerror = function() {
					comp.trigger('error', x.ImageError.WRONG_FORMAT);
				};
				fr.readAsDataURL(file);
			} else {
				return callback(file.getAsDataURL());
			}
		}

		function _drawToCanvas(img, canvas, x, y, w, h) {
			if (Env.OS === 'iOS') {
				// avoid squish bug in iOS6
				MegaPixel.renderTo(img, canvas, { width: w, height: h, x: x, y: y });
			} else {
				var ctx = canvas.getContext('2d');
				ctx.drawImage(img, x, y, w, h);
			}
		}

		/**
		* Transform canvas coordination according to specified frame size and orientation
		* Orientation value is from EXIF tag
		* @author Shinichi Tomita <shinichi.tomita@gmail.com>
		*/
		function _rotateToOrientaion(width, height, orientation) {
			switch (orientation) {
				case 5:
				case 6:
				case 7:
				case 8:
					_canvas.width = height;
					_canvas.height = width;
					break;
				default:
					_canvas.width = width;
					_canvas.height = height;
			}

			/**
			1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
			2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
			3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
			4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
			5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
			6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
			7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
			8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
			*/

			var ctx = _canvas.getContext('2d');
			switch (orientation) {
				case 2:
					// horizontal flip
					ctx.translate(width, 0);
					ctx.scale(-1, 1);
					break;
				case 3:
					// 180 rotate left
					ctx.translate(width, height);
					ctx.rotate(Math.PI);
					break;
				case 4:
					// vertical flip
					ctx.translate(0, height);
					ctx.scale(1, -1);
					break;
				case 5:
					// vertical flip + 90 rotate right
					ctx.rotate(0.5 * Math.PI);
					ctx.scale(1, -1);
					break;
				case 6:
					// 90 rotate right
					ctx.rotate(0.5 * Math.PI);
					ctx.translate(0, -height);
					break;
				case 7:
					// horizontal flip + 90 rotate right
					ctx.rotate(0.5 * Math.PI);
					ctx.translate(width, -height);
					ctx.scale(-1, 1);
					break;
				case 8:
					// 90 rotate left
					ctx.rotate(-0.5 * Math.PI);
					ctx.translate(-width, 0);
					break;
			}
		}

		function _purge() {
			if (_imgInfo) {
				_imgInfo.purge();
				_imgInfo = null;
			}
			_binStr = _img = _canvas = _blob = null;
			_modified = false;
		}
	}

	return (extensions.Image = HTML5Image);
});
<commit_msg>Image, HTML5: Use ResizerCanvas only for now (ResizerWebGL fails in IE11 for some reason).<commit_after>/**
 * Image.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/**
@class moxie/runtime/html5/image/Image
@private
*/
define("moxie/runtime/html5/image/Image", [
	"moxie/runtime/html5/Runtime",
	"moxie/core/utils/Basic",
	"moxie/core/Exceptions",
	"moxie/core/utils/Encode",
	"moxie/file/Blob",
	"moxie/file/File",
	"moxie/runtime/html5/image/ImageInfo",
	"moxie/runtime/html5/image/MegaPixel",
	"moxie/runtime/html5/image/ResizerCanvas",
	"moxie/runtime/html5/image/ResizerWebGL",
	"moxie/core/utils/Mime",
	"moxie/core/utils/Env"
], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, MegaPixel, ResizerCanvas, ResizerWebGL, Mime, Env) {

	function HTML5Image() {
		var me = this
		, _img, _imgInfo, _canvas, _binStr, _blob
		, _modified = false // is set true whenever image is modified
		, _preserveHeaders = true
		;

		Basic.extend(this, {
			loadFromBlob: function(blob) {
				var comp = this, I = comp.getRuntime()
				, asBinary = arguments.length > 1 ? arguments[1] : true
				;

				if (!I.can('access_binary')) {
					throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
				}

				_blob = blob;

				if (blob.isDetached()) {
					_binStr = blob.getSource();
					_preload.call(this, _binStr);
					return;
				} else {
					_readAsDataUrl.call(this, blob.getSource(), function(dataUrl) {
						if (asBinary) {
							_binStr = _toBinary(dataUrl);
						}
						_preload.call(comp, dataUrl);
					});
				}
			},

			loadFromImage: function(img, exact) {
				this.meta = img.meta;

				_blob = new File(null, {
					name: img.name,
					size: img.size,
					type: img.type
				});

				_preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL());
			},

			getInfo: function() {
				var I = this.getRuntime(), info;

				if (!_imgInfo && _binStr && I.can('access_image_binary')) {
					_imgInfo = new ImageInfo(_binStr);
				}

				info = {
					width: _getImg().width || 0,
					height: _getImg().height || 0,
					type: _blob.type || Mime.getFileMime(_blob.name),
					size: _binStr && _binStr.length || _blob.size || 0,
					name: _blob.name || '',
					meta: null
				};

				if (_preserveHeaders) {
					info.meta = _imgInfo && _imgInfo.meta || this.meta || {};

					// store thumbnail data as blob
					if (info.meta && info.meta.thumb && !(info.meta.thumb.data instanceof Blob)) {
						info.meta.thumb.data = new Blob(null, {
							type: 'image/jpeg',
							data: info.meta.thumb.data
						});
					}
				}

				return info;
			},

			resize: function(rect, scale, options) {
				var canvas = document.createElement('canvas');
				canvas.width = rect.width;
				canvas.height = rect.height;

				canvas.getContext("2d").drawImage(_getImg(), rect.x, rect.y, rect.width, rect.height, 0, 0, canvas.width, canvas.height);

				_canvas = ResizerCanvas.scale(canvas, scale);

				_preserveHeaders = options.preserveHeaders;

				// rotate if required, according to orientation tag
				if (!_preserveHeaders) {
					var orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;
					_rotateToOrientaion(_canvas.width, _canvas.height, orientation);
				}

				this.width = _canvas.width;
				this.height = _canvas.height;

				_modified = true;

				this.trigger('Resize');
			},

			getAsCanvas: function() {
				if (_canvas) {
					_canvas.id = this.uid + '_canvas';
				}
				return _canvas;
			},

			getAsBlob: function(type, quality) {
				if (type !== this.type) {
					// if different mime type requested prepare image for conversion
					_downsize.call(this, this.width, this.height, false);
				}
				return new File(null, {
					name: _blob.name || '',
					type: type,
					data: me.getAsBinaryString.call(this, type, quality)
				});
			},

			getAsDataURL: function(type) {
				var quality = arguments[1] || 90;

				// if image has not been modified, return the source right away
				if (!_modified) {
					return _img.src;
				}

				if ('image/jpeg' !== type) {
					return _canvas.toDataURL('image/png');
				} else {
					try {
						// older Geckos used to result in an exception on quality argument
						return _canvas.toDataURL('image/jpeg', quality/100);
					} catch (ex) {
						return _canvas.toDataURL('image/jpeg');
					}
				}
			},

			getAsBinaryString: function(type, quality) {
				// if image has not been modified, return the source right away
				if (!_modified) {
					// if image was not loaded from binary string
					if (!_binStr) {
						_binStr = _toBinary(me.getAsDataURL(type, quality));
					}
					return _binStr;
				}

				if ('image/jpeg' !== type) {
					_binStr = _toBinary(me.getAsDataURL(type, quality));
				} else {
					var dataUrl;

					// if jpeg
					if (!quality) {
						quality = 90;
					}

					try {
						// older Geckos used to result in an exception on quality argument
						dataUrl = _canvas.toDataURL('image/jpeg', quality/100);
					} catch (ex) {
						dataUrl = _canvas.toDataURL('image/jpeg');
					}

					_binStr = _toBinary(dataUrl);

					if (_imgInfo) {
						_binStr = _imgInfo.stripHeaders(_binStr);

						if (_preserveHeaders) {
							// update dimensions info in exif
							if (_imgInfo.meta && _imgInfo.meta.exif) {
								_imgInfo.setExif({
									PixelXDimension: this.width,
									PixelYDimension: this.height
								});
							}

							// re-inject the headers
							_binStr = _imgInfo.writeHeaders(_binStr);
						}

						// will be re-created from fresh on next getInfo call
						_imgInfo.purge();
						_imgInfo = null;
					}
				}

				_modified = false;

				return _binStr;
			},

			destroy: function() {
				me = null;
				_purge.call(this);
				this.getRuntime().getShim().removeInstance(this.uid);
			}
		});

		function _getImg() {
			if (!_canvas && !_img) {
				throw new x.ImageError(x.DOMException.INVALID_STATE_ERR);
			}
			return _canvas || _img;
		}

		function _toBinary(str) {
			return Encode.atob(str.substring(str.indexOf('base64,') + 7));
		}

		function _toDataUrl(str, type) {
			return 'data:' + (type || '') + ';base64,' + Encode.btoa(str);
		}

		function _preload(str) {
			var comp = this;

			_img = new Image();
			_img.onerror = function() {
				_purge.call(this);
				comp.trigger('error', x.ImageError.WRONG_FORMAT);
			};
			_img.onload = function() {
				comp.trigger('load');
			};

			_img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type);
		}

		function _readAsDataUrl(file, callback) {
			var comp = this, fr;

			// use FileReader if it's available
			if (window.FileReader) {
				fr = new FileReader();
				fr.onload = function() {
					callback(this.result);
				};
				fr.onerror = function() {
					comp.trigger('error', x.ImageError.WRONG_FORMAT);
				};
				fr.readAsDataURL(file);
			} else {
				return callback(file.getAsDataURL());
			}
		}

		function _drawToCanvas(img, canvas, x, y, w, h) {
			if (Env.OS === 'iOS') {
				// avoid squish bug in iOS6
				MegaPixel.renderTo(img, canvas, { width: w, height: h, x: x, y: y });
			} else {
				var ctx = canvas.getContext('2d');
				ctx.drawImage(img, x, y, w, h);
			}
		}

		/**
		* Transform canvas coordination according to specified frame size and orientation
		* Orientation value is from EXIF tag
		* @author Shinichi Tomita <shinichi.tomita@gmail.com>
		*/
		function _rotateToOrientaion(width, height, orientation) {
			switch (orientation) {
				case 5:
				case 6:
				case 7:
				case 8:
					_canvas.width = height;
					_canvas.height = width;
					break;
				default:
					_canvas.width = width;
					_canvas.height = height;
			}

			/**
			1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
			2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
			3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
			4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
			5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
			6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
			7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
			8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
			*/

			var ctx = _canvas.getContext('2d');
			switch (orientation) {
				case 2:
					// horizontal flip
					ctx.translate(width, 0);
					ctx.scale(-1, 1);
					break;
				case 3:
					// 180 rotate left
					ctx.translate(width, height);
					ctx.rotate(Math.PI);
					break;
				case 4:
					// vertical flip
					ctx.translate(0, height);
					ctx.scale(1, -1);
					break;
				case 5:
					// vertical flip + 90 rotate right
					ctx.rotate(0.5 * Math.PI);
					ctx.scale(1, -1);
					break;
				case 6:
					// 90 rotate right
					ctx.rotate(0.5 * Math.PI);
					ctx.translate(0, -height);
					break;
				case 7:
					// horizontal flip + 90 rotate right
					ctx.rotate(0.5 * Math.PI);
					ctx.translate(width, -height);
					ctx.scale(-1, 1);
					break;
				case 8:
					// 90 rotate left
					ctx.rotate(-0.5 * Math.PI);
					ctx.translate(-width, 0);
					break;
			}
		}

		function _purge() {
			if (_imgInfo) {
				_imgInfo.purge();
				_imgInfo = null;
			}
			_binStr = _img = _canvas = _blob = null;
			_modified = false;
		}
	}

	return (extensions.Image = HTML5Image);
});
<|endoftext|>


<commit_before>'use strict';

var $ = require('jquery');
var Backbone = require('backbone');
Backbone.$ = $;
var UserUtils = require('../../utils/userUtils');

var DigitsLoginView = Backbone.View.extend({

    events: {
        'click': 'launchLogin'
    },

    launchLogin: function(e) {
        e.preventDefault();

        if(typeof Digits === 'undefined') {
            throw new Error('Digits is not yet initialized');
        }

        //swtich based on current status
        var user = UserUtils.getCurrentUser();
        console.log(user);
        if(user && user.get('loggedIn')) {
            UserUtils.logout();
        } else {
            UserUtils.login().done(this.loginSuccess);
        }
    },

    loginSuccess: function() {
        console.log('login complete! Forwarding onward.');
        Backbone.history.navigate('q', {trigger: true});
    }
});

module.exports = DigitsLoginView;<commit_msg>tweaked logout action<commit_after>'use strict';

var $ = require('jquery');
var Backbone = require('backbone');
Backbone.$ = $;
var UserUtils = require('../../utils/userUtils');

var DigitsLoginView = Backbone.View.extend({

    events: {
        'click': 'launchLogin'
    },

    launchLogin: function(e) {
        e.preventDefault();

        if(typeof Digits === 'undefined') {
            throw new Error('Digits is not yet initialized');
        }

        //swtich based on current status
        var user = UserUtils.getCurrentUser();
        console.log(user);
        if(user && user.get('loggedIn')) {
            if(confirm('Are you sure you want to log out?')) {
                UserUtils.logout();
                Backbone.history.navigate('', {trigger: true});
            }
        } else {
            UserUtils.login().done(this.loginSuccess);
        }
    },

    loginSuccess: function() {
        console.log('login complete! Forwarding onward.');
        Backbone.history.navigate('q', {trigger: true});
    }
});

module.exports = DigitsLoginView;<|endoftext|>