<commit_before>/**
 * @module storj/constants
 * @license LGPL-3.0
 */

'use strict';

module.exports = {
  /** @constant {String} CIPHER_ALG - Cipher/Decipher algorithm */
  CIPHER_ALG: 'aes-256-ctr',
  /** @constant {Number} PREFIX - NodeID prefix (same as bitcoin) */
  PREFIX: 0x00,
  /** @constant {Number} NONCE_EXPIRE - Time to honor a signed message */
  NONCE_EXPIRE: 60000,
  /** @constant {Number} RPC_TIMEOUT - Max wait time for a RPC response */
  RPC_TIMEOUT: 60000,
  /** @constant {Number} PUBLISH_TTL - Max time for publication relay */
  PUBLISH_TTL: 5000,
  /** @constant {Number} NET_REENTRY - Max wait time before re-entering net */
  NET_REENTRY: 600000,
  /** @constant {Number} AUDIT_BYTES - Number of bytes for audit challenge */
  AUDIT_BYTES: 32,
  /** @constant {Number} CLEAN_INTERVAL - Interval for reaping stale shards */
  CLEAN_INTERVAL: 10800000,
  /** @constant {Number} CONSIGN_THRESHOLD - Threshold for consign time */
  CONSIGN_THRESHOLD: 86400000,
  /** @constant {Number} TOKEN_EXPIRE - Reject datachannl token after time */
  TOKEN_EXPIRE: 86400000,
  /** @constant {Number} TUNNEL_ANNOUNCE_INTERVAL - Announce tunnel state */
  TUNNEL_ANNOUNCE_INTERVAL: 900000,
  /** @constant {Number} OFFER_TIMEOUT - Max wait time for storage offer */
  OFFER_TIMEOUT: 15000,
  /** @constant {Number} ROUTER_CLEAN_INTERVAL - Drop bad contacts */
  ROUTER_CLEAN_INTERVAL: 60000,
  /** @constant {Number} OPCODE_TUNRPC_PREFIX - Opcode for tunnel rpc message */
  OPCODE_TUNRPC_PREFIX: 0x0c,
  /** @constant {Number} OPCODE_TUNDCX_PREFIX - Opcode for tunnel datachannel */
  OPCODE_TUNDCX_PREFIX: 0x0d,
  /** @constant {Number} OPCODE_TUNNELER_PREFIX - Prefix opcode for tunneler */
  OPCODE_TUNNELER_PREFIX: 0x0e,
  /** @constant {Number} OPCODE_CONTRACT_PREFIX - Prefix opcode for contracts */
  OPCODE_CONTRACT_PREFIX: 0x0f,
  /** @constant {Number} OPCODE_DEG_NULL - Opcode for null criteria degree */
  OPCODE_DEG_NULL: 0x00,
  /** @constant {Number} OPCODE_DEG_LOW - Opcode for low criteria degree */
  OPCODE_DEG_LOW: 0x01,
  /** @constant {Number} OPCODE_DEG_MED - Opcode for medium criteria degree */
  OPCODE_DEG_MED: 0x02,
  /** @constant {Number} OPCODE_DEG_HIGH - Opcode for medium criteria degree */
  OPCODE_DEG_HIGH: 0x03,
  /** @constant {Number} MAX_CONCURRENT_OFFERS - Number of concurrent offers */
  MAX_CONCURRENT_OFFERS: 3,
  /** @constant {Number} MAX_CONCURRENT_AUDITS - Number of concurrent audits */
  MAX_CONCURRENT_AUDITS: 3,
  /** @constant MAX_FIND_TUNNEL_RELAYS - Max times to relay FIND_TUNNEL */
  MAX_FIND_TUNNEL_RELAYS: 2
};
<commit_msg>reduce RPC timeout<commit_after>/**
 * @module storj/constants
 * @license LGPL-3.0
 */

'use strict';

module.exports = {
  /** @constant {String} CIPHER_ALG - Cipher/Decipher algorithm */
  CIPHER_ALG: 'aes-256-ctr',
  /** @constant {Number} PREFIX - NodeID prefix (same as bitcoin) */
  PREFIX: 0x00,
  /** @constant {Number} NONCE_EXPIRE - Time to honor a signed message */
  NONCE_EXPIRE: 15000,
  /** @constant {Number} RPC_TIMEOUT - Max wait time for a RPC response */
  RPC_TIMEOUT: 15000,
  /** @constant {Number} PUBLISH_TTL - Max time for publication relay */
  PUBLISH_TTL: 5000,
  /** @constant {Number} NET_REENTRY - Max wait time before re-entering net */
  NET_REENTRY: 600000,
  /** @constant {Number} AUDIT_BYTES - Number of bytes for audit challenge */
  AUDIT_BYTES: 32,
  /** @constant {Number} CLEAN_INTERVAL - Interval for reaping stale shards */
  CLEAN_INTERVAL: 10800000,
  /** @constant {Number} CONSIGN_THRESHOLD - Threshold for consign time */
  CONSIGN_THRESHOLD: 86400000,
  /** @constant {Number} TOKEN_EXPIRE - Reject datachannl token after time */
  TOKEN_EXPIRE: 86400000,
  /** @constant {Number} TUNNEL_ANNOUNCE_INTERVAL - Announce tunnel state */
  TUNNEL_ANNOUNCE_INTERVAL: 900000,
  /** @constant {Number} OFFER_TIMEOUT - Max wait time for storage offer */
  OFFER_TIMEOUT: 15000,
  /** @constant {Number} ROUTER_CLEAN_INTERVAL - Drop bad contacts */
  ROUTER_CLEAN_INTERVAL: 60000,
  /** @constant {Number} OPCODE_TUNRPC_PREFIX - Opcode for tunnel rpc message */
  OPCODE_TUNRPC_PREFIX: 0x0c,
  /** @constant {Number} OPCODE_TUNDCX_PREFIX - Opcode for tunnel datachannel */
  OPCODE_TUNDCX_PREFIX: 0x0d,
  /** @constant {Number} OPCODE_TUNNELER_PREFIX - Prefix opcode for tunneler */
  OPCODE_TUNNELER_PREFIX: 0x0e,
  /** @constant {Number} OPCODE_CONTRACT_PREFIX - Prefix opcode for contracts */
  OPCODE_CONTRACT_PREFIX: 0x0f,
  /** @constant {Number} OPCODE_DEG_NULL - Opcode for null criteria degree */
  OPCODE_DEG_NULL: 0x00,
  /** @constant {Number} OPCODE_DEG_LOW - Opcode for low criteria degree */
  OPCODE_DEG_LOW: 0x01,
  /** @constant {Number} OPCODE_DEG_MED - Opcode for medium criteria degree */
  OPCODE_DEG_MED: 0x02,
  /** @constant {Number} OPCODE_DEG_HIGH - Opcode for medium criteria degree */
  OPCODE_DEG_HIGH: 0x03,
  /** @constant {Number} MAX_CONCURRENT_OFFERS - Number of concurrent offers */
  MAX_CONCURRENT_OFFERS: 3,
  /** @constant {Number} MAX_CONCURRENT_AUDITS - Number of concurrent audits */
  MAX_CONCURRENT_AUDITS: 3,
  /** @constant MAX_FIND_TUNNEL_RELAYS - Max times to relay FIND_TUNNEL */
  MAX_FIND_TUNNEL_RELAYS: 2
};
<|endoftext|>


<commit_before>'use strict'

let { isClean, isComplete } = require('./symbols')
let Declaration = require('./declaration')
let Comment = require('./comment')
let Node = require('./node')

let parse, Rule, AtRule

function cleanSource (nodes) {
  return nodes.map(i => {
    if (i.nodes) i.nodes = cleanSource(i.nodes)
    delete i.source
    return i
  })
}

function markDirtyUp (node) {
  node[isClean] = false
  node[isComplete] = false
  if (node.proxyOf.nodes) {
    for (let i of node.proxyOf.nodes) {
      markDirtyUp(i)
    }
  }
}

class Container extends Node {
  push (child) {
    child.parent = this
    this.proxyOf.nodes.push(child)
    return this
  }

  each (callback) {
    if (!this.proxyOf.nodes) return undefined
    let iterator = this.getIterator()

    let index, result
    while (this.indexes[iterator] < this.proxyOf.nodes.length) {
      index = this.indexes[iterator]
      result = callback(this.proxyOf.nodes[index], index)
      if (result === false) break

      this.indexes[iterator] += 1
    }

    delete this.indexes[iterator]
    return result
  }

  walk (callback) {
    return this.each((child, i) => {
      let result
      try {
        result = callback(child, i)
      } catch (e) {
        throw child.addToError(e)
      }
      if (result !== false && child.walk) {
        result = child.walk(callback)
      }

      return result
    })
  }

  walkDecls (prop, callback) {
    if (!callback) {
      callback = prop
      return this.walk((child, i) => {
        if (child.type === 'decl') {
          return callback(child, i)
        }
      })
    }
    if (prop instanceof RegExp) {
      return this.walk((child, i) => {
        if (child.type === 'decl' && prop.test(child.prop)) {
          return callback(child, i)
        }
      })
    }
    return this.walk((child, i) => {
      if (child.type === 'decl' && child.prop === prop) {
        return callback(child, i)
      }
    })
  }

  walkRules (selector, callback) {
    if (!callback) {
      callback = selector

      return this.walk((child, i) => {
        if (child.type === 'rule') {
          return callback(child, i)
        }
      })
    }
    if (selector instanceof RegExp) {
      return this.walk((child, i) => {
        if (child.type === 'rule' && selector.test(child.selector)) {
          return callback(child, i)
        }
      })
    }
    return this.walk((child, i) => {
      if (child.type === 'rule' && child.selector === selector) {
        return callback(child, i)
      }
    })
  }

  walkAtRules (name, callback) {
    if (!callback) {
      callback = name
      return this.walk((child, i) => {
        if (child.type === 'atrule') {
          return callback(child, i)
        }
      })
    }
    if (name instanceof RegExp) {
      return this.walk((child, i) => {
        if (child.type === 'atrule' && name.test(child.name)) {
          return callback(child, i)
        }
      })
    }
    return this.walk((child, i) => {
      if (child.type === 'atrule' && child.name === name) {
        return callback(child, i)
      }
    })
  }

  walkComments (callback) {
    return this.walk((child, i) => {
      if (child.type === 'comment') {
        return callback(child, i)
      }
    })
  }

  append (...children) {
    for (let child of children) {
      let nodes = this.normalize(child, this.last)
      for (let node of nodes) this.proxyOf.nodes.push(node)
    }

    this.markDirty()

    return this
  }

  prepend (...children) {
    children = children.reverse()
    for (let child of children) {
      let nodes = this.normalize(child, this.first, 'prepend').reverse()
      for (let node of nodes) this.proxyOf.nodes.unshift(node)
      for (let id in this.indexes) {
        this.indexes[id] = this.indexes[id] + nodes.length
      }
    }

    this.markDirty()

    return this
  }

  cleanRaws (keepBetween) {
    super.cleanRaws(keepBetween)
    if (this.nodes) {
      for (let node of this.nodes) node.cleanRaws(keepBetween)
    }
  }

  insertBefore (exist, add) {
    exist = this.index(exist)

    let type = exist === 0 ? 'prepend' : false
    let nodes = this.normalize(add, this.proxyOf.nodes[exist], type).reverse()
    for (let node of nodes) this.proxyOf.nodes.splice(exist, 0, node)

    let index
    for (let id in this.indexes) {
      index = this.indexes[id]
      if (exist <= index) {
        this.indexes[id] = index + nodes.length
      }
    }

    this.markDirty()

    return this
  }

