<commit_before>
const needTagFix = function() {
  if (LEGACY) {
    const testElem = document.createElement("div")
    const tempTagName = "div123"

    // Needed for old IE--v
    testElem.innerHTML = "1<" + tempTagName + "></" + tempTagName + ">"

    return getChar(testElem.getElementsByTagName("*")[0].nodeName, 0) === '/'

  } else {
    return false
  }
}()

const needCommentFilter = LEGACY ?
    document.createElement("div")
      .appendChild(document.createComment(""))
      .parentNode
      .getElementsByTagName("*").length !== 0 :
    false

/**
 * General function to check if the given element matches any of the selectors
 * in the given subGroup.
 *
 * @param {!Element} origEl
 * @param {!Array<!Selector>} subGroup
 * @return {boolean}
 */
function _matches(root, origEl, subGroup) {

  SUBGROUP_LOOP:
  for (var i = 0; i < subGroup.length; i+=1) {
    var selector = subGroup[i]
    ,   el = origEl
    ,   haltOnFail = false
    ,   lastCombinatorIdx = -1

    // Process starting at the end so that we're doing a RtoL evaluation.
    for (var j = selector.parts.length-1; j > -1; j-=1) {
      var part = selector.parts[j]

      if (part.kind === COMBINATOR) {
      // If we have a combinator, traverse to the related element
        haltOnFail = false

        switch (part.subKind) {
        case NO_COMB:           haltOnFail = true; break // Far right end
        case CHILD_COMB:        haltOnFail = true; /*falls through*/
        case DESCENDANT_COMB:   el = el.parentNode; break
        case ADJACENT_SIB_COMB: haltOnFail = true; /*falls through*/
        case GENERAL_SIB_COMB:  el = prevElemSib(el); break
        default: if (DEBUG_MODE) { throw errInternal }
        }

        if (!el || el.nodeType !== 1) { // No more elems to traverse, so fail
          return false
        }

        // Set to go back to this combinator if needed (+1 for the decrement)
        lastCombinatorIdx = j + 1

        continue
      }

      var temp = ""
      ,   thisSeqQualName = ""

      switch (part.kind) {
      case UNIVERSAL_TAG_TOKEN:
        thisSeqQualName = ""
        continue // Always matches

      case TAG_TOKEN:
        thisSeqQualName = part.value

        if (nodeName(el) === thisSeqQualName) { continue }
        break

      case CLASS_TOKEN:
        if (fieldMatch(el.className, part.value)) { continue }
        break

      case ID_TOKEN:
        if (el.id === part.value) { continue }
        break

      // A selector that doesn't return any element (e.g. ::first-letter)
      case NO_TOKEN:
        break

      // Simple pseudos
      case PSEUDO_TOKEN:
        if (part.subKind === SCOPE) {
          if (el === root) { continue }

        } else if (part.subKind(el)) { continue }

        break

      // Function pseudos
      case PSEUDO_FUNCTION_TOKEN:
        switch (part.subKind) {
        case NOT_TOKEN:
          if (!part.subSelector["matches"](el)) { continue }
          break

        case MATCHES_TOKEN:
          if (part.subSelector["matches"](el)) { continue }
          break

        case NTH_CHILD_TOKEN:
          if (isNth(el, part, "", false)) { continue }
          break

        case NTH_LAST_CHILD_TOKEN:
          if (isNth(el, part, "", true)) { continue }
          break

        case NTH_OF_TYPE_TOKEN: // First item in a sequence is always tag
          if (isNth(el, part, thisSeqQualName, false)) { continue }
          break

        case NTH_LAST_OF_TYPE_TOKEN:
          if (isNth(el, part, thisSeqQualName, true)) { continue }
          break

        case LANG_TOKEN:
          var tempEl = el
          while (tempEl && !tempEl.lang) { tempEl = tempEl.parentNode }

          if (tempEl && dashMatch(tempEl.lang, part.value)) { continue }
          break

        default:
          if (DEBUG_MODE) {
            throw errInternal // Should have been caught while parsing
          }
        } // End function pseudos
        break

      // Attribute selectors
      case ATTR_TOKEN:
      case ATTR_INSENSITIVE_TOKEN:
        if ((temp = getAttr(el, part.name)) == null) {
          break
        }

        if (part.kind === ATTR_INSENSITIVE_TOKEN) {
          temp = temp.toLowerCase()
        }

        switch (part.subKind) {
        case EQUAL_ATTR_TOKEN:
          if (temp === part.value) { continue }
          break

        case PREFIX_MATCH_TOKEN:
          if (temp.lastIndexOf(part.value, 0) === 0) { continue }
          break

        case SUFFIX_MATCH_TOKEN:
          if (temp.lastIndexOf(part.value)+part.value.length === temp.length) {
            continue
          }
          break

        case DASH_MATCH_TOKEN:
          if (dashMatch(temp, part.value)) { continue }
          break

        case INCLUDE_MATCH_TOKEN:
          if (fieldMatch(temp, part.value)) { continue }
          break

        case HAS_ATTR_TOKEN:
          continue // Already know it isn't null, so it has the attr

        case SUBSTRING_MATCH_TOKEN:
          if (temp.indexOf(part.value) !== -1) { continue }
          break

        default:
          if (DEBUG_MODE) {
            throw errInternal // Should have been caught while parsing
          }
        } // End attribute selectors

        break

      default:
        if (DEBUG_MODE) {
          throw errInternal // Unknown kind
        }
      }

      if (haltOnFail) {
        continue SUBGROUP_LOOP // Try the next selector in the subGroup
      }

      // A simple selector failed, so go back to the last combinator.
      j = lastCombinatorIdx
    }

    return true // Success for all parts
  } // end SUBGROUP_LOOP

  return false // No successful selectors in the group
}

/**
 * Matches a prefix followed by a dash. ("foo-bar" matches "foo" but not "f")
 *
 * @param {!string} target
 * @param {!string} pattern
 * @return {!boolean}
 */
function dashMatch(target, pattern) {
  const last = getChar(target, pattern.length)
  return (!last || last === '-') && target.lastIndexOf(pattern, 0) === 0
}

/**
 * Matches `pattern` if it has space or start of string before it and space or
 * end of string after it.
 *
 * @param {!string} target
 * @param {!string} pattern
 * @return {!boolean}
 */
function fieldMatch(target, pattern) {
  var idx = 0

  while ((idx = target.indexOf(pattern, idx)) !== -1) {
    // Both before and after there's either a space or no character
    if (getSpaceAt(target, idx-1) && getSpaceAt(target, idx+pattern.length)) {
      return true
    }

    // We move one more character extra past the end of the match, since the
    // last character in `pattern` is definitely not a space, so it would
    // not work as the boundary of an adjacent field match.
    idx += pattern.length + 1
  }

  return false
}

/**
 * Checks that the element matches as the nth described by the nth selector.
 *
 * @param {!Element} el
 * @param {!Token} simple
 * @param {!string} nn
 * @param {!boolean} fromEnd
 * @return {!boolean}
 */
function isNth(el, simple, nn, fromEnd) {
  const nth = simple.a
//  ,   offset = simple.b
//  ,   cap = nth <= 0 ? offset : Infinity // Don't traverse farther than needed

  if (!el.parentNode) {
    return false
  }

  var idx = 1-simple.b // 1-based index, less the offset
  ,   curr = fromEnd ? lastElemChild(el.parentNode) : firstElemChild(el.parentNode)

  while (curr !== el /*&& idx <= cap*/) {
    if (!nn || nodeName(curr) === nn) {
      idx += 1
    }

    curr = fromEnd ? prevElemSib(curr) : nextElemSib(curr)
  }

  return idx === 0 || (idx % nth === 0 && idx / nth >= 0)
}

const formControls = {
  "INPUT":1, "TEXTAREA":1, "SELECT":1, "BUTTON":1, "OPTION":1, "OPTGROUP":1
}
const hiddenOrButton = {
  "hidden":1, "image": 1, "button": 1, "submit": 1, "reset": 1
}

/**
 * Selector engine matcher functions for pseudo classes.
 */
const pseudoClassFns = {
  "root": function(el) {
    return el.ownerDocument.documentElement === el
  },
  "empty": function(el) {
    return !el.firstChild
  },
  "optional": function(el) {
    return !pseudoClassFns["required"](el)
  },
  "required": function(el) {
    return checkBooleanAttr(el, "required") &&
            formControls[nodeName(el)] &&
            !hiddenOrButton[el.type]

  },
  "checked": function(el) {
    return (el.checked && (el.type === "checkbox" || el.type === "radio")) ||
           (el.selected && nodeName(el) === "OPTION")
  },
  "indeterminate": function(el) {
    return checkBooleanAttr(el, "indeterminate") &&
            el.type === "checkbox" &&
            nodeName(el) === "INPUT"
  },
  "out-of-range": function(el) {
    return !pseudoClassFns["in-range"](el)
  },
  "in-range": function(el) {
    return isNumberInput(el) &&
            // no min or GTE min, and...
            ((+el.min !== +el.min || +el.value >= +el.min) &&
            // no max or LTE max
            (+el.max !== +el.max || +el.value <= +el.max)) === true
  },
  "default-option": function(el) {
    if (el.defaultChecked || el.defaultSelected) { return true }

    const sel = "BUTTON, INPUT[type=submit]"

    return el.form && el.form.nodeType === 1 &&
            Query["matches"](el, sel) &&
            Query["one"](el.form, sel) === el
  },
  "enabled": function(el) {
    return !pseudoClassFns["disabled"](el)
  },
  "disabled": function(el) {
    return checkBooleanAttr(el, "disabled") && formControls[nodeName(el)]
  },
  "target": function(el) {
    return el.id && window.location.hash.slice(1) === el.id
  },
  "any-link": function(el) {
    return nodeName(el) === "A" && hasAttr(el, "href")
  },
  "hover": function(el) {
    // We only add the mouseover handler if absolutely necessary.
    if (needHoverHelperSetup) {
      hoverHelperSetup()
    }

    if (el.contains) {
      return el.contains(hoverHelper)
    }

    var helper = hoverHelper
    do {
      if (el === helper) {
        return true
      }
    } while(helper && (helper = helper.parentNode))

    /*
      Alternate solution would be to force a mouseover event on a temporary handler
      whenever this is needed. It gets the target element using `.elementFromPoint`.
      Advantage is that there's no continuous `mouseover` event taking place, and no
      traversal to check the element. Would need to test to make sure the removal and
      append of the `body` fires the `mouseover` handler in all browsers.

      This would only be done once for each group of elements to be tested for qSA.

      Would there be problems with other handlers firing?

      var body = document.body
      if (body) {
        var sib = body.nextSibling
        ,   par = body.parentNode
        ,   prev_handler = window.onmouseover

        window.onmouseover = function(event) {
          hoverHelper=document.elementFromPoint(event.clientX, event.clientY)
        }

        par.removeChild(body)
        par.insertBefore(body, sib)

        window.onmouseover = prev_handler
        return hoverHelper
      }
    */

    return false
  },
  "focus": function(el) {
    return el === el.ownerDocument.activeElement
  },
  "first-child": function(el) {
    return !prevElemSib(el)
  },
  "last-child": function(el) {
    return !nextElemSib(el)
  },
  "only-child": function(el) {
    return !prevElemSib(el) && !nextElemSib(el)
  },
  "first-of-type": function(el) {
    const name = nodeName(el)

    while ((el = prevElemSib(el)) && (nodeName(el) !== name)) {
    }
    return !el
  },
  "last-of-type": function(el) {
    const name = nodeName(el)

    while ((el = nextElemSib(el)) && (nodeName(el) !== name)) {
    }
    return !el
  },
  "only-of-type": function(el) {
    return pseudoClassFns["first-of-type"](el) &&
            pseudoClassFns["last-of-type"](el)
  }
}

