<commit_before>const debug = require('debug')('p3api-server:TranscriptomicsGene')
const { httpRequest, httpsGetUrl, httpsRequestUrl } = require('../util/http')
const Config = require('../config')
const WORKSPACE_API_URL = Config.get('workspaceAPI')
const http = require('http')
const SolrAgentConfig = Config.get('solr').shortLiveAgent
const SolrAgent = new http.Agent(SolrAgentConfig)

function getWorkspaceObjects (paths, metadataOnly, token) {
  return new Promise((resolve, reject) => {
    if (!(paths instanceof Array)) {
      paths = [paths]
    }
    paths = paths.map(decodeURIComponent)

    httpsRequestUrl(WORKSPACE_API_URL, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'authorization': token
      },
      method: 'POST'
    }, JSON.stringify({
      id: 1,
      method: 'Workspace.get',
      version: '1.1',
      params: [{ objects: paths, metadata_only: metadataOnly }]
    })).then((body) => {
      const results = JSON.parse(body)
      if (results.result) {
        const defs = results.result[0].map((obj) => {
          const meta = {
            name: obj[0][0],
            type: obj[0][1],
            path: obj[0][2],
            creation_time: obj[0][3],
            id: obj[0][4],
            owner_id: obj[0][5],
            size: obj[0][6],
            userMeta: obj[0][7],
            autoMeta: obj[0][8],
            user_permissions: obj[0][9],
            global_permission: obj[0][10],
            link_reference: obj[0][11]
          }

          if (metadataOnly) {
            return meta
          }
          if (!meta.link_reference) {
            return ({ metadata: meta, data: obj[1] })
          } else {
            return httpsGetUrl(`${meta.link_reference}?download`, {
              headers: {
                'Authorization': 'OAuth ' + token
              }
            }).then((body) => {
              return {
                'metadata': meta,
                'data': body
              }
            }, (error) => {
              throw error
            })
          }
        })

        Promise.all(defs).then((d) => {
          resolve(d)
        })
      }
    }, (err) => {
      reject(err)
    })
  })
}

function readWorkspaceExperiments (tgState, options) {
  const wsExpIds = tgState['wsExpIds']
  const wsComparisonIds = tgState['wsComparisonIds']
  const expressionFiles = wsExpIds.map(function (exp_id) {
    const parts = exp_id.split('/')
    const jobName = parts.pop()
    return parts.join('/') + '/.' + jobName + '/expression.json'
  })

  return new Promise((resolve, reject) => {
    getWorkspaceObjects(expressionFiles, false, options.token).then((results) => {
      const p3FeatureIdSet = {}
      const p2FeatureIdSet = {}

      const expressions = results.map(function (d) {
        if (!wsComparisonIds) {
          return JSON.parse(d.data)['expression']
        } else {
          return JSON.parse(d.data)['expression'].filter(function (e) {
            return wsComparisonIds.indexOf(e.pid) >= 0
          })
        }
      })

      const flattened = [].concat.apply([], expressions)
      flattened.forEach(function (expression) {
        if (expression.hasOwnProperty('feature_id')) {
          if (!p3FeatureIdSet.hasOwnProperty(expression.feature_id)) {
            p3FeatureIdSet[expression.feature_id] = true
          }
        } else if (expression.hasOwnProperty('na_feature_id')) {
          if (!p2FeatureIdSet.hasOwnProperty(expression.na_feature_id)) {
            p2FeatureIdSet[expression.na_feature_id] = true
          }
        }
      })

      resolve({
        expressions: flattened,
        p3FeatureIds: Object.keys(p3FeatureIdSet),
        p2FeatureIds: Object.keys(p2FeatureIdSet)
      })
    })
  })
}

function readPublicExperiments (tgState, options) {
  return new Promise(async (resolve, reject) => {
    const res = await httpRequest({
      port: Config.get('http_port'),
      headers: {
        'Accept': 'application/solr+json',
        'Content-Type': 'application/rqlquery+x-www-form-urlencoded',
        'Authorization': options.token || ''
      },
      method: 'POST',
      agent: SolrAgent,
      path: '/transcriptomics_gene/'
    }, `${tgState.query}&select(pid,refseq_locus_tag,feature_id,log_ratio,z_score)&limit(1)`)

    let response
    try {
      response = JSON.parse(res)
    } catch (err) {
      reject(new Error(`readPublicExperiments(): Error parsing JSON from SOLR: ${err}`))
    }

    const numFound = response.response.numFound

    const fetchSize = 25000
    const steps = Math.ceil(numFound / fetchSize)
    const allRequests = []

    for (let i = 0; i < steps; i++) {
      const range = 'items=' + (i * fetchSize) + '-' + ((i + 1) * fetchSize - 1)
      const subPromise = httpRequest({
        port: Config.get('http_port'),
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/rqlquery+x-www-form-urlencoded',
          'Range': range,
          'Authorization': options.token || ''
        },
        method: 'POST',
        agent: SolrAgent,
        path: '/transcriptomics_gene/'
      }, `${tgState.query}&select(pid,refseq_locus_tag,feature_id,log_ratio,z_score)`)
        .then((body) => JSON.parse(body))
      allRequests.push(subPromise)
    }

    Promise.all(allRequests).then((results) => {
      const expressions = []
      const p3FeatureIdSet = {}

      results.forEach(function (genes) {
        genes.forEach(function (gene) {
          expressions.push(gene)

          if (gene.hasOwnProperty('feature_id')) {
            if (!p3FeatureIdSet.hasOwnProperty(gene.feature_id)) {
              p3FeatureIdSet[gene.feature_id] = true
            }
          }
        })
      })

      resolve({ expressions: expressions, p3FeatureIds: Object.keys(p3FeatureIdSet), p2FeatureIds: [] })
    })
  })
}

function processTranscriptomicsGene (tgState, options) {
  return new Promise((resolve, reject) => {
    let wsCall
    if (tgState.hasOwnProperty('wsExpIds')) {
      wsCall = readWorkspaceExperiments(tgState, options)
    } else {
      wsCall = { expressions: [], p3FeatureIds: [], p2FeatureIds: [] }
    }

    let publicCall
    if (tgState.hasOwnProperty('pbExpIds')) {
      publicCall = readPublicExperiments(tgState, options)
    } else {
      publicCall = { expressions: [], p3FeatureIds: [], p2FeatureIds: [] }
    }

    Promise.all([publicCall, wsCall]).then((results) => {
      const comparisonIdList = tgState.comparisonIds

      const wsP3FeatureIdList = results[1].p3FeatureIds
      const wsP2FeatureIdList = results[1].p2FeatureIds
      const wsExpressions = results[1].expressions

      const pbP3FeatureIdList = results[0].p3FeatureIds
      const pbP2FeatureIdList = results[0].p2FeatureIds // []
      const pbExpressions = results[0].expressions

      const p3FeatureIdList = wsP3FeatureIdList.concat(pbP3FeatureIdList)
      const p2FeatureIdList = wsP2FeatureIdList.concat(pbP2FeatureIdList)
      const expressions = wsExpressions.concat(pbExpressions)

      debug('p3 ids: ', p3FeatureIdList.length, 'p2 ids: ', p2FeatureIdList.length)

      const query = {
        q: [(p3FeatureIdList.length > 0) ? 'feature_id:(' + p3FeatureIdList.join(' OR ') + ')' : '',
          (p3FeatureIdList.length > 0 && p2FeatureIdList.length > 0) ? ' OR ' : '',
          (p2FeatureIdList.length > 0) ? 'p2_feature_id:(' + p2FeatureIdList.join(' OR ') + ')' : ''].join(''),
        fl: 'feature_id,p2_feature_id,strand,product,accession,start,end,patric_id,refseq_locus_tag,alt_locus_tag,genome_name,genome_id,gene'
      }

      const q = Object.keys(query).map(p => p + '=' + query[p]).join('&')
      const fetchSize = 25000
      const steps = Math.ceil((p3FeatureIdList.length + p2FeatureIdList.length) / fetchSize)
      const allRequests = []

      for (let i = 0; i < steps; i++) {
        const range = 'items=' + (i * fetchSize) + '-' + ((i + 1) * fetchSize - 1)
        const subDef = httpRequest({
          port: Config.get('http_port'),
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/solrquery+x-www-form-urlencoded',
            'Range': range,
            'Authorization': options.token || ''
          },
          method: 'POST',
          agent: SolrAgent,
          path: '/genome_feature/'
        }, q).then((body) => JSON.parse(body))
        allRequests.push(subDef)
      }

      Promise.all(allRequests).then((body) => {
        const features = [].concat.apply([], body)

        const expressionHash = {}

        expressions.forEach(function (expression) {
          let featureId
          if (expression.hasOwnProperty('feature_id')) {
            featureId = expression.feature_id
          } else if (expression.hasOwnProperty('na_feature_id')) {
            featureId = expression.na_feature_id
          }

          if (!expressionHash.hasOwnProperty(featureId)) {
            var expr = { samples: {} }
            if (expression.hasOwnProperty('feature_id')) { expr.feature_id = expression.feature_id }
            if (expression.hasOwnProperty('na_feature_id')) { expr.p2_feature_id = expression.na_feature_id }
            if (expression.hasOwnProperty('refseq_locus_tag')) { expr.refseq_locus_tag = expression.refseq_locus_tag }
            const log_ratio = expression.log_ratio
            const z_score = expression.z_score
            expr.samples[expression.pid.toString()] = {
              log_ratio: log_ratio || '',
              z_score: z_score || ''
            }
            expr.up = (log_ratio != null && Number(log_ratio) > 0) ? 1 : 0
            expr.down = (log_ratio != null && Number(log_ratio) < 0) ? 1 : 0

            expressionHash[featureId] = expr
          } else {
            expr = expressionHash[featureId]
            if (!expr.samples.hasOwnProperty(expression.pid.toString())) {
              const log_ratio = expression.log_ratio
              const z_score = expression.z_score
              expr.samples[expression.pid.toString()] = {
                log_ratio: log_ratio || '',
                z_score: z_score || ''
              }
              if (log_ratio != null && Number(log_ratio) > 0) { expr.up++ }
              if (log_ratio != null && Number(log_ratio) < 0) { expr.down++ }

              expressionHash[featureId] = expr
            }
          }
        })

        const data = []
        features.forEach(function (feature) {
          let expr
          if (expressionHash.hasOwnProperty(feature.feature_id)) {
            expr = expressionHash[feature.feature_id]
          } else if (expressionHash.hasOwnProperty(feature.p2_feature_id)) {
            expr = expressionHash[feature.p2_feature_id]
          }
          if (expr) {
            // build expr object
            let count = 0
            expr.sample_binary = comparisonIdList.map(function (comparisonId) {
              if (expr.samples.hasOwnProperty(comparisonId) && expr.samples[comparisonId].log_ratio !== '') {
                count++
                return '1'
              } else {
                return '0'
              }
            }).join('')
            expr.sample_size = count

            const datum = Object.assign(feature, expr)
            data.push(datum)
          }
        })

        resolve(data)
      })
    })
  })
}