  insertAfter (exist, add) {
    exist = this.index(exist)

    let nodes = this.normalize(add, this.proxyOf.nodes[exist]).reverse()
    for (let node of nodes) this.proxyOf.nodes.splice(exist + 1, 0, node)

    let index
    for (let id in this.indexes) {
      index = this.indexes[id]
      if (exist < index) {
        this.indexes[id] = index + nodes.length
      }
    }

    this.markDirty()

    return this
  }

  removeChild (child) {
    child = this.index(child)
    this.proxyOf.nodes[child].parent = undefined
    this.proxyOf.nodes.splice(child, 1)

    let index
    for (let id in this.indexes) {
      index = this.indexes[id]
      if (index >= child) {
        this.indexes[id] = index - 1
      }
    }

    this.markDirty()

    return this
  }

  removeAll () {
    for (let node of this.proxyOf.nodes) node.parent = undefined
    this.proxyOf.nodes = []

    this.markDirty()

    return this
  }

  replaceValues (pattern, opts, callback) {
    if (!callback) {
      callback = opts
      opts = {}
    }

    this.walkDecls(decl => {
      if (opts.props && !opts.props.includes(decl.prop)) return
      if (opts.fast && !decl.value.includes(opts.fast)) return

      decl.value = decl.value.replace(pattern, callback)
    })

    this.markDirty()

    return this
  }

  every (condition) {
    return this.nodes.every(condition)
  }

  some (condition) {
    return this.nodes.some(condition)
  }

  index (child) {
    if (typeof child === 'number') return child
    if (child.proxyOf) child = child.proxyOf
    return this.proxyOf.nodes.indexOf(child)
  }

  get first () {
    if (!this.proxyOf.nodes) return undefined
    return this.proxyOf.nodes[0]
  }

  get last () {
    if (!this.proxyOf.nodes) return undefined
    return this.proxyOf.nodes[this.proxyOf.nodes.length - 1]
  }

  normalize (nodes, sample) {
    if (typeof nodes === 'string') {
      nodes = cleanSource(parse(nodes).nodes)
    } else if (Array.isArray(nodes)) {
      nodes = nodes.slice(0)
      for (let i of nodes) {
        if (i.parent) i.parent.removeChild(i, 'ignore')
      }
    } else if (nodes.type === 'root') {
      nodes = nodes.nodes.slice(0)
      for (let i of nodes) {
        if (i.parent) i.parent.removeChild(i, 'ignore')
      }
    } else if (nodes.type) {
      nodes = [nodes]
    } else if (nodes.prop) {
      if (typeof nodes.value === 'undefined') {
        throw new Error('Value field is missed in node creation')
      } else if (typeof nodes.value !== 'string') {
        nodes.value = String(nodes.value)
      }
      nodes = [new Declaration(nodes)]
    } else if (nodes.selector) {
      nodes = [new Rule(nodes)]
    } else if (nodes.name) {
      nodes = [new AtRule(nodes)]
    } else if (nodes.text) {
      nodes = [new Comment(nodes)]
    } else {
      throw new Error('Unknown node type in node creation')
    }

    let processed = nodes.map(i => {
      if (i.parent) i.parent.removeChild(i)
      if (i[isClean]) markDirtyUp(i)
      if (typeof i.raws.before === 'undefined') {
        if (sample && typeof sample.raws.before !== 'undefined') {
          i.raws.before = sample.raws.before.replace(/\S/g, '')
        }
      }
      i.parent = this
      return i
    })

    return processed
  }

  getProxyProcessor () {
    return {
      set (node, prop, value) {
        if (node[prop] === value) return true
        node[prop] = value
        if (prop === 'name' || prop === 'params' || prop === 'selector') {
          node.markDirty()
        }
        return true
      },

      get (node, prop) {
        if (prop === 'proxyOf') {
          return node
        } else if (!node[prop]) {
          return node[prop]
        } else if (
          prop === 'each' ||
          (typeof prop === 'string' && prop.startsWith('walk'))
        ) {
          return (...args) => {
            return node[prop](
              ...args.map(i => {
                if (typeof i === 'function') {
                  return (child, index) => i(child.toProxy(), index)
                } else {
                  return i
                }
              })
            )
          }
        } else if (prop === 'every' || prop === 'some') {
          return cb => {
            return node[prop]((child, ...other) =>
              cb(child.toProxy(), ...other)
            )
          }
        } else if (prop === 'root') {
          return () => node.root().toProxy()
        } else if (prop === 'nodes') {
          return node.nodes.map(i => i.toProxy())
        } else if (prop === 'first' || prop === 'last') {
          return node[prop].toProxy()
        } else {
          return node[prop]
        }
      }
    }
  }

  getIterator () {
    if (!this.lastEach) this.lastEach = 0
    if (!this.indexes) this.indexes = {}

    this.lastEach += 1
    let iterator = this.lastEach
    this.indexes[iterator] = 0

    return iterator
  }
}

Container.registerParse = dependant => {
  parse = dependant
}

Container.registerRule = dependant => {
  Rule = dependant
}

Container.registerAtRule = dependant => {
  AtRule = dependant
}

module.exports = Container
<commit_msg>Rebuild PostCSS 7 nodes<commit_after>'use strict'

let { isClean, isComplete } = require('./symbols')
let Declaration = require('./declaration')
let Comment = require('./comment')
let Node = require('./node')

let parse, Rule, AtRule

function cleanSource (nodes) {
  return nodes.map(i => {
    if (i.nodes) i.nodes = cleanSource(i.nodes)
    delete i.source
    return i
  })
}

function markDirtyUp (node) {
  node[isClean] = false
  node[isComplete] = false
  if (node.proxyOf.nodes) {
    for (let i of node.proxyOf.nodes) {
      markDirtyUp(i)
    }
  }
}

// istanbul ignore next
function rebuild (node, parent) {
  let fix
  if (node.type === 'atrule') {
    fix = new AtRule()
  } else if (node.type === 'rule') {
    fix = new Rule()
  } else if (node.type === 'decl') {
    fix = new Declaration()
  } else if (node.type === 'comment') {
    fix = new Comment()
  }

  for (let i in node) {
    if (i === 'nodes') {
      fix.nodes = node.nodes.map(j => rebuild(j, fix))
    } else if (i === 'parent' && parent) {
      fix.parent = parent
    } else if (Object.prototype.hasOwnProperty.call(i)) {
      fix[i] = node[i]
    }
  }

  return fix
}

class Container extends Node {
  push (child) {
    child.parent = this
    this.proxyOf.nodes.push(child)
    return this
  }

  each (callback) {
    if (!this.proxyOf.nodes) return undefined
    let iterator = this.getIterator()

    let index, result
    while (this.indexes[iterator] < this.proxyOf.nodes.length) {
      index = this.indexes[iterator]
      result = callback(this.proxyOf.nodes[index], index)
      if (result === false) break

      this.indexes[iterator] += 1
    }

    delete this.indexes[iterator]
    return result
  }

  walk (callback) {
    return this.each((child, i) => {
      let result
      try {
        result = callback(child, i)
      } catch (e) {
        throw child.addToError(e)
      }
      if (result !== false && child.walk) {
        result = child.walk(callback)
      }

      return result
    })
  }

  walkDecls (prop, callback) {
    if (!callback) {
      callback = prop
      return this.walk((child, i) => {
        if (child.type === 'decl') {
          return callback(child, i)
        }
      })
    }
    if (prop instanceof RegExp) {
      return this.walk((child, i) => {
        if (child.type === 'decl' && prop.test(child.prop)) {
          return callback(child, i)
        }
      })
    }
    return this.walk((child, i) => {
      if (child.type === 'decl' && child.prop === prop) {
        return callback(child, i)
      }
    })
  }

  walkRules (selector, callback) {
    if (!callback) {
      callback = selector

      return this.walk((child, i) => {
        if (child.type === 'rule') {
          return callback(child, i)
        }
      })
    }
    if (selector instanceof RegExp) {
      return this.walk((child, i) => {
        if (child.type === 'rule' && selector.test(child.selector)) {
          return callback(child, i)
        }
      })
    }
    return this.walk((child, i) => {
      if (child.type === 'rule' && child.selector === selector) {
        return callback(child, i)
      }
    })
  }

  walkAtRules (name, callback) {
    if (!callback) {
      callback = name
      return this.walk((child, i) => {
        if (child.type === 'atrule') {
          return callback(child, i)
        }
      })
    }
    if (name instanceof RegExp) {
      return this.walk((child, i) => {
        if (child.type === 'atrule' && name.test(child.name)) {
          return callback(child, i)
        }
      })
    }
    return this.walk((child, i) => {
      if (child.type === 'atrule' && child.name === name) {
        return callback(child, i)
      }
    })
  }

  walkComments (callback) {
    return this.walk((child, i) => {
      if (child.type === 'comment') {
        return callback(child, i)
      }
    })
  }

  append (...children) {
    for (let child of children) {
      let nodes = this.normalize(child, this.last)
      for (let node of nodes) this.proxyOf.nodes.push(node)
    }

    this.markDirty()

    return this
  }

  prepend (...children) {
    children = children.reverse()
    for (let child of children) {
      let nodes = this.normalize(child, this.first, 'prepend').reverse()
      for (let node of nodes) this.proxyOf.nodes.unshift(node)
      for (let id in this.indexes) {
        this.indexes[id] = this.indexes[id] + nodes.length
      }
    }

    this.markDirty()

    return this
  }

  cleanRaws (keepBetween) {
    super.cleanRaws(keepBetween)
    if (this.nodes) {
      for (let node of this.nodes) node.cleanRaws(keepBetween)
    }
  }

  insertBefore (exist, add) {
    exist = this.index(exist)

    let type = exist === 0 ? 'prepend' : false
    let nodes = this.normalize(add, this.proxyOf.nodes[exist], type).reverse()
    for (let node of nodes) this.proxyOf.nodes.splice(exist, 0, node)

    let index
    for (let id in this.indexes) {
      index = this.indexes[id]
      if (exist <= index) {
        this.indexes[id] = index + nodes.length
      }
    }

    this.markDirty()

    return this
  }

  insertAfter (exist, add) {
    exist = this.index(exist)

    let nodes = this.normalize(add, this.proxyOf.nodes[exist]).reverse()
    for (let node of nodes) this.proxyOf.nodes.splice(exist + 1, 0, node)

    let index
    for (let id in this.indexes) {
      index = this.indexes[id]
      if (exist < index) {
        this.indexes[id] = index + nodes.length
      }
    }

    this.markDirty()

    return this
  }

  removeChild (child) {
    child = this.index(child)
    this.proxyOf.nodes[child].parent = undefined
    this.proxyOf.nodes.splice(child, 1)

    let index
    for (let id in this.indexes) {
      index = this.indexes[id]
      if (index >= child) {
        this.indexes[id] = index - 1
      }
    }

    this.markDirty()

    return this
  }

  removeAll () {
    for (let node of this.proxyOf.nodes) node.parent = undefined
    this.proxyOf.nodes = []

    this.markDirty()

    return this
  }

  replaceValues (pattern, opts, callback) {
    if (!callback) {
      callback = opts
      opts = {}
    }

    this.walkDecls(decl => {
      if (opts.props && !opts.props.includes(decl.prop)) return
      if (opts.fast && !decl.value.includes(opts.fast)) return

      decl.value = decl.value.replace(pattern, callback)
    })

    this.markDirty()

    return this
  }

  every (condition) {
    return this.nodes.every(condition)
  }

  some (condition) {
    return this.nodes.some(condition)
  }

  index (child) {
    if (typeof child === 'number') return child
    if (child.proxyOf) child = child.proxyOf
    return this.proxyOf.nodes.indexOf(child)
  }

  get first () {
    if (!this.proxyOf.nodes) return undefined
    return this.proxyOf.nodes[0]
  }

  get last () {
    if (!this.proxyOf.nodes) return undefined
    return this.proxyOf.nodes[this.proxyOf.nodes.length - 1]
  }