var needHoverHelperSetup = true
,   hoverHelper = null

/*
Used by the :hover fix to track the currently hovered element, if needed.
*/
function hoverHelperSetup() {
  if (!needHoverHelperSetup) {
    return
  }

  needHoverHelperSetup = false

  if (!LEGACY || window.addEventListener) {
    window.addEventListener("mouseover", function(event) {
      hoverHelper = event.target
    }, true)

  } else if (window.attachEvent) {
    window.attachEvent("onmouseover", function(event) {
      hoverHelper = event.srcElement
    })
  }

  // Try to force a "mouseover" event after the handler is set up.
  const body = document.body
  if (body) {
    const sib = body.nextSibling
    ,   par = body.parentNode

    par.removeChild(body)
    par.insertBefore(body, sib)
  }
}
<commit_msg>Fix qualified name for nth-of-type selection<commit_after>
const needTagFix = function() {
  if (LEGACY) {
    const testElem = document.createElement("div")
    const tempTagName = "div123"

    // Needed for old IE--v
    testElem.innerHTML = "1<" + tempTagName + "></" + tempTagName + ">"

    return getChar(testElem.getElementsByTagName("*")[0].nodeName, 0) === '/'

  } else {
    return false
  }
}()

const needCommentFilter = LEGACY ?
    document.createElement("div")
      .appendChild(document.createComment(""))
      .parentNode
      .getElementsByTagName("*").length !== 0 :
    false

/**
 * General function to check if the given element matches any of the selectors
 * in the given subGroup.
 *
 * @param {!Element} origEl
 * @param {!Array<!Selector>} subGroup
 * @return {boolean}
 */
function _matches(root, origEl, subGroup) {

  SUBGROUP_LOOP:
  for (var i = 0; i < subGroup.length; i+=1) {
    var selector = subGroup[i]
    ,   el = origEl
    ,   haltOnFail = false
    ,   lastCombinatorIdx = -1
    ,   thisSeqQualName = ""

    // Process starting at the end so that we're doing a RtoL evaluation.
    for (var j = selector.parts.length-1; j > -1; j-=1) {
      var part = selector.parts[j]

      if (part.kind === COMBINATOR) {
      // If we have a combinator, traverse to the related element
        haltOnFail = false
        thisSeqQualName = ""

        switch (part.subKind) {
        case NO_COMB:           haltOnFail = true; break // Far right end
        case CHILD_COMB:        haltOnFail = true; /*falls through*/
        case DESCENDANT_COMB:   el = el.parentNode; break
        case ADJACENT_SIB_COMB: haltOnFail = true; /*falls through*/
        case GENERAL_SIB_COMB:  el = prevElemSib(el); break
        default: if (DEBUG_MODE) { throw errInternal }
        }

        if (!el || el.nodeType !== 1) { // No more elems to traverse, so fail
          return false
        }

        // Set to go back to this combinator if needed (+1 for the decrement)
        lastCombinatorIdx = j + 1

        continue
      }

      // TODO: Maybe move TAG to its own property so that it's immediately
      // available for `thisSeqQualName`, which would let us move this switch
      // out to a separate function.

      switch (part.kind) {
      case UNIVERSAL_TAG_TOKEN:
        continue // Always matches

      case TAG_TOKEN:
        thisSeqQualName = part.value

        if (nodeName(el) === thisSeqQualName) { continue }
        break

      case CLASS_TOKEN:
        if (fieldMatch(el.className, part.value)) { continue }
        break

      case ID_TOKEN:
        if (el.id === part.value) { continue }
        break

      // Simple pseudos
      case PSEUDO_TOKEN:
        if (part.subKind === SCOPE) {
          if (el === root) { continue }

        } else if (part.subKind(el)) { continue }

        break

      // Function pseudos
      case PSEUDO_FUNCTION_TOKEN:
        switch (part.subKind) {
        case NOT_TOKEN:
          if (!part.subSelector["matches"](el)) { continue }
          break

        case MATCHES_TOKEN:
          if (part.subSelector["matches"](el)) { continue }
          break

        case NTH_CHILD_TOKEN:
          if (isNth(el, part, "", false)) { continue }
          break

        case NTH_LAST_CHILD_TOKEN:
          if (isNth(el, part, "", true)) { continue }
          break

        case NTH_OF_TYPE_TOKEN: // First item in a sequence is always tag
          if (isNth(el, part, thisSeqQualName, false)) { continue }
          break

        case NTH_LAST_OF_TYPE_TOKEN:
          if (isNth(el, part, thisSeqQualName, true)) { continue }
          break

        case LANG_TOKEN:
          var tempEl = el
          while (tempEl && !tempEl.lang) { tempEl = tempEl.parentNode }

          if (tempEl && dashMatch(tempEl.lang, part.value)) { continue }
          break

        default:
          if (DEBUG_MODE) {
            throw errInternal // Should have been caught while parsing
          }
        } // End function pseudos
        break

      // Attribute selectors
      case ATTR_TOKEN:
      case ATTR_INSENSITIVE_TOKEN:
        var attrVal = getAttr(el, part.name)
        if (attrVal == null) {
          break
        }

        if (part.kind === ATTR_INSENSITIVE_TOKEN) {
          attrVal = attrVal.toLowerCase()
        }

        switch (part.subKind) {
        case EQUAL_ATTR_TOKEN:
          if (attrVal === part.value) { continue }
          break

        case PREFIX_MATCH_TOKEN:
          if (attrVal.lastIndexOf(part.value, 0) === 0) { continue }
          break

        case SUFFIX_MATCH_TOKEN:
          if (attrVal.lastIndexOf(part.value)+part.value.length === attrVal.length) {
            continue
          }
          break

        case DASH_MATCH_TOKEN:
          if (dashMatch(attrVal, part.value)) { continue }
          break

        case INCLUDE_MATCH_TOKEN:
          if (fieldMatch(attrVal, part.value)) { continue }
          break

        case HAS_ATTR_TOKEN:
          continue // Already know it isn't null, so it has the attr

        case SUBSTRING_MATCH_TOKEN:
          if (attrVal.indexOf(part.value) !== -1) { continue }
          break

        default:
          if (DEBUG_MODE) {
            throw errInternal // Should have been caught while parsing
          }
        } // End attribute selectors

        break

      default:
        if (DEBUG_MODE) {
          throw errInternal // Unknown kind
        }
      }

      if (haltOnFail) {
        continue SUBGROUP_LOOP // Try the next selector in the subGroup
      }

      // A simple selector failed, so go back to the last combinator.
      j = lastCombinatorIdx
    }

    return true // Success for all parts
  } // end SUBGROUP_LOOP

  return false // No successful selectors in the group
}

/**
 * Matches a prefix followed by a dash. ("foo-bar" matches "foo" but not "f")
 *
 * @param {!string} target
 * @param {!string} pattern
 * @return {!boolean}
 */
function dashMatch(target, pattern) {
  const last = getChar(target, pattern.length)
  return (!last || last === '-') && target.lastIndexOf(pattern, 0) === 0
}

/**
 * Matches `pattern` if it has space or start of string before it and space or
 * end of string after it.
 *
 * @param {!string} target
 * @param {!string} pattern
 * @return {!boolean}
 */
function fieldMatch(target, pattern) {
  var idx = 0

  while ((idx = target.indexOf(pattern, idx)) !== -1) {
    // Both before and after there's either a space or no character
    if (getSpaceAt(target, idx-1) && getSpaceAt(target, idx+pattern.length)) {
      return true
    }

    // We move one more character extra past the end of the match, since the
    // last character in `pattern` is definitely not a space, so it would
    // not work as the boundary of an adjacent field match.
    idx += pattern.length + 1
  }

  return false
}

/**
 * Checks that the element matches as the nth described by the nth selector.
 *
 * @param {!Element} el
 * @param {!Token} simple
 * @param {!string} nn
 * @param {!boolean} fromEnd
 * @return {!boolean}
 */
function isNth(el, simple, nn, fromEnd) {
  const nth = simple.a
//  ,   offset = simple.b
//  ,   cap = nth <= 0 ? offset : Infinity // Don't traverse farther than needed

  if (!el.parentNode) {
    return false
  }

  var idx = 1-simple.b // 1-based index, less the offset
  ,   curr = fromEnd ? lastElemChild(el.parentNode) : firstElemChild(el.parentNode)

  while (curr !== el /*&& idx <= cap*/) {
    if (!nn || nodeName(curr) === nn) {
      idx += 1
    }

    curr = fromEnd ? prevElemSib(curr) : nextElemSib(curr)
  }

  return idx === 0 || (idx % nth === 0 && idx / nth >= 0)
}

const formControls = {
  "INPUT":1, "TEXTAREA":1, "SELECT":1, "BUTTON":1, "OPTION":1, "OPTGROUP":1
}
const hiddenOrButton = {
  "hidden":1, "image": 1, "button": 1, "submit": 1, "reset": 1
}

/**
 * Selector engine matcher functions for pseudo classes.
 */