module.exports = {
  requireAuthentication: false,
  validate: function (params) {
    const tgState = params[0]
    return tgState && tgState.comparisonIds.length > 0
  },
  execute: function (params) {
    return new Promise((resolve, reject) => {
      const tgState = params[0]
      const opts = params[1]

      processTranscriptomicsGene(tgState, opts).then((result) => {
        resolve(result)
      }, (err) => {
        reject(new Error(`Unable to process protein family queries. ${err}`))
      })
    })
  }
}
<commit_msg>send subset of ids instead of scrolling, use terms query parser<commit_after>const debug = require('debug')('p3api-server:TranscriptomicsGene')
const { httpRequest, httpsGetUrl, httpsRequestUrl } = require('../util/http')
const Config = require('../config')
const WORKSPACE_API_URL = Config.get('workspaceAPI')
const http = require('http')
const SolrAgentConfig = Config.get('solr').shortLiveAgent
const SolrAgent = new http.Agent(SolrAgentConfig)

function getWorkspaceObjects (paths, metadataOnly, token) {
  return new Promise((resolve, reject) => {
    if (!(paths instanceof Array)) {
      paths = [paths]
    }
    paths = paths.map(decodeURIComponent)

    httpsRequestUrl(WORKSPACE_API_URL, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'authorization': token
      },
      method: 'POST'
    }, JSON.stringify({
      id: 1,
      method: 'Workspace.get',
      version: '1.1',
      params: [{ objects: paths, metadata_only: metadataOnly }]
    })).then((body) => {
      const results = JSON.parse(body)
      if (results.result) {
        const defs = results.result[0].map((obj) => {
          const meta = {
            name: obj[0][0],
            type: obj[0][1],
            path: obj[0][2],
            creation_time: obj[0][3],
            id: obj[0][4],
            owner_id: obj[0][5],
            size: obj[0][6],
            userMeta: obj[0][7],
            autoMeta: obj[0][8],
            user_permissions: obj[0][9],
            global_permission: obj[0][10],
            link_reference: obj[0][11]
          }

          if (metadataOnly) {
            return meta
          }
          if (!meta.link_reference) {
            return ({ metadata: meta, data: obj[1] })
          } else {
            return httpsGetUrl(`${meta.link_reference}?download`, {
              headers: {
                'Authorization': 'OAuth ' + token
              }
            }).then((body) => {
              return {
                'metadata': meta,
                'data': body
              }
            }, (error) => {
              throw error
            })
          }
        })

        Promise.all(defs).then((d) => {
          resolve(d)
        })
      }
    }, (err) => {
      reject(err)
    })
  })
}

function readWorkspaceExperiments (tgState, options) {
  const wsExpIds = tgState['wsExpIds']
  const wsComparisonIds = tgState['wsComparisonIds']
  const expressionFiles = wsExpIds.map(function (exp_id) {
    const parts = exp_id.split('/')
    const jobName = parts.pop()
    return parts.join('/') + '/.' + jobName + '/expression.json'
  })

  return new Promise((resolve, reject) => {
    getWorkspaceObjects(expressionFiles, false, options.token).then((results) => {
      const p3FeatureIdSet = {}
      const p2FeatureIdSet = {}

      const expressions = results.map(function (d) {
        if (!wsComparisonIds) {
          return JSON.parse(d.data)['expression']
        } else {
          return JSON.parse(d.data)['expression'].filter(function (e) {
            return wsComparisonIds.indexOf(e.pid) >= 0
          })
        }
      })

      const flattened = [].concat.apply([], expressions)
      flattened.forEach(function (expression) {
        if (expression.hasOwnProperty('feature_id')) {
          if (!p3FeatureIdSet.hasOwnProperty(expression.feature_id)) {
            p3FeatureIdSet[expression.feature_id] = true
          }
        } else if (expression.hasOwnProperty('na_feature_id')) {
          if (!p2FeatureIdSet.hasOwnProperty(expression.na_feature_id)) {
            p2FeatureIdSet[expression.na_feature_id] = true
          }
        }
      })

      resolve({
        expressions: flattened,
        p3FeatureIds: Object.keys(p3FeatureIdSet),
        p2FeatureIds: Object.keys(p2FeatureIdSet)
      })
    })
  })
}

function readPublicExperiments (tgState, options) {
  return new Promise(async (resolve, reject) => {
    const res = await httpRequest({
      port: Config.get('http_port'),
      headers: {
        'Accept': 'application/solr+json',
        'Content-Type': 'application/rqlquery+x-www-form-urlencoded',
        'Authorization': options.token || ''
      },
      method: 'POST',
      agent: SolrAgent,
      path: '/transcriptomics_gene/'
    }, `${tgState.query}&select(pid,refseq_locus_tag,feature_id,log_ratio,z_score)&limit(1)`)

    let response
    try {
      response = JSON.parse(res)
    } catch (err) {
      reject(new Error(`readPublicExperiments(): Error parsing JSON from SOLR: ${err}`))
    }

    const numFound = response.response.numFound

    const fetchSize = 25000
    const steps = Math.ceil(numFound / fetchSize)
    const allRequests = []

    for (let i = 0; i < steps; i++) {
      const range = 'items=' + (i * fetchSize) + '-' + ((i + 1) * fetchSize - 1)
      const subPromise = httpRequest({
        port: Config.get('http_port'),
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/rqlquery+x-www-form-urlencoded',
          'Range': range,
          'Authorization': options.token || ''
        },
        method: 'POST',
        agent: SolrAgent,
        path: '/transcriptomics_gene/'
      }, `${tgState.query}&select(pid,refseq_locus_tag,feature_id,log_ratio,z_score)`)
        .then((body) => JSON.parse(body))
      allRequests.push(subPromise)
    }

    Promise.all(allRequests).then((results) => {
      const expressions = []
      const p3FeatureIdSet = {}

      results.forEach(function (genes) {
        genes.forEach(function (gene) {
          expressions.push(gene)

          if (gene.hasOwnProperty('feature_id')) {
            if (!p3FeatureIdSet.hasOwnProperty(gene.feature_id)) {
              p3FeatureIdSet[gene.feature_id] = true
            }
          }
        })
      })

      resolve({ expressions: expressions, p3FeatureIds: Object.keys(p3FeatureIdSet), p2FeatureIds: [] })
    })
  })
}

function processTranscriptomicsGene (tgState, options) {
  return new Promise((resolve, reject) => {
    let wsCall
    if (tgState.hasOwnProperty('wsExpIds')) {
      wsCall = readWorkspaceExperiments(tgState, options)
    } else {
      wsCall = { expressions: [], p3FeatureIds: [], p2FeatureIds: [] }
    }

    let publicCall
    if (tgState.hasOwnProperty('pbExpIds')) {
      publicCall = readPublicExperiments(tgState, options)
    } else {
      publicCall = { expressions: [], p3FeatureIds: [], p2FeatureIds: [] }
    }

    Promise.all([publicCall, wsCall]).then((results) => {
      const comparisonIdList = tgState.comparisonIds

      const wsP3FeatureIdList = results[1].p3FeatureIds
      const wsP2FeatureIdList = results[1].p2FeatureIds
      const wsExpressions = results[1].expressions

      const pbP3FeatureIdList = results[0].p3FeatureIds
      const pbP2FeatureIdList = results[0].p2FeatureIds // []
      const pbExpressions = results[0].expressions

      const p3FeatureIdList = wsP3FeatureIdList.concat(pbP3FeatureIdList)
      const p2FeatureIdList = wsP2FeatureIdList.concat(pbP2FeatureIdList)
      const expressions = wsExpressions.concat(pbExpressions)

      debug('p3 ids: ', p3FeatureIdList.length, 'p2 ids: ', p2FeatureIdList.length)

      const query_fl = 'feature_id,p2_feature_id,strand,product,accession,start,end,patric_id,refseq_locus_tag,alt_locus_tag,genome_name,genome_id,gene'

      const fetchSize = 10000
      const p3IdSteps = Math.ceil(p3FeatureIdList.length / fetchSize)
      const p2IdSteps = Math.ceil(p2FeatureIdList.length / fetchSize)
      const allRequests = []

      for (let i = 0; i < p3IdSteps; i++) {
        const ids = p3FeatureIdList.slice(i * fetchSize, (i + 1) * fetchSize)
        const partial_q = `q=*:*&fq={!terms f=feature_id method=automaton}${ids.join(',')}&fl=${query_fl}`

        const range = `items=0-${ids.length}`
        const subDef = httpRequest({
          port: Config.get('http_port'),
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/solrquery+x-www-form-urlencoded',
            'Range': range,
            'Authorization': options.token || ''
          },
          method: 'POST',
          agent: SolrAgent,
          path: '/genome_feature/'
        }, partial_q).then((body) => JSON.parse(body))
        allRequests.push(subDef)
      }

      for (let i = 0; i < p2IdSteps; i++) {
        const ids = p2FeatureIdList.slice(i * fetchSize, (i + 1) * fetchSize)
        const partial_q = `q=*:*&fq={!terms f=p2_feature_id method=automaton}${ids.join(',')}&fl=${query_fl}`

        const range = `items=0-${ids.length}`
        const subDef = httpRequest({
          port: Config.get('http_port'),
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/solrquery+x-www-form-urlencoded',
            'Range': range,
            'Authorization': options.token || ''
          },
          method: 'POST',
          agent: SolrAgent,
          path: '/genome_feature/'
        }, partial_q).then((body) => JSON.parse(body))
        allRequests.push(subDef)
      }

      Promise.all(allRequests).then((body) => {
        const features = [].concat.apply([], body)

        const expressionHash = {}

        expressions.forEach(function (expression) {
          let featureId
          if (expression.hasOwnProperty('feature_id')) {
            featureId = expression.feature_id
          } else if (expression.hasOwnProperty('na_feature_id')) {
            featureId = expression.na_feature_id
          }

          if (!expressionHash.hasOwnProperty(featureId)) {
            var expr = { samples: {} }
            if (expression.hasOwnProperty('feature_id')) { expr.feature_id = expression.feature_id }
            if (expression.hasOwnProperty('na_feature_id')) { expr.p2_feature_id = expression.na_feature_id }
            if (expression.hasOwnProperty('refseq_locus_tag')) { expr.refseq_locus_tag = expression.refseq_locus_tag }
            const log_ratio = expression.log_ratio
            const z_score = expression.z_score
            expr.samples[expression.pid.toString()] = {
              log_ratio: log_ratio || '',
              z_score: z_score || ''
            }
            expr.up = (log_ratio != null && Number(log_ratio) > 0) ? 1 : 0
            expr.down = (log_ratio != null && Number(log_ratio) < 0) ? 1 : 0

            expressionHash[featureId] = expr
          } else {
            expr = expressionHash[featureId]
            if (!expr.samples.hasOwnProperty(expression.pid.toString())) {
              const log_ratio = expression.log_ratio
              const z_score = expression.z_score
              expr.samples[expression.pid.toString()] = {
                log_ratio: log_ratio || '',
                z_score: z_score || ''
              }
              if (log_ratio != null && Number(log_ratio) > 0) { expr.up++ }
              if (log_ratio != null && Number(log_ratio) < 0) { expr.down++ }

              expressionHash[featureId] = expr
            }
          }
        })

        const data = []
        features.forEach(function (feature) {
          let expr
          if (expressionHash.hasOwnProperty(feature.feature_id)) {
            expr = expressionHash[feature.feature_id]
          } else if (expressionHash.hasOwnProperty(feature.p2_feature_id)) {
            expr = expressionHash[feature.p2_feature_id]
          }
          if (expr) {
            // build expr object
            let count = 0
            expr.sample_binary = comparisonIdList.map(function (comparisonId) {
              if (expr.samples.hasOwnProperty(comparisonId) && expr.samples[comparisonId].log_ratio !== '') {
                count++
                return '1'
              } else {
                return '0'
              }
            }).join('')
            expr.sample_size = count

            const datum = Object.assign(feature, expr)
            data.push(datum)
          }
        })

        resolve(data)
      })
    })
  })
}