  normalize (nodes, sample) {
    if (typeof nodes === 'string') {
      nodes = cleanSource(parse(nodes).nodes)
    } else if (Array.isArray(nodes)) {
      nodes = nodes.slice(0)
      for (let i of nodes) {
        if (i.parent) i.parent.removeChild(i, 'ignore')
      }
    } else if (nodes.type === 'root') {
      nodes = nodes.nodes.slice(0)
      for (let i of nodes) {
        if (i.parent) i.parent.removeChild(i, 'ignore')
      }
    } else if (nodes.type) {
      nodes = [nodes]
    } else if (nodes.prop) {
      if (typeof nodes.value === 'undefined') {
        throw new Error('Value field is missed in node creation')
      } else if (typeof nodes.value !== 'string') {
        nodes.value = String(nodes.value)
      }
      nodes = [new Declaration(nodes)]
    } else if (nodes.selector) {
      nodes = [new Rule(nodes)]
    } else if (nodes.name) {
      nodes = [new AtRule(nodes)]
    } else if (nodes.text) {
      nodes = [new Comment(nodes)]
    } else {
      throw new Error('Unknown node type in node creation')
    }

    let processed = nodes.map(i => {
      // istanbul ignore next
      if (typeof i.markDirty !== 'function') i = rebuild(i)
      if (i.parent) i.parent.removeChild(i)
      if (i[isClean]) markDirtyUp(i)
      if (typeof i.raws.before === 'undefined') {
        if (sample && typeof sample.raws.before !== 'undefined') {
          i.raws.before = sample.raws.before.replace(/\S/g, '')
        }
      }
      i.parent = this
      return i
    })

    return processed
  }

  getProxyProcessor () {
    return {
      set (node, prop, value) {
        if (node[prop] === value) return true
        node[prop] = value
        if (prop === 'name' || prop === 'params' || prop === 'selector') {
          node.markDirty()
        }
        return true
      },

      get (node, prop) {
        if (prop === 'proxyOf') {
          return node
        } else if (!node[prop]) {
          return node[prop]
        } else if (
          prop === 'each' ||
          (typeof prop === 'string' && prop.startsWith('walk'))
        ) {
          return (...args) => {
            return node[prop](
              ...args.map(i => {
                if (typeof i === 'function') {
                  return (child, index) => i(child.toProxy(), index)
                } else {
                  return i
                }
              })
            )
          }
        } else if (prop === 'every' || prop === 'some') {
          return cb => {
            return node[prop]((child, ...other) =>
              cb(child.toProxy(), ...other)
            )
          }
        } else if (prop === 'root') {
          return () => node.root().toProxy()
        } else if (prop === 'nodes') {
          return node.nodes.map(i => i.toProxy())
        } else if (prop === 'first' || prop === 'last') {
          return node[prop].toProxy()
        } else {
          return node[prop]
        }
      }
    }
  }

  getIterator () {
    if (!this.lastEach) this.lastEach = 0
    if (!this.indexes) this.indexes = {}

    this.lastEach += 1
    let iterator = this.lastEach
    this.indexes[iterator] = 0

    return iterator
  }
}

Container.registerParse = dependant => {
  parse = dependant
}

Container.registerRule = dependant => {
  Rule = dependant
}

Container.registerAtRule = dependant => {
  AtRule = dependant
}

module.exports = Container
<|endoftext|>


<commit_before>// Convert presskit() data.xml file into the new JSON format
'use strict'
var fs = require('fs')
var xmlParser = require('xml2js').parseString

// -------------------------------------------------------------
// Module.
// -------------------------------------------------------------
var Converter = function () {}

// Convert data.xml content into a JSON string
Converter.prototype.convert = function (xml, callback) {
  var json

  if (!xml) callback(new Error('XML input was null or empty'), json)

  xmlParser(xml, function (err, result) {
    if (!err && result) {
      json = JSON.stringify(result, null, 2)
    }
    callback(err, json)
  })
}

// Convert an XML data file to a formatted JSON file
Converter.prototype.convertFile = function (source, destination, callback) {
  fs.readFile(source, function (err, data) {
    Converter.convert(data, function (error, result) {
      if (!error) {
        fs.writeFile(destination, data, function (err) {
          callback(err)
        })
      } else {
        callback(err)
      }
    })
  })
}

// -------------------------------------------------------------
// Exports.
// -------------------------------------------------------------
module.exports = new Converter()
<commit_msg>Return a valid JSON object for a valid XML presskit<commit_after>// Convert presskit() data.xml file into the new JSON format
'use strict'
var fs = require('fs')
var xml2js = require('xml2js')

// Configure parser
// -- Avoid arrays for single elements
var xmlParser = new xml2js.Parser({explicitArray: false})

// -------------------------------------------------------------
// Module.
// -------------------------------------------------------------
var Converter = function () {
}

// Convert data.xml content into a JSON string
Converter.prototype.convert = function (xml, callback) {
  var presskit

  if (!xml) callback(new Error('XML input was null or empty'), presskit)

  xmlParser.parseString(xml, function (err, result) {
    if (!err && result) {
      // Values are nested in the "game" node
      if (result.game) {
        presskit = result.game
      }
    }
    callback(err, presskit)
  })
}

// Convert an XML data file to a formatted JSON file
Converter.prototype.convertFile = function (source, destination, format, callback) {
  fs.readFile(source, function (err, data) {
    Converter.convert(data, function (error, result) {
      if (!error) {
        var json = JSON.stringify(result.game, null, (format ? 2 : 0))
        fs.writeFile(destination, json, function (err) {
          callback(err)
        })
      } else {
        callback(err)
      }
    })
  })
}

// -------------------------------------------------------------
// Exports.
// -------------------------------------------------------------
module.exports = new Converter()
<|endoftext|>


<commit_before>  'use strict';

  /***
   * @package Core
   * @description Core method extension and restoration.
   ***/

  // The global to export.
  var Sugar = {};

  // An optimization for GCC.
  var object = Object;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : window;

  // No conflict mode
  var noConflict = typeof process !== 'undefined' && process.env['SUGAR_NO_CONFLICT'];

  // Internal hasOwnProperty
  var internalHasOwnProperty = object.prototype.hasOwnProperty;

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Natives by name.
  var natives = 'Boolean,Number,String,Array,Date,RegExp,Function'.split(',');

  // Proxy objects by class.
  var proxies = {};

  function initializeGlobal() {
    Sugar = {
      'extend': extend,
      'revert': revert,
      'restore': restore,
      'noConflict': noConflict
    };
    if (isNode()) {
      module.exports = Sugar;
    } else {
      globalContext['Sugar'] = Sugar;
    }
  }

  function isNode() {
    return typeof module !== 'undefined' && module.exports;
  }

  function initializeNatives() {
    iterateOverObject(natives.concat('Object'), function(i, name) {
      proxies[globalContext[name]] = name;
      Sugar[name] = {};
    });
  }

  // Class extending methods

  function extend(klass, methods, instance, polyfill, override) {
    var extendee;
    instance = instance !== false;
    extendee = instance ? klass.prototype : klass;
    iterateOverObject(methods, function(name, prop) {
      var existing = checkGlobal('method', klass, name, extendee),
          original = checkGlobal('original', klass, name, extendee),
          existed  = name in extendee;
      if(typeof polyfill === 'function' && existing) {
        prop = wrapExisting(existing, prop, polyfill);
      }
      defineOnGlobal(klass, name, instance, original, prop, existed);
      if(canDefineOnNative(klass, polyfill, existing, override)) {
        defineProperty(extendee, name, prop);
      }
    });
  }

  function alias(klass, target, source) {
    var method = getProxy(klass)[source];
    var obj = {};
    obj[target] = method['method'];
    extend(klass, obj, method['instance']);
  }

  function restore(klass, methods) {
    return batchMethodExecute(klass, methods, function(target, name, m) {
      defineProperty(target, name, m.method);
    });
  }

  function revert(klass, methods) {
    return batchMethodExecute(klass, methods, function(target, name, m) {
      if(m['existed']) {
        defineProperty(target, name, m['original']);
      } else {
        delete target[name];
      }
    });
  }

  function batchMethodExecute(klass, methods, fn) {
    var all = !methods, changed = false;
    if(typeof methods === 'string') methods = [methods];
    iterateOverObject(getProxy(klass), function(name, m) {
      if(all || methods.indexOf(name) !== -1) {
        changed = true;
        fn(m['instance'] ? klass.prototype : klass, name, m);
      }
    });
    return changed;
  }

  function checkGlobal(type, klass, name, extendee) {
    var proxy = getProxy(klass), method;
    method = proxy && proxy[name];
    if(method) {
      return method[type];
    } else {
      return extendee[name];
    }
  }

  function canDefineOnNative(klass, polyfill, existing, override) {
    if(override) {
      return true;
    } else if(polyfill === true) {
      return !existing;
    }
    return !noConflict || !proxies[klass];
  }

  function wrapExisting(originalFn, extendedFn, condition) {
    return function(a) {
      return condition.apply(this, arguments) ?
             extendedFn.apply(this, arguments) :
             originalFn.apply(this, arguments);
    }
  }

  function wrapInstanceAsClass(fn) {
    return function(obj) {
      var args = arguments, newArgs = [], i;
      for(i = 1;i < args.length;i++) {
        newArgs.push(args[i]);
      }
      return fn.apply(obj, newArgs);
    };
  }

  function defineOnGlobal(klass, name, instance, original, prop, existed) {
    var proxy = getProxy(klass), result;
    if(!proxy) return;
    result = instance ? wrapInstanceAsClass(prop) : prop;
    defineProperty(proxy, name, result, true);
    if(typeof prop === 'function') {
      defineProperty(result, 'original', original);
      defineProperty(result, 'method', prop);
      defineProperty(result, 'existed', existed);
      defineProperty(result, 'instance', instance);
    }
  }

  function getProxy(klass) {
    return Sugar[proxies[klass]];
  }

  function defineProperty(target, name, property, enumerable) {
    if(definePropertySupport) {
      object.defineProperty(target, name, {
        'value': property,
        'enumerable': !!enumerable,
        'configurable': true,
        'writable': true
      });
    } else {
      target[name] = property;
    }
  }

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key], obj) === false) break;
    }
  }

  function hasOwnProperty(obj, prop) {
    return !!obj && internalHasOwnProperty.call(obj, prop);
  }

  initializeGlobal();
  initializeNatives();