const pseudoClassFns = {
  "root": function(el) {
    return el.ownerDocument.documentElement === el
  },
  "empty": function(el) {
    return !el.firstChild
  },
  "optional": function(el) {
    return !pseudoClassFns["required"](el)
  },
  "required": function(el) {
    return checkBooleanAttr(el, "required") &&
            formControls[nodeName(el)] &&
            !hiddenOrButton[el.type]

  },
  "checked": function(el) {
    return (el.checked && (el.type === "checkbox" || el.type === "radio")) ||
           (el.selected && nodeName(el) === "OPTION")
  },
  "indeterminate": function(el) {
    return checkBooleanAttr(el, "indeterminate") &&
            el.type === "checkbox" &&
            nodeName(el) === "INPUT"
  },
  "out-of-range": function(el) {
    return !pseudoClassFns["in-range"](el)
  },
  "in-range": function(el) {
    return isNumberInput(el) &&
            // no min or GTE min, and...
            ((+el.min !== +el.min || +el.value >= +el.min) &&
            // no max or LTE max
            (+el.max !== +el.max || +el.value <= +el.max)) === true
  },
  "default-option": function(el) {
    if (el.defaultChecked || el.defaultSelected) { return true }

    const sel = "BUTTON, INPUT[type=submit]"

    return el.form && el.form.nodeType === 1 &&
            Query["matches"](el, sel) &&
            Query["one"](el.form, sel) === el
  },
  "enabled": function(el) {
    return !pseudoClassFns["disabled"](el)
  },
  "disabled": function(el) {
    return checkBooleanAttr(el, "disabled") && formControls[nodeName(el)]
  },
  "target": function(el) {
    return el.id && window.location.hash.slice(1) === el.id
  },
  "any-link": function(el) {
    return nodeName(el) === "A" && hasAttr(el, "href")
  },
  "hover": function(el) {
    // We only add the mouseover handler if absolutely necessary.
    if (needHoverHelperSetup) {
      hoverHelperSetup()
    }

    if (el.contains) {
      return el.contains(hoverHelper)
    }

    var helper = hoverHelper
    do {
      if (el === helper) {
        return true
      }
    } while(helper && (helper = helper.parentNode))

    /*
      Alternate solution would be to force a mouseover event on a temporary handler
      whenever this is needed. It gets the target element using `.elementFromPoint`.
      Advantage is that there's no continuous `mouseover` event taking place, and no
      traversal to check the element. Would need to test to make sure the removal and
      append of the `body` fires the `mouseover` handler in all browsers.

      This would only be done once for each group of elements to be tested for qSA.

      Would there be problems with other handlers firing?

      var body = document.body
      if (body) {
        var sib = body.nextSibling
        ,   par = body.parentNode
        ,   prev_handler = window.onmouseover

        window.onmouseover = function(event) {
          hoverHelper=document.elementFromPoint(event.clientX, event.clientY)
        }

        par.removeChild(body)
        par.insertBefore(body, sib)

        window.onmouseover = prev_handler
        return hoverHelper
      }
    */

    return false
  },
  "focus": function(el) {
    return el === el.ownerDocument.activeElement
  },
  "first-child": function(el) {
    return !prevElemSib(el)
  },
  "last-child": function(el) {
    return !nextElemSib(el)
  },
  "only-child": function(el) {
    return !prevElemSib(el) && !nextElemSib(el)
  },
  "first-of-type": function(el) {
    const name = nodeName(el)

    while ((el = prevElemSib(el)) && (nodeName(el) !== name)) {
    }
    return !el
  },
  "last-of-type": function(el) {
    const name = nodeName(el)

    while ((el = nextElemSib(el)) && (nodeName(el) !== name)) {
    }
    return !el
  },
  "only-of-type": function(el) {
    return pseudoClassFns["first-of-type"](el) &&
            pseudoClassFns["last-of-type"](el)
  }
}

var needHoverHelperSetup = true
,   hoverHelper = null

/*
Used by the :hover fix to track the currently hovered element, if needed.
*/
function hoverHelperSetup() {
  if (!needHoverHelperSetup) {
    return
  }

  needHoverHelperSetup = false

  if (!LEGACY || window.addEventListener) {
    window.addEventListener("mouseover", function(event) {
      hoverHelper = event.target
    }, true)

  } else if (window.attachEvent) {
    window.attachEvent("onmouseover", function(event) {
      hoverHelper = event.srcElement
    })
  }

  // Try to force a "mouseover" event after the handler is set up.
  const body = document.body
  if (body) {
    const sib = body.nextSibling
    ,   par = body.parentNode

    par.removeChild(body)
    par.insertBefore(body, sib)
  }
}
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import Path from 'path';
import shell from 'shell';

import './ProductPage.css';
import Background from '../../Background';
import BrandTitle from '../../BrandTitle';
import Placemat from '../../Placemat';
import ProfileSummary from '../../ProfileSummary';
import Navigation from '../../Navigation';
import ContentText from '../../Text/ContentText';
import TitleText from '../../Text/TitleText';
import ErrorText from '../../Text/ErrorText';
import PageContent from '../../PageContent';
import ProductCard from '../ProductCard';
import ProductActionButtons from '../ProductActionButtons';

import ContentListItem from './ContentListItem/ContentListItem'
import StoreService from '../../../services/StoreService';

import InstallerStore from '../../../stores/InstallerStore';
import InstallerService from '../../../services/InstallerService';
import NotificationStore from '../../../stores/NotificationStore';
import StoreStore from '../../../stores/StoreStore';
import StateStore from '../../../stores/StateStore';
import StateService from '../../../services/StateService';
import ProductActions from '../../../actions/ProductActions';
import ProductStore from '../../../stores/ProductStore';

var State = require('react-router').State;

import mui from 'material-ui';
var ThemeManager = new mui.Styles.ThemeManager();
var List = mui.List;
var ListItem = mui.ListItem;
var CircularProgress = mui.CircularProgress;
var Card = mui.Card;
var CardHeader = mui.CardHeader;
var CardMedia = mui.CardMedia;
var CardTitle = mui.CardTitle;
var CardText = mui.CardText;
var RaisedButton = mui.RaisedButton;
var Paper = mui.Paper;
var LinearProgress = mui.LinearProgress;

const BYTES_PER_MB = 1048576;

export default class ProductPage extends React.Component {
  static mixins = [ State ];

  constructor(props) {
    super(props);

    this.props.id = props.params.id;

    ProductActions.loadProduct(this.props.id);

    this.state =
    {
      isBusy: false,
      error: this._getErrorMessage(),
    };
  }

  _getErrorMessage() {
    return NotificationStore.hasProductError();
  }

  _onChange() {
  }

  componentDidMount() {
    this.changeListener = this._onChange.bind(this);
    NotificationStore.addChangeListener(this.changeListener);
    StateStore.addChangeListener(this.changeListener);
    InstallerStore.addChangeListener(this.changeListener);
    ProductStore.addChangeListener(this.changeListener);
  }

  componentWillUnmount() {
    NotificationStore.removeChangeListener(this.changeListener);
    StateStore.removeChangeListener(this.changeListener);
    InstallerStore.removeChangeListener(this.changeListener);
    ProductStore.removeChangeListener(this.changeListener);
  }

  static childContextTypes = {
    muiTheme: React.PropTypes.object
  }

  getChildContext() {
    return {
      muiTheme: ThemeManager.getCurrentTheme()
    };
  }

  render() {
    const contentStyle = {
      height: this.state.height + "px"
    }

    const cardStyle = {
      height: this.props.cardHeight + "px",
      width: this.props.cardWidth + "px"
    }

    return (

        <Background animate={false} />
        <Navigation currentPage='product' />
        <PageContent width={80} className="ProductPage">

            <ErrorText text={NotificationStore.productError} />

            <TitleText text={ProductStore.product.name} size={6} level={2} className="ProductPage-h1"/>
            <TitleText text={ProductStore.publisher.name} link={ProductStore.publisher.externalUrl} level={3} className="ProductPage-h2 ProductPage-link"/>

              <ProductCard imgSrc={ProductStore.product.imageUrl} width={this.props.cardWidth} height={this.props.cardHeight} />

              <ProductActionButtons />
              <Placemat width={this.props.buttonWidth} className="ProductPage-descriptionContainer">

                  <ContentText enableMarkdown={true} text={ProductStore.product.description} />

              </Placemat>

        </PageContent>

    );
  }
}

ProductPage.propTypes = {
  title: PropTypes.string,
  cardHeight: React.PropTypes.number,
  cardWidth: React.PropTypes.number
};

ProductPage.defaultProps = {
  cardHeight: 300,
  cardWidth: 530,
  buttonWidth: 400
}
<commit_msg>show content description isntead of product<commit_after>import React, { PropTypes } from 'react';
import Path from 'path';
import shell from 'shell';

import './ProductPage.css';
import Background from '../../Background';
import BrandTitle from '../../BrandTitle';
import Placemat from '../../Placemat';
import ProfileSummary from '../../ProfileSummary';
import Navigation from '../../Navigation';
import ContentText from '../../Text/ContentText';
import TitleText from '../../Text/TitleText';
import ErrorText from '../../Text/ErrorText';
import PageContent from '../../PageContent';
import ProductCard from '../ProductCard';
import ProductActionButtons from '../ProductActionButtons';

import ContentListItem from './ContentListItem/ContentListItem'
import StoreService from '../../../services/StoreService';

import InstallerStore from '../../../stores/InstallerStore';
import InstallerService from '../../../services/InstallerService';
import NotificationStore from '../../../stores/NotificationStore';
import StoreStore from '../../../stores/StoreStore';
import StateStore from '../../../stores/StateStore';
import StateService from '../../../services/StateService';
import ProductActions from '../../../actions/ProductActions';
import ProductStore from '../../../stores/ProductStore';

var State = require('react-router').State;

import mui from 'material-ui';
var ThemeManager = new mui.Styles.ThemeManager();
var List = mui.List;
var ListItem = mui.ListItem;
var CircularProgress = mui.CircularProgress;
var Card = mui.Card;
var CardHeader = mui.CardHeader;
var CardMedia = mui.CardMedia;
var CardTitle = mui.CardTitle;
var CardText = mui.CardText;
var RaisedButton = mui.RaisedButton;
var Paper = mui.Paper;
var LinearProgress = mui.LinearProgress;

const BYTES_PER_MB = 1048576;

export default class ProductPage extends React.Component {
  static mixins = [ State ];

  constructor(props) {
    super(props);

    this.props.id = props.params.id;

    ProductActions.loadProduct(this.props.id);

    this.state =
    {
      isBusy: false,
      error: this._getErrorMessage(),
    };
  }

  _getErrorMessage() {
    return NotificationStore.hasProductError();
  }

  _onChange() {
  }

  componentDidMount() {
    this.changeListener = this._onChange.bind(this);
    NotificationStore.addChangeListener(this.changeListener);
    StateStore.addChangeListener(this.changeListener);
    InstallerStore.addChangeListener(this.changeListener);
    ProductStore.addChangeListener(this.changeListener);
  }

  componentWillUnmount() {
    NotificationStore.removeChangeListener(this.changeListener);
    StateStore.removeChangeListener(this.changeListener);
    InstallerStore.removeChangeListener(this.changeListener);
    ProductStore.removeChangeListener(this.changeListener);
  }

  static childContextTypes = {
    muiTheme: React.PropTypes.object
  }

  getChildContext() {
    return {
      muiTheme: ThemeManager.getCurrentTheme()
    };
  }

  render() {
    const contentStyle = {
      height: this.state.height + "px"
    }

    const cardStyle = {
      height: this.props.cardHeight + "px",
      width: this.props.cardWidth + "px"
    }

    return (

        <Background animate={false} />
        <Navigation currentPage='product' />
        <PageContent width={80} className="ProductPage">

            <ErrorText text={NotificationStore.productError} />

            <TitleText text={ProductStore.product.name} size={6} level={2} className="ProductPage-h1"/>
            <TitleText text={ProductStore.publisher.name} link={ProductStore.publisher.externalUrl} level={3} className="ProductPage-h2 ProductPage-link"/>

              <ProductCard imgSrc={ProductStore.product.imageUrl} width={this.props.cardWidth} height={this.props.cardHeight} />

              <ProductActionButtons />
              <Placemat width={this.props.buttonWidth} className="ProductPage-descriptionContainer">

                  <ContentText enableMarkdown={true} text={ProductStore.content.description} />

              </Placemat>

        </PageContent>

    );
  }
}

ProductPage.propTypes = {
  title: PropTypes.string,
  cardHeight: React.PropTypes.number,
  cardWidth: React.PropTypes.number
};

ProductPage.defaultProps = {
  cardHeight: 300,
  cardWidth: 530,
  buttonWidth: 400
}
<|endoftext|>


<commit_before>dbs_progress = function(pId) {
	dbsfaces.progress.initialize($(pId));
}