module.exports = {
  requireAuthentication: false,
  validate: function (params) {
    const tgState = params[0]
    return tgState && tgState.comparisonIds.length > 0
  },
  execute: function (params) {
    return new Promise((resolve, reject) => {
      const tgState = params[0]
      const opts = params[1]

      processTranscriptomicsGene(tgState, opts).then((result) => {
        resolve(result)
      }, (err) => {
        reject(new Error(`Unable to process protein family queries. ${err}`))
      })
    })
  }
}
<|endoftext|>


<commit_before>var fs           = require('fs'),
    sys          = require('sys'),
    exec         = require('child_process').exec,
    getFilesSync = require('./libs/getFilesSync').getFilesSync

exec ("npm install", function (error, stdout, stderr) {
  if (error) {
    buffered_out += error
  }

  console.log (stdout)
  getFilesSync ("alerts", [], "package.json").forEach (function (alert, index, array) {
    var data = require ("./" + alert),
        keys = Object.keys(data.dependencies)

      keys.forEach (function (dependency, index, array) {
        var cmd = "npm install " + dependency
        console.log (cmd)
        exec (cmd, function (error, stdout, stderr) {
          if (error) {
            buffered_out += error
          }

          console.log (stdout)
        })
      })
  })
})
<commit_msg>clean up installer; package.json is installed the same way as the alert package files<commit_after>var fs           = require('fs'),
    sys          = require('sys'),
    exec         = require('child_process').exec,
    getFilesSync = require('./libs/getFilesSync').getFilesSync

installDependancies ("package.json")
getFilesSync ("alerts", [], "package.json").forEach (function (package_path, index, array) {
  installDependancies (package_path)
})

function installDependancies (package_path) {
  var data = require ("./" + package_path),
    keys = Object.keys(data.dependencies)

  keys.forEach (function (dependency, index, array) {
    var cmd = "npm install " + dependency
    console.log (cmd)
    exec (cmd, function (error, stdout, stderr) {
      if (error) {
        buffered_out += error
      }

      console.log (stdout)
    })
  })
}
<|endoftext|>