<commit_msg>changing up node environment check<commit_after>  'use strict';

  /***
   * @package Core
   * @description Core method extension and restoration.
   ***/

  // The global to export.
  var Sugar = {};

  // An optimization for GCC.
  var object = Object;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : window;

  // Is the environment node?
  var isNode = typeof module !== 'undefined' && module.exports;

  // No conflict mode
  var noConflict = isNode ? process.env['SUGAR_NO_CONFLICT'] : false;

  // Internal hasOwnProperty
  var internalHasOwnProperty = object.prototype.hasOwnProperty;

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Natives by name.
  var natives = 'Boolean,Number,String,Array,Date,RegExp,Function'.split(',');

  // Proxy objects by class.
  var proxies = {};

  function initializeGlobal() {
    Sugar = {
      'extend': extend,
      'revert': revert,
      'restore': restore,
      'noConflict': noConflict
    };
    if (isNode) {
      module.exports = Sugar;
    } else {
      globalContext['Sugar'] = Sugar;
    }
  }

  function initializeNatives() {
    iterateOverObject(natives.concat('Object'), function(i, name) {
      proxies[globalContext[name]] = name;
      Sugar[name] = {};
    });
  }

  // Class extending methods

  function extend(klass, methods, instance, polyfill, override) {
    var extendee;
    instance = instance !== false;
    extendee = instance ? klass.prototype : klass;
    iterateOverObject(methods, function(name, prop) {
      var existing = checkGlobal('method', klass, name, extendee),
          original = checkGlobal('original', klass, name, extendee),
          existed  = name in extendee;
      if(typeof polyfill === 'function' && existing) {
        prop = wrapExisting(existing, prop, polyfill);
      }
      defineOnGlobal(klass, name, instance, original, prop, existed);
      if(canDefineOnNative(klass, polyfill, existing, override)) {
        defineProperty(extendee, name, prop);
      }
    });
  }

  function alias(klass, target, source) {
    var method = getProxy(klass)[source];
    var obj = {};
    obj[target] = method['method'];
    extend(klass, obj, method['instance']);
  }

  function restore(klass, methods) {
    return batchMethodExecute(klass, methods, function(target, name, m) {
      defineProperty(target, name, m.method);
    });
  }

  function revert(klass, methods) {
    return batchMethodExecute(klass, methods, function(target, name, m) {
      if(m['existed']) {
        defineProperty(target, name, m['original']);
      } else {
        delete target[name];
      }
    });
  }

  function batchMethodExecute(klass, methods, fn) {
    var all = !methods, changed = false;
    if(typeof methods === 'string') methods = [methods];
    iterateOverObject(getProxy(klass), function(name, m) {
      if(all || methods.indexOf(name) !== -1) {
        changed = true;
        fn(m['instance'] ? klass.prototype : klass, name, m);
      }
    });
    return changed;
  }

  function checkGlobal(type, klass, name, extendee) {
    var proxy = getProxy(klass), method;
    method = proxy && proxy[name];
    if(method) {
      return method[type];
    } else {
      return extendee[name];
    }
  }

  function canDefineOnNative(klass, polyfill, existing, override) {
    if(override) {
      return true;
    } else if(polyfill === true) {
      return !existing;
    }
    return !noConflict || !proxies[klass];
  }

  function wrapExisting(originalFn, extendedFn, condition) {
    return function(a) {
      return condition.apply(this, arguments) ?
             extendedFn.apply(this, arguments) :
             originalFn.apply(this, arguments);
    }
  }

  function wrapInstanceAsClass(fn) {
    return function(obj) {
      var args = arguments, newArgs = [], i;
      for(i = 1;i < args.length;i++) {
        newArgs.push(args[i]);
      }
      return fn.apply(obj, newArgs);
    };
  }

  function defineOnGlobal(klass, name, instance, original, prop, existed) {
    var proxy = getProxy(klass), result;
    if(!proxy) return;
    result = instance ? wrapInstanceAsClass(prop) : prop;
    defineProperty(proxy, name, result, true);
    if(typeof prop === 'function') {
      defineProperty(result, 'original', original);
      defineProperty(result, 'method', prop);
      defineProperty(result, 'existed', existed);
      defineProperty(result, 'instance', instance);
    }
  }

  function getProxy(klass) {
    return Sugar[proxies[klass]];
  }

  function defineProperty(target, name, property, enumerable) {
    if(definePropertySupport) {
      object.defineProperty(target, name, {
        'value': property,
        'enumerable': !!enumerable,
        'configurable': true,
        'writable': true
      });
    } else {
      target[name] = property;
    }
  }

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key], obj) === false) break;
    }
  }

  function hasOwnProperty(obj, prop) {
    return !!obj && internalHasOwnProperty.call(obj, prop);
  }

  initializeGlobal();
  initializeNatives();

<|endoftext|>


<commit_before>  'use strict';

  /***
   * @package Core
   * @description Core method extension and restoration.
   ***/

  // The global to export.
  var Sugar = {};

  // An optimization for GCC.
  var object = Object;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : this;

  // No conflict mode
  var noConflict = true;

  // Internal hasOwnProperty
  var internalHasOwnProperty = object.prototype.hasOwnProperty;

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Natives by name.
  var natives = 'Boolean,Number,String,Array,Date,RegExp,Function'.split(',');

  // Proxy objects by class.
  var proxies = {};

  function initializeGlobal() {
    extend(Sugar, {
      'noConflict': noConflict,
      'extend': extend,
      'revert': revert,
      'restore': restore,
      'iterate': iterateOverObject,
      'define': defineProperty,
      'global': globalContext,
      'natives': natives,
      'has': hasOwnProperty
    }, false);
    globalContext['Sugar'] = Sugar;
  }

  function initializeNatives() {
    iterateOverObject(natives.concat('Object'), function(i, name) {
      proxies[globalContext[name]] = name;
      Sugar[name] = {};
    });
  }

  // Class extending methods

  function extend(klass, methods, instance, polyfill, override) {
    var extendee;
    instance = instance !== false;
    extendee = instance ? klass.prototype : klass;
    iterateOverObject(methods, function(name, prop) {
      var original = extendee[name],
          existed  = name in extendee;
      if(typeof polyfill === 'function' && original) {
        prop = wrapNative(original, prop, polyfill);
      }
      defineProxy(klass, name, instance, original, prop, existed);
      if(canDefineOnNative(klass, polyfill, original, override)) {
        defineProperty(extendee, name, prop);
      }
    });
  }

  function alias(klass, target, source) {
    var method = getProxy(klass)[source];
    var obj = {};
    obj[target] = method['method'];
    extend(klass, obj, method['instance']);
  }

  function restore(klass, methods) {
    return batchMethodExecute(klass, methods, function(target, name, m) {
      defineProperty(target, name, m.method);
    });
  }

  function revert(klass, methods) {
    return batchMethodExecute(klass, methods, function(target, name, m) {
      if(m['existed']) {
        defineProperty(target, name, m['original']);
      } else {
        delete target[name];
      }
    });
  }

  function batchMethodExecute(klass, methods, fn) {
    var all = !methods, changed = false;
    if(typeof methods === 'string') methods = [methods];
    iterateOverObject(getProxy(klass), function(name, m) {
      if(all || methods.indexOf(name) !== -1) {
        changed = true;
        fn(m['instance'] ? klass.prototype : klass, name, m);
      }
    });
    return changed;
  }

  function canDefineOnNative(klass, polyfill, original, override) {
    if(override) {
      return true;
    } else if(polyfill === true) {
      return !original;
    }
    return !noConflict || !proxies[klass];
  }

  function wrapNative(originalFn, extendedFn, condition) {
    return function(a) {
      return condition.apply(this, arguments) ?
             extendedFn.apply(this, arguments) :
             originalFn.apply(this, arguments);
    }
  }

  function wrapNoConflict(fn) {
    return function(native) {
      var args = Array.prototype.slice.call(arguments, 1);
      return fn.apply(native, args);
    };
  }

  function defineProxy(klass, name, instance, original, prop, existed) {
    var proxy = proxies[klass], meta;
    if(!proxy || (klass === object && instance)) return;
    prop = instance ? wrapNoConflict(prop) : prop;
    defineProperty(getProxy(klass), name, prop, true);
    if(typeof prop === 'function') {
      defineProperty(prop, 'original', original);
      defineProperty(prop, 'method', prop);
      defineProperty(prop, 'existed', existed);
      defineProperty(prop, 'instance', instance);
    }
  }

  function getProxy(klass) {
    return Sugar[proxies[klass]];
  }

  function defineProperty(target, name, method, enumerable) {
    if(definePropertySupport) {
      object.defineProperty(target, name, {
        'value': method,
        'enumerable': !!enumerable,
        'configurable': true,
        'writable': true
      });
    } else {
      target[name] = method;
    }
  }

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key], obj) === false) break;
    }
  }

  function hasOwnProperty(obj, prop) {
    return !!obj && internalHasOwnProperty.call(obj, prop);
  }

  initializeGlobal();
  initializeNatives();

<commit_msg>retained method should be the non-wrapped version to allow aliasing<commit_after>  'use strict';

  /***
   * @package Core
   * @description Core method extension and restoration.
   ***/

  // The global to export.
  var Sugar = {};

  // An optimization for GCC.
  var object = Object;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : this;

  // No conflict mode
  var noConflict = true;

  // Internal hasOwnProperty
  var internalHasOwnProperty = object.prototype.hasOwnProperty;

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Natives by name.
  var natives = 'Boolean,Number,String,Array,Date,RegExp,Function'.split(',');

  // Proxy objects by class.
  var proxies = {};

  function initializeGlobal() {
    extend(Sugar, {
      'noConflict': noConflict,
      'extend': extend,
      'revert': revert,
      'restore': restore,
      'iterate': iterateOverObject,
      'define': defineProperty,
      'global': globalContext,
      'natives': natives,
      'has': hasOwnProperty
    }, false);
    globalContext['Sugar'] = Sugar;
  }

  function initializeNatives() {
    iterateOverObject(natives.concat('Object'), function(i, name) {
      proxies[globalContext[name]] = name;
      Sugar[name] = {};
    });
  }

  // Class extending methods

  function extend(klass, methods, instance, polyfill, override) {
    var extendee;
    instance = instance !== false;
    extendee = instance ? klass.prototype : klass;
    iterateOverObject(methods, function(name, prop) {
      var original = extendee[name],
          existed  = name in extendee;
      if(typeof polyfill === 'function' && original) {
        prop = wrapNative(original, prop, polyfill);
      }
      defineOnGlobal(klass, name, instance, original, prop, existed);
      if(canDefineOnNative(klass, polyfill, original, override)) {
        defineProperty(extendee, name, prop);
      }
    });
  }

  function alias(klass, target, source) {
    var method = getProxy(klass)[source];
    var obj = {};
    obj[target] = method['method'];
    extend(klass, obj, method['instance']);
  }

  function restore(klass, methods) {
    return batchMethodExecute(klass, methods, function(target, name, m) {
      defineProperty(target, name, m.method);
    });
  }

  function revert(klass, methods) {
    return batchMethodExecute(klass, methods, function(target, name, m) {
      if(m['existed']) {
        defineProperty(target, name, m['original']);
      } else {
        delete target[name];
      }
    });
  }

  function batchMethodExecute(klass, methods, fn) {
    var all = !methods, changed = false;
    if(typeof methods === 'string') methods = [methods];
    iterateOverObject(getProxy(klass), function(name, m) {
      if(all || methods.indexOf(name) !== -1) {
        changed = true;
        fn(m['instance'] ? klass.prototype : klass, name, m);
      }
    });
    return changed;
  }

  function canDefineOnNative(klass, polyfill, original, override) {
    if(override) {
      return true;
    } else if(polyfill === true) {
      return !original;
    }
    return !noConflict || !proxies[klass];
  }

  function wrapNative(originalFn, extendedFn, condition) {
    return function(a) {
      return condition.apply(this, arguments) ?
             extendedFn.apply(this, arguments) :
             originalFn.apply(this, arguments);
    }
  }

  function wrapNoConflict(fn) {
    return function(native) {
      var args = Array.prototype.slice.call(arguments, 1);
      return fn.apply(native, args);
    };
  }

  function defineOnGlobal(klass, name, instance, original, prop, existed) {
    var proxy = getProxy(klass), result;
    if(!proxy || (klass === object && instance)) return;
    result = instance ? wrapNoConflict(prop) : prop;
    defineProperty(proxy, name, result, true);
    if(typeof prop === 'function') {
      defineProperty(result, 'original', original);
      defineProperty(result, 'method', prop);
      defineProperty(result, 'existed', existed);
      defineProperty(result, 'instance', instance);
    }
  }

  function getProxy(klass) {
    return Sugar[proxies[klass]];
  }

  function defineProperty(target, name, method, enumerable) {
    if(definePropertySupport) {
      object.defineProperty(target, name, {
        'value': method,
        'enumerable': !!enumerable,
        'configurable': true,
        'writable': true
      });
    } else {
      target[name] = method;
    }
  }

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key], obj) === false) break;
    }
  }

  function hasOwnProperty(obj, prop) {
    return !!obj && internalHasOwnProperty.call(obj, prop);
  }

  initializeGlobal();
  initializeNatives();

<|endoftext|>