dbsfaces.progress = {
	initialize: function(pProgress){
		dbsfaces.progress.pvInitializeData(pProgress);
		dbsfaces.progress.pvInitializeLayout(pProgress);
	},

	pvInitializeData: function(pProgress){
		pProgress.data("container", pProgress.children(".-container"));
		pProgress.data("content", pProgress.data("container").children(".-content"));
		pProgress.data("label", pProgress.data("content").find(".-label").first());
		pProgress.data("labelvalue", pProgress.data("label").children(".-value"));
		pProgress.data("labelsufix", pProgress.data("label").children(".-sufix"));
		pProgress.data("point", pProgress.data("content").find("> g > .-point"));
		pProgress.data("back", pProgress.data("content").find("> g > .-back"));
		pProgress.data("type", (pProgress.hasClass("-c") ? "c": (pProgress.hasClass("-h") ? "h" : "v")));
		pProgress.data("ani", (pProgress.hasClass("-ani") ? true: false));
		pProgress.data("dimension", Math.min(pProgress[0].getBoundingClientRect().height, pProgress[0].getBoundingClientRect().width));
		dbsfaces.progress.pvSetValue(pProgress, pProgress.attr("v"));
	},

	pvInitializeLayout: function(pProgress){
		if (pProgress.data("type") == "c"){
			dbsfaces.progress.pvInitializeLayoutCircle(pProgress);
		}else{
			dbsfaces.progress.pvInitializeLayoutHorizontalVertical(pProgress);
		}
		pProgress.removeClass("-hide");
		setTimeout(function(e){
			dbsfaces.progress.pvEncodeValue(pProgress);
		}, 0);
	},

	pvInitializeLayoutHorizontalVertical: function(pProgress){
		var xColor = tinycolor(pProgress.css("color"));
		pProgress.data("container").css("border-color", xColor.setAlpha(.2))
		   						   .css("background-color", xColor.setAlpha(.05));
		var xBackground = "linear-gradient(135deg," + xColor.setAlpha(.7) + " 0%, " + xColor.setAlpha(1) + " 100%)";
		pProgress.data("content").css("background", xBackground);
	},

	pvInitializeLayoutCircle: function(pProgress){
		var xColor = tinycolor(pProgress.css("color"));
		var xStops = pProgress.data("content").find("> defs > linearGradient > stop");
		$(xStops[0]).svgAttr("stop-color", xColor.setAlpha(.7));
		$(xStops[1]).svgAttr("stop-color", xColor.setAlpha(1));
		dbsfaces.progress.pvInitializeLayoutCirclePath(pProgress);
	},

	pvInitializeLayoutCirclePath: function(pProgress){
		var xDimension = pProgress.data("dimension");
		var xStrokeWidth = parseFloat(pProgress.data("point").css("stroke-width")) - 1;
		var xDimensionHalf = xDimension / 2;
		var xStrokeWidthHalf = xStrokeWidth / 2;
		var xPath = "";
		pProgress.data("sw", xStrokeWidth); //Salva strokewidth
		xPath += "M" + xDimensionHalf + "," + xStrokeWidthHalf;
		xPath += "A" + (xDimensionHalf - xStrokeWidthHalf) + "," + (xDimensionHalf - xStrokeWidthHalf);
		xPath += " 0 1 1 ";
		xPath += xDimensionHalf - .0001 + "," + xStrokeWidthHalf;
		pProgress.data("point").svgAttr("d", xPath);
		pProgress.data("back").svgAttr("d", xPath);
		dbsfaces.progress.pvInitializeDash(pProgress);
	},

	pvInitializeDash: function(pProgress){
		var xPoint = pProgress.data("point")[0];
		if (typeof(xPoint.getTotalLength) == "undefined"){return;}
		var xTotalLenght = xPoint.getTotalLength();
		pProgress.data("point").css("stroke-dasharray", xTotalLenght);
		pProgress.data("point").css("stroke-dashoffset", xTotalLenght);
		pProgress.data("totallenght", xTotalLenght);
	},

	pvEncodeValue: function(pProgress){
		var xType = pProgress.data("type");
		if (xType == "c"){
			dbsfaces.progress.pvEncodeValueCircle(pProgress);
		}else if (xType == "h"){
			dbsfaces.progress.pvEncodeValueHorizontal(pProgress);
		}else{
			dbsfaces.progress.pvEncodeValueVertical(pProgress);
		}
		dbsfaces.progress.pvEncodeValueLabel(pProgress, xType);
	},

	pvEncodeValueLabel: function(pProgress, pType){
		var xDimension = pProgress.data("dimension");
		var xLabelFontSize;
		var xLabel = pProgress.data("label");
		var xLabelValue = pProgress.data("labelvalue");
		var xLabelSufix = pProgress.data("labelsufix");
		var xValue = pProgress.attr("v");
		var xPerc = pProgress.attr("perc");
		var xClass = "";

		if (pType == "c"){
			xLabelFontSize = (xDimension - (pProgress.data("sw") * 2)) / 2.2;
			xLabel.svgAttr("x", xDimension / 2);
			xLabel.svgAttr("y", (xDimension + (xLabelFontSize / 2)) / 2);
		}else{
			xLabelFontSize = xDimension * .35;
		}
		xLabel.css("font-size", xLabelFontSize);
		if (xValue > 45){
			xLabel.addClass("-th_i");
		}else{
			xLabel.removeClass("-th_i");
		}
		pProgress.data("labelvalue").text(pProgress.data("percI"));
		pProgress.data("labelsufix").text(pProgress.data("percD") + "%");
	},

	pvEncodeValueHorizontal: function(pProgress){
		var xContent = pProgress.data("content");
		var xValue = pProgress.attr("v");
		xContent.css("width", xValue + "%");
	},

	pvEncodeValueVertical: function(pProgress){
		var xContent = pProgress.data("content");
		var xValue = pProgress.attr("v");
		xContent.css("height", xValue + "%");
	},

	pvEncodeValueCircle: function(pProgress){
		var xPoint = pProgress.data("point");
		var xPerc = pProgress.data("perc");
		var xTotalLenght = pProgress.data("totallenght") - (pProgress.data("totallenght") * xPerc);
		pProgress.data("point").css("stroke-dashoffset", xTotalLenght);
	},

	pvSetValue: function(pProgress, pValue){
		pValue = dbsfaces.math.round(parseFloat(pValue),2);
		xInt = String(dbsfaces.math.trunc(pValue, 0)); //Parte interira
		xDec = String(dbsfaces.math.round(pValue - xInt, 4)).substring(1, 4); //Parte decimal
		pProgress.attr("v", pValue);
		pProgress.data("percI", xInt);
		pProgress.data("percD", xDec);
		pProgress.data("perc", (pValue / 100));
	}

}
<commit_msg>Resize automático<commit_after>dbs_progress = function(pId) {
	dbsfaces.progress.initialize($(pId));
	$(window).resize(function(e){
		dbsfaces.progress.resize($(pId));
	});
}

dbsfaces.progress = {
	initialize: function(pProgress){
		dbsfaces.progress.pvInitializeData(pProgress);
		dbsfaces.progress.resize(pProgress);
	},

	resize: function(pProgress){
		dbsfaces.progress.pvSetValue(pProgress, pProgress.attr("v"));
		dbsfaces.progress.pvInitializeLayout(pProgress);
	},

	pvInitializeData: function(pProgress){
		pProgress.data("container", pProgress.children(".-container"));
		pProgress.data("content", pProgress.data("container").children(".-content"));
		pProgress.data("label", pProgress.data("content").find(".-label").first());
		pProgress.data("labelvalue", pProgress.data("label").children(".-value"));
		pProgress.data("labelsufix", pProgress.data("label").children(".-sufix"));
		pProgress.data("point", pProgress.data("content").find("> g > .-point"));
		pProgress.data("back", pProgress.data("content").find("> g > .-back"));
		pProgress.data("type", (pProgress.hasClass("-c") ? "c": (pProgress.hasClass("-h") ? "h" : "v")));
		pProgress.data("ani", (pProgress.hasClass("-ani") ? true: false));
	},

	pvInitializeLayout: function(pProgress){
		if (pProgress.data("type") == "c"){
			dbsfaces.progress.pvInitializeLayoutCircle(pProgress);
		}else{
			dbsfaces.progress.pvInitializeLayoutHorizontalVertical(pProgress);
		}
		pProgress.removeClass("-hide");
		setTimeout(function(e){
			dbsfaces.progress.pvEncodeValue(pProgress);
		}, 0);
	},

	pvInitializeLayoutHorizontalVertical: function(pProgress){
		var xColor = tinycolor(pProgress.css("color"));
		pProgress.data("container").css("border-color", xColor.setAlpha(.2))
		   						   .css("background-color", xColor.setAlpha(.05));
		var xBackground = "linear-gradient(135deg," + xColor.setAlpha(.7) + " 0%, " + xColor.setAlpha(1) + " 100%)";
		pProgress.data("content").css("background", xBackground);
	},

	pvInitializeLayoutCircle: function(pProgress){
		var xColor = tinycolor(pProgress.css("color"));
		var xStops = pProgress.data("content").find("> defs > linearGradient > stop");
		$(xStops[0]).svgAttr("stop-color", xColor.setAlpha(.7));
		$(xStops[1]).svgAttr("stop-color", xColor.setAlpha(1));
		dbsfaces.progress.pvInitializeLayoutCirclePath(pProgress);
	},

	pvInitializeLayoutCirclePath: function(pProgress){
		var xDimension = pProgress.data("dimension");
		var xStrokeWidth = parseFloat(pProgress.data("point").css("stroke-width")) - 1;
		var xDimensionHalf = xDimension / 2;
		var xStrokeWidthHalf = xStrokeWidth / 2;
		var xPath = "";
		pProgress.data("sw", xStrokeWidth); //Salva strokewidth
		xPath += "M" + xDimensionHalf + "," + xStrokeWidthHalf;
		xPath += "A" + (xDimensionHalf - xStrokeWidthHalf) + "," + (xDimensionHalf - xStrokeWidthHalf);
		xPath += " 0 1 1 ";
		xPath += xDimensionHalf - .0001 + "," + xStrokeWidthHalf;
		pProgress.data("point").svgAttr("d", xPath);
		pProgress.data("back").svgAttr("d", xPath);
		dbsfaces.progress.pvInitializeDash(pProgress);
	},

	pvInitializeDash: function(pProgress){
		var xPoint = pProgress.data("point")[0];
		if (typeof(xPoint.getTotalLength) == "undefined"){return;}
		var xTotalLenght = xPoint.getTotalLength();
		pProgress.data("point").css("stroke-dasharray", xTotalLenght);
		pProgress.data("point").css("stroke-dashoffset", xTotalLenght);
		pProgress.data("totallenght", xTotalLenght);
	},

	pvEncodeValue: function(pProgress){
		var xType = pProgress.data("type");
		if (xType == "c"){
			dbsfaces.progress.pvEncodeValueCircle(pProgress);
		}else if (xType == "h"){
			dbsfaces.progress.pvEncodeValueHorizontal(pProgress);
		}else{
			dbsfaces.progress.pvEncodeValueVertical(pProgress);
		}
		dbsfaces.progress.pvEncodeValueLabel(pProgress, xType);
	},

	pvEncodeValueLabel: function(pProgress, pType){
		var xDimension = pProgress.data("dimension");
		var xLabelFontSize;
		var xLabel = pProgress.data("label");
		var xLabelValue = pProgress.data("labelvalue");
		var xLabelSufix = pProgress.data("labelsufix");
		var xValue = pProgress.attr("v");
		var xPerc = pProgress.attr("perc");
		var xClass = "";

		if (pType == "c"){
			xLabelFontSize = (xDimension - (pProgress.data("sw") * 2)) / 2.2;
			xLabel.svgAttr("x", xDimension / 2);
			xLabel.svgAttr("y", (xDimension + (xLabelFontSize / 2)) / 2);
		}else{
			xLabelFontSize = xDimension * .35;
		}
		xLabel.css("font-size", xLabelFontSize);
		if (xValue > 45){
			xLabel.addClass("-th_i");
		}else{
			xLabel.removeClass("-th_i");
		}
		pProgress.data("labelvalue").text(pProgress.data("percI"));
		pProgress.data("labelsufix").text(pProgress.data("percD") + "%");
	},

	pvEncodeValueHorizontal: function(pProgress){
		var xContent = pProgress.data("content");
		var xValue = pProgress.attr("v");
		xContent.css("width", xValue + "%");
	},

	pvEncodeValueVertical: function(pProgress){
		var xContent = pProgress.data("content");
		var xValue = pProgress.attr("v");
		xContent.css("height", xValue + "%");
	},

	pvEncodeValueCircle: function(pProgress){
		var xPoint = pProgress.data("point");
		var xPerc = pProgress.data("perc");
		var xTotalLenght = pProgress.data("totallenght") - (pProgress.data("totallenght") * xPerc);
		pProgress.data("point").css("stroke-dashoffset", xTotalLenght);
	},

	pvSetValue: function(pProgress, pValue){
		pValue = dbsfaces.math.round(parseFloat(pValue),2);
		xInt = String(dbsfaces.math.trunc(pValue, 0)); //Parte interira
		xDec = String(dbsfaces.math.round(pValue - xInt, 4)).substring(1, 4); //Parte decimal
		pProgress.attr("v", pValue);
		pProgress.data("percI", xInt);
		pProgress.data("percD", xDec);
		pProgress.data("perc", (pValue / 100));
		pProgress.data("dimension", Math.min(pProgress[0].getBoundingClientRect().height, pProgress[0].getBoundingClientRect().width));
	}

}
<|endoftext|>