<commit_before>(function(tiy, $) {
    'use strict';

    // Public API methods
    tiy.loadModule = loadModule;
    tiy.showMessage = showMessage;

    // locals & constants
    let tiyoData = null;
    let navUI = null;
    let mainUI = null;
    let notifyUI = null;
    let modulesLoaded = [];
    let moduleDisplayed = null;
    let dataLoaded = false;
    let uiLoaded = false;

    const MAIN_TEMPLATE = 'templates/main.html';
    const NAV_TEMPLATE = 'templates/nav.html';
    const NOTIFICATIONS_TEMPLATE = 'templates/notifications.html';
    const PANEL_ANIMATION_TIME = 200;

    function main() {
        let spaceUsed = Object.keys(localStorage).reduce(function(total, k) {
            return ((typeof(total) === 'number' && total) || 0) + ((localStorage[k].length * 2)/1024/1024);
        }, 0);
        console.info('Initializing Newline assistant... total localStorage used: ~%sMB', spaceUsed.toFixed(2));

        addFontAwesomeStyleSheet();
        setupNotificationsUI();

        collectData()
        .then(function getNavUI(data) {
            tiyoData = data;
            dataLoaded = true;
            console.log('Data gathered', data);
            return $.get(chrome.extension.getURL(NAV_TEMPLATE));
        })
        .then(function getMainUI(html) {
            navUI = $(html);
            $('.main .row:first').append(navUI);

            modulesLoaded.forEach(addNavIcon);
            navUI.on('click', 'li', toggleModuleUI);

            return $.get(chrome.extension.getURL(MAIN_TEMPLATE));
        })
        .then(function callModuleRenders(html) {
            mainUI = $(html);
            $('.main .row:nth-child(2)').before(mainUI);
            uiLoaded = true;

            setupContentClose();

            console.log('UI base loaded, calling render methods', mainUI);
            modulesLoaded.forEach(function(mod) {
                doRender(mod);
            });
        });
    }

    /**
    * Chrome extensions have issues with access files from css like fonts, so
    * we need to embed the styelsheet using the chromse extension URL, which
    * is dynamically generated. The remainder of the FA styles are in a static
    * stylesheet in /vendor
    */
    function addFontAwesomeStyleSheet() {
        $('head').append(
            $('<style>')
            .attr('type', 'text/css')
            .text(
                `@font-face {
                    font-family: FontAwesome;
                    src: url('${chrome.extension.getURL('vendor/fontawesome-webfont.woff')}');
                }`
            )
        );
    }

    function getUser() {
        try {
            return  JSON.parse(
                $( '#IntercomSettingsScriptTag' )
                .text()
                .split(';')[0]
                .replace('window.intercomSettings =', '')
                .replace(';', '')
                .trim()
            );
        } catch (e) {
            return;
        }
    }

    function collectData() {
        let pathname = window.location.pathname.split(/\//),
            data = {
                user: null,
                path: null,
                assignment_submission: null,
                assignment: null,
                content: null,
                group: null,
                students: []
            },
            group = $('.card-block dt:contains("Group")').next().find('a');

        data.user = getUser();

        // Admin view of path
        if (/\/admin\/paths\/[0-9]+/.test(window.location.pathname)) {
            data.path = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(1)').text(),
                onPage: true
            };
        }

        if (/\/admin\/assignment_submissions\/[0-9]+/.test(window.location.pathname)) {
            data.assignment_submission = {
                id: Number(pathname[3]),
                onPage: true
            };
        }

        if (/\/admin\/assignments\/[0-9]+/.test(window.location.pathname)) {
            data.assignment = {
                id: Number(pathname[3]),
                onPage: true
            };
        }

        // Admin view of content piece
        if (/\/admin\/(lessons|assignmnents)\/[0-9]+/.test(window.location.pathname)) {
            data.content = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(3)').text(),
                type: pathname[2],
                isAdmin: true
            };
        }

        // Student view of content piece
        if (/\/paths\/[0-9]+\/units\/[0-9]+\/[^\/]+\/[0-9]+/.test(window.location.pathname)) {
            data.path = {
                id: Number(pathname[2]),
                title: $('.m-pathheader-info-title').text(),
                onPage: false
            };
            data.content = {
                id: Number(pathname[6]),
                title: $('.m-lessonheader-title').text(),
                type: pathname[5],
                isAdmin: false
            };
        }

        let p;
        if (group.length) {
            data.group = {
                title: group.text(),
                id: Number(group.attr('href').match(/\/([0-9]+)/)[1])
            };

            p = new Promise(
              function(res) {
                $.get(group.attr('href')).then(function(html) {
                let students = $(html).find('#students tr td:first-child a');
                students.each(function() {
                    let studentElem = $(this).find('.profile-placeholder-medium, img').remove().end();
                    data.students.push({
                        id: Number(studentElem.attr('href').match(/\/([0-9]+)/)[1]),
                        name: studentElem.text()
                    });
                });
                res(data);
              }, function() {
                console.log( 'Group Missing or you do not have access.' );
                res(data);
              });
            });
        } else {
            p = Promise.resolve(data);
        }

        return p;
    }

    function addNavIcon(mod) {
        if (!navUI) { return; }

        navUI.find('ul').append(
            `<li data-module='${mod.name}' title='${mod.name}' aria-title='${mod.name}'><i class='fa ${mod.navIcon} fa-lg' aria-hidden='true'></i></li>`
        );
    }

    function toggleModuleUI(e) {
        e.preventDefault();
        var name = $(this).data('module');
        var mod = modulesLoaded.filter(function(m) { return m.name === name;});
        if (!mod.length) { return; }

        if (moduleDisplayed === mod[0].name) {
            console.log('hiding ', mod[0]);
            closeContent(e);
        } else {
            console.log('showing ', mod[0]);
            moduleDisplayed = mod[0].name;
            $('.tiyo-assistant-module').hide();
            $(`[data-module="${mod[0].name}"]`).show().trigger('showing');
            mainUI.slideDown(PANEL_ANIMATION_TIME);
        }
    }

    function closeContent(e) {
        e.preventDefault();
        $(`[data-module="${moduleDisplayed}"]`).show().trigger('hiding');
        moduleDisplayed = null;
        mainUI.slideUp(PANEL_ANIMATION_TIME);
    }

    function setupContentClose() {
        $('.tiyo-assistant-close').click(closeContent);
    }

    function loadModule(api) {
        if (!api) { return; }
        if (!api.name) { api.name = Date.getTime(); }

        console.info('loading module', api);

        modulesLoaded.push(api);

        addNavIcon(api);
        doRender(api);
    }

    function doRender(mod) {
        if (uiLoaded && typeof(mod.render) === 'function') {
            var elem = createModuleWrapper(mod);
            mod.render(tiyoData, elem);
        }
    }

    function createModuleWrapper(mod) {
        var elem = $(`<article data-module='${mod.name}'>`).addClass('tiyo-assistant-module');
        $(mainUI).find('.tiyo-assistant-content').append(elem);
        return elem;
    }

    function setupNotificationsUI() {
        $.get(chrome.extension.getURL(NOTIFICATIONS_TEMPLATE)).then(function(html) {
            notifyUI = $(html).appendTo('body');
            notifyUI.on('click', '.close', function() {
                $(this).parent().fadeOut(function() { $(this).remove(); });
            });
        });
    }

    function showMessage(msg, options = {}) {
        options.type = options.type || 'danger';
        options.duration = (Number(options.duration) || options.duration === 0) ? options.duration : 4;

        let dismissable = (options.canDismiss === false) ? '' : 'alert-dismissible';

        let msgNode = $(`<p class='alert alert-${options.type} ${dismissable}'>`).text(msg);

        if (dismissable.length) {
            msgNode.append(`<button class='close'>×</button>`);
        }

        notifyUI.append(msgNode);

        if (options.duration && options.duration > 0) {
            setTimeout(function() {
                msgNode.fadeOut(function() { $(this).remove(); });
            }, (options.duration * 1000));
        }
    }

    // Kick things off...
    main();
    // Then export our module API
    window.tiy = tiy;

})(window.tiy || {}, window.jQuery);
<commit_msg>Fixed selectors to prevent injection of multiple main elements into Newline DOM.<commit_after>(function(tiy, $) {
    'use strict';

    // Public API methods
    tiy.loadModule = loadModule;
    tiy.showMessage = showMessage;

    // locals & constants
    let tiyoData = null;
    let navUI = null;
    let mainUI = null;
    let notifyUI = null;
    let modulesLoaded = [];
    let moduleDisplayed = null;
    let dataLoaded = false;
    let uiLoaded = false;

    const MAIN_TEMPLATE = 'templates/main.html';
    const NAV_TEMPLATE = 'templates/nav.html';
    const NOTIFICATIONS_TEMPLATE = 'templates/notifications.html';
    const PANEL_ANIMATION_TIME = 200;

    function main() {
        let spaceUsed = Object.keys(localStorage).reduce(function(total, k) {
            return ((typeof(total) === 'number' && total) || 0) + ((localStorage[k].length * 2)/1024/1024);
        }, 0);
        console.info('Initializing Newline assistant... total localStorage used: ~%sMB', spaceUsed.toFixed(2));

        addFontAwesomeStyleSheet();
        setupNotificationsUI();

        collectData()
        .then(function getNavUI(data) {
            tiyoData = data;
            dataLoaded = true;
            console.log('Data gathered', data);
            return $.get(chrome.extension.getURL(NAV_TEMPLATE));
        })
        .then(function getMainUI(html) {
            navUI = $(html);
            $('.main #page-title:first').append(navUI);

            modulesLoaded.forEach(addNavIcon);
            navUI.on('click', 'li', toggleModuleUI);

            return $.get(chrome.extension.getURL(MAIN_TEMPLATE));
        })
        .then(function callModuleRenders(html) {
            mainUI = $(html);
            $('.main>.row:nth-child(2)').before(mainUI);
            uiLoaded = true;

            setupContentClose();

            console.log('UI base loaded, calling render methods', mainUI);
            modulesLoaded.forEach(function(mod) {
                doRender(mod);
            });
        });
    }

    /**
    * Chrome extensions have issues with access files from css like fonts, so
    * we need to embed the styelsheet using the chromse extension URL, which
    * is dynamically generated. The remainder of the FA styles are in a static
    * stylesheet in /vendor
    */
    function addFontAwesomeStyleSheet() {
        $('head').append(
            $('<style>')
            .attr('type', 'text/css')
            .text(
                `@font-face {
                    font-family: FontAwesome;
                    src: url('${chrome.extension.getURL('vendor/fontawesome-webfont.woff')}');
                }`
            )
        );
    }

    function getUser() {
        try {
            return  JSON.parse(
                $( '#IntercomSettingsScriptTag' )
                .text()
                .split(';')[0]
                .replace('window.intercomSettings =', '')
                .replace(';', '')
                .trim()
            );
        } catch (e) {
            return;
        }
    }

    function collectData() {
        let pathname = window.location.pathname.split(/\//),
            data = {
                user: null,
                path: null,
                assignment_submission: null,
                assignment: null,
                content: null,
                group: null,
                students: []
            },
            group = $('.card-block dt:contains("Group")').next().find('a');

        data.user = getUser();

        // Admin view of path
        if (/\/admin\/paths\/[0-9]+/.test(window.location.pathname)) {
            data.path = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(1)').text(),
                onPage: true
            };
        }

        if (/\/admin\/assignment_submissions\/[0-9]+/.test(window.location.pathname)) {
            data.assignment_submission = {
                id: Number(pathname[3]),
                onPage: true
            };
        }

        if (/\/admin\/assignments\/[0-9]+/.test(window.location.pathname)) {
            data.assignment = {
                id: Number(pathname[3]),
                onPage: true
            };
        }

        // Admin view of content piece
        if (/\/admin\/(lessons|assignmnents)\/[0-9]+/.test(window.location.pathname)) {
            data.content = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(3)').text(),
                type: pathname[2],
                isAdmin: true
            };
        }

        // Student view of content piece
        if (/\/paths\/[0-9]+\/units\/[0-9]+\/[^\/]+\/[0-9]+/.test(window.location.pathname)) {
            data.path = {
                id: Number(pathname[2]),
                title: $('.m-pathheader-info-title').text(),
                onPage: false
            };
            data.content = {
                id: Number(pathname[6]),
                title: $('.m-lessonheader-title').text(),
                type: pathname[5],
                isAdmin: false
            };
        }

        let p;
        if (group.length) {
            data.group = {
                title: group.text(),
                id: Number(group.attr('href').match(/\/([0-9]+)/)[1])
            };

            p = new Promise(
              function(res) {
                $.get(group.attr('href')).then(function(html) {
                let students = $(html).find('#students tr td:first-child a');
                students.each(function() {
                    let studentElem = $(this).find('.profile-placeholder-medium, img').remove().end();
                    data.students.push({
                        id: Number(studentElem.attr('href').match(/\/([0-9]+)/)[1]),
                        name: studentElem.text()
                    });
                });
                res(data);
              }, function() {
                console.log( 'Group Missing or you do not have access.' );
                res(data);
              });
            });
        } else {
            p = Promise.resolve(data);
        }

        return p;
    }

    function addNavIcon(mod) {
        if (!navUI) { return; }

        navUI.find('ul').append(
            `<li data-module='${mod.name}' title='${mod.name}' aria-title='${mod.name}'><i class='fa ${mod.navIcon} fa-lg' aria-hidden='true'></i></li>`
        );
    }

    function toggleModuleUI(e) {
        e.preventDefault();
        var name = $(this).data('module');
        var mod = modulesLoaded.filter(function(m) { return m.name === name;});
        if (!mod.length) { return; }

        if (moduleDisplayed === mod[0].name) {
            console.log('hiding ', mod[0]);
            closeContent(e);
        } else {
            console.log('showing ', mod[0]);
            moduleDisplayed = mod[0].name;
            $('.tiyo-assistant-module').hide();
            $(`[data-module="${mod[0].name}"]`).show().trigger('showing');
            mainUI.slideDown(PANEL_ANIMATION_TIME);
        }
    }

    function closeContent(e) {
        e.preventDefault();
        $(`[data-module="${moduleDisplayed}"]`).show().trigger('hiding');
        moduleDisplayed = null;
        mainUI.slideUp(PANEL_ANIMATION_TIME);
    }

    function setupContentClose() {
        $('.tiyo-assistant-close').click(closeContent);
    }

    function loadModule(api) {
        if (!api) { return; }
        if (!api.name) { api.name = Date.getTime(); }

        console.info('loading module', api);

        modulesLoaded.push(api);

        addNavIcon(api);
        doRender(api);
    }

    function doRender(mod) {
        if (uiLoaded && typeof(mod.render) === 'function') {
            var elem = createModuleWrapper(mod);
            mod.render(tiyoData, elem);
        }
    }

    function createModuleWrapper(mod) {
        var elem = $(`<article data-module='${mod.name}'>`).addClass('tiyo-assistant-module');
        $(mainUI).find('.tiyo-assistant-content').append(elem);
        return elem;
    }

    function setupNotificationsUI() {
        $.get(chrome.extension.getURL(NOTIFICATIONS_TEMPLATE)).then(function(html) {
            notifyUI = $(html).appendTo('body');
            notifyUI.on('click', '.close', function() {
                $(this).parent().fadeOut(function() { $(this).remove(); });
            });
        });
    }

    function showMessage(msg, options = {}) {
        options.type = options.type || 'danger';
        options.duration = (Number(options.duration) || options.duration === 0) ? options.duration : 4;

        let dismissable = (options.canDismiss === false) ? '' : 'alert-dismissible';

        let msgNode = $(`<p class='alert alert-${options.type} ${dismissable}'>`).text(msg);

        if (dismissable.length) {
            msgNode.append(`<button class='close'>×</button>`);
        }

        notifyUI.append(msgNode);

        if (options.duration && options.duration > 0) {
            setTimeout(function() {
                msgNode.fadeOut(function() { $(this).remove(); });
            }, (options.duration * 1000));
        }
    }

    // Kick things off...
    main();
    // Then export our module API
    window.tiy = tiy;

})(window.tiy || {}, window.jQuery);
<|endoftext|>


<commit_before>// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
<% if (!options['external-chrome']) { -%>

process.env.CHROME_BIN = require('puppeteer').executablePath();
<% } -%>