<commit_before>var co = require('co')
	, thunkify = require('thunkify')
	, path = require('path')
	, fs = require('fs')
	, readFile = fs.readFileSync
	, exists = fs.existsSync
	, inherit = require('util').inherits
	, FileCache = require('../utils/FileCache')
	, identify = require('identify-resource').identify
	, resolve = require('identify-resource').resolve
	, lodash = require('lodash')
	, merge = lodash.merge
	, clone = lodash.clone
	, flatten = lodash.flatten
	, compact = lodash.compact
	, truncate = require('../utils/truncate')
	, cnsl = require('../utils/cnsl')
	, warn = cnsl.warn
	, debug = cnsl.debug
	, colour = cnsl.colour
	, print = cnsl.print
	, strong = cnsl.strong
	, helpers = {
			write: require('./helpers/write'),
			compile: thunkify(require('transfigure')),
			compress: require('./helpers/compress'),
			concat: require('./helpers/concat'),
			inline: require('./helpers/inline'),
			lint: require('./helpers/lint'),
			escape: require('./helpers/escape'),
			parse: require('./helpers/parse'),
			replace: require('./helpers/replace'),
			wrap: require('./helpers/wrap')
		}

	, BOILERPLATE = fs.readFileSync(path.resolve(__filename, '../../../node_modules/simple-browser-require/require.js'), 'utf8');

/**
 * File instance factory
 * @param {String} filepath
 * @param {Object} options
 * @returns {File}
 */
var factory = module.exports = function (filepath, options) {
	var file, id;

	if (factory.cache.hasFile(filepath)) {
		file = factory.cache.getFile(filepath);
	} else if (id = identify(filepath, options)) {
		if (factory.cache.hasFile(options.type + ':' + id)) {
			file = factory.cache.getFile(options.type + ':' + id);
		} else {
			file = new File(id, filepath, options);
			factory.cache.addFile(file);
		}
	}

	return file;
};

/*
 * Default file cache
 */
module.exports.cache = new FileCache();

/**
 * Constructor
 * @param {String} id
 * @param {String} filepath
 * @param {Object} options
 */
function File (id, filepath, options) {
	this.options = options;
	this.type = options.type;
	this.id = id;
	this.filepath = filepath;
	this.relPath = truncate(path.relative(process.cwd(), filepath));
	this.extension = path.extname(this.filepath).slice(1);
	this.name = path.basename(this.filepath);
	this.content = '';
	this.originalContent = '';
	this.compiledContent = '';
	this.dependencies = [];
	this.dependencyReferences = [];
	this.workflow = null;
	this.isRoot = false;
	this.isDependency = false;
	this.isLocked = false;

	debug("created "
		+ this.type
		+ " File instance "
		+ strong(this.relPath), 3);
}

/**
 * Retrieve writeable state
 * @returns {Boolean}
 */
File.prototype.getIsWriteable = function () {
	return this.isRoot || !this.isDependency;
};

/**
 * Retrieve flattened dependency tree
 * @param {Boolean} asReferences
 * @returns {Array}
 */
File.prototype.getDependencies = function (asReferences) {
	var self = this
		, deps = []
		, key = asReferences ? 'dependencyReferences' : 'dependencies';

	function add (dependency, dependant) {
		if ((dependency.instance || dependency) !== self && !~deps.indexOf(dependency)) {
			deps.push(dependency);
			(dependency.instance || dependency)[key].forEach(function (dep) {
				// Protect against circular references
				if ((dep.instance || dep) != dependant) add(dep, dependency);
			});
		}
	};

	this[key].forEach(add);

	return deps;
};

/**
 * Run 'workflow' tasks in sequence
 * @param {Array} workflow
 * @returns {Promise(File)}
 */
File.prototype.run = function * (workflow) {
	var dependencies, cmd;

	if (workflow && this.workflow != workflow) {

		this.workflow = workflow;
		// Execute commands in sequence
		for (var i = 0, n = workflow.length; i < n; i++) {
			cmd = workflow[i];
			if ('GeneratorFunction' == this[cmd].constructor.name) {
				yield this[cmd]();
			} else {
				this[cmd]();
			}
			// Parse needs special handling of dependencies
			if (cmd == 'parse') dependencies = this.dependencies;
		}
	}

	return dependencies;
};

/**
 * Read and store file contents
 * @returns {Function}
 */
File.prototype.load = function () {
	if (!this.originalContent) {
		var content = readFile(this.filepath, 'utf8');
		debug('load: ' + strong(this.relPath), 4);
		this.content = this.originalContent = content;
	} else {
		this.content = this.originalContent;
	}
};

/**
 * Compile file contents
 */
File.prototype.compile = function * () {
	// Only compile if not already
	if (!this.compiledContent) {
		var options = {}
			, dataUrl;

		// Expose properties for compilers
		options.id = this.id;
		options.type = this.type;
		if (this.type == 'html') {
			// Gather all dependencies
			options.includes = this.getDependencies();
			// Check/load data json file of same name in same directory
			if (fs.existsSync((dataUrl = path.resolve(path.dirname(this.filepath), this.name.replace(this.extension, 'json'))))) {
				options.data = require(dataUrl);
			}
		} else if (this.type == 'css') {
			// Gather all directories
			options.paths = factory.cache.getDirs();
		}

		this.content = this.compiledContent = yield helpers['compile'](this.filepath, this.content, options);
		debug('compile: ' + strong(this.relPath), 4);
	}
};

/**
 * Parse file contents for dependency references
 * @returns {Array}
 */
File.prototype.parse = function () {
	var dependencies = helpers['parse'](this.filepath, this.type, this.content)
		, filepath, instance;

	if (dependencies) {
		dependencies.forEach(function (dependency) {
			// Validate and add
			filepath = resolve(this.filepath, dependency.filepath, this.options);
			instance = factory(filepath, this.options);
			if (filepath && instance) {
				// Save context for future inlining
				this.dependencyReferences.push(dependency);
				// Store instance
				dependency.instance = instance;
				// Process if not locked (parent target files are locked)
				if (!instance.isLocked) {
					// Store if not already stored
					if (!~this.dependencies.indexOf(instance)) {
						instance.isDependency = true;
						this.dependencies.push(instance);
					}
				}

			// Unable to resolve filepath
			} else {
				warn("dependency "
					+ (strong(dependency.filepath))
					+ " for "
					+ (strong(this.id))
					+ " not found (ids are case-sensitive)", 4);
			}
		}, this);
	}

	debug('parse: ' + strong(this.relPath), 4);

	return this.dependencies;
};

/**
 * Inline dependency content
 */
File.prototype.inline = function () {
	var deps = (this.type == 'html')
		? this.getDependencies(true)
		: this.dependencyReferences;

	this.content = helpers['inline'](this.filepath, this.type, this.content, deps);
	debug('inline: ' + strong(this.relPath), 4);
};

/**
 * Replace relative dependency references with fully resolved
 */
File.prototype.replace = function () {
	this.content = helpers['replace'](this.content, this.dependencyReferences);
	debug('replace: ' + strong(this.relPath), 4);
};

/**
 * Lint file contents
 */
File.prototype.lint = function () {
	// Don't lint compiled files
	if (this.extension == this.type) {
		var warnings = helpers['lint'](this.type, this.content)
		if (warnings) {
			warn('failed linting', 3);
			warnings.forEach(function (item) {
				if (item) {
					print("["
						+ (colour(item.line, cnsl.CYAN))
						+ ":"
						+ (colour(item.col, cnsl.CYAN))
						+ "] "
						+ item.reason
						+ ":", 4);
					if (item.evidence) print("" + (strong(item.evidence)), 5);
				}
			});
			return warnings;
		} else {
			debug('lint: ' + strong(this.relPath), 4);
		}
	}
};

/**
 * Escape file contents for lazy js modules
 */
File.prototype.escape = function () {
	this.content = helpers['escape'](this.content);
	debug('escape: ' + strong(this.relPath), 4);
};

/**
 * Compress file contents
 */
File.prototype.compress = function () {
	var type = (this.type == 'html')
		// Use extension to force compilation of inlineable content
		? this.extension
		: this.type;

	// TODO: trap errors here
	this.content = helpers['compress'](type, this.content);
	debug('compressed: ' + strong(this.relPath), 4);
};

/**
 * Wrap JS file contents in a module definition
 */
File.prototype.wrap = function () {
	var lazy = this.options.runtimeOptions
		? this.options.runtimeOptions.lazy
		: false;

	this.content = helpers['wrap'](this.id, this.content, lazy);
	debug('wrap: ' + strong(this.relPath), 4);
};

/**
 * Concatenate file contents
 */
File.prototype.concat = function () {
	this.content = helpers['concat'](this.type, this.content, this.getDependencies().reverse());
	debug('concat: ' + strong(this.relPath), 4);
};

/**
 * Write file contents to disk
 * @param {String} filepath
 * @param {Object} options
 * @returns {String}
 */
File.prototype.write = function * (filepath, options) {
	if (filepath) {
		options = options || {};

		// Add require boilerplate
		if (options.boilerplate) {
			this.content = BOILERPLATE
				+ '\n'
				+ this.content;
		}

		// Add bootstrap call
		if (options.bootstrap) {
			this.content += '\nrequire(\'' + this.id + '\');'
		}

		// Write
		yield helpers['write'](filepath, this.content);
		print(colour('built', cnsl.GREEN)
			+ " "
			+ strong(path.relative(process.cwd(), filepath)), 3);

		return filepath;
	}
};

/**
 * Reset content
 * @param {Boolean} hard
 */
File.prototype.reset = function (hard) {
	this.workflow = null;
	this.isRoot = false;
	this.isLocked = false;
	this.isDependency = false;
	this.dependencies = [];
	this.dependencyReferences = [];
	if (this.type != 'js') {
		this.content = this.originalContent;
		this.compiledContent = '';
	} else {
		this.content = this.compiledContent || this.originalContent;
	}
	if (hard) {
		this.content = this.originalContent = this.compiledContent = '';
	}
};

/**
 * Destroy instance
 */
File.prototype.destroy = function () {
	this.reset(true);
	this.options = null;
};<commit_msg>add compressed label<commit_after>var co = require('co')
	, thunkify = require('thunkify')
	, path = require('path')
	, fs = require('fs')
	, readFile = fs.readFileSync
	, exists = fs.existsSync
	, inherit = require('util').inherits
	, FileCache = require('../utils/FileCache')
	, identify = require('identify-resource').identify
	, resolve = require('identify-resource').resolve
	, lodash = require('lodash')
	, merge = lodash.merge
	, clone = lodash.clone
	, flatten = lodash.flatten
	, compact = lodash.compact
	, truncate = require('../utils/truncate')
	, cnsl = require('../utils/cnsl')
	, warn = cnsl.warn
	, debug = cnsl.debug
	, colour = cnsl.colour
	, print = cnsl.print
	, strong = cnsl.strong
	, helpers = {
			write: require('./helpers/write'),
			compile: thunkify(require('transfigure')),
			compress: require('./helpers/compress'),
			concat: require('./helpers/concat'),
			inline: require('./helpers/inline'),
			lint: require('./helpers/lint'),
			escape: require('./helpers/escape'),
			parse: require('./helpers/parse'),
			replace: require('./helpers/replace'),
			wrap: require('./helpers/wrap')
		}

	, BOILERPLATE = fs.readFileSync(path.resolve(__filename, '../../../node_modules/simple-browser-require/require.js'), 'utf8');

/**
 * File instance factory
 * @param {String} filepath
 * @param {Object} options
 * @returns {File}
 */
var factory = module.exports = function (filepath, options) {
	var file, id;

	if (factory.cache.hasFile(filepath)) {
		file = factory.cache.getFile(filepath);
	} else if (id = identify(filepath, options)) {
		if (factory.cache.hasFile(options.type + ':' + id)) {
			file = factory.cache.getFile(options.type + ':' + id);
		} else {
			file = new File(id, filepath, options);
			factory.cache.addFile(file);
		}
	}

	return file;
};