<commit_before>
function LogonViewModel() {
  //JS used when the user is not yet logged on
  var self = this;

  self.enteredPassphrase = ko.observable('');
  self.generatedPassphrase = ko.observable('');
  self.walletGenProgressVal = ko.observable(0);

  self.USE_TESTNET = USE_TESTNET;
  self.IS_DEV = IS_DEV;

  self.sanitizedEnteredPassphrase = ko.computed(function(){ //cleans whitespace and gunk off the passphrase
    return $.trim(self.enteredPassphrase().toLowerCase());
  }, self);

  self.walletGenProgressWidth = ko.computed(function(){
    return self.walletGenProgressVal() + '%';
  }, self);

  self.isPassphraseValid = ko.computed(function() {
    var words = self.sanitizedEnteredPassphrase().split(' ');

    if (words.length != 12 && (words.length != 13 || words[0] != 'old')) {
      return false;
    }

    if (words.length==13) {
      words.shift();
    }

     var valid = true;
     words.forEach(function (word) {
       if (Mnemonic.words.indexOf(word) == -1) {
          valid = false;
       }
     });
     return valid;
  }, self);

  self.generatePassphrase = function() {
    var m = new Mnemonic(128); //128 bits of entropy (12 word passphrase)

    var words = m.toWords();
    self.generatedPassphrase(words.join(' '));

    //select the generated passphrase text
    selectText('generated');
  }

  self.showSecureKeyboard = function() {
    LOGON_PASSWORD_MODAL.show();
  }

  self.onReceivedPreferences = function(data) {
    //Initialize chat feeds (even through the chat pane will remain closed by default and the user has not started chatting)
    CHAT_FEED.init();

    var mustSavePreferencesToServer = false;

    if(data) { //user stored preferences located successfully
      assert(data && data.hasOwnProperty('preferences'), "Invalid stored preferences");
      PREFERENCES = data['preferences'];

      //Provide defaults for any missing fields in the stored preferences object
      for(var prop in DEFAULT_PREFERENCES) {
        if(DEFAULT_PREFERENCES.hasOwnProperty(prop)) {
          if(PREFERENCES[prop] === undefined) {
            $.jqlog.info("Providing default for preferences property: " + prop);
            PREFERENCES[prop] = DEFAULT_PREFERENCES[prop];
            mustSavePreferencesToServer = true;
          }
        }
      }
    } else { //could not find user stored preferences
      //No server had the preferences
      $.jqlog.log("Stored preferences NOT found on server(s). Creating new...");
      WALLET.isNew(true);

      //no stored preferences on any server(s) in the federation, go with the default...
      PREFERENCES = DEFAULT_PREFERENCES;
      mustSavePreferencesToServer = true;
    }

    WALLET_OPTIONS_MODAL.selectedTheme(PREFERENCES['selected_theme']);
    WALLET_OPTIONS_MODAL.selectedLang(PREFERENCES['selected_lang']);

    self.displayLicenseIfNecessary(mustSavePreferencesToServer);
  }

  self.openWallet = function() {
    //Start with a gate check to make sure at least one of the servers is ready and caught up before we try to log in
    multiAPI("is_ready", [], function(data, endpoint) {
      assert(data['caught_up'], "Invalid is_ready result"); //otherwise we should have gotten a 525 error
      assert(USE_TESTNET == data['testnet'], "USE_TESTNET is " + USE_TESTNET + " from URL-based detection, but the server API disagrees!");

      $.jqlog.log("Backend is ready. Testnet status: " + USE_TESTNET + ". Last message feed index: " + data['last_message_index']);
      assert(data['last_message_index'] > 0);

      //User is logging in...
      self.walletGenProgressVal(0); //reset so the progress bar hides again...
      $('#newAccountInfoPane').animate({opacity:0}); //fade out the new account pane if visible
      $('#createNewAcctBtnPane').animate({opacity:0}); //fade out the new account button pane if visible
      $('#extra-info').animate({opacity:0});
      $('#disclaimer').animate({opacity:0});

      //generate the wallet ID from a double SHA256 hash of the passphrase and the network (if testnet)
      var hashBase = CryptoJS.SHA256(self.sanitizedEnteredPassphrase() + (USE_TESTNET ? '_testnet' : ''));
      var hash = CryptoJS.SHA256(hashBase).toString(CryptoJS.enc.Base64);
      //var hashBase = self.sanitizedEnteredPassphrase() + (USE_TESTNET ? '_testnet' : '');

      WALLET.identifier(hash);
      $.jqlog.log("My wallet ID: " + WALLET.identifier());

      //Set initial block height (will be updated again on each periodic refresh of BTC account balances)
      WALLET.networkBlockHeight(data['block_height']);

      //Initialize the socket.io-driven event feed (notifies us in realtime of new events, as counterparty processes confirmed blocks)
      MESSAGE_FEED.init(data['last_message_index']);
      //^ set the "starting" message_index, under which we will ignore if received on the messages feed

      var onError = function(jqXHR, textStatus, errorThrown) {
        if (textStatus.indexOf('Already connected.') != -1) {
          var message = "<b class='errorColor'>You appear to be logged into Counterwallet elsewhere.</b> It's not safe to be logged into the same wallet account from multiple devices at the same time. If you are sure that this is not the case, press Continue. Otherwise, please press Cancel, logout from your other device, and try again.";
          var force = bootbox.confirm(message, function(force) {
            if (force) {
              multiAPINewest("get_preferences", {wallet_id: WALLET.identifier(), force_login: true}, 'last_updated', self.onReceivedPreferences);
            }
          });
        }
      }

      //Grab preferences
      multiAPINewest("get_preferences", [WALLET.identifier()], 'last_updated', self.onReceivedPreferences, onError);
    },
    function(jqXHR, textStatus, errorThrown, endpoint) {
      var message = describeError(jqXHR, textStatus, errorThrown);
      bootbox.alert("No counterparty servers are currently available. Please try again later. ERROR: " + message);
    });
  }

  self.displayLicenseIfNecessary = function(mustSavePreferencesToServer) {
    if(!PREFERENCES['has_accepted_license']) {
      LICENSE_MODAL.show(mustSavePreferencesToServer); //User must accept the license before moving on
    } else {
      //Generate the wallet addresses
      self.openWalletPt2(mustSavePreferencesToServer);
    }
  }

  self.openWalletPt2 = function(mustSavePreferencesToServer) {
      //generate the appropriate number of addresses
      WALLET.BITCOIN_WALLET = new CWHierarchicalKey(self.enteredPassphrase());
      WALLET.isOldWallet(WALLET.BITCOIN_WALLET.useOldHierarchicalKey);
      //kick off address generation (we have to take this hacky approach of using setTimeout, otherwise the
      // progress bar does not update correctly through the HD wallet build process....)
      setTimeout(function() { self.genAddress(mustSavePreferencesToServer) }, 1);
  }

  self.genAddress = function(mustSavePreferencesToServer) {

    var i = WALLET.addresses().length;
    var address = WALLET.addAddress();
    var addressHash = hashToB64(address);

    if(PREFERENCES.address_aliases[addressHash] === undefined) { //no existing label. we need to set one
      mustSavePreferencesToServer = true; //if not already true
      PREFERENCES.address_aliases[addressHash] = "My Address #" + (i + 1);
    }

    var progress = (i + 1) * (100 / PREFERENCES['num_addresses_used']);
    self.walletGenProgressVal(progress);
    $.jqlog.debug("Progress: Address " + (i + 1) + " of " + PREFERENCES['num_addresses_used']
      + " (" + self.walletGenProgressVal() + "%) -- " + address);

    if(i + 1 < PREFERENCES['num_addresses_used']) {
      setTimeout(function() { self.genAddress(mustSavePreferencesToServer) }, 1);
    } else {
      return self.openWalletPt3(mustSavePreferencesToServer);
    }
  }

  self.updateBalances = function(onSuccess) {
    //updates all balances for all addesses, creating the asset objects on the address if need be
    WALLET.refreshBTCBalances(true);
    //^ specify true here to start a recurring get BTC balances timer chain

    WALLET.refreshCounterpartyBalances(WALLET.getAddressesList(), onSuccess);
  }

  self.openWalletPt3 = function(mustSavePreferencesToServer) {
    var i = null;

    //add in the watch only addresses
    if(PREFERENCES['watch_only_addresses'] === undefined) {
      PREFERENCES['watch_only_addresses'] = [];
      mustSavePreferencesToServer = true;
    }
    for(i=0; i < PREFERENCES['watch_only_addresses'].length; i++) {
      WALLET.addWatchOnlyAddress(PREFERENCES['watch_only_addresses'][i]);
    }

    /* hide the login div and show the other divs */
    $('#logon').hide();
    $('#header').show();
    $('#left-panel').show();
    $('#main').show();

    //store the preferences on the server(s) for future use
    if(mustSavePreferencesToServer) {
      $.jqlog.info("Preferences updated/generated during login. Updating on server(s)...");
      multiAPI("store_preferences",
        {'wallet_id': WALLET.identifier(),
         'preferences': PREFERENCES,
         'network': USE_TESTNET ? 'testnet' : 'mainnet',
         'for_login': true,
         'referer': ORIG_REFERER
        });
    }

    //Update the wallet balances (isAtLogon = true)
    self.updateBalances(self.openWalletPt4);
  }

  self.openWalletPt4 = function() {
    PENDING_ACTION_FEED.restoreFromLocalStorage(function() {
      //load the waiting btc feed after the pending action feed is all done loading, as we look at the pending action
      // feed to determine whether a btcpay process is in progress (pending) or not
      WAITING_BTCPAY_FEED.restore();
    });
    OPEN_ORDER_FEED.restore();

    //all done. load the balances screen
    $.jqlog.debug("Login complete. Directing to balances page...");
    window.location.hash = 'pages/balances.html';
  }
}