module.exports = function(config) {
  config.set({
    basePath: '..',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-junit-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('@angular-devkit/build-angular/plugins/karma')
    ],
    client: {
      clearContext: false, // leave Jasmine Spec Runner output visible in browser
      captureConsole: Boolean(process.env.KARMA_ENABLE_CONSOLE)
    },
    junitReporter: {
      outputDir: './reports/junit/',
      outputFile: 'TESTS-xunit.xml',
      useBrowserName: false,
      suite: '' // Will become the package name attribute in xml testsuite element
    },
    coverageIstanbulReporter: {
      reports: ['html', 'lcovonly', 'text-summary'],
      dir: './reports/coverage',
      fixWebpackSourcePaths: true
    },
    angularCli: {
      environment: 'dev'
    },
    reporters: ['progress', 'junit'],
    port: 9876,
    colors: true,
    // Level of logging, can be: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['ChromeHeadless'],
    singleRun: false
  });
};
<commit_msg>Updated karma config<commit_after>// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
<% if (!options['external-chrome']) { -%>

process.env.CHROME_BIN = require('puppeteer').executablePath();
<% } -%>
const path = require('path');

module.exports = function(config) {
  config.set({
    basePath: '..',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-junit-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('@angular-devkit/build-angular/plugins/karma')
    ],
    client: {
      clearContext: false, // leave Jasmine Spec Runner output visible in browser
      captureConsole: Boolean(process.env.KARMA_ENABLE_CONSOLE)
    },
    junitReporter: {
      outputDir: path.join(__dirname, '../reports/junit/'),
      outputFile: 'TESTS-xunit.xml',
      useBrowserName: false,
      suite: '' // Will become the package name attribute in xml testsuite element
    },
    coverageIstanbulReporter: {
      reports: ['html', 'lcovonly', 'text-summary'],
      dir: path.join(__dirname, '../reports/coverage'),
      fixWebpackSourcePaths: true
    },
    angularCli: {
      environment: 'dev'
    },
    reporters: ['progress', 'junit'],
    port: 9876,
    colors: true,
    // Level of logging, can be: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['ChromeHeadless'],
    singleRun: false
  });
};
<|endoftext|>


<commit_before>// From rust:
/* global resourcesSuffix */

var currentTheme = document.getElementById("themeStyle");
var mainTheme = document.getElementById("mainThemeStyle");

var savedHref = [];

function hasClass(elem, className) {
    return elem && elem.classList && elem.classList.contains(className);
}

function addClass(elem, className) {
    if (!elem || !elem.classList) {
        return;
    }
    elem.classList.add(className);
}

function removeClass(elem, className) {
    if (!elem || !elem.classList) {
        return;
    }
    elem.classList.remove(className);
}

function isHidden(elem) {
    return elem.offsetParent === null;
}

function onEach(arr, func, reversed) {
    if (arr && arr.length > 0 && func) {
        var length = arr.length;
        if (reversed !== true) {
            for (var i = 0; i < length; ++i) {
                if (func(arr[i]) === true) {
                    return true;
                }
            }
        } else {
            for (var i = length - 1; i >= 0; --i) {
                if (func(arr[i]) === true) {
                    return true;
                }
            }
        }
    }
    return false;
}

function onEachLazy(lazyArray, func, reversed) {
    return onEach(
        Array.prototype.slice.call(lazyArray),
        func,
        reversed);
}

function usableLocalStorage() {
    // Check if the browser supports localStorage at all:
    if (typeof Storage === "undefined") {
        return false;
    }
    // Check if we can access it; this access will fail if the browser
    // preferences deny access to localStorage, e.g., to prevent storage of
    // "cookies" (or cookie-likes, as is the case here).
    try {
        return window.localStorage !== null && window.localStorage !== undefined;
    } catch(err) {
        // Storage is supported, but browser preferences deny access to it.
        return false;
    }
}

function updateLocalStorage(name, value) {
    if (usableLocalStorage()) {
        localStorage[name] = value;
    } else {
        // No Web Storage support so we do nothing
    }
}

function getCurrentValue(name) {
    if (usableLocalStorage() && localStorage[name] !== undefined) {
        return localStorage[name];
    }
    return null;
}

function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
    var fullBasicCss = "rustdoc" + resourcesSuffix + ".css";
    var fullNewTheme = newTheme + resourcesSuffix + ".css";
    var newHref = mainStyleElem.href.replace(fullBasicCss, fullNewTheme);

    if (styleElem.href === newHref) {
        return;
    }

    var found = false;
    if (savedHref.length === 0) {
        onEachLazy(document.getElementsByTagName("link"), function(el) {
            savedHref.push(el.href);
        });
    }
    onEach(savedHref, function(el) {
        if (el === newHref) {
            found = true;
            return true;
        }
    });
    if (found === true) {
        styleElem.href = newHref;
        // If this new value comes from a system setting or from the previously saved theme, no
        // need to save it.
        if (saveTheme === true) {
            updateLocalStorage("rustdoc-theme", newTheme);
        }
    }
}

function getSystemValue() {
    var property = getComputedStyle(document.documentElement).getPropertyValue('content');
    return property.replace(/\"\'/g, "");
}

switchTheme(currentTheme, mainTheme,
            getCurrentValue("rustdoc-theme") || getSystemValue() || "light",
            false);
<commit_msg>Fix regex replacement in theme detection<commit_after>// From rust:
/* global resourcesSuffix */

var currentTheme = document.getElementById("themeStyle");
var mainTheme = document.getElementById("mainThemeStyle");

var savedHref = [];

function hasClass(elem, className) {
    return elem && elem.classList && elem.classList.contains(className);
}

function addClass(elem, className) {
    if (!elem || !elem.classList) {
        return;
    }
    elem.classList.add(className);
}

function removeClass(elem, className) {
    if (!elem || !elem.classList) {
        return;
    }
    elem.classList.remove(className);
}

function isHidden(elem) {
    return elem.offsetParent === null;
}

function onEach(arr, func, reversed) {
    if (arr && arr.length > 0 && func) {
        var length = arr.length;
        if (reversed !== true) {
            for (var i = 0; i < length; ++i) {
                if (func(arr[i]) === true) {
                    return true;
                }
            }
        } else {
            for (var i = length - 1; i >= 0; --i) {
                if (func(arr[i]) === true) {
                    return true;
                }
            }
        }
    }
    return false;
}

function onEachLazy(lazyArray, func, reversed) {
    return onEach(
        Array.prototype.slice.call(lazyArray),
        func,
        reversed);
}

function usableLocalStorage() {
    // Check if the browser supports localStorage at all:
    if (typeof Storage === "undefined") {
        return false;
    }
    // Check if we can access it; this access will fail if the browser
    // preferences deny access to localStorage, e.g., to prevent storage of
    // "cookies" (or cookie-likes, as is the case here).
    try {
        return window.localStorage !== null && window.localStorage !== undefined;
    } catch(err) {
        // Storage is supported, but browser preferences deny access to it.
        return false;
    }
}

function updateLocalStorage(name, value) {
    if (usableLocalStorage()) {
        localStorage[name] = value;
    } else {
        // No Web Storage support so we do nothing
    }
}

function getCurrentValue(name) {
    if (usableLocalStorage() && localStorage[name] !== undefined) {
        return localStorage[name];
    }
    return null;
}

function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
    var fullBasicCss = "rustdoc" + resourcesSuffix + ".css";
    var fullNewTheme = newTheme + resourcesSuffix + ".css";
    var newHref = mainStyleElem.href.replace(fullBasicCss, fullNewTheme);

    if (styleElem.href === newHref) {
        return;
    }

    var found = false;
    if (savedHref.length === 0) {
        onEachLazy(document.getElementsByTagName("link"), function(el) {
            savedHref.push(el.href);
        });
    }
    onEach(savedHref, function(el) {
        if (el === newHref) {
            found = true;
            return true;
        }
    });
    if (found === true) {
        styleElem.href = newHref;
        // If this new value comes from a system setting or from the previously saved theme, no
        // need to save it.
        if (saveTheme === true) {
            updateLocalStorage("rustdoc-theme", newTheme);
        }
    }
}