/*
 * Default file cache
 */
module.exports.cache = new FileCache();

/**
 * Constructor
 * @param {String} id
 * @param {String} filepath
 * @param {Object} options
 */
function File (id, filepath, options) {
	this.options = options;
	this.type = options.type;
	this.id = id;
	this.filepath = filepath;
	this.relPath = truncate(path.relative(process.cwd(), filepath));
	this.extension = path.extname(this.filepath).slice(1);
	this.name = path.basename(this.filepath);
	this.content = '';
	this.originalContent = '';
	this.compiledContent = '';
	this.dependencies = [];
	this.dependencyReferences = [];
	this.workflow = null;
	this.isRoot = false;
	this.isDependency = false;
	this.isLocked = false;

	debug("created "
		+ this.type
		+ " File instance "
		+ strong(this.relPath), 3);
}

/**
 * Retrieve writeable state
 * @returns {Boolean}
 */
File.prototype.getIsWriteable = function () {
	return this.isRoot || !this.isDependency;
};

/**
 * Retrieve flattened dependency tree
 * @param {Boolean} asReferences
 * @returns {Array}
 */
File.prototype.getDependencies = function (asReferences) {
	var self = this
		, deps = []
		, key = asReferences ? 'dependencyReferences' : 'dependencies';

	function add (dependency, dependant) {
		if ((dependency.instance || dependency) !== self && !~deps.indexOf(dependency)) {
			deps.push(dependency);
			(dependency.instance || dependency)[key].forEach(function (dep) {
				// Protect against circular references
				if ((dep.instance || dep) != dependant) add(dep, dependency);
			});
		}
	};

	this[key].forEach(add);

	return deps;
};

/**
 * Run 'workflow' tasks in sequence
 * @param {Array} workflow
 * @returns {Promise(File)}
 */
File.prototype.run = function * (workflow) {
	var dependencies, cmd;

	if (workflow && this.workflow != workflow) {

		this.workflow = workflow;
		// Execute commands in sequence
		for (var i = 0, n = workflow.length; i < n; i++) {
			cmd = workflow[i];
			if ('GeneratorFunction' == this[cmd].constructor.name) {
				yield this[cmd]();
			} else {
				this[cmd]();
			}
			// Parse needs special handling of dependencies
			if (cmd == 'parse') dependencies = this.dependencies;
		}
	}

	return dependencies;
};

/**
 * Read and store file contents
 * @returns {Function}
 */
File.prototype.load = function () {
	if (!this.originalContent) {
		var content = readFile(this.filepath, 'utf8');
		debug('load: ' + strong(this.relPath), 4);
		this.content = this.originalContent = content;
	} else {
		this.content = this.originalContent;
	}
};

/**
 * Compile file contents
 */
File.prototype.compile = function * () {
	// Only compile if not already
	if (!this.compiledContent) {
		var options = {}
			, dataUrl;

		// Expose properties for compilers
		options.id = this.id;
		options.type = this.type;
		if (this.type == 'html') {
			// Gather all dependencies
			options.includes = this.getDependencies();
			// Check/load data json file of same name in same directory
			if (fs.existsSync((dataUrl = path.resolve(path.dirname(this.filepath), this.name.replace(this.extension, 'json'))))) {
				options.data = require(dataUrl);
			}
		} else if (this.type == 'css') {
			// Gather all directories
			options.paths = factory.cache.getDirs();
		}

		this.content = this.compiledContent = yield helpers['compile'](this.filepath, this.content, options);
		debug('compile: ' + strong(this.relPath), 4);
	}
};

/**
 * Parse file contents for dependency references
 * @returns {Array}
 */
File.prototype.parse = function () {
	var dependencies = helpers['parse'](this.filepath, this.type, this.content)
		, filepath, instance;

	if (dependencies) {
		dependencies.forEach(function (dependency) {
			// Validate and add
			filepath = resolve(this.filepath, dependency.filepath, this.options);
			instance = factory(filepath, this.options);
			if (filepath && instance) {
				// Save context for future inlining
				this.dependencyReferences.push(dependency);
				// Store instance
				dependency.instance = instance;
				// Process if not locked (parent target files are locked)
				if (!instance.isLocked) {
					// Store if not already stored
					if (!~this.dependencies.indexOf(instance)) {
						instance.isDependency = true;
						this.dependencies.push(instance);
					}
				}

			// Unable to resolve filepath
			} else {
				warn("dependency "
					+ (strong(dependency.filepath))
					+ " for "
					+ (strong(this.id))
					+ " not found (ids are case-sensitive)", 4);
			}
		}, this);
	}

	debug('parse: ' + strong(this.relPath), 4);

	return this.dependencies;
};

/**
 * Inline dependency content
 */
File.prototype.inline = function () {
	var deps = (this.type == 'html')
		? this.getDependencies(true)
		: this.dependencyReferences;

	this.content = helpers['inline'](this.filepath, this.type, this.content, deps);
	debug('inline: ' + strong(this.relPath), 4);
};

/**
 * Replace relative dependency references with fully resolved
 */
File.prototype.replace = function () {
	this.content = helpers['replace'](this.content, this.dependencyReferences);
	debug('replace: ' + strong(this.relPath), 4);
};

/**
 * Lint file contents
 */
File.prototype.lint = function () {
	// Don't lint compiled files
	if (this.extension == this.type) {
		var warnings = helpers['lint'](this.type, this.content)
		if (warnings) {
			warn('failed linting', 3);
			warnings.forEach(function (item) {
				if (item) {
					print("["
						+ (colour(item.line, cnsl.CYAN))
						+ ":"
						+ (colour(item.col, cnsl.CYAN))
						+ "] "
						+ item.reason
						+ ":", 4);
					if (item.evidence) print("" + (strong(item.evidence)), 5);
				}
			});
			return warnings;
		} else {
			debug('lint: ' + strong(this.relPath), 4);
		}
	}
};

/**
 * Escape file contents for lazy js modules
 */
File.prototype.escape = function () {
	this.content = helpers['escape'](this.content);
	debug('escape: ' + strong(this.relPath), 4);
};

/**
 * Compress file contents
 */
File.prototype.compress = function () {
	var type = (this.type == 'html')
		// Use extension to force compilation of inlineable content
		? this.extension
		: this.type;

	// TODO: trap errors here
	this.content = helpers['compress'](type, this.content);
	debug('compressed: ' + strong(this.relPath), 4);
};

/**
 * Wrap JS file contents in a module definition
 */
File.prototype.wrap = function () {
	var lazy = this.options.runtimeOptions
		? this.options.runtimeOptions.lazy
		: false;

	this.content = helpers['wrap'](this.id, this.content, lazy);
	debug('wrap: ' + strong(this.relPath), 4);
};

/**
 * Concatenate file contents
 */
File.prototype.concat = function () {
	this.content = helpers['concat'](this.type, this.content, this.getDependencies().reverse());
	debug('concat: ' + strong(this.relPath), 4);
};

/**
 * Write file contents to disk
 * @param {String} filepath
 * @param {Object} options
 * @returns {String}
 */
File.prototype.write = function * (filepath, options) {
	if (filepath) {
		options = options || {};

		// Add require boilerplate
		if (options.boilerplate) {
			this.content = BOILERPLATE
				+ '\n'
				+ this.content;
		}

		// Add bootstrap call
		if (options.bootstrap) {
			this.content += '\nrequire(\'' + this.id + '\');'
		}

		// Write
		yield helpers['write'](filepath, this.content);
		print(colour('built' + (this.options.runtimeOptions.compress ? ' and compressed' : ''), cnsl.GREEN)
			+ " "
			+ strong(path.relative(process.cwd(), filepath)), 3);

		return filepath;
	}
};

/**
 * Reset content
 * @param {Boolean} hard
 */
File.prototype.reset = function (hard) {
	this.workflow = null;
	this.isRoot = false;
	this.isLocked = false;
	this.isDependency = false;
	this.dependencies = [];
	this.dependencyReferences = [];
	if (this.type != 'js') {
		this.content = this.originalContent;
		this.compiledContent = '';
	} else {
		this.content = this.compiledContent || this.originalContent;
	}
	if (hard) {
		this.content = this.originalContent = this.compiledContent = '';
	}
};

/**
 * Destroy instance
 */
File.prototype.destroy = function () {
	this.reset(true);
	this.options = null;
};<|endoftext|>


<commit_before>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