function LicenseModalViewModel() {
  var self = this;
  self.shown = ko.observable(false);

  self.show = function() {
    self.shown(true);

    //Load in the license file text into the textarea
    $.get( "pages/license.html", function( data ) {
      $("#licenseAgreementText").val(data);
    });
  }

  self.hide = function() {
    self.shown(false);
  }

  self.acceptTerms = function() {
    //Continue on to generate the wallet addresses
    PREFERENCES['has_accepted_license'] = true;
    self.shown(false);
    LOGON_VIEW_MODEL.openWalletPt2(true); //save the prefs to the server as we updated them
  }
}

ko.validation.rules['isValidPassphrasePart'] = {
    validator: function (val, self) {
      return Mnemonic.words.indexOf(val)!=-1;
    },
    message: 'Invalid phrase word.'
};
ko.validation.registerExtenders();
function LogonPasswordModalViewModel() {
  var self = this;
  self.shown = ko.observable(false);
  self.pwPart01 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart02 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart03 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart04 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart05 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart06 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart07 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart08 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart09 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart10 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart11 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart12 = ko.observable().extend({ required: true, isValidPassphrasePart: self });

  self.validationModel = ko.validatedObservable({
    pwPart01: self.pwPart01,
    pwPart02: self.pwPart02,
    pwPart03: self.pwPart03,
    pwPart04: self.pwPart04,
    pwPart05: self.pwPart05,
    pwPart06: self.pwPart06,
    pwPart07: self.pwPart07,
    pwPart08: self.pwPart08,
    pwPart09: self.pwPart09,
    pwPart10: self.pwPart10,
    pwPart11: self.pwPart11,
    pwPart12: self.pwPart12
  });

  self.dispFullPassphrase = ko.computed(function() {
    return [
      self.pwPart01(), self.pwPart02(), self.pwPart03(), self.pwPart04(),
      self.pwPart05(), self.pwPart06(), self.pwPart07(), self.pwPart08(),
      self.pwPart09(), self.pwPart10(), self.pwPart11(), self.pwPart12()
    ].join(' ');
  }, self);

  self.resetForm = function() {
    self.pwPart01('');
    self.pwPart02('');
    self.pwPart03('');
    self.pwPart04('');
    self.pwPart05('');
    self.pwPart06('');
    self.pwPart07('');
    self.pwPart08('');
    self.pwPart09('');
    self.pwPart10('');
    self.pwPart11('');
    self.pwPart12('');
    self.validationModel.errors.showAllMessages(false);
  }

  self.submitForm = function() {
    if (!self.validationModel.isValid()) {
      self.validationModel.errors.showAllMessages();
      return false;
    }
    //data entry is valid...submit to trigger doAction()
    $('#logonPassphaseModal form').submit();
  }

  self.show = function(resetForm) {
    if(typeof(resetForm)==='undefined') resetForm = true;
    if(resetForm) self.resetForm();

    //TODO: choose a random X/Y coords for the modal

    $('#logonPassphaseModal input').click(function(e) {
      $(e.currentTarget).val(''); //clear the field on click
    });

    //Set up keyboard
    $('#logonPassphaseModal input').keyboard({
      display: {
        'bksp'   :  "\u2190",
        'accept' : 'Accept',
      },
      layout: 'custom',
      customLayout: {
        'default': [
          'q w e r t y u i o p {bksp}',
          'a s d f g h j k l',
          ' z x c v b n m {accept}'
        ],
      },
      autoAccept: true,
      usePreview: true,
      initialFocus : false,
      restrictInput: true,
      preventPaste: true
      /*acceptValue: true,
      validate: function(keyboard, value, isClosing) {
        return Mnemonic.words.indexOf(value)!=-1;
      }*/
    }).autocomplete({
      source: Mnemonic.words
    }).addAutocomplete();

    // Overrides the default autocomplete filter function to search only from the beginning of the string
    $.ui.autocomplete.filter = function (array, term) {
        var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(term), "i");
        return $.grep(array, function (value) {
            return matcher.test(value.label || value.value || value);
        });
    };

    self.shown(true);
  }

  self.hide = function() {
    self.shown(false);
  }

  self.doAction = function() {
    //simply fill in the data back into the passphrase field and close the dialog
    $('#password').val(self.dispFullPassphrase());
    self.resetForm(); //clear out the dialog too, for security
    self.shown(false);
    $('#walletLogin').click();
  }
}

/*NOTE: Any code here is only triggered the first time the page is visited. Put JS that needs to run on the
  first load and subsequent ajax page switches in the .html <script> tag*/
<commit_msg>button continue<commit_after>
function LogonViewModel() {
  //JS used when the user is not yet logged on
  var self = this;

  self.enteredPassphrase = ko.observable('');
  self.generatedPassphrase = ko.observable('');
  self.walletGenProgressVal = ko.observable(0);

  self.USE_TESTNET = USE_TESTNET;
  self.IS_DEV = IS_DEV;

  self.sanitizedEnteredPassphrase = ko.computed(function(){ //cleans whitespace and gunk off the passphrase
    return $.trim(self.enteredPassphrase().toLowerCase());
  }, self);

  self.walletGenProgressWidth = ko.computed(function(){
    return self.walletGenProgressVal() + '%';
  }, self);

  self.isPassphraseValid = ko.computed(function() {
    var words = self.sanitizedEnteredPassphrase().split(' ');

    if (words.length != 12 && (words.length != 13 || words[0] != 'old')) {
      return false;
    }

    if (words.length==13) {
      words.shift();
    }

     var valid = true;
     words.forEach(function (word) {
       if (Mnemonic.words.indexOf(word) == -1) {
          valid = false;
       }
     });
     return valid;
  }, self);

  self.generatePassphrase = function() {
    var m = new Mnemonic(128); //128 bits of entropy (12 word passphrase)

    var words = m.toWords();
    self.generatedPassphrase(words.join(' '));

    //select the generated passphrase text
    selectText('generated');
  }

  self.showSecureKeyboard = function() {
    LOGON_PASSWORD_MODAL.show();
  }

  self.onReceivedPreferences = function(data) {
    //Initialize chat feeds (even through the chat pane will remain closed by default and the user has not started chatting)
    CHAT_FEED.init();

    var mustSavePreferencesToServer = false;

    if(data) { //user stored preferences located successfully
      assert(data && data.hasOwnProperty('preferences'), "Invalid stored preferences");
      PREFERENCES = data['preferences'];

      //Provide defaults for any missing fields in the stored preferences object
      for(var prop in DEFAULT_PREFERENCES) {
        if(DEFAULT_PREFERENCES.hasOwnProperty(prop)) {
          if(PREFERENCES[prop] === undefined) {
            $.jqlog.info("Providing default for preferences property: " + prop);
            PREFERENCES[prop] = DEFAULT_PREFERENCES[prop];
            mustSavePreferencesToServer = true;
          }
        }
      }
    } else { //could not find user stored preferences
      //No server had the preferences
      $.jqlog.log("Stored preferences NOT found on server(s). Creating new...");
      WALLET.isNew(true);

      //no stored preferences on any server(s) in the federation, go with the default...
      PREFERENCES = DEFAULT_PREFERENCES;
      mustSavePreferencesToServer = true;
    }

    WALLET_OPTIONS_MODAL.selectedTheme(PREFERENCES['selected_theme']);
    WALLET_OPTIONS_MODAL.selectedLang(PREFERENCES['selected_lang']);

    self.displayLicenseIfNecessary(mustSavePreferencesToServer);
  }

  self.openWallet = function() {
    //Start with a gate check to make sure at least one of the servers is ready and caught up before we try to log in
    multiAPI("is_ready", [], function(data, endpoint) {
      assert(data['caught_up'], "Invalid is_ready result"); //otherwise we should have gotten a 525 error
      assert(USE_TESTNET == data['testnet'], "USE_TESTNET is " + USE_TESTNET + " from URL-based detection, but the server API disagrees!");

      $.jqlog.log("Backend is ready. Testnet status: " + USE_TESTNET + ". Last message feed index: " + data['last_message_index']);
      assert(data['last_message_index'] > 0);

      //User is logging in...
      self.walletGenProgressVal(0); //reset so the progress bar hides again...
      $('#newAccountInfoPane').animate({opacity:0}); //fade out the new account pane if visible
      $('#createNewAcctBtnPane').animate({opacity:0}); //fade out the new account button pane if visible
      $('#extra-info').animate({opacity:0});
      $('#disclaimer').animate({opacity:0});

      //generate the wallet ID from a double SHA256 hash of the passphrase and the network (if testnet)
      var hashBase = CryptoJS.SHA256(self.sanitizedEnteredPassphrase() + (USE_TESTNET ? '_testnet' : ''));
      var hash = CryptoJS.SHA256(hashBase).toString(CryptoJS.enc.Base64);
      //var hashBase = self.sanitizedEnteredPassphrase() + (USE_TESTNET ? '_testnet' : '');

      WALLET.identifier(hash);
      $.jqlog.log("My wallet ID: " + WALLET.identifier());

      //Set initial block height (will be updated again on each periodic refresh of BTC account balances)
      WALLET.networkBlockHeight(data['block_height']);

      //Initialize the socket.io-driven event feed (notifies us in realtime of new events, as counterparty processes confirmed blocks)
      MESSAGE_FEED.init(data['last_message_index']);
      //^ set the "starting" message_index, under which we will ignore if received on the messages feed

      var onError = function(jqXHR, textStatus, errorThrown) {
        if (textStatus.indexOf('Already connected.') != -1) {
          var message = "<b class='errorColor'>You appear to be logged into Counterwallet elsewhere.</b> It's not safe to be logged into the same wallet account from multiple devices at the same time. If you are sure that this is not the case, press Continue. Otherwise, please press Cancel, logout from your other device, and try again.";

          bootbox.dialog({
            title: "Confirm connection",
            message: message,
            buttons: {
              "cancel": {
                label: "Cancel",
                className: "btn-danger",
                callback: function() {
                  bootbox.hideAll();
                  return false;
                }
              },
              "continue": {
                label: "Continue",
                className: "btn-primary",
                callback: function() {
                  multiAPINewest("get_preferences", {wallet_id: WALLET.identifier(), force_login: true}, 'last_updated', self.onReceivedPreferences);
                }
              }
            }
          });

        }
      }

      //Grab preferences
      multiAPINewest("get_preferences", [WALLET.identifier()], 'last_updated', self.onReceivedPreferences, onError);
    },
    function(jqXHR, textStatus, errorThrown, endpoint) {
      var message = describeError(jqXHR, textStatus, errorThrown);
      bootbox.alert("No counterparty servers are currently available. Please try again later. ERROR: " + message);
    });
  }

  self.displayLicenseIfNecessary = function(mustSavePreferencesToServer) {
    if(!PREFERENCES['has_accepted_license']) {
      LICENSE_MODAL.show(mustSavePreferencesToServer); //User must accept the license before moving on
    } else {
      //Generate the wallet addresses
      self.openWalletPt2(mustSavePreferencesToServer);
    }
  }

  self.openWalletPt2 = function(mustSavePreferencesToServer) {
      //generate the appropriate number of addresses
      WALLET.BITCOIN_WALLET = new CWHierarchicalKey(self.enteredPassphrase());
      WALLET.isOldWallet(WALLET.BITCOIN_WALLET.useOldHierarchicalKey);
      //kick off address generation (we have to take this hacky approach of using setTimeout, otherwise the
      // progress bar does not update correctly through the HD wallet build process....)
      setTimeout(function() { self.genAddress(mustSavePreferencesToServer) }, 1);
  }

  self.genAddress = function(mustSavePreferencesToServer) {

    var i = WALLET.addresses().length;
    var address = WALLET.addAddress();
    var addressHash = hashToB64(address);

    if(PREFERENCES.address_aliases[addressHash] === undefined) { //no existing label. we need to set one
      mustSavePreferencesToServer = true; //if not already true
      PREFERENCES.address_aliases[addressHash] = "My Address #" + (i + 1);
    }

    var progress = (i + 1) * (100 / PREFERENCES['num_addresses_used']);
    self.walletGenProgressVal(progress);
    $.jqlog.debug("Progress: Address " + (i + 1) + " of " + PREFERENCES['num_addresses_used']
      + " (" + self.walletGenProgressVal() + "%) -- " + address);

    if(i + 1 < PREFERENCES['num_addresses_used']) {
      setTimeout(function() { self.genAddress(mustSavePreferencesToServer) }, 1);
    } else {
      return self.openWalletPt3(mustSavePreferencesToServer);
    }
  }

  self.updateBalances = function(onSuccess) {
    //updates all balances for all addesses, creating the asset objects on the address if need be
    WALLET.refreshBTCBalances(true);
    //^ specify true here to start a recurring get BTC balances timer chain

    WALLET.refreshCounterpartyBalances(WALLET.getAddressesList(), onSuccess);
  }

  self.openWalletPt3 = function(mustSavePreferencesToServer) {
    var i = null;

    //add in the watch only addresses
    if(PREFERENCES['watch_only_addresses'] === undefined) {
      PREFERENCES['watch_only_addresses'] = [];
      mustSavePreferencesToServer = true;
    }
    for(i=0; i < PREFERENCES['watch_only_addresses'].length; i++) {
      WALLET.addWatchOnlyAddress(PREFERENCES['watch_only_addresses'][i]);
    }

    /* hide the login div and show the other divs */
    $('#logon').hide();
    $('#header').show();
    $('#left-panel').show();
    $('#main').show();

    //store the preferences on the server(s) for future use
    if(mustSavePreferencesToServer) {
      $.jqlog.info("Preferences updated/generated during login. Updating on server(s)...");
      multiAPI("store_preferences",
        {'wallet_id': WALLET.identifier(),
         'preferences': PREFERENCES,
         'network': USE_TESTNET ? 'testnet' : 'mainnet',
         'for_login': true,
         'referer': ORIG_REFERER
        });
    }

    //Update the wallet balances (isAtLogon = true)
    self.updateBalances(self.openWalletPt4);
  }

  self.openWalletPt4 = function() {
    PENDING_ACTION_FEED.restoreFromLocalStorage(function() {
      //load the waiting btc feed after the pending action feed is all done loading, as we look at the pending action
      // feed to determine whether a btcpay process is in progress (pending) or not
      WAITING_BTCPAY_FEED.restore();
    });
    OPEN_ORDER_FEED.restore();

    //all done. load the balances screen
    $.jqlog.debug("Login complete. Directing to balances page...");
    window.location.hash = 'pages/balances.html';
  }
}