function getSystemValue() {
    var property = getComputedStyle(document.documentElement).getPropertyValue('content');
    return property.replace(/[\"\']/g, "");
}

switchTheme(currentTheme, mainTheme,
            getCurrentValue("rustdoc-theme") || getSystemValue() || "light",
            false);
<|endoftext|>


<commit_before>// $Revision$

Ensembl.Panel.Genoverse = Ensembl.Panel.ImageMap.extend({
  init: function () {
    this.prevHighlight = {};

    this.base();

    if (this.genoverse.failed) {
      return;
    }

    this.elLk.img         = this.genoverse.container;
    this.elLk.boundaries  = this.genoverse.labelContainer;
    this.elLk.controls    = $('.genoverse_controls', this.elLk.container).each(function () { $(this).prev().append(this); });
    this.elLk.autoHeight  = $('.auto_height',        this.elLk.controls);
    this.elLk.resetHeight = $('.reset_height',       this.elLk.controls);
    this.elLk.dragging    = $('.dragging',           this.elLk.controls);
    this.elLk.wheelZoom   = $('.wheel_zoom',         this.elLk.controls);

    this.initControls();

    Ensembl.EventManager.register('changeTrackOrder', this, this.sortUpdate);
    Ensembl.EventManager.register('updatePanel',      this, this.update);
    Ensembl.EventManager.register('imageResize',      this, this.resize);
    Ensembl.EventManager.register('changeWidth',      this, this.resize);
    Ensembl.EventManager.register('resetGenoverse',   this, function () { this.genoverse.resetConfig(); });
  },

  makeImageMap: function () {
    var panel  = this;
    var tracks = $.extend(true, [], Ensembl.genoverseConfig.tracks);
    var parent = this.el.parents('.image_panel')[0];

    $('.image_panel').each(function (i) {
      if (this === parent) {
        panel.imageNumber = i + 1;
        Ensembl.images[panel.imageNumber] = { 0: [ panel.imageNumber, 0, Ensembl.genoverseConfig.start, Ensembl.genoverseConfig.end ] };
      }
    });

    delete Ensembl.genoverseConfig.tracks;

    this.genoverse = new Ensembl.Genoverse($.extend({
      id        : this.id + 'Browser',
      panel     : this,
      container : $('.canvas_container', this.el),
      width     : Ensembl.width,
      tracks    : tracks
    }, Ensembl.genoverseConfig));

    if (this.genoverse.failed) {
      return;
    }

    this.genoverse.labelContainer.sortable('option', 'handle', '.handle');

    if (this.genoverse.wheelAction === false) {
      this.genoverse.selectorControls.prepend('<button class="jumpHere">Jump here</button>');
    }

    Ensembl.EventManager.trigger('highlightAllImages');

    parent = null;
  },

  initControls: function () {
    var panel     = this;
    var genoverse = this.genoverse;
    var buttons   = $('button', this.elLk.controls).on('mousedown', function () { genoverse.hideMessages(); });

    buttons.filter('button.scroll').on({
      mousedown : function () { genoverse.startDragScroll(); },
      mouseup   : function () { genoverse.stopDragScroll();  }
    });

    buttons.filter('button.scroll_right').mousehold(50, function () { genoverse.move(-100); });
    buttons.filter('button.scroll_left' ).mousehold(50, function () { genoverse.move(100);  });

    buttons.filter('button.zoom_in' ).on('click', function () { genoverse.zoomIn();  });
    buttons.filter('button.zoom_out').on('click', function () { genoverse.zoomOut(); });

    this.elLk.dragging.on('click', function () {
      genoverse.setDragAction(panel.elLk.dragging.toggleClass('on off').hasClass('on') ? 'scroll' : 'select');
      panel.changeControlTitle('dragging');
    });

    this.elLk.wheelZoom.on('click', function () {
      genoverse.setWheelAction(panel.elLk.wheelZoom.toggleClass('on off').hasClass('on') ? 'zoom' : 'off');
      panel.changeControlTitle('wheelZoom');
    });

    this.elLk.resetHeight.on('click', function () {
      if (!panel.resetTrackHeights) {
        panel.resetTrackHeights = $.ajax({
          url      : this.value,
          context  : panel.genoverse,
          success  : panel.genoverse.resetTrackHeights,
          complete : function () { panel.resetTrackHeights = false; }
        });
      }

      panel.elLk.autoHeight.removeClass('off');
      panel.changeControlTitle('autoHeight');
    });

    this.elLk.autoHeight.on('click', function () {
      if (!panel.toggleAutoHeight) {
        panel.toggleAutoHeight = $.ajax({
          url      : this.value,
          data     : { auto_height: panel.genoverse.autoHeight ? 0 : 1 },
          dataType : 'json',
          context  : panel.genoverse,
          success  : panel.genoverse.toggleAutoHeight,
          complete : function () { panel.toggleAutoHeight = false; }
        });

        panel.elLk.autoHeight[panel.genoverse.autoHeight ? 'removeClass' : 'addClass']('off');
        panel.changeControlTitle('autoHeight');
      }
    });

    this.elLk.imageResize = $('a.image_resize', this.elLk.resizeMenu).off().on('click', function () {
      if (!$(this).has('.current').length) {
        panel.resize(parseInt($(this).text(), 10) || Ensembl.imageWidth());
      }

      return false;
    }).not(':first').children();

    buttons = null;
  },

  changeControlTitle: function (el) {
    var title = {
      dragging   : [ 'Scroll to a new region',           'Select a portion of this region' ],
      wheelZoom  : [ 'Zoom in or out',                   'Scroll the browser window'       ],
      autoHeight : [ 'Set tracks to auto-adjust height', 'Set tracks to fixed height'      ]
    };

    this.elLk[el].attr('title', title[el][this.elLk[el].hasClass('off') ? 1 : 0]);
  },

  hashChange: function () {
    this.params.updateURL = Ensembl.urlFromHash(this.params.updateURL);

    if (this.genoverse.updatingURL) {
      return this.genoverse.updatingURL = false;
    }

    var coords = this.genoverse.getURLCoords();

    if (coords.chr !== this.genoverse.chr) {
      this.hashChangeReload = true;
      return this.base.apply(this, arguments); // TODO: do a complete reset without having to go get HTML again (currently, reset doesn't care about chr change)
    }

    this.genoverse.popState();
    this.genoverse.updatingURL = false;
  },

  highlightImage: function (imageNumber, speciesNumber, start, end) {
    // Make sure each image is highlighted based only on the next image on the page
    if (!this.genoverse || imageNumber - this.imageNumber !== 1) {
      return;
    }

    var left  = Math.round((start * this.genoverse.scale) - this.genoverse.scaledStart);
    var width = Math.round((end - start) * this.genoverse.scale);

    if (left === 0) {
      left++;
    }

    if (width === this.genoverse.width) {
      width--;
    }

    if (this.prevHighlight.start !== start || this.prevHighlight.end !== end) {
      this.genoverse.selector.hide();
      this.prevHighlight = { start: start, end: end };
    }

    this.genoverse.highlightRegion.css({ left: left, width: width, display: 'block' });
  },

  sortUpdate: function (label, order) {
    var labels = this.genoverse.labelContainer.children(':not(.unsortable)');

    label = labels.filter('.' + label).detach();

    if (!label.length) {
      return;
    }

    var track = label.data('track');
    var i     = labels.length;

    while (i--) {
      if ($(labels[i]).data('track').order < order && labels[i] !== label[0]) {
        label.insertAfter(labels[i]);
        break;
      }
    }

    if (i === -1) {
      label.insertBefore(labels[0]);
    }

    track.order = order;

    this.genoverse.sortTracks();
    this.removeShare();

    labels = label = null;

    return order;
  },

  makeHoverLabels: function () {
    var panel = this;

    if (this.genoverse.failed) {
      return;
    }

    this.base();

    this.elLk.drag.off();

    $.each(this.genoverse.tracks, function () {
      var track = this;

      if (this.label.find('.name').length) {
        this.hoverLabel = panel.elLk.hoverLabels.filter('.' + Ensembl.species + '_' + this.id);

        if (this.heightToggler) {
          this.hoverLabel.find('img.height').on('click', function () {
            track.heightToggler.trigger('click');
            track.updateHeightToggler();
          });

          if (this.autoHeight) {
            this.updateHeightToggler();
          }
        } else {
          this.hoverLabel.find('img.height').hide();
        }

        this.label.find('.name').on({
          mouseover: function () {
            var offset   = panel.genoverse.container.offset();
            var position = $(this.parentNode).position();

            position.left += offset.left + $(this).position().left;
            position.top  += offset.top  + panel.genoverse.labelContainer.position().top;

            if (!track.hoverLabel.hasClass('active')) {
              panel.elLk.hoverLabels.filter('.active').removeClass('active');
              track.hoverLabel.addClass('active');
            }

            clearTimeout(panel.hoverTimeout);

            panel.hoverTimeout = setTimeout(function () {
              panel.elLk.hoverLabels.filter(':visible').hide().end().filter('.active').css({
                left    : position.left,
                top     : position.top,
                display : 'block'
              });
            }, 100);
          },
          mouseleave: function (e) {
            if (e.relatedTarget) {
              var active = panel.elLk.hoverLabels.filter('.active');

              if (!active.has(e.relatedTarget).length) {
                active.removeClass('active').hide();
              }

              active = null;
            }
          }
        });
      }
    });

    $('a.config', this.elLk.hoverLabels).off().on('click', function () {
      var config = this.rel;
      var update = this.href.split(';').reverse()[0].split('='); // update = [ trackName, renderer ]
      var fav    = '';

      if ($(this).hasClass('favourite')) {
        fav = $(this).hasClass('selected') ? 'off' : 'on';
        Ensembl.EventManager.trigger('changeFavourite', update[0], fav === 'on');
      } else {
        $(this).parents('.hover_label').width(function (i, value) {
          return value > 100 ? value : 100;
        }).find('.spinner').show().siblings('div').hide();
      }

      $.ajax({
        url      : this.href + fav,
        dataType : 'json',
        context  : this,
        success  : function (json) {
          if (json.updated) {
            Ensembl.EventManager.trigger('hideHoverLabels'); // Hide labels and z menus on other ImageMap panels
            Ensembl.EventManager.triggerSpecific('changeConfiguration', 'modal_config_' + config, update[0], update[1]);

            panel.updateTrackRenderer(update[0], update[1]);
          }
        }
      });

      return false;
    });
  },

  updateTrackRenderer: function (trackName, renderer) {
    var track      = this.genoverse.tracksById[trackName];
    var otherTrack = track.reverseTrack || track.forwardTrack;

    if (renderer === 'off') {
      this.genoverse.removeTrack(track); // must call removeTrack rather than track.remove() to get the functionality of removing background colours
    } else {
      track.setRenderer(renderer, true);

      if (otherTrack) {
        otherTrack.setRenderer(renderer, true);
      }
    }

    this.removeShare();
  },

  update: function () {
    var panel     = this;
    var genoverse = this.genoverse;

    $.ajax({
      url      : '/' + Ensembl.species + '/Genoverse/update',
      data     : { existing: $.map(genoverse.tracksById, function (track, id) { return id + '=' + (track.renderer || 1); }).join(','), config: this.id },
      dataType : 'json',
      context  : this,
      success  : function (json) {
        var flanking = typeof json.viewConfig.flanking === 'undefined' ? false : parseInt(json.viewConfig.flanking, 10);
        var reorder  = false;

        if (json.remove.length) {
          genoverse.removeTracks($.map(json.remove, function (id) { return genoverse.tracksById[id]; }));
        }

        if (json.add.length) {
          genoverse.addTracks(json.add);
          this.elLk.hoverLabels = this.elLk.hoverLabels.add($(json.labels.trim()).appendTo('body'));
          this.makeHoverLabels();
        }

        if (json.change.length) {
          $.each(json.change, function () { panel.updateTrackRenderer(this[0], this[1]); });
        }

        $.each(json.order, function () {
          var track        = genoverse.tracksById[this[0]];
          var order        = this[1];
          var orderReverse = this[2];

          if (track && track.unsortable !== true) {
            if (track.strand === -1 && orderReverse) {
              track.order = orderReverse;
              track.label.data('order', orderReverse);

              track = track.forwardTrack;
            }

            if (track.order !== order) {
              track.order = order;
              track.label.data('order', order);

              reorder = true;
            }
          }
        });

        if (reorder) {
          genoverse.sortTracks();
        }

        if (typeof flanking === 'number' && this.genoverse.flanking !== flanking) {
          this.genoverse.flanking = flanking;
          this.genoverse.setRange(this.start, this.end, true);
        }

        this.el[json.viewConfig.show_panel === 'no' ? 'hide' : 'show']();
        this.removeShare();
      }
    });
  },

  resize: function (width) {
    width = width || Ensembl.width;

    this.elLk.exportMenu.add(this.elLk.resizeMenu).hide();
    this.elLk.imageResize.html(function (i) { var w = (i - 3) * 100 + width; $(this.parentNode.parentNode)[w < 500 ? 'hide' : 'show'](); return w + ' px'; });
    this.elLk.controls[width < 800 ? 'addClass' : 'removeClass']('narrow');
    this.elLk.container.css({ width: width, height: '' }).resizable('option', 'maxWidth', $(window).width() - this.el.offset().left);
    this.genoverse.setWidth(width);
  }
});
<commit_msg>trigger ajaxLoaded on getContent success - fixes a bug where removing the overview panel on region in detail causes interactions with the bottom panel to stop working<commit_after>// $Revision$

Ensembl.Panel.Genoverse = Ensembl.Panel.ImageMap.extend({
  init: function () {
    this.prevHighlight = {};

    this.base();

    if (this.genoverse.failed) {
      return;
    }

    this.elLk.img         = this.genoverse.container;
    this.elLk.boundaries  = this.genoverse.labelContainer;
    this.elLk.controls    = $('.genoverse_controls', this.elLk.container).each(function () { $(this).prev().append(this); });
    this.elLk.autoHeight  = $('.auto_height',        this.elLk.controls);
    this.elLk.resetHeight = $('.reset_height',       this.elLk.controls);
    this.elLk.dragging    = $('.dragging',           this.elLk.controls);
    this.elLk.wheelZoom   = $('.wheel_zoom',         this.elLk.controls);

    this.initControls();

    Ensembl.EventManager.register('changeTrackOrder', this, this.sortUpdate);
    Ensembl.EventManager.register('updatePanel',      this, this.update);
    Ensembl.EventManager.register('imageResize',      this, this.resize);
    Ensembl.EventManager.register('changeWidth',      this, this.resize);
    Ensembl.EventManager.register('resetGenoverse',   this, function () { this.genoverse.resetConfig(); });
  },

  makeImageMap: function () {
    var panel  = this;
    var tracks = $.extend(true, [], Ensembl.genoverseConfig.tracks);
    var parent = this.el.parents('.image_panel')[0];

    $('.image_panel').each(function (i) {
      if (this === parent) {
        panel.imageNumber = i + 1;
        Ensembl.images[panel.imageNumber] = { 0: [ panel.imageNumber, 0, Ensembl.genoverseConfig.start, Ensembl.genoverseConfig.end ] };
      }
    });

    delete Ensembl.genoverseConfig.tracks;

    this.genoverse = new Ensembl.Genoverse($.extend({
      id        : this.id + 'Browser',
      panel     : this,
      container : $('.canvas_container', this.el),
      width     : Ensembl.width,
      tracks    : tracks
    }, Ensembl.genoverseConfig));

    if (this.genoverse.failed) {
      return;
    }

    this.genoverse.labelContainer.sortable('option', 'handle', '.handle');

    if (this.genoverse.wheelAction === false) {
      this.genoverse.selectorControls.prepend('<button class="jumpHere">Jump here</button>');
    }

    Ensembl.EventManager.trigger('highlightAllImages');

    parent = null;
  },

  initControls: function () {
    var panel     = this;
    var genoverse = this.genoverse;
    var buttons   = $('button', this.elLk.controls).on('mousedown', function () { genoverse.hideMessages(); });

    buttons.filter('button.scroll').on({
      mousedown : function () { genoverse.startDragScroll(); },
      mouseup   : function () { genoverse.stopDragScroll();  }
    });

    buttons.filter('button.scroll_right').mousehold(50, function () { genoverse.move(-100); });
    buttons.filter('button.scroll_left' ).mousehold(50, function () { genoverse.move(100);  });

    buttons.filter('button.zoom_in' ).on('click', function () { genoverse.zoomIn();  });
    buttons.filter('button.zoom_out').on('click', function () { genoverse.zoomOut(); });

    this.elLk.dragging.on('click', function () {
      genoverse.setDragAction(panel.elLk.dragging.toggleClass('on off').hasClass('on') ? 'scroll' : 'select');
      panel.changeControlTitle('dragging');
    });

    this.elLk.wheelZoom.on('click', function () {
      genoverse.setWheelAction(panel.elLk.wheelZoom.toggleClass('on off').hasClass('on') ? 'zoom' : 'off');
      panel.changeControlTitle('wheelZoom');
    });

    this.elLk.resetHeight.on('click', function () {
      if (!panel.resetTrackHeights) {
        panel.resetTrackHeights = $.ajax({
          url      : this.value,
          context  : panel.genoverse,
          success  : panel.genoverse.resetTrackHeights,
          complete : function () { panel.resetTrackHeights = false; }
        });
      }

      panel.elLk.autoHeight.removeClass('off');
      panel.changeControlTitle('autoHeight');
    });

    this.elLk.autoHeight.on('click', function () {
      if (!panel.toggleAutoHeight) {
        panel.toggleAutoHeight = $.ajax({
          url      : this.value,
          data     : { auto_height: panel.genoverse.autoHeight ? 0 : 1 },
          dataType : 'json',
          context  : panel.genoverse,
          success  : panel.genoverse.toggleAutoHeight,
          complete : function () { panel.toggleAutoHeight = false; }
        });

        panel.elLk.autoHeight[panel.genoverse.autoHeight ? 'removeClass' : 'addClass']('off');
        panel.changeControlTitle('autoHeight');
      }
    });

    this.elLk.imageResize = $('a.image_resize', this.elLk.resizeMenu).off().on('click', function () {
      if (!$(this).has('.current').length) {
        panel.resize(parseInt($(this).text(), 10) || Ensembl.imageWidth());
      }

      return false;
    }).not(':first').children();

    buttons = null;
  },

  changeControlTitle: function (el) {
    var title = {
      dragging   : [ 'Scroll to a new region',           'Select a portion of this region' ],
      wheelZoom  : [ 'Zoom in or out',                   'Scroll the browser window'       ],
      autoHeight : [ 'Set tracks to auto-adjust height', 'Set tracks to fixed height'      ]
    };

    this.elLk[el].attr('title', title[el][this.elLk[el].hasClass('off') ? 1 : 0]);
  },

  hashChange: function () {
    this.params.updateURL = Ensembl.urlFromHash(this.params.updateURL);

    if (this.genoverse.updatingURL) {
      return this.genoverse.updatingURL = false;
    }

    var coords = this.genoverse.getURLCoords();

    if (coords.chr !== this.genoverse.chr) {
      this.hashChangeReload = true;
      return this.base.apply(this, arguments); // TODO: do a complete reset without having to go get HTML again (currently, reset doesn't care about chr change)
    }

    this.genoverse.popState();
    this.genoverse.updatingURL = false;
  },

  highlightImage: function (imageNumber, speciesNumber, start, end) {
    // Make sure each image is highlighted based only on the next image on the page
    if (!this.genoverse || imageNumber - this.imageNumber !== 1) {
      return;
    }

    var left  = Math.round((start * this.genoverse.scale) - this.genoverse.scaledStart);
    var width = Math.round((end - start) * this.genoverse.scale);

    if (left === 0) {
      left++;
    }

    if (width === this.genoverse.width) {
      width--;
    }

    if (this.prevHighlight.start !== start || this.prevHighlight.end !== end) {
      this.genoverse.selector.hide();
      this.prevHighlight = { start: start, end: end };
    }

    this.genoverse.highlightRegion.css({ left: left, width: width, display: 'block' });
  },

  sortUpdate: function (label, order) {
    var labels = this.genoverse.labelContainer.children(':not(.unsortable)');

    label = labels.filter('.' + label).detach();

    if (!label.length) {
      return;
    }

    var track = label.data('track');
    var i     = labels.length;

    while (i--) {
      if ($(labels[i]).data('track').order < order && labels[i] !== label[0]) {
        label.insertAfter(labels[i]);
        break;
      }
    }

    if (i === -1) {
      label.insertBefore(labels[0]);
    }

    track.order = order;

    this.genoverse.sortTracks();
    this.removeShare();

    labels = label = null;

    return order;
  },

  makeHoverLabels: function () {
    var panel = this;

    if (this.genoverse.failed) {
      return;
    }

    this.base();

    this.elLk.drag.off();

    $.each(this.genoverse.tracks, function () {
      var track = this;

      if (this.label.find('.name').length) {
        this.hoverLabel = panel.elLk.hoverLabels.filter('.' + Ensembl.species + '_' + this.id);

        if (this.heightToggler) {
          this.hoverLabel.find('img.height').on('click', function () {
            track.heightToggler.trigger('click');
            track.updateHeightToggler();
          });

          if (this.autoHeight) {
            this.updateHeightToggler();
          }
        } else {
          this.hoverLabel.find('img.height').hide();
        }

        this.label.find('.name').on({
          mouseover: function () {
            var offset   = panel.genoverse.container.offset();
            var position = $(this.parentNode).position();

            position.left += offset.left + $(this).position().left;
            position.top  += offset.top  + panel.genoverse.labelContainer.position().top;

            if (!track.hoverLabel.hasClass('active')) {
              panel.elLk.hoverLabels.filter('.active').removeClass('active');
              track.hoverLabel.addClass('active');
            }

            clearTimeout(panel.hoverTimeout);

            panel.hoverTimeout = setTimeout(function () {
              panel.elLk.hoverLabels.filter(':visible').hide().end().filter('.active').css({
                left    : position.left,
                top     : position.top,
                display : 'block'
              });
            }, 100);
          },
          mouseleave: function (e) {
            if (e.relatedTarget) {
              var active = panel.elLk.hoverLabels.filter('.active');

              if (!active.has(e.relatedTarget).length) {
                active.removeClass('active').hide();
              }

              active = null;
            }
          }
        });
      }
    });

    $('a.config', this.elLk.hoverLabels).off().on('click', function () {
      var config = this.rel;
      var update = this.href.split(';').reverse()[0].split('='); // update = [ trackName, renderer ]
      var fav    = '';

      if ($(this).hasClass('favourite')) {
        fav = $(this).hasClass('selected') ? 'off' : 'on';
        Ensembl.EventManager.trigger('changeFavourite', update[0], fav === 'on');
      } else {
        $(this).parents('.hover_label').width(function (i, value) {
          return value > 100 ? value : 100;
        }).find('.spinner').show().siblings('div').hide();
      }

      $.ajax({
        url      : this.href + fav,
        dataType : 'json',
        context  : this,
        success  : function (json) {
          if (json.updated) {
            Ensembl.EventManager.trigger('hideHoverLabels'); // Hide labels and z menus on other ImageMap panels
            Ensembl.EventManager.triggerSpecific('changeConfiguration', 'modal_config_' + config, update[0], update[1]);

            panel.updateTrackRenderer(update[0], update[1]);
          }
        }
      });

      return false;
    });
  },

  updateTrackRenderer: function (trackName, renderer) {
    var track      = this.genoverse.tracksById[trackName];
    var otherTrack = track.reverseTrack || track.forwardTrack;

    if (renderer === 'off') {
      this.genoverse.removeTrack(track); // must call removeTrack rather than track.remove() to get the functionality of removing background colours
    } else {
      track.setRenderer(renderer, true);

      if (otherTrack) {
        otherTrack.setRenderer(renderer, true);
      }
    }

    this.removeShare();
  },

  update: function () {
    var panel     = this;
    var genoverse = this.genoverse;

    $.ajax({
      url      : '/' + Ensembl.species + '/Genoverse/update',
      data     : { existing: $.map(genoverse.tracksById, function (track, id) { return id + '=' + (track.renderer || 1); }).join(','), config: this.id },
      dataType : 'json',
      context  : this,
      success  : function (json) {
        var flanking = typeof json.viewConfig.flanking === 'undefined' ? false : parseInt(json.viewConfig.flanking, 10);
        var reorder  = false;

        if (json.remove.length) {
          genoverse.removeTracks($.map(json.remove, function (id) { return genoverse.tracksById[id]; }));
        }

        if (json.add.length) {
          genoverse.addTracks(json.add);
          this.elLk.hoverLabels = this.elLk.hoverLabels.add($(json.labels.trim()).appendTo('body'));
          this.makeHoverLabels();
        }

        if (json.change.length) {
          $.each(json.change, function () { panel.updateTrackRenderer(this[0], this[1]); });
        }

        $.each(json.order, function () {
          var track        = genoverse.tracksById[this[0]];
          var order        = this[1];
          var orderReverse = this[2];

          if (track && track.unsortable !== true) {
            if (track.strand === -1 && orderReverse) {
              track.order = orderReverse;
              track.label.data('order', orderReverse);

              track = track.forwardTrack;
            }

            if (track.order !== order) {
              track.order = order;
              track.label.data('order', order);

              reorder = true;
            }
          }
        });

        if (reorder) {
          genoverse.sortTracks();
        }

        if (typeof flanking === 'number' && this.genoverse.flanking !== flanking) {
          this.genoverse.flanking = flanking;
          this.genoverse.setRange(this.start, this.end, true);
        }

        this.el[json.viewConfig.show_panel === 'no' ? 'hide' : 'show']();
        this.removeShare();
        Ensembl.EventManager.trigger('ajaxLoaded');
      }
    });
  },

  resize: function (width) {
    width = width || Ensembl.width;

    this.elLk.exportMenu.add(this.elLk.resizeMenu).hide();
    this.elLk.imageResize.html(function (i) { var w = (i - 3) * 100 + width; $(this.parentNode.parentNode)[w < 500 ? 'hide' : 'show'](); return w + ' px'; });
    this.elLk.controls[width < 800 ? 'addClass' : 'removeClass']('narrow');
    this.elLk.container.css({ width: width, height: '' }).resizable('option', 'maxWidth', $(window).width() - this.el.offset().left);
    this.genoverse.setWidth(width);
  }
});
<|endoftext|>


<commit_before>'use strict';

const { cloneDeep } = require('lodash');

const { removeKeys } = require('./exclude');
const { renameKeys } = require('./rename');
const { reduceInput } = require('./input');
const { reduceAllModels } = require('./models');

// Builds `requestInfo` object, which contains request-related log information:
//   - requestId {string}
//   - timestamp {string}
//   - requestTime {number} - time it took to handle the request, in millisecs.
//     Only defined if the request was successful.
//   - ip {string}
//   - protocol {string} - e.g. HTTP
//   - protocolFullName {string} - e.g. HTTP/1.1
//   - url {string} - full URL
//   - origin {string} - protocol + host + port
//   - path {string} - only the URL path, with no query string nor hash
//   - route {string} - internal route picked according to the URL,
//     among `GraphQL`, `GraphiQL` and `GraphQLPrint`
//   - method {string} - protocol-specific method, e.g. GET
//   - goal {string} - like method, but protocol-agnostic, e.g. `find`
//   - protocolStatus {string} - protocol-specific status, e.g. HTTP status code
//   - status {string} - protocol-agnostic status, among 'INTERNALS', 'SUCCESS',
//     'CLIENT_ERROR' and 'SERVER_ERROR'
//   - pathVars {object} - URL variables, as a hash table
//   - params {object} - Parameters, as a hash table.
//   - settings {object} - Settings, as a hash table.
//   - queryVars {object} - Query variables, as a hash table
//   - headers {object} - protocol headers (e.g. HTTP headers), as a hash table
//   - payload {any} - request payload
//   - operation {string} - operation, among `GraphQL`, `GraphiQL` and
//     `GraphQLPrint`
//   - actions {object} - represented all actions fired
//      - ACTION_PATH {key} - action full path, e.g. 'findModel.findSubmodel'
//         - model {string} - model name
//         - args {object} - action arguments, e.g. filter or sort argument
//         - responses {object[]}
//            - content {object|object[]} - action response (model or
//              collection)
//   - response {object}
//      - content {string} - full response raw content
//      - type {string} - among 'model', 'collection', 'error', 'object',
//        'html', 'text'
//   - phase {string} - 'request', 'startup', 'shutdown' or 'process'
//   - error {string} - error reason
// Each of those fields is optional, i.e. might not be present.
// Remove some properties of log which could be of big size, specifically:
//   - queryVars, headers, params, settings:
//      - apply server option loggerFilter.queryVars|headers|params|settings,
//        which is either a simple mapping function or a list of attribute
//        names.
//        It defaults to returning an empty object.
//   - payload, actions.ACTION_PATH.args.data,
//     actions.ACTION_PATH.responses.content, response.content:
//      - apply server option loggerFilter.payload|argData|actionResponses|
//        response, which is either a simple mapping function or a list of
//        attribute names. It is applied to each model if the value is an array.
//        It defaults to keeping only 'id'.
//      - set JSON size, e.g. `payloadSize`
//        'unknown' if cannot calculate. Not set if value is undefined.
//      - set array length, e.g. `payloadCount` if it is an array.
// Also rename `errorReason` to `error`.
const getRequestInfo = function (log, loggerFilter) {
  const requestInfo = cloneDeep(log);
  return processors.reduce(
    (info, processor) => processor(info, loggerFilter),
    requestInfo,
  );
};

const processors = [
  removeKeys,
  renameKeys,
  reduceInput,
  reduceAllModels,
];

module.exports = {
  getRequestInfo,
};
<commit_msg>Remove useless deep cloning<commit_after>'use strict';

const { removeKeys } = require('./exclude');
const { renameKeys } = require('./rename');
const { reduceInput } = require('./input');
const { reduceAllModels } = require('./models');

// Builds `requestInfo` object, which contains request-related log information:
//   - requestId {string}
//   - timestamp {string}
//   - requestTime {number} - time it took to handle the request, in millisecs.
//     Only defined if the request was successful.
//   - ip {string}
//   - protocol {string} - e.g. HTTP
//   - protocolFullName {string} - e.g. HTTP/1.1
//   - url {string} - full URL
//   - origin {string} - protocol + host + port
//   - path {string} - only the URL path, with no query string nor hash
//   - route {string} - internal route picked according to the URL,
//     among `GraphQL`, `GraphiQL` and `GraphQLPrint`
//   - method {string} - protocol-specific method, e.g. GET
//   - goal {string} - like method, but protocol-agnostic, e.g. `find`
//   - protocolStatus {string} - protocol-specific status, e.g. HTTP status code
//   - status {string} - protocol-agnostic status, among 'INTERNALS', 'SUCCESS',
//     'CLIENT_ERROR' and 'SERVER_ERROR'
//   - pathVars {object} - URL variables, as a hash table
//   - params {object} - Parameters, as a hash table.
//   - settings {object} - Settings, as a hash table.
//   - queryVars {object} - Query variables, as a hash table
//   - headers {object} - protocol headers (e.g. HTTP headers), as a hash table
//   - payload {any} - request payload
//   - operation {string} - operation, among `GraphQL`, `GraphiQL` and
//     `GraphQLPrint`
//   - actions {object} - represented all actions fired
//      - ACTION_PATH {key} - action full path, e.g. 'findModel.findSubmodel'
//         - model {string} - model name
//         - args {object} - action arguments, e.g. filter or sort argument
//         - responses {object[]}
//            - content {object|object[]} - action response (model or
//              collection)
//   - response {object}
//      - content {string} - full response raw content
//      - type {string} - among 'model', 'collection', 'error', 'object',
//        'html', 'text'
//   - phase {string} - 'request', 'startup', 'shutdown' or 'process'
//   - error {string} - error reason
// Each of those fields is optional, i.e. might not be present.
// Remove some properties of log which could be of big size, specifically:
//   - queryVars, headers, params, settings:
//      - apply server option loggerFilter.queryVars|headers|params|settings,
//        which is either a simple mapping function or a list of attribute
//        names.
//        It defaults to returning an empty object.
//   - payload, actions.ACTION_PATH.args.data,
//     actions.ACTION_PATH.responses.content, response.content:
//      - apply server option loggerFilter.payload|argData|actionResponses|
//        response, which is either a simple mapping function or a list of
//        attribute names. It is applied to each model if the value is an array.
//        It defaults to keeping only 'id'.
//      - set JSON size, e.g. `payloadSize`
//        'unknown' if cannot calculate. Not set if value is undefined.
//      - set array length, e.g. `payloadCount` if it is an array.
// Also rename `errorReason` to `error`.
const getRequestInfo = function (log, loggerFilter) {
  return processors.reduce(
    (requestInfo, processor) => processor(requestInfo, loggerFilter),
    log,
  );
};

const processors = [
  removeKeys,
  renameKeys,
  reduceInput,
  reduceAllModels,
];

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