YUI.add('viewlet-inspector-overview', function(Y) {
  var ns = Y.namespace('juju.viewlets'),
      views = Y.namespace('juju.views'),
      templates = Y.namespace('juju.views').Templates,
      models = Y.namespace('juju.models'),
      utils = Y.namespace('juju.views.utils');

  var unitListNameMap = {
    error: 'Error',
    pending: 'Pending',
    running: 'Running',
    'landscape-needs-reboot': 'Needs Reboot',
    'landscape-security-upgrades': 'Security Upgrade'
  };

  /**
    Return a category name based on a status, generated either from the
    `unitListNameMap` (in the case of units) or from a data-driven function.

    @method categoryName
    @param {Object} status The status to name.
    @return {String} a name for the status.
  */
  function categoryName(status) {
    var nameMap = {
      'unit': unitListNameMap,
      'service': {
        'upgrade-service': function(status) {
          return status.upgradeAvailable ?
              'A new upgrade is available' :
              'Upgrade service';
        }
      }
    };

    var name = nameMap[status.type][status.category];
    return typeof name === 'function' ? name(status) : name;
  }

  /**
    Generates the unit list sorted by status category and landscape
    annotation key and returns an array with the data to
    generate the unit list UI.

    @method updateStatusList
    @param {Object} values From the databinding update method.
    @return {Array} An array of status objects. For units, this means
    agent_state or landscape annotation id as category and an array of units
    [{ type: 'unit', category: 'started', units: [model, model, ...]}].  For
    services, this means whether or not an upgrade is available
    [{ type: 'service', upgradeAvailable: true, upgradeTo: ...}].
    */
  function updateStatusList(values) {
    var statuses = [],
        unitByStatus = {};

    values.each(function(value) {
      var category = utils.simplifyState(value);
      if (!unitByStatus[category]) {
        unitByStatus[category] = [];
      }
      unitByStatus[category].push(value);

      // landscape annotations
      var lIds = utils.landscapeAnnotations(value);
      lIds.forEach(function(annotation) {
        if (!unitByStatus[annotation]) {
          unitByStatus[annotation] = [];
        }
        unitByStatus[annotation].push(value);
      });
    });

    // This will generate a list with all categories.
    Y.Object.each(unitListNameMap, function(value, key) {
      var unit = {};
      if (unitByStatus[key]) {
        unit = unitByStatus[key];
      }
      statuses.push({type: 'unit', category: key, units: unit});
    });

    var flags = window.flags;
    if (flags.upgradeCharm) {
      // Disable strict violation warning for use of `this`.
      /* jshint -W040 */
      var service = this.model;
      var upgradeServiceStatus = {
        type: 'service',
        category: 'upgrade-service',
        upgradeAvailable: service.get('upgrade_available'),
        upgradeTo: service.get('upgrade_to'),
        downgrades: []
      };
      // Retrieve the charm ID (minus the schema).
      var charm = service.get('charm');
      // Find the latest version number - if we have an upgrade, it will be
      // that charm's version; otherwise it will be the current charm's
      // version.
      var currVersion = parseInt(charm.split('-').pop(), 10),
          maxVersion = upgradeServiceStatus.upgradeAvailable ?
              parseInt(upgradeServiceStatus.upgradeTo.split('-').pop(), 10) :
              currVersion;
      // Remove the version number from the charm so that we can build a
      // list of downgrades.
      charm = charm.replace(/-\d+$/, '');
      // Build a list of available downgrades
      if (maxVersion > 1) {
        // Disable -- operator warning so that we can loop.
        /* jshint -W016 */
        for (var version = maxVersion - 1; version > 0; version--) {
          if (version === currVersion) {
            continue;
          }
          upgradeServiceStatus.downgrades.push(charm + '-' + version);
        }
      }
      // If we have an upgrade for this service, then it needs to appear under
      // the pending units (at index 1, so insert at index 2); otherwise, it
      // should just be pushed onto the end of the list of statuses.
      if (upgradeServiceStatus.upgradeAvailable) {
        statuses.splice(2, 0, upgradeServiceStatus);
      } else {
        statuses.push(upgradeServiceStatus);
      }
    }

    return statuses;
  }

  /**
    Generates the list of allowable buttons for the
    different inspector unit lists.

    @method generateActionButtonList
    @param {String} category The unit status category.
    */
  function generateActionButtonList(category) {
    var showingButtons = {},
        buttonTypes = ['resolve', 'retry', 'remove', 'landscape'],
        // if you adjust this list don't forget to edit
        // the list in the unit tests
        buttons = {
          error: ['resolve', 'retry', 'remove'],
          pending: ['retry', 'remove'],
          running: ['remove'],
          'landscape-needs-reboot': ['landscape'],
          'landscape-security-upgrades': ['landscape']
        };

    buttonTypes.forEach(function(buttonType) {
      buttons[category].forEach(function(allowedButton) {
        if (buttonType === allowedButton) {
          showingButtons[buttonType] = true;
        }
      });
    });
    return showingButtons;
  }

  /**
    Binds the statuses data set to d3

    @method generateAndBindStatusHeaders
    @param {Y.Node} node The YUI node object.
    @param {Array} statuses A key value pair of categories to unit list.
    @param {Model} environment The Environment model instance.
    */
  function generateAndBindStatusHeaders(node, statuses, environment) {
    /* jshint -W040 */
    // Ignore 'possible strict violation'
    var self = this,
        buttonHeight;

    var categoryWrapperNodes = d3.select(node.getDOMNode())
    .selectAll('.unit-list-wrapper')
    .data(statuses, function(d) {
          return d.category;
        });

    // D3 header enter section
    var categoryStatusWrapper = categoryWrapperNodes
    .enter()
    .append('div')
    .classed('unit-list-wrapper hidden', true);

    var categoryStatusHeader = categoryStatusWrapper
    .append('div')
    .attr('class', function(d) {
          return 'status-unit-header ' +
              'closed-unit-list ' + d.category;
        });

    var serviceStatusContentForm = categoryStatusWrapper
    .filter(function(d) { return d.type === 'service'; })
    .append('div')
    .attr('class', function(d) {
          return 'status-unit-content ' +
              'close-unit ' + d.category;
        });

    var serviceUpgradeLi = serviceStatusContentForm
    .filter(function(d) {
          return d.category === 'upgrade-service';
        })
    .selectAll('li.top-upgrade')
    .data(function(d) {
          if (d.upgradeAvailable) {
            return [d.upgradeTo];
          } else {
            return d.downgrades.slice(0, 5);
          }
        })
    .enter()
    .append('li')
    .classed('top-upgrade', true);

    serviceUpgradeLi.append('a')
      .attr('href', function(d) {
          return '/' + d.replace(/^cs:/, '');
        })
      .text(function(d) { return d; });

    serviceUpgradeLi.append('a')
      .classed('upgrade-link right-link', true)
      .attr('data-upgradeto', function(d) { return d; })
      .text('Upgrade');

    serviceStatusContentForm
      .filter(function(d) {
          return d.category === 'upgrade-service' && (d.upgradeAvailable ||
              d.downgrades.length - 5 > 0);
        })
      .append('li')
      .append('a')
      .classed('right-link', true)
      .text(function(d) {
          return (d.downgrades.length - (d.upgradeAvailable ? 0 : 5)) +
              ' hidden upgrades';
        })
      .on('click', function(d) {
          // Toggle the 'hidden' class.
          serviceStatusContentForm.select('.other-charms')
          .classed('hidden', function() {
                return !d3.select(this).classed('hidden');
              });
        });

    var serviceUpgradeOtherCharms = serviceStatusContentForm
      .filter(function(d) {
          return d.category === 'upgrade-service';
        })
      .append('div')
      .classed('other-charms', true)
      .classed('hidden', true)
      .selectAll('.other-charm')
      .data(function(d) {
          return d.downgrades.slice(d.upgradeAvailable ? 0 : 5);
        })
      .enter()
      .append('li')
      .classed('other-charm', true);

    serviceUpgradeOtherCharms
      .append('a')
      .attr('href', function(d) {
          return '/' + d.replace(/^cs:/, '');
        })
      .text(function(d) { return d; });

    serviceUpgradeOtherCharms
      .append('a')
      .classed('upgrade-link right-link', true)
      .attr('data-upgradeto', function(d) { return d; })
      .text('Upgrade');

    var unitStatusContentForm = categoryStatusWrapper
    .filter(function(d) { return d.type === 'unit'; })
    .append('div')
    .attr('class', function(d) {
          return 'status-unit-content ' +
              'close-unit ' + d.category;
        })
    .append('form');

    unitStatusContentForm.append('li')
    .append('input')
    .attr('type', 'checkbox')
    .classed('toggle-select-all', true);

    unitStatusContentForm.append('ul');

    unitStatusContentForm.append('div')
    .classed('action-button-wrapper', true)
    .html(
        function(d) {
          var context = generateActionButtonList(d.category);
          if (context.landscape) {
            context.landscapeURL = utils.getLandscapeURL(
              environment, self.model);
          }
          var template = templates['unit-action-buttons'](context);
          buttonHeight = template.offsetHeight;
          return template;
        });

    categoryStatusHeader
    .filter(function(d) { return d.type === 'unit'; })
    .append('span')
    .classed('unit-qty', true);

    categoryStatusHeader.append('span')
    .classed('category-label', true);

    categoryStatusHeader.append('span')
    .classed('chevron', true);

    // D3 header update section
    categoryWrapperNodes.select('.unit-qty')
    .text(function(d) {
          return d.units.length;
        });

    // Toggles the sections visible or hidden based on if this is a service
    // status or, if it's a unit status, whether there are units in the list.
    categoryWrapperNodes.filter(function(d) {
      return d.type === 'service' || (d.type === 'unit' && d.units.length > 0);
    })
    .classed('hidden', false);

    categoryWrapperNodes.filter(function(d) {
      return d.type === 'unit' && d.units.length === undefined;
    })
    .classed('hidden', true);

    // Add the category label to each heading
    categoryWrapperNodes.select('.category-label')
    .text(categoryName);

    var unitsList = categoryWrapperNodes
    .filter(function(d) { return d.type === 'unit'; })
    .select('ul')
    .selectAll('li')
    .data(function(d) {
          return d.units;
        }, function(unit) {
          return unit.id;
        });

    // D3 content enter section
    var unitItem = unitsList.enter()
    .append('li');

    unitItem.append('input')
    .attr({
          'type': 'checkbox',
          'name': function(unit) {
            return unit.id;
          }});

    unitItem.append('a').text(
        function(d) {
          return d.id;
        })
      .attr('data-unit', function(d) {
          return d.service + '/' + d.number;
        });

    // Handle Landscape actions.
    unitItem.filter(function() {
      return Y.Node(this).ancestor('.landscape-needs-reboot');
    }).append('a').classed('right-link', true).attr({
      // Retrieve the Landscape reboot URL for the unit.
      'href': function(d) {
        return utils.getLandscapeURL(environment, d, 'reboot');
      },
      target: '_blank'
    }).text('Reboot');

    unitItem.filter(function() {
      return Y.Node(this).ancestor('.landscape-security-upgrades');
    }).append('a').classed('right-link', true).attr({
      // Retrieve the Landscape security upgrade URL for the unit.
      'href': function(d) {
        return utils.getLandscapeURL(environment, d, 'security');
      },
      target: '_blank'
    }).text('Upgrade');

    // D3 content update section
    unitsList.sort(
        function(a, b) {
          return a.number - b.number;
        });

    categoryWrapperNodes
      .select('.status-unit-content')
      .style('max-height', function(d) {
          if (!self._itemHeight) {
            self._itemHeight =
                d3.select(this).select('li').property('offsetHeight');
          }
          var numItems = 0;
          if (d.type === 'unit') {
            numItems = d.units.length + 1;
          } else {
            if (d.category === 'upgrade-service') {
              // If there is an upgrade available, make room for that, plus the
              // link to show hidden upgrades; otherwise, just return the number
              // of downgrades.
              numItems = d.downgrades.length + (d.upgradeAvailable ? 2 : 0);
            }
          }
          return ((self._itemHeight * numItems) + buttonHeight) + 'px';
        });

    // D3 content exit section
    unitsList.exit().remove();

    // D3 header exit section
    categoryWrapperNodes.exit().remove();
  }

  ns.overview = {
    name: 'overview',
    template: templates.serviceOverview,
    bindings: {
      aggregated_status: {
        'update': function(node, value) {
          var bar = this._statusbar;
          if (!bar) {
            bar = this._statusbar = new views.StatusBar({
              width: 250,
              target: node.getDOMNode(),
              labels: false,
              height: 30
            }).render();
          }
          bar.update(value);
        }
      },
      units: {
        depends: ['aggregated_status', 'upgrade_to'],
        'update': function(node, value) {
          // Called under the databinding context.
          // Subordinates may not have a value.
          if (value) {
            var statuses = this.viewlet.updateStatusList(value);
            this.viewlet.generateAndBindStatusHeaders(
                node, statuses, this.viewlet.options.db.environment);
          }
        }
      }
    },
    // These methods are exposed here to allow us access for testing.
    categoryName: categoryName,
    generateAndBindStatusHeaders: generateAndBindStatusHeaders,
    generateActionButtonList: generateActionButtonList,
    updateStatusList: updateStatusList
  };

}, '0.0.1', {
  requires: [
    'node',
    'd3',
    'd3-statusbar',
    'juju-charm-models',
    'juju-view'
  ]
});
<commit_msg>Per review, pull count to a constant<commit_after>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