function LicenseModalViewModel() {
  var self = this;
  self.shown = ko.observable(false);

  self.show = function() {
    self.shown(true);

    //Load in the license file text into the textarea
    $.get( "pages/license.html", function( data ) {
      $("#licenseAgreementText").val(data);
    });
  }

  self.hide = function() {
    self.shown(false);
  }

  self.acceptTerms = function() {
    //Continue on to generate the wallet addresses
    PREFERENCES['has_accepted_license'] = true;
    self.shown(false);
    LOGON_VIEW_MODEL.openWalletPt2(true); //save the prefs to the server as we updated them
  }
}

ko.validation.rules['isValidPassphrasePart'] = {
    validator: function (val, self) {
      return Mnemonic.words.indexOf(val)!=-1;
    },
    message: 'Invalid phrase word.'
};
ko.validation.registerExtenders();
function LogonPasswordModalViewModel() {
  var self = this;
  self.shown = ko.observable(false);
  self.pwPart01 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart02 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart03 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart04 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart05 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart06 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart07 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart08 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart09 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart10 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart11 = ko.observable().extend({ required: true, isValidPassphrasePart: self });
  self.pwPart12 = ko.observable().extend({ required: true, isValidPassphrasePart: self });

  self.validationModel = ko.validatedObservable({
    pwPart01: self.pwPart01,
    pwPart02: self.pwPart02,
    pwPart03: self.pwPart03,
    pwPart04: self.pwPart04,
    pwPart05: self.pwPart05,
    pwPart06: self.pwPart06,
    pwPart07: self.pwPart07,
    pwPart08: self.pwPart08,
    pwPart09: self.pwPart09,
    pwPart10: self.pwPart10,
    pwPart11: self.pwPart11,
    pwPart12: self.pwPart12
  });

  self.dispFullPassphrase = ko.computed(function() {
    return [
      self.pwPart01(), self.pwPart02(), self.pwPart03(), self.pwPart04(),
      self.pwPart05(), self.pwPart06(), self.pwPart07(), self.pwPart08(),
      self.pwPart09(), self.pwPart10(), self.pwPart11(), self.pwPart12()
    ].join(' ');
  }, self);

  self.resetForm = function() {
    self.pwPart01('');
    self.pwPart02('');
    self.pwPart03('');
    self.pwPart04('');
    self.pwPart05('');
    self.pwPart06('');
    self.pwPart07('');
    self.pwPart08('');
    self.pwPart09('');
    self.pwPart10('');
    self.pwPart11('');
    self.pwPart12('');
    self.validationModel.errors.showAllMessages(false);
  }

  self.submitForm = function() {
    if (!self.validationModel.isValid()) {
      self.validationModel.errors.showAllMessages();
      return false;
    }
    //data entry is valid...submit to trigger doAction()
    $('#logonPassphaseModal form').submit();
  }

  self.show = function(resetForm) {
    if(typeof(resetForm)==='undefined') resetForm = true;
    if(resetForm) self.resetForm();

    //TODO: choose a random X/Y coords for the modal

    $('#logonPassphaseModal input').click(function(e) {
      $(e.currentTarget).val(''); //clear the field on click
    });

    //Set up keyboard
    $('#logonPassphaseModal input').keyboard({
      display: {
        'bksp'   :  "\u2190",
        'accept' : 'Accept',
      },
      layout: 'custom',
      customLayout: {
        'default': [
          'q w e r t y u i o p {bksp}',
          'a s d f g h j k l',
          ' z x c v b n m {accept}'
        ],
      },
      autoAccept: true,
      usePreview: true,
      initialFocus : false,
      restrictInput: true,
      preventPaste: true
      /*acceptValue: true,
      validate: function(keyboard, value, isClosing) {
        return Mnemonic.words.indexOf(value)!=-1;
      }*/
    }).autocomplete({
      source: Mnemonic.words
    }).addAutocomplete();

    // Overrides the default autocomplete filter function to search only from the beginning of the string
    $.ui.autocomplete.filter = function (array, term) {
        var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(term), "i");
        return $.grep(array, function (value) {
            return matcher.test(value.label || value.value || value);
        });
    };

    self.shown(true);
  }

  self.hide = function() {
    self.shown(false);
  }

  self.doAction = function() {
    //simply fill in the data back into the passphrase field and close the dialog
    $('#password').val(self.dispFullPassphrase());
    self.resetForm(); //clear out the dialog too, for security
    self.shown(false);
    $('#walletLogin').click();
  }
}

/*NOTE: Any code here is only triggered the first time the page is visited. Put JS that needs to run on the
  first load and subsequent ajax page switches in the .html <script> tag*/
<|endoftext|>


<commit_before>angular.module('fileupload', [])
.directive('myFileupload', function() {
    return {
        restrict: 'A'
      , link: function(scope, element, attrs) {
            $(element).fileupload({
                dataType: 'json'
              , change: function(e, data) {
 		            $('#changeCoverButton #changeButtonText').html('Uploading...');
                }
              , success: function(data) {
	                $('#changeCoverButton #changeButtonText').html('Crunching Image...');

                    if(data.error) {

                        $('#changeCoverButton #changeButtonText').html(data.error + ' Click to Choose File Again' );

                    } else {

                        $('#coverPhoto').attr('src', data.msg);
                        $('#defaultCoverPhoto').remove();

                        $('<img />')
                            .attr('src', data.msg)
                            .load(function() {
                                $('#changeCoverButton').fadeOut('fast',function(){
                                    $(this).find('#changeButtonText').html('Change Cover');
                                    $('#dragPhoto').fadeIn('fast');
                                    $('#saveCoverButton').fadeIn('fast');
                                });
                        });
                        make_cover_undraggable(false);
                    }
                }
            });
        }
    }
})
.directive('saveMyupload', function() {
    return {
        restrict: 'A'
      , link: function(scope, element, attrs) {
            $(element).bind('click', function(e) {

                var cover_src = $('#theCover img');
                var img_src_attrs = {
                    src : cover_src.attr('src'),
                    top : cover_src.offset().top,
                    left: 0
                }

                $.ajax({
                    url: "/imageprocessing/savecoverphoto",
                    type: "POST",
                    dataType: "JSON",
                    data: img_src_attrs,
                    success: function(res) {
     		            $(element).html('Cover Saved');
                        var timeout;
                        if(timeout) {
                            clearTimeout(timeout);
                            timeout = null;
                        }
                        timeout = setTimeout(hide_save_button, 1000);
                    }
                });

                e.preventDefault();
            });
        }
    }
})

function make_cover_undraggable(opt) {
    if(!opt) {
        console.log('Making Draggable');
        $("#theCover img").load(function(){
            var offset = $(this).parent().offset();
            var offsetX = offset.left;
            $(this).each(function(){
                var imgH = $(this).height();
                var parH = $(this).parent().height();
                var imgW = $(this).width();
                var parW = $(this).parent().width();
                var ipH = imgH-parH;
                var ipW = imgW-parW-offsetX;
                $(this).draggable({ containment: [-ipW, -ipH, offsetX, 0], scroll: false, disabled: opt});
            });
        });
    } else {
        console.log('Draggable Disabled');
        $("#theCover img").draggable({disabled: true});
    }
}

function hide_save_button(){
    $('#saveCoverButton').fadeOut('fast',function(){
        $(this).html('Save Cover');
    });
    $('#changeCoverButton').fadeIn('fast');
    $('#dragPhoto').fadeOut('fast');
    make_cover_undraggable(true);
}
<commit_msg>updated<commit_after>angular.module('fileupload', [])
.directive('myFileupload', function() {
    return {
        restrict: 'A'
      , link: function(scope, element, attrs) {
            $(element).fileupload({
                dataType: 'json'
              , change: function(e, data) {
 		            $('#changeCoverButton #changeButtonText').html('Uploading...');
                }
              , success: function(data) {
	                $('#changeCoverButton #changeButtonText').html('Crunching Image...');

                    if(data.error) {

                        $('#changeCoverButton #changeButtonText').html(data.error + ' Click to Choose File Again' );

                    } else {

                        $('#coverPhoto').attr('src', data.msg);
                        $('#defaultCoverPhoto').remove();

                        $('<img />')
                            .attr('src', data.msg)
                            .load(function() {
                                $('#changeCoverButton').fadeOut('fast',function(){
                                    $(this).find('#changeButtonText').html('Change Cover');
                                    $('#dragPhoto').fadeIn('fast');
                                    $('#saveCoverButton').fadeIn('fast');
                                });
                        });
                        make_cover_undraggable(false);
                    }
                }
            });
        }
    }
})
.directive('saveMyupload', function() {
    return {
        restrict: 'A'
      , link: function(scope, element, attrs) {
            $(element).bind('click', function(e) {

                var cover_src = $('#theCover img');
                var img_src_attrs = {
                    src : cover_src.attr('src'),
                    top : cover_src.offset().top,
                    left: 0
                }

                $.ajax({
                    url: "/imageprocessing/savecoverphoto",
                    type: "POST",
                    dataType: "JSON",
                    data: img_src_attrs,
                    success: function(res) {
     		            $(element).html('Cover Saved');
                        /*
                        var timeout;
                        if(timeout) {
                            clearTimeout(timeout);
                            timeout = null;
                        }
                        timeout = setTimeout(hide_save_button, 1000);
                        */
                        hide_save_button();
                    }
                });

                e.preventDefault();
            });
        }
    }
})

function make_cover_undraggable(opt) {
    if(!opt) {
        console.log('Making Draggable');
        $("#theCover img").load(function(){
            var offset = $(this).parent().offset();
            var offsetX = offset.left;
            $(this).each(function(){
                var imgH = $(this).height();
                var parH = $(this).parent().height();
                var imgW = $(this).width();
                var parW = $(this).parent().width();
                var ipH = imgH-parH;
                var ipW = imgW-parW-offsetX;
                $(this).draggable({ containment: [-ipW, -ipH, offsetX, 0], scroll: false, disabled: opt});
            });
        });
    } else {
        console.log('Draggable Disabled');
        $("#theCover img").draggable({disabled: true});
    }
}

function hide_save_button(){
    $('#saveCoverButton').fadeOut('fast',function(){
        $(this).html('Save Cover');
    });
    $('#changeCoverButton').fadeIn('fast');
    $('#dragPhoto').fadeOut('fast');
    make_cover_undraggable(true);
}
<|endoftext|>


<commit_before>require('./raf-polyfill')();

var Game = require('./game');

var Input = require('./input');
var Time = require('./time');

var Debugger = require('potion-debugger');

var StateManager = require('./state-manager');

/**
 * Main Engine class which calls the game methods
 * @constructor
 */
var Engine = function(container, methods) {
  var GameClass = this._subclassGame(container, methods);

  container.style.position = 'relative';

  var canvas = document.createElement('canvas');
  canvas.width = container.clientWidth;
  canvas.height = container.clientHeight;
  canvas.style.display = 'block';
  container.appendChild(canvas);

  this.game = new GameClass(canvas);
  this.game.debug = new Debugger(this.game);

  this._setDefaultStates();

  if (this.game.config.addInputEvents) {
    this.game.input = new Input(this.game, container);
  }

  this.tickFunc = (function (self) { return function() { self.tick(); }; })(this);
  this.preloaderTickFunc = (function (self) { return function() { self._preloaderTick(); }; })(this);

  this.strayTime = 0;

  this._time = Time.now();

  this.game.assets.onload(function() {
    this.start();

    window.cancelAnimationFrame(this.preloaderId);
    window.requestAnimationFrame(this.tickFunc);
  }.bind(this));

  if (this.game.assets.isLoading) {
    this.preloaderId = window.requestAnimationFrame(this.preloaderTickFunc);
  }
};

/**
 * Add event listener for window events
 * @private
 */
Engine.prototype.addEvents = function() {
  var self = this;

  var game = self.game;
  window.addEventListener('resize', function() {
    game.video.setSize(self.game.canvas.parentElement.clientWidth, self.game.canvas.parentElement.clientHeight);

    game.width = game.video.width;
    game.height = game.video.height;
  });

  window.addEventListener('blur', function() {
    self.game.input.resetKeys();
    self.game.blur();
  });

  window.addEventListener('focus', function() {
    self.game.input.resetKeys();
    self.game.focus();
  });
};

/**
 * Starts the game, adds events and run first frame
 * @private
 */
Engine.prototype.start = function() {
  if (this.game.config.addInputEvents) {
    this.addEvents();
  }
};

/**
 * Main tick function in game loop
 * @private
 */
Engine.prototype.tick = function() {
  window.requestAnimationFrame(this.tickFunc);

  var now = Time.now();
  var time = (now - this._time) / 1000;
  this._time = now;

  this.update(time);
  this.game.states.exitUpdate(time);
  this.render();
};

/**
 * Updates the game
 * @param {number} time - time in seconds since last frame
 * @private
 */
Engine.prototype.update = function(time) {
  if (time > this.game.config.maxStepTime) { time = this.game.config.maxStepTime; }

  if (this.game.config.fixedStep) {
    this.strayTime = this.strayTime + time;
    while (this.strayTime >= this.game.config.stepTime) {
      this.strayTime = this.strayTime - this.game.config.stepTime;
      this.game.states.update(this.game.config.stepTime);
    }
  } else {
    this.game.states.update(time);
  }
};

/**
 * Renders the game
 * @private
 */
Engine.prototype.render = function() {
  this.game.video.beginFrame();

  this.game.video.clear();

  this.game.states.render();

  this.game.video.endFrame();
};

/**
 * Main tick function in preloader loop
 * @private
 */
Engine.prototype._preloaderTick = function() {
  this.preloaderId = window.requestAnimationFrame(this.preloaderTickFunc);

  var now = Time.now();
  var time = (now - this._time) / 1000;
  this._time = now;

  if (this.game.config.showPreloader) {
    this.game.video.clear();
    this.game.preloading(time);
  }
};

Engine.prototype._setDefaultStates = function() {
  var states = new StateManager();
  states.add('app', this.game);
  states.add('debug', this.game.debug);

  states.protect('app');
  states.protect('debug');

  this.game.states = states;
};

Engine.prototype._subclassGame = function(container, methods) {
  var GameClass = function(container) {
    Game.call(this, container);
  };

  GameClass.prototype = Object.create(Game.prototype);

  for (var method in methods) {
    GameClass.prototype[method] = methods[method];
  }

  return GameClass;
};

module.exports = Engine;
<commit_msg>use correct method for resizing in resize event<commit_after>require('./raf-polyfill')();

var Game = require('./game');

var Input = require('./input');
var Time = require('./time');

var Debugger = require('potion-debugger');

var StateManager = require('./state-manager');

/**
 * Main Engine class which calls the game methods
 * @constructor
 */
var Engine = function(container, methods) {
  var GameClass = this._subclassGame(container, methods);

  container.style.position = 'relative';

  var canvas = document.createElement('canvas');
  canvas.width = container.clientWidth;
  canvas.height = container.clientHeight;
  canvas.style.display = 'block';
  container.appendChild(canvas);

  this.game = new GameClass(canvas);
  this.game.debug = new Debugger(this.game);

  this._setDefaultStates();

  if (this.game.config.addInputEvents) {
    this.game.input = new Input(this.game, container);
  }

  this.tickFunc = (function (self) { return function() { self.tick(); }; })(this);
  this.preloaderTickFunc = (function (self) { return function() { self._preloaderTick(); }; })(this);

  this.strayTime = 0;

  this._time = Time.now();

  this.game.assets.onload(function() {
    this.start();

    window.cancelAnimationFrame(this.preloaderId);
    window.requestAnimationFrame(this.tickFunc);
  }.bind(this));

  if (this.game.assets.isLoading) {
    this.preloaderId = window.requestAnimationFrame(this.preloaderTickFunc);
  }
};

/**
 * Add event listener for window events
 * @private
 */
Engine.prototype.addEvents = function() {
  var self = this;

  var game = self.game;
  window.addEventListener('resize', function() {
    game.setSize(self.game.canvas.parentElement.clientWidth, self.game.canvas.parentElement.clientHeight);
  });

  window.addEventListener('blur', function() {
    self.game.input.resetKeys();
    self.game.blur();
  });

  window.addEventListener('focus', function() {
    self.game.input.resetKeys();
    self.game.focus();
  });
};

/**
 * Starts the game, adds events and run first frame
 * @private
 */
Engine.prototype.start = function() {
  if (this.game.config.addInputEvents) {
    this.addEvents();
  }
};

/**
 * Main tick function in game loop
 * @private
 */
Engine.prototype.tick = function() {
  window.requestAnimationFrame(this.tickFunc);

  var now = Time.now();
  var time = (now - this._time) / 1000;
  this._time = now;

  this.update(time);
  this.game.states.exitUpdate(time);
  this.render();
};

/**
 * Updates the game
 * @param {number} time - time in seconds since last frame
 * @private
 */
Engine.prototype.update = function(time) {
  if (time > this.game.config.maxStepTime) { time = this.game.config.maxStepTime; }

  if (this.game.config.fixedStep) {
    this.strayTime = this.strayTime + time;
    while (this.strayTime >= this.game.config.stepTime) {
      this.strayTime = this.strayTime - this.game.config.stepTime;
      this.game.states.update(this.game.config.stepTime);
    }
  } else {
    this.game.states.update(time);
  }
};

/**
 * Renders the game
 * @private
 */
Engine.prototype.render = function() {
  this.game.video.beginFrame();

  this.game.video.clear();

  this.game.states.render();

  this.game.video.endFrame();
};

/**
 * Main tick function in preloader loop
 * @private
 */
Engine.prototype._preloaderTick = function() {
  this.preloaderId = window.requestAnimationFrame(this.preloaderTickFunc);

  var now = Time.now();
  var time = (now - this._time) / 1000;
  this._time = now;

  if (this.game.config.showPreloader) {
    this.game.video.clear();
    this.game.preloading(time);
  }
};

Engine.prototype._setDefaultStates = function() {
  var states = new StateManager();
  states.add('app', this.game);
  states.add('debug', this.game.debug);

  states.protect('app');
  states.protect('debug');

  this.game.states = states;
};

Engine.prototype._subclassGame = function(container, methods) {
  var GameClass = function(container) {
    Game.call(this, container);
  };

  GameClass.prototype = Object.create(Game.prototype);

  for (var method in methods) {
    GameClass.prototype[method] = methods[method];
  }

  return GameClass;
};

module.exports = Engine;
<|endoftext|>