YUI.add('viewlet-inspector-overview', function(Y) {
  var ns = Y.namespace('juju.viewlets'),
      views = Y.namespace('juju.views'),
      templates = Y.namespace('juju.views').Templates,
      models = Y.namespace('juju.models'),
      utils = Y.namespace('juju.views.utils');

  var SHOWCOUNT = 5;

  var unitListNameMap = {
    error: 'Error',
    pending: 'Pending',
    running: 'Running',
    'landscape-needs-reboot': 'Needs Reboot',
    'landscape-security-upgrades': 'Security Upgrade'
  };

  /**
    Return a category name based on a status, generated either from the
    `unitListNameMap` (in the case of units) or from a data-driven function.

    @method categoryName
    @param {Object} status The status to name.
    @return {String} a name for the status.
  */
  function categoryName(status) {
    var nameMap = {
      'unit': unitListNameMap,
      'service': {
        'upgrade-service': function(status) {
          return status.upgradeAvailable ?
              'A new upgrade is available' :
              'Upgrade service';
        }
      }
    };

    var name = nameMap[status.type][status.category];
    return typeof name === 'function' ? name(status) : name;
  }

  /**
    Generates the unit list sorted by status category and landscape
    annotation key and returns an array with the data to
    generate the unit list UI.

    @method updateStatusList
    @param {Object} values From the databinding update method.
    @return {Array} An array of status objects. For units, this means
    agent_state or landscape annotation id as category and an array of units
    [{ type: 'unit', category: 'started', units: [model, model, ...]}].  For
    services, this means whether or not an upgrade is available
    [{ type: 'service', upgradeAvailable: true, upgradeTo: ...}].
    */
  function updateStatusList(values) {
    var statuses = [],
        unitByStatus = {};

    values.each(function(value) {
      var category = utils.simplifyState(value);
      if (!unitByStatus[category]) {
        unitByStatus[category] = [];
      }
      unitByStatus[category].push(value);

      // landscape annotations
      var lIds = utils.landscapeAnnotations(value);
      lIds.forEach(function(annotation) {
        if (!unitByStatus[annotation]) {
          unitByStatus[annotation] = [];
        }
        unitByStatus[annotation].push(value);
      });
    });

    // This will generate a list with all categories.
    Y.Object.each(unitListNameMap, function(value, key) {
      var unit = {};
      if (unitByStatus[key]) {
        unit = unitByStatus[key];
      }
      statuses.push({type: 'unit', category: key, units: unit});
    });

    var flags = window.flags;
    if (flags.upgradeCharm) {
      // Disable strict violation warning for use of `this`.
      /* jshint -W040 */
      var service = this.model;
      var upgradeServiceStatus = {
        type: 'service',
        category: 'upgrade-service',
        upgradeAvailable: service.get('upgrade_available'),
        upgradeTo: service.get('upgrade_to'),
        downgrades: []
      };
      // Retrieve the charm ID (minus the schema).
      var charm = service.get('charm');
      // Find the latest version number - if we have an upgrade, it will be
      // that charm's version; otherwise it will be the current charm's
      // version.
      var currVersion = parseInt(charm.split('-').pop(), 10),
          maxVersion = upgradeServiceStatus.upgradeAvailable ?
              parseInt(upgradeServiceStatus.upgradeTo.split('-').pop(), 10) :
              currVersion;
      // Remove the version number from the charm so that we can build a
      // list of downgrades.
      charm = charm.replace(/-\d+$/, '');
      // Build a list of available downgrades
      if (maxVersion > 1) {
        // Disable -- operator warning so that we can loop.
        /* jshint -W016 */
        for (var version = maxVersion - 1; version > 0; version--) {
          if (version === currVersion) {
            continue;
          }
          upgradeServiceStatus.downgrades.push(charm + '-' + version);
        }
      }
      // If we have an upgrade for this service, then it needs to appear under
      // the pending units (at index 1, so insert at index 2); otherwise, it
      // should just be pushed onto the end of the list of statuses.
      if (upgradeServiceStatus.upgradeAvailable) {
        statuses.splice(2, 0, upgradeServiceStatus);
      } else {
        statuses.push(upgradeServiceStatus);
      }
    }

    return statuses;
  }

  /**
    Generates the list of allowable buttons for the
    different inspector unit lists.

    @method generateActionButtonList
    @param {String} category The unit status category.
    */
  function generateActionButtonList(category) {
    var showingButtons = {},
        buttonTypes = ['resolve', 'retry', 'remove', 'landscape'],
        // if you adjust this list don't forget to edit
        // the list in the unit tests
        buttons = {
          error: ['resolve', 'retry', 'remove'],
          pending: ['retry', 'remove'],
          running: ['remove'],
          'landscape-needs-reboot': ['landscape'],
          'landscape-security-upgrades': ['landscape']
        };

    buttonTypes.forEach(function(buttonType) {
      buttons[category].forEach(function(allowedButton) {
        if (buttonType === allowedButton) {
          showingButtons[buttonType] = true;
        }
      });
    });
    return showingButtons;
  }

  /**
    Binds the statuses data set to d3

    @method generateAndBindStatusHeaders
    @param {Y.Node} node The YUI node object.
    @param {Array} statuses A key value pair of categories to unit list.
    @param {Model} environment The Environment model instance.
    */
  function generateAndBindStatusHeaders(node, statuses, environment) {
    /* jshint -W040 */
    // Ignore 'possible strict violation'
    var self = this,
        buttonHeight;

    var categoryWrapperNodes = d3.select(node.getDOMNode())
    .selectAll('.unit-list-wrapper')
    .data(statuses, function(d) {
          return d.category;
        });

    // D3 header enter section
    var categoryStatusWrapper = categoryWrapperNodes
    .enter()
    .append('div')
    .classed('unit-list-wrapper hidden', true);

    var categoryStatusHeader = categoryStatusWrapper
    .append('div')
    .attr('class', function(d) {
          return 'status-unit-header ' +
              'closed-unit-list ' + d.category;
        });

    var serviceStatusContentForm = categoryStatusWrapper
    .filter(function(d) { return d.type === 'service'; })
    .append('div')
    .attr('class', function(d) {
          return 'status-unit-content ' +
              'close-unit ' + d.category;
        });

    var serviceUpgradeLi = serviceStatusContentForm
    .filter(function(d) {
          return d.category === 'upgrade-service';
        })
    .selectAll('li.top-upgrade')
    .data(function(d) {
          if (d.upgradeAvailable) {
            return [d.upgradeTo];
          } else {
            return d.downgrades.slice(0, SHOWCOUNT);
          }
        })
    .enter()
    .append('li')
    .classed('top-upgrade', true);

    serviceUpgradeLi.append('a')
      .attr('href', function(d) {
          return '/' + d.replace(/^cs:/, '');
        })
      .text(function(d) { return d; });

    serviceUpgradeLi.append('a')
      .classed('upgrade-link right-link', true)
      .attr('data-upgradeto', function(d) { return d; })
      .text('Upgrade');

    serviceStatusContentForm
      .filter(function(d) {
          return d.category === 'upgrade-service' && (d.upgradeAvailable ||
              d.downgrades.length - SHOWCOUNT > 0);
        })
      .append('li')
      .append('a')
      .classed('right-link', true)
      .text(function(d) {
          return (d.downgrades.length - (d.upgradeAvailable ? 0 : SHOWCOUNT)) +
              ' hidden upgrades';
        })
      .on('click', function(d) {
          // Toggle the 'hidden' class.
          serviceStatusContentForm.select('.other-charms')
          .classed('hidden', function() {
                return !d3.select(this).classed('hidden');
              });
        });

    var serviceUpgradeOtherCharms = serviceStatusContentForm
      .filter(function(d) {
          return d.category === 'upgrade-service';
        })
      .append('div')
      .classed('other-charms', true)
      .classed('hidden', true)
      .selectAll('.other-charm')
      .data(function(d) {
          return d.downgrades.slice(d.upgradeAvailable ? 0 : SHOWCOUNT);
        })
      .enter()
      .append('li')
      .classed('other-charm', true);

    serviceUpgradeOtherCharms
      .append('a')
      .attr('href', function(d) {
          return '/' + d.replace(/^cs:/, '');
        })
      .text(function(d) { return d; });

    serviceUpgradeOtherCharms
      .append('a')
      .classed('upgrade-link right-link', true)
      .attr('data-upgradeto', function(d) { return d; })
      .text('Upgrade');

    var unitStatusContentForm = categoryStatusWrapper
    .filter(function(d) { return d.type === 'unit'; })
    .append('div')
    .attr('class', function(d) {
          return 'status-unit-content ' +
              'close-unit ' + d.category;
        })
    .append('form');

    unitStatusContentForm.append('li')
    .append('input')
    .attr('type', 'checkbox')
    .classed('toggle-select-all', true);

    unitStatusContentForm.append('ul');

    unitStatusContentForm.append('div')
    .classed('action-button-wrapper', true)
    .html(
        function(d) {
          var context = generateActionButtonList(d.category);
          if (context.landscape) {
            context.landscapeURL = utils.getLandscapeURL(
              environment, self.model);
          }
          var template = templates['unit-action-buttons'](context);
          buttonHeight = template.offsetHeight;
          return template;
        });

    categoryStatusHeader
    .filter(function(d) { return d.type === 'unit'; })
    .append('span')
    .classed('unit-qty', true);

    categoryStatusHeader.append('span')
    .classed('category-label', true);

    categoryStatusHeader.append('span')
    .classed('chevron', true);

    // D3 header update section
    categoryWrapperNodes.select('.unit-qty')
    .text(function(d) {
          return d.units.length;
        });

    // Toggles the sections visible or hidden based on if this is a service
    // status or, if it's a unit status, whether there are units in the list.
    categoryWrapperNodes.filter(function(d) {
      return d.type === 'service' || (d.type === 'unit' && d.units.length > 0);
    })
    .classed('hidden', false);

    categoryWrapperNodes.filter(function(d) {
      return d.type === 'unit' && d.units.length === undefined;
    })
    .classed('hidden', true);

    // Add the category label to each heading
    categoryWrapperNodes.select('.category-label')
    .text(categoryName);

    var unitsList = categoryWrapperNodes
    .filter(function(d) { return d.type === 'unit'; })
    .select('ul')
    .selectAll('li')
    .data(function(d) {
          return d.units;
        }, function(unit) {
          return unit.id;
        });

    // D3 content enter section
    var unitItem = unitsList.enter()
    .append('li');

    unitItem.append('input')
    .attr({
          'type': 'checkbox',
          'name': function(unit) {
            return unit.id;
          }});

    unitItem.append('a').text(
        function(d) {
          return d.id;
        })
      .attr('data-unit', function(d) {
          return d.service + '/' + d.number;
        });

    // Handle Landscape actions.
    unitItem.filter(function() {
      return Y.Node(this).ancestor('.landscape-needs-reboot');
    }).append('a').classed('right-link', true).attr({
      // Retrieve the Landscape reboot URL for the unit.
      'href': function(d) {
        return utils.getLandscapeURL(environment, d, 'reboot');
      },
      target: '_blank'
    }).text('Reboot');

    unitItem.filter(function() {
      return Y.Node(this).ancestor('.landscape-security-upgrades');
    }).append('a').classed('right-link', true).attr({
      // Retrieve the Landscape security upgrade URL for the unit.
      'href': function(d) {
        return utils.getLandscapeURL(environment, d, 'security');
      },
      target: '_blank'
    }).text('Upgrade');

    // D3 content update section
    unitsList.sort(
        function(a, b) {
          return a.number - b.number;
        });

    categoryWrapperNodes
      .select('.status-unit-content')
      .style('max-height', function(d) {
          if (!self._itemHeight) {
            self._itemHeight =
                d3.select(this).select('li').property('offsetHeight');
          }
          var numItems = 0;
          if (d.type === 'unit') {
            numItems = d.units.length + 1;
          } else {
            if (d.category === 'upgrade-service') {
              // If there is an upgrade available, make room for that, plus the
              // link to show hidden upgrades; otherwise, just return the number
              // of downgrades.
              numItems = d.downgrades.length + (d.upgradeAvailable ? 2 : 0);
            }
          }
          return ((self._itemHeight * numItems) + buttonHeight) + 'px';
        });

    // D3 content exit section
    unitsList.exit().remove();

    // D3 header exit section
    categoryWrapperNodes.exit().remove();
  }

  ns.overview = {
    name: 'overview',
    template: templates.serviceOverview,
    bindings: {
      aggregated_status: {
        'update': function(node, value) {
          var bar = this._statusbar;
          if (!bar) {
            bar = this._statusbar = new views.StatusBar({
              width: 250,
              target: node.getDOMNode(),
              labels: false,
              height: 30
            }).render();
          }
          bar.update(value);
        }
      },
      units: {
        depends: ['aggregated_status', 'upgrade_to'],
        'update': function(node, value) {
          // Called under the databinding context.
          // Subordinates may not have a value.
          if (value) {
            var statuses = this.viewlet.updateStatusList(value);
            this.viewlet.generateAndBindStatusHeaders(
                node, statuses, this.viewlet.options.db.environment);
          }
        }
      }
    },
    // These methods are exposed here to allow us access for testing.
    categoryName: categoryName,
    generateAndBindStatusHeaders: generateAndBindStatusHeaders,
    generateActionButtonList: generateActionButtonList,
    updateStatusList: updateStatusList
  };

}, '0.0.1', {
  requires: [
    'node',
    'd3',
    'd3-statusbar',
    'juju-charm-models',
    'juju-view'
  ]
});
<|endoftext|>