<commit_before>'use strict'

const got = require('got')
const path = require('path')
const moment = require('moment')
const pad = require('lodash.padstart')
const _ = require('lodash')
const AWS = require('aws-sdk')
const local = require('kes/src/local')
const satlib = require('sat-api-lib')
var through2 = require('through2')

// s3 client
const s3 = new AWS.S3()

const collection = {
  "collection_name": "landsat-8",
  "collection_description": "Landat 8 imagery radiometrically calibrated and orthorectified using gound points and Digital Elevation Model (DEM) data to correct relief displacement.",
  "provider": "USGS",
  "license": "PDDL-1.0",
  "eo:gsd" : 30,
  "eo:platform": "landsat-8",
  "eo:instrument": "OLI_TIRS",
  "eo:off_nadir": 0,
  "eo:bands": {
    "B1": {
      "common_name": "coastal",
      "gsd": 30.0,
      "accuracy": null,
      "wavelength": 0.44,
      "fwhm": 0.02
    },
    "B2": {
      "common_name": "blue",
      "gsd": 30.0,
      "accuracy": null,
      "wavelength": 0.48,
      "fwhm": 0.06
    },
    "B3": {
      "common_name": "green",
      "gsd": 30.0,
      "accuracy": null,
      "wavelength": 0.56,
      "fwhm": 0.06
    },
    "B4": {
      "common_name": "red",
      "gsd": 30.0,
      "accuracy": null,
      "wavelength": 0.65,
      "fwhm": 0.04
    },
    "B5": {
      "common_name": "nir",
      "gsd": 30.0,
      "accuracy": null,
      "wavelength": 0.86,
      "fwhm": 0.03
    },
    "B6": {
      "common_name": "swir16",
      "gsd": 30.0,
      "accuracy": null,
      "wavelength": 1.6,
      "fwhm": 0.08
    },
    "B7": {
      "common_name": "swir22",
      "gsd": 30.0,
      "accuracy": null,
      "wavelength": 2.2,
      "fwhm": 0.2
    },
    "B8": {
      "common_name": "pan",
      "gsd": 15.0,
      "accuracy": null,
      "wavelength": 0.59,
      "fwhm": 0.18
    },
    "B9": {
      "common_name": "cirrus",
      "gsd": 30.0,
      "accuracy": null,
      "wavelength": 1.37,
      "fwhm": 0.02
    },
    "B10": {
      "common_name": "lwir11",
      "gsd": 100.0,
      "accuracy": null,
      "wavelength": 10.9,
      "fwhm": 0.8
    },
    "B11": {
      "common_name": "lwir12",
      "gsd": 100.0,
      "accuracy": null,
      "wavelength": 12.0,
      "fwhm": 1.0
    }
  }
}

//! Check to see if a URL exists
function fileExists(url) {
  var params = {
    Bucket: 'landsat-pds',
    Key: url.slice(36)
  }
  return new Promise(function(resolve, reject) {
    s3.headObject(params, function (err, metadata) {
      if (err && err.code === 'NotFound') {
        reject(url)
      } else {
        resolve(url)
      }
    })
  })
}

//! iterate over an array synchronously, invoke function on each element
function arrayIterate(values, fn) {
  return new Promise(function(resolve, reject) {
    // Are there any values to check?
    if (values.length === 0) {
      // All were rejected
      reject()
    }
    // Try the first value
    fn(values[0]).then(function(val) {
      // Resolved, we're all done
      resolve(val)
    }).catch(function() {
      // Rejected, remove the first item from the array and recursively
      // try the next one
      values.shift();
      arrayIterate(values, fn).then(resolve).catch(reject);
    })
  })
}

function awsLinks(data) {
  // generates links for the data on AWS
  const row = pad(data.row, 3, '0')
  const _path = pad(data.path, 3, '0')
  const sceneId = data.sceneID
  const productId = data.LANDSAT_PRODUCT_ID

  const files = ['ANG.txt','B1.TIF','B2.TIF','B3.TIF','B4.TIF','B5.TIF','B6.TIF',
                 'B7.TIF','B8.TIF','B9.TIF','B10.TIF','B11.TIF','BQA.TIF','MTL.txt']
  var _bands = Object.keys(collection["eo:bands"])

  const c1Base = `https://landsat-pds.s3.amazonaws.com/c1/L8/${path.join(_path, row, productId)}`
  //const c1Files = bands.map((b) => [{name: b.slice(0, -4), href: `${c1Base}/${productId}_${b}`}])
  var key, val
  const c1Files = _.fromPairs(files.map(function(b) {
    key = b.slice(0,-4)
    val = {href: `${c1Base}/${productId}_${b}`}
    if (_bands.includes(key)) {
      val["eo:bands"] = [key]
    }
    return [key, val]
  }))
  c1Files.thumbnail = {href: `${c1Base}/${productId}_thumb_large.jpg`}

  const c1 = {
    index: `${c1Base}/index.html`,
    files: c1Files
  }

  return new Promise(function(resolve, reject) {
    // AWS doesn't include all C1 scenes, we return the old urls for
    // any scenes that is before May 1 2017
    info = {};
    if (moment(data.acquisitionDate) > moment('2017-04-30')) {
      resolve(c1)
    } else {
      const _sceneId = sceneId.slice(0, -2);
      var sid;
      const rev = sceneId.slice(-2)
      var prefix = `http://landsat-pds.s3.amazonaws.com/L8/${path.join(_path, row, _sceneId)}`
      var links = _.range(rev, -1, -1).map(r => `${prefix}` + pad(r, 2, '0') + '/index.html')
      //var files = _.fromPairs(files.map(function(b) { return [b.slice(0,-4), {href: `${prefix}/${sid}_${b}`}] }))
      var key, val
      var files = _.fromPairs(files.map(function(b) {
        key = b.slice(0,-4)
        val = {href: `${c1Base}/${productId}_${b}`}
        if (_bands.includes(key)) {
          val["eo:bands"] = [key]
        }
        return [key, val]
      }))
      files.thumbnail = {href: `${prefix}/${sid}_thumb_large.jpg`}

      arrayIterate(links.reverse(), fileExists).then(val => {
        prefix = prefix + val.slice(-13, -11)
        sid = _sceneId + val.slice(-13, -11)
        const pre = {
          index: `${prefix}/index.html`,
          //files: bands.map((b) => [{name: b.slice(0, -4), href: `${prefix}/${sid}_${b}`}]),
          files: files
        }
        resolve(pre);
      }).catch(e => {
        reject(`${prefix} not available`);
      })
    }
  })
}

function transform(data, encoding, next) {

  // concert numeric fields to numbers
  const numberFields = [
    'cloudCoverFull',
    'path',
    'row',
    'upperLeftCornerLatitude',
    'upperLeftCornerLongitude',
    'upperRightCornerLatitude',
    'upperRightCornerLongitude',
    'lowerLeftCornerLatitude',
    'lowerLeftCornerLongitude',
    'lowerRightCornerLatitude',
    'lowerRightCornerLongitude',
    'sceneCenterLatitude',
    'sceneCenterLongitude',
    'cloudCover',
    'sunElevation',
    'sunAzimuth',
    'receivingStation',
    'imageQuality1',
    'ROLL_ANGLE',
    'GEOMETRIC_RMSE_MODEL',
    'GEOMETRIC_RMSE_MODEL_X',
    'GEOMETRIC_RMSE_MODEL_Y',
    'COLLECTION_NUMBER',
    'CLOUD_COVER_LAND'
  ]
  numberFields.forEach(f => {
    data[f] = parseFloat(data[f]);
  })

  const geometry = {
    type: 'Polygon',
    coordinates: [[
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude],
      [data.upperLeftCornerLongitude, data.upperLeftCornerLatitude],
      [data.lowerLeftCornerLongitude, data.lowerLeftCornerLatitude],
      [data.lowerRightCornerLongitude, data.lowerRightCornerLatitude],
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude]
    ]]
  }

  // check for crossing antimeridian
  const leftLong = Math.min(data.lowerLeftCornerLongitude, data.upperLeftCornerLongitude)
  const rightLong = Math.max(data.lowerRightCornerLongitude, data.upperRightCornerLongitude)
  if (leftLong < -1000000) { //> rightLong) {
    console.log(`warning: skipping ${data.sceneID} for crossing 180th Meridian (${JSON.stringify(geometry)})`)
    next()
  } else {
    awsLinks(data).then((info) => {
      const start = moment(data.sceneStartTime, "YYYY:DDD:HH:mm:ss.SSSSS")
      const end = moment(data.sceneStopTime, "YYYY:DDD:HH:mm:ss.SSSSS")
      const record = {
        id: data.LANDSAT_PRODUCT_ID,
        bbox: [
          data.lowerLeftCornerLongitude, data.lowerLeftCornerLatitude, data.upperRightCornerLongitude, data.upperRightCornerLatitude
        ],
        geometry: geometry,
        collection: 'landsat-8',
        datetime: start.toISOString(),
        //'datetime': (end - start)/2 + start
        // eo extension metadata
        'eo:cloud_cover': parseInt(data.cloudCoverFull),
        'eo:sun_azimuth': data.sunAzimuth,
        'eo:sun_elevation': data.sunElevation,
        links: [
          {rel: 'index', 'href': info.index},
          {rel: 'collection', 'href': '/collections?id=landsat-8'}
        ],
        assets: info.files
      }
      this.push(record)
      next()
    }).catch(e => {
      console.log(`error processing ${data.sceneID}: ${e}`)
      next()
    })
  }
}

function handler (event, context=null, cb=function(){}) {
  console.log(event)
  // create stream from transform function
  var _transform = through2({'objectMode': true, 'consume': true}, transform)
  const bucket = _.get(event, 'bucket')
  const key = _.get(event, 'key')
  const currentFileNum = _.get(event, 'currentFileNum', 0)
  const lastFileNum = _.get(event, 'lastFileNum', 0)
  const arn = _.get(event, 'arn', null)
  const retries = _.get(event, 'retries', 0)

  // add collection
  satlib.es.client().then((client) => {
    satlib.es.putMapping(client, 'collections').catch((err) => {})
    collection.id = collection.collection_name
    satlib.es.saveRecords(client, [collection], index='collections', (err, updated, errors) => {
      console.log('err', err)
      console.log('updated', updated)
      console.log('errors', errors)
    })
    satlib.ingest.update({bucket, key, transform:_transform, cb, currentFileNum, lastFileNum, arn, retries})
  })
}

local.localRun(() => {
  console.log('running locally')
  // test payload
  const a = {
    bucket: 'sat-api',
    key: 'testing/landsat',
    currentFileNum: 1,
    lastFileNum: 1
  }

  handler(a, null, (err, r) => {
    if (err) {
      console.log(`error: ${e}`)
    } else {
      console.log(`success: ${r}`)
    }
  })

})

module.exports.handler = handler
<commit_msg>update field names for wavelength<commit_after>'use strict'

const got = require('got')
const path = require('path')
const moment = require('moment')
const pad = require('lodash.padstart')
const _ = require('lodash')
const AWS = require('aws-sdk')
const local = require('kes/src/local')
const satlib = require('sat-api-lib')
var through2 = require('through2')

// s3 client
const s3 = new AWS.S3()

const collection = {
  "collection": "landsat-8",
  "description": "Landat 8 imagery radiometrically calibrated and orthorectified using gound points and Digital Elevation Model (DEM) data to correct relief displacement.",
  "provider": "USGS",
  "license": "PDDL-1.0",
  "eo:gsd" : 30,
  "eo:platform": "landsat-8",
  "eo:instrument": "OLI_TIRS",
  "eo:off_nadir": 0,
  "eo:bands": {
    "B1": {
      "common_name": "coastal",
      "gsd": 30.0,
      "accuracy": null,
      "center_wavelength": 0.44,
      "full_width_half_max": 0.02
    },
    "B2": {
      "common_name": "blue",
      "gsd": 30.0,
      "accuracy": null,
      "center_wavelength": 0.48,
      "full_width_half_max": 0.06
    },
    "B3": {
      "common_name": "green",
      "gsd": 30.0,
      "accuracy": null,
      "center_wavelength": 0.56,
      "full_width_half_max": 0.06
    },
    "B4": {
      "common_name": "red",
      "gsd": 30.0,
      "accuracy": null,
      "center_wavelength": 0.65,
      "full_width_half_max": 0.04
    },
    "B5": {
      "common_name": "nir",
      "gsd": 30.0,
      "accuracy": null,
      "center_wavelength": 0.86,
      "full_width_half_max": 0.03
    },
    "B6": {
      "common_name": "swir16",
      "gsd": 30.0,
      "accuracy": null,
      "center_wavelength": 1.6,
      "full_width_half_max": 0.08
    },
    "B7": {
      "common_name": "swir22",
      "gsd": 30.0,
      "accuracy": null,
      "center_wavelength": 2.2,
      "full_width_half_max": 0.2
    },
    "B8": {
      "common_name": "pan",
      "gsd": 15.0,
      "accuracy": null,
      "center_wavelength": 0.59,
      "full_width_half_max": 0.18
    },
    "B9": {
      "common_name": "cirrus",
      "gsd": 30.0,
      "accuracy": null,
      "center_wavelength": 1.37,
      "full_width_half_max": 0.02
    },
    "B10": {
      "common_name": "lwir11",
      "gsd": 100.0,
      "accuracy": null,
      "center_wavelength": 10.9,
      "full_width_half_max": 0.8
    },
    "B11": {
      "common_name": "lwir12",
      "gsd": 100.0,
      "accuracy": null,
      "center_wavelength": 12.0,
      "full_width_half_max": 1.0
    }
  }
}

//! Check to see if a URL exists
function fileExists(url) {
  var params = {
    Bucket: 'landsat-pds',
    Key: url.slice(36)
  }
  return new Promise(function(resolve, reject) {
    s3.headObject(params, function (err, metadata) {
      if (err && err.code === 'NotFound') {
        reject(url)
      } else {
        resolve(url)
      }
    })
  })
}

//! iterate over an array synchronously, invoke function on each element
function arrayIterate(values, fn) {
  return new Promise(function(resolve, reject) {
    // Are there any values to check?
    if (values.length === 0) {
      // All were rejected
      reject()
    }
    // Try the first value
    fn(values[0]).then(function(val) {
      // Resolved, we're all done
      resolve(val)
    }).catch(function() {
      // Rejected, remove the first item from the array and recursively
      // try the next one
      values.shift();
      arrayIterate(values, fn).then(resolve).catch(reject);
    })
  })
}

function awsLinks(data) {
  // generates links for the data on AWS
  const row = pad(data.row, 3, '0')
  const _path = pad(data.path, 3, '0')
  const sceneId = data.sceneID
  const productId = data.LANDSAT_PRODUCT_ID

  const files = ['ANG.txt','B1.TIF','B2.TIF','B3.TIF','B4.TIF','B5.TIF','B6.TIF',
                 'B7.TIF','B8.TIF','B9.TIF','B10.TIF','B11.TIF','BQA.TIF','MTL.txt']
  var _bands = Object.keys(collection["eo:bands"])

  const c1Base = `https://landsat-pds.s3.amazonaws.com/c1/L8/${path.join(_path, row, productId)}`
  //const c1Files = bands.map((b) => [{name: b.slice(0, -4), href: `${c1Base}/${productId}_${b}`}])
  var key, val
  const c1Files = _.fromPairs(files.map(function(b) {
    key = b.slice(0,-4)
    val = {href: `${c1Base}/${productId}_${b}`}
    if (_bands.includes(key)) {
      val["eo:bands"] = [key]
    }
    return [key, val]
  }))
  c1Files.thumbnail = {href: `${c1Base}/${productId}_thumb_large.jpg`}

  const c1 = {
    index: `${c1Base}/index.html`,
    files: c1Files
  }

  return new Promise(function(resolve, reject) {
    // AWS doesn't include all C1 scenes, we return the old urls for
    // any scenes that is before May 1 2017
    info = {};
    if (moment(data.acquisitionDate) > moment('2017-04-30')) {
      resolve(c1)
    } else {
      const _sceneId = sceneId.slice(0, -2);
      var sid;
      const rev = sceneId.slice(-2)
      var prefix = `http://landsat-pds.s3.amazonaws.com/L8/${path.join(_path, row, _sceneId)}`
      var links = _.range(rev, -1, -1).map(r => `${prefix}` + pad(r, 2, '0') + '/index.html')
      //var files = _.fromPairs(files.map(function(b) { return [b.slice(0,-4), {href: `${prefix}/${sid}_${b}`}] }))
      var key, val
      var files = _.fromPairs(files.map(function(b) {
        key = b.slice(0,-4)
        val = {href: `${c1Base}/${productId}_${b}`}
        if (_bands.includes(key)) {
          val["eo:bands"] = [key]
        }
        return [key, val]
      }))
      files.thumbnail = {href: `${prefix}/${sid}_thumb_large.jpg`}

      arrayIterate(links.reverse(), fileExists).then(val => {
        prefix = prefix + val.slice(-13, -11)
        sid = _sceneId + val.slice(-13, -11)
        const pre = {
          index: `${prefix}/index.html`,
          //files: bands.map((b) => [{name: b.slice(0, -4), href: `${prefix}/${sid}_${b}`}]),
          files: files
        }
        resolve(pre);
      }).catch(e => {
        reject(`${prefix} not available`);
      })
    }
  })
}

function transform(data, encoding, next) {

  // concert numeric fields to numbers
  const numberFields = [
    'cloudCoverFull',
    'path',
    'row',
    'upperLeftCornerLatitude',
    'upperLeftCornerLongitude',
    'upperRightCornerLatitude',
    'upperRightCornerLongitude',
    'lowerLeftCornerLatitude',
    'lowerLeftCornerLongitude',
    'lowerRightCornerLatitude',
    'lowerRightCornerLongitude',
    'sceneCenterLatitude',
    'sceneCenterLongitude',
    'cloudCover',
    'sunElevation',
    'sunAzimuth',
    'receivingStation',
    'imageQuality1',
    'ROLL_ANGLE',
    'GEOMETRIC_RMSE_MODEL',
    'GEOMETRIC_RMSE_MODEL_X',
    'GEOMETRIC_RMSE_MODEL_Y',
    'COLLECTION_NUMBER',
    'CLOUD_COVER_LAND'
  ]
  numberFields.forEach(f => {
    data[f] = parseFloat(data[f]);
  })

  const geometry = {
    type: 'Polygon',
    coordinates: [[
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude],
      [data.upperLeftCornerLongitude, data.upperLeftCornerLatitude],
      [data.lowerLeftCornerLongitude, data.lowerLeftCornerLatitude],
      [data.lowerRightCornerLongitude, data.lowerRightCornerLatitude],
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude]
    ]]
  }

  // check for crossing antimeridian
  const leftLong = Math.min(data.lowerLeftCornerLongitude, data.upperLeftCornerLongitude)
  const rightLong = Math.max(data.lowerRightCornerLongitude, data.upperRightCornerLongitude)
  if (leftLong < -1000000) { //> rightLong) {
    console.log(`warning: skipping ${data.sceneID} for crossing 180th Meridian (${JSON.stringify(geometry)})`)
    next()
  } else {
    awsLinks(data).then((info) => {
      const start = moment(data.sceneStartTime, "YYYY:DDD:HH:mm:ss.SSSSS")
      const end = moment(data.sceneStopTime, "YYYY:DDD:HH:mm:ss.SSSSS")
      const record = {
        id: data.LANDSAT_PRODUCT_ID,
        bbox: [
          data.lowerLeftCornerLongitude, data.lowerLeftCornerLatitude, data.upperRightCornerLongitude, data.upperRightCornerLatitude
        ],
        geometry: geometry,
        collection: 'landsat-8',
        datetime: start.toISOString(),
        //'datetime': (end - start)/2 + start
        // eo extension metadata
        'eo:cloud_cover': parseInt(data.cloudCoverFull),
        'eo:sun_azimuth': data.sunAzimuth,
        'eo:sun_elevation': data.sunElevation,
        links: [
          {rel: 'index', 'href': info.index},
          {rel: 'collection', 'href': '/collections?id=landsat-8'}
        ],
        assets: info.files
      }
      this.push(record)
      next()
    }).catch(e => {
      console.log(`error processing ${data.sceneID}: ${e}`)
      next()
    })
  }
}

function handler (event, context=null, cb=function(){}) {
  console.log(event)
  // create stream from transform function
  var _transform = through2({'objectMode': true, 'consume': true}, transform)
  const bucket = _.get(event, 'bucket')
  const key = _.get(event, 'key')
  const currentFileNum = _.get(event, 'currentFileNum', 0)
  const lastFileNum = _.get(event, 'lastFileNum', 0)
  const arn = _.get(event, 'arn', null)
  const retries = _.get(event, 'retries', 0)

  // add collection
  satlib.es.client().then((client) => {
    satlib.es.putMapping(client, 'collections').catch((err) => {})
    collection.id = collection.collection
    satlib.es.saveRecords(client, [collection], index='collections', (err, updated, errors) => {
      console.log('err', err)
      console.log('updated', updated)
      console.log('errors', errors)
    })
    satlib.ingest.update({bucket, key, transform:_transform, cb, currentFileNum, lastFileNum, arn, retries})
  })
}

local.localRun(() => {
  console.log('running locally')
  // test payload
  const a = {
    bucket: 'sat-api',
    key: 'testing/landsat',
    currentFileNum: 1,
    lastFileNum: 1
  }

  handler(a, null, (err, r) => {
    if (err) {
      console.log(`error: ${e}`)
    } else {
      console.log(`success: ${r}`)
    }
  })

})

module.exports.handler = handler
<|endoftext|>


<commit_before> // Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview Offline message screen implementation.
 */

cr.define('login', function() {
  // Screens that should have offline message overlay.
  const MANAGED_SCREENS = ['gaia-signin', 'signin'];

  /**
   * Creates a new offline message screen div.
   * @constructor
   * @extends {HTMLDivElement}
   */
  var OfflineMessageScreen = cr.ui.define('div');

  /**
   * Registers with Oobe.
   */
  OfflineMessageScreen.register = function() {
    var screen = $('offline-message');
    OfflineMessageScreen.decorate(screen);

    // Note that OfflineMessageScreen is not registered with Oobe because
    // it is shown on top of sign-in screen instead of as an independent screen.
  };

  OfflineMessageScreen.prototype = {
    __proto__: HTMLDivElement.prototype,

    /** @inheritDoc */
    decorate: function() {
      window.addEventListener('online',
                              this.handleNetworkStateChange_.bind(this));
      window.addEventListener('offline',
                              this.handleNetworkStateChange_.bind(this));
      cr.ui.DropDown.decorate($('offline-networks-list'));
    },

    onBeforeShow: function() {
      cr.ui.DropDown.setActive('offline-networks-list', true);
    },

    onBeforeHide: function() {
      cr.ui.DropDown.setActive('offline-networks-list', false);
    },

    /**
     * Shows or hides offline message based on network on/offline state.
     */
    update: function() {
      var currentScreen = Oobe.getInstance().currentScreen;
      var offlineMessage = this;
      var isOffline = !window.navigator.onLine;
      var shouldOverlay = MANAGED_SCREENS.indexOf(currentScreen.id) != -1;

      if (isOffline && shouldOverlay) {
        offlineMessage.onBeforeShow();

        $('offline-message-text').hidden = false;
        $('captive-portal-message-text').hidden = true;

        offlineMessage.classList.remove('hidden');
        offlineMessage.classList.remove('faded');

        if (!currentScreen.classList.contains('faded')) {
          currentScreen.classList.add('faded');
          currentScreen.addEventListener('webkitTransitionEnd',
            function f(e) {
              currentScreen.removeEventListener('webkitTransitionEnd', f);
              currentScreen.classList.add('hidden');
            });
        }
      } else {
        if (!offlineMessage.classList.contains('faded')) {
          offlineMessage.onBeforeHide();

          offlineMessage.classList.add('faded');
          offlineMessage.addEventListener('webkitTransitionEnd',
            function f(e) {
              offlineMessage.removeEventListener('webkitTransitionEnd', f);
              offlineMessage.classList.add('hidden');
            });

          currentScreen.classList.remove('hidden');
          currentScreen.classList.remove('faded');

          // Triggers refresh for Gaia sign-in screen.
          if (currentScreen.id == 'gaia-signin')
            chrome.send('showAddUser');
        }
      }
    },

    /**
     * Handler of online/offline event.
     */
    handleNetworkStateChange_: function() {
      this.update();
    }
  };

  /**
   * Handler for iframe's error notification coming from the outside.
   * For more info see C++ class 'SnifferObserver' which calls this method.
   * @param {number} error Error code.
   */
  OfflineMessageScreen.onFrameError = function(error) {
    var currentScreen = Oobe.getInstance().currentScreen;
    var offlineMessage = $('offline-message');
    var isOffline = !window.navigator.onLine;
    var shouldOverlay = MANAGED_SCREENS.indexOf(currentScreen.id) != -1;

    if (!shouldOverlay)
      return;

    if (!isOffline) {
      $('offline-message-text').hidden = true;
      $('captive-portal-message-text').hidden = false;
    }

    if (!currentScreen.classList.contains('faded')) {
      offlineMessage.onBeforeShow();

      offlineMessage.classList.remove('hidden');
      offlineMessage.classList.remove('faded');

      currentScreen.classList.add('faded');
      currentScreen.addEventListener('webkitTransitionEnd',
        function f(e) {
          currentScreen.removeEventListener('webkitTransitionEnd', f);
          currentScreen.classList.add('hidden');
        });
    }
  };

  return {
    OfflineMessageScreen: OfflineMessageScreen
  };
});
<commit_msg>[ChromeOS] Fix automation login flakyness.<commit_after> // Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview Offline message screen implementation.
 */

cr.define('login', function() {
  // Screens that should have offline message overlay.
  const MANAGED_SCREENS = ['gaia-signin', 'signin'];

  /**
   * Creates a new offline message screen div.
   * @constructor
   * @extends {HTMLDivElement}
   */
  var OfflineMessageScreen = cr.ui.define('div');

  /**
   * Registers with Oobe.
   */
  OfflineMessageScreen.register = function() {
    var screen = $('offline-message');
    OfflineMessageScreen.decorate(screen);

    // Note that OfflineMessageScreen is not registered with Oobe because
    // it is shown on top of sign-in screen instead of as an independent screen.
  };

  OfflineMessageScreen.prototype = {
    __proto__: HTMLDivElement.prototype,

    /** @inheritDoc */
    decorate: function() {
      window.addEventListener('online',
                              this.handleNetworkStateChange_.bind(this));
      window.addEventListener('offline',
                              this.handleNetworkStateChange_.bind(this));
      cr.ui.DropDown.decorate($('offline-networks-list'));
    },

    onBeforeShow: function() {
      cr.ui.DropDown.setActive('offline-networks-list', true);
    },

    onBeforeHide: function() {
      cr.ui.DropDown.setActive('offline-networks-list', false);
    },

    /**
     * Shows or hides offline message based on network on/offline state.
     */
    update: function() {
      var currentScreen = Oobe.getInstance().currentScreen;
      var offlineMessage = this;
      var isOffline = !window.navigator.onLine;
      var shouldOverlay = MANAGED_SCREENS.indexOf(currentScreen.id) != -1;

      if (isOffline && shouldOverlay) {
        offlineMessage.onBeforeShow();

        $('offline-message-text').hidden = false;
        $('captive-portal-message-text').hidden = true;

        offlineMessage.classList.remove('hidden');
        offlineMessage.classList.remove('faded');

        if (!currentScreen.classList.contains('faded')) {
          currentScreen.classList.add('faded');
          currentScreen.addEventListener('webkitTransitionEnd',
            function f(e) {
              currentScreen.removeEventListener('webkitTransitionEnd', f);
              currentScreen.classList.add('hidden');
            });
        }
      } else {
        if (!offlineMessage.classList.contains('faded')) {
          offlineMessage.onBeforeHide();

          offlineMessage.classList.add('faded');
          offlineMessage.addEventListener('webkitTransitionEnd',
            function f(e) {
              offlineMessage.removeEventListener('webkitTransitionEnd', f);
              offlineMessage.classList.add('hidden');
            });

          currentScreen.classList.remove('hidden');
          currentScreen.classList.remove('faded');
        }
      }
    },

    /**
     * Handler of online/offline event.
     */
    handleNetworkStateChange_: function() {
      this.update();
    }
  };

  /**
   * Handler for iframe's error notification coming from the outside.
   * For more info see C++ class 'SnifferObserver' which calls this method.
   * @param {number} error Error code.
   */
  OfflineMessageScreen.onFrameError = function(error) {
    var currentScreen = Oobe.getInstance().currentScreen;
    var offlineMessage = $('offline-message');
    var isOffline = !window.navigator.onLine;
    var shouldOverlay = MANAGED_SCREENS.indexOf(currentScreen.id) != -1;

    if (!shouldOverlay)
      return;

    if (!isOffline) {
      $('offline-message-text').hidden = true;
      $('captive-portal-message-text').hidden = false;
    }

    if (!currentScreen.classList.contains('faded')) {
      offlineMessage.onBeforeShow();

      offlineMessage.classList.remove('hidden');
      offlineMessage.classList.remove('faded');

      currentScreen.classList.add('faded');
      currentScreen.addEventListener('webkitTransitionEnd',
        function f(e) {
          currentScreen.removeEventListener('webkitTransitionEnd', f);
          currentScreen.classList.add('hidden');
        });
    }
  };

  return {
    OfflineMessageScreen: OfflineMessageScreen
  };
});
<|endoftext|>


<commit_before>function featureIsEnabled (state, feature) {
    return !state.geneFeatures || state.geneFeatures.indexOf(feature) >= 0;
}

function menuIsDisabled (state, feature) {
    return featureIsEnabled(state, feature) && (
        (state.availableFeatures || []).length <= 1 ||
        (state.geneFeatures || []).length === 1
    );
}

function enableFeature (state, feature, track) {
    const geneFeatures = (state.geneFeatures || []).slice();
    state.geneFeatures = [...geneFeatures, feature];
    if (track && track._flags) {
        track._flags.dataChanged = true;
        track.reportTrackState();
        if (typeof track.featureTypesChanged === 'function') {
            track.featureTypesChanged();
        }
    }
}

function disableFeature (state, feature, track) {
    let geneFeatures = state.geneFeatures;
    if (!geneFeatures || !geneFeatures.length) {
        geneFeatures = (state.availableFeatures || []).slice();
    }
    state.geneFeatures = geneFeatures.filter(geneFeature => geneFeature !== feature);
    if (track && track._flags) {
        track._flags.dataChanged = true;
        track.reportTrackState();
        if (typeof track.featureTypesChanged === 'function') {
            track.featureTypesChanged();
        }
    }
}

function getDisplayName (state) {
    if (
        !state.geneFeatures ||
        !state.availableFeatures
    ) {
        return 'all';
    }
    const filtered = state.geneFeatures.filter(feature => state.availableFeatures.indexOf(feature) >= 0);
    if (filtered.length === state.availableFeatures.length) {
        return 'all';
    }
    if (filtered.length > 3) {
        const length = filtered.length;
        return `${length} type${length > 1 ? 's' : ''}`;
    }
    return filtered.join(', ');
}

export default {
    displayName: state => getDisplayName(state),
    isVisible: (state) => (state.availableFeatures || []).length > 1,
    dynamicFields: (state, tracks, track) => (state.availableFeatures || []).map(featureName => ({
        disable: () => disableFeature(state, featureName, track),
        enable: () => enableFeature(state, featureName, track),
        disabled: () => menuIsDisabled(state, featureName),
        isEnabled: () => featureIsEnabled(state, featureName),
        label: featureName,
        name: `gene>features>${featureName}`,
        type: 'checkbox',
        hash: () => `gene>features>${featureName}`
    })),
    label: 'Features',
    name: 'gene>features',
    type: 'submenu',
    preventAutoClose: true
};
<commit_msg>GENE tracks: customization of displayed features and track duplication (#455) - hiding "Features" menu for histogram drawing mode<commit_after>function featureIsEnabled (state, feature) {
    return !state.geneFeatures || state.geneFeatures.indexOf(feature) >= 0;
}

function menuIsDisabled (state, feature) {
    return featureIsEnabled(state, feature) && (
        (state.availableFeatures || []).length <= 1 ||
        (state.geneFeatures || []).length === 1
    );
}

function enableFeature (state, feature, track) {
    const geneFeatures = (state.geneFeatures || []).slice();
    state.geneFeatures = [...geneFeatures, feature];
    if (track && track._flags) {
        track._flags.dataChanged = true;
        track.reportTrackState();
        if (typeof track.featureTypesChanged === 'function') {
            track.featureTypesChanged();
        }
    }
}

function disableFeature (state, feature, track) {
    let geneFeatures = state.geneFeatures;
    if (!geneFeatures || !geneFeatures.length) {
        geneFeatures = (state.availableFeatures || []).slice();
    }
    state.geneFeatures = geneFeatures.filter(geneFeature => geneFeature !== feature);
    if (track && track._flags) {
        track._flags.dataChanged = true;
        track.reportTrackState();
        if (typeof track.featureTypesChanged === 'function') {
            track.featureTypesChanged();
        }
    }
}

function getDisplayName (state) {
    if (
        !state.geneFeatures ||
        !state.availableFeatures
    ) {
        return 'all';
    }
    const filtered = state.geneFeatures.filter(feature => state.availableFeatures.indexOf(feature) >= 0);
    if (filtered.length === state.availableFeatures.length) {
        return 'all';
    }
    if (filtered.length > 3) {
        const length = filtered.length;
        return `${length} type${length > 1 ? 's' : ''}`;
    }
    return filtered.join(', ');
}

export default {
    displayName: state => getDisplayName(state),
    isVisible: (state, tracks, track) => {
        if (
            track &&
            track.transformer &&
            typeof track.transformer.isHistogramDrawingModeForViewport === 'function' &&
            track.viewport &&
            track.cache &&
            track.transformer.isHistogramDrawingModeForViewport(track.viewport, track.cache)
        ) {
            return false;
        }
        return (state.availableFeatures || []).length > 1;
    },
    dynamicFields: (state, tracks, track) => (state.availableFeatures || []).map(featureName => ({
        disable: () => disableFeature(state, featureName, track),
        enable: () => enableFeature(state, featureName, track),
        disabled: () => menuIsDisabled(state, featureName),
        isEnabled: () => featureIsEnabled(state, featureName),
        label: featureName,
        name: `gene>features>${featureName}`,
        type: 'checkbox',
        hash: () => `gene>features>${featureName}`
    })),
    label: 'Features',
    name: 'gene>features',
    type: 'submenu',
    preventAutoClose: true
};
<|endoftext|>


<commit_before>module.exports = {

    incoming: function (message, bot, builder) {
        console.log('conversations/state')
        console.log(global.conversations);
        console.log('************');
        console.log('users');
        console.log(global.users);
        console.log('agents');
        console.log(global.agent);

        if (message.text) { // saves a ping from adding a user/agent

            if (message.text === 'help') {
                // user initiated connect to agent
                global.conversations[message.address.conversation.id] = Object.assign({}, global.conversations[message.address.conversation.id], { 'status': 'Finding_Agent' });
                message.text = 'hold on while I connect you';
                // return message
            };

            // find out who is talking / add new convo if not found
            if (message.user.isStaff) { // move logic to an API for agents
                console.log('is staff');
                var agentId = message.address.conversation.id;
                var thisAgent = global.conversations[agentId];
                if (typeof thisAgent === 'undefined') { // agent not in state yet, add them ****This will happen for each conversation, not agent.
                    global.agent.push(agentId);
                    global.conversations[agentId].address = message.address;
                }
            }
            // End Agent

            // Setting User state logic
            else {
                console.log('not staff');
                var userId = message.address.conversation.id;
                var thisUser = global.conversations[userId];
                // Add a user not yet in state

                if (typeof thisUser === 'undefined') {
                    console.log('got undefined');
                    global.users.push(userId);
                    global.conversations[userId] = { transcript: [message], address: message.address, status: 'Talking_To_Bot' };
                    return
                } else {
                    global.conversations[userId].transcript.push(message);
                }
                // if in state, update transcript for the user

                // Check for choices to be made
                console.log('about to make the switch')
                console.log(global.conversations[userId].status);
                switch (global.conversations[userId].status) {
                    case 'Finding_Agent':
                        message.text = 'getting agent';
                        var myAgent = global.conversations[global.agent[0]];
                        // global.conversations[userId] = Object.assign({}, global.conversations[userId], { agentAddress: myAgent.address, 'status': 'Talking_To_Agent' });
                        global.conversations[userId].status = 'Talking_To_Agent';

                        return message;
                        break;
                    case 'Talking_To_Agent':
                        message.text = 'talking to agent';
                        break;
                    case 'Talking_To_Bot':
                        message.text = 'talk to bot';
                        return message;
                        break;
                    default:
                        message.text = 'defaulting';
                        return message;
                        break;

                }

            }
        }
        // if talking to Agent/waiting for agent, suppress default bot functionality (how if on a prompt and it's looking for a certain response? override somehow)
    }
}
<commit_msg>getting close<commit_after>module.exports = {

    incoming: function (message, bot, builder) {
        console.log('conversations/state')
        console.log(global.conversations);
        console.log('************');
        console.log('users');
        console.log(global.users);
        console.log('agents');
        console.log(global.agent);

        if (message.text) { // saves a ping from adding a user/agent

            if (message.text === 'help') {
                // user initiated connect to agent
                global.conversations[message.address.conversation.id] = Object.assign({}, global.conversations[message.address.conversation.id], { 'status': 'Finding_Agent' });
                message.text = 'hold on while I connect you';
                // return message
            };

            // find out who is talking / add new convo if not found
            if (message.user.isStaff) { // move logic to an API for agents
                console.log('is staff');
                var agentId = message.address.conversation.id;
                var thisAgent = global.conversations[agentId];
                if (typeof thisAgent === 'undefined') { // agent not in state yet, add them ****This will happen for each conversation, not agent.
                    global.agent.push(agentId);
                    global.conversations[agentId] = { address: message.address };
                }
            }
            // End Agent

            // Setting User state logic
            else {
                console.log('not staff');
                var userId = message.address.conversation.id;
                var thisUser = global.conversations[userId];
                // Add a user not yet in state

                if (typeof thisUser === 'undefined') {
                    console.log('got undefined');
                    global.users.push(userId);
                    global.conversations[userId] = { transcript: [message], address: message.address, status: 'Talking_To_Bot' };
                    return
                } else {
                    global.conversations[userId].transcript.push(message);
                }
                // if in state, update transcript for the user

                // Check for choices to be made
                console.log('about to make the switch')
                console.log(global.conversations[userId].status);
                switch (global.conversations[userId].status) {
                    case 'Finding_Agent':
                        message.text = 'getting agent';
                        var myAgent = global.conversations[global.agent[0]];
                        // global.conversations[userId] = Object.assign({}, global.conversations[userId], { agentAddress: myAgent.address, 'status': 'Talking_To_Agent' });
                        global.conversations[userId].status = 'Talking_To_Agent';
                        global.conversations[userId].agentAddress = myAgent.address;

                        return message;
                        break;
                    case 'Talking_To_Agent':
                        message.text = 'talking to agent';
                        break;
                    case 'Talking_To_Bot':
                        message.text = 'talk to bot';
                        return message;
                        break;
                    default:
                        message.text = 'defaulting';
                        return message;
                        break;

                }

            }
        }
        // if talking to Agent/waiting for agent, suppress default bot functionality (how if on a prompt and it's looking for a certain response? override somehow)
    }
}
<|endoftext|>


<commit_before>// SNIP: 9d6557d3936d0c8700fdedde9eec3026 | xhrml.jsx
// CHANGELOG:
//  - 2019-11-25 支持 target 嵌套
//  - 2018-07-04 添加 replace 属性, 决定是否替换容器
//  - 2018-05-25 优化代码风格
//  - 2018-05-25 添加 fields-container 属性, 支持提交追加字段
//  - 2017-03-11 添加数据载入完成后, 触发 content:loading 事件
//  - 2017-01-24 优化使用 jQuery 发送事件, 而不是原生代码
//  - 2016-08-04 添加数据载入完成后, 触发 content:loaded 事件
//  - 2016-05-16 独立成 javascript 组件
//  - 2015-04-19 后台引入 xhrml

import $ from 'jquery'

function findContainer(element, container, target) {
  let $container = null
  if (container.match(/^#/)) {
    $container = $(container)
  } else {
    $container = $(element).closest(container)
  }

  if (target) {
    return $container.find(target)
  } else {
    return $container
  }
}

function findContent(data, container, target) {
  if (!target) {
    return $(data)
  } else {
    return $(data).find(container).find(target)
  }
}

function replaceContent($element, data, container, target) {
  const $container = findContainer($element, container, target)
  const $data = findContent(data, container, target)

  if ($element.data('replace') || target) {
    $container.replaceWith($data)
    return $data
  } else {
    $container.html($data)
    return $container
  }
}

function handleResponse($element, data) {
  if (!$element.data('xhrml')) { return }
  $element.removeData('xhrml')
  $element.data('type', 'xhrml')

  const selector = $element.data("target")
  const [ container, target ] = selector.replace(" ", "|||").split("|||")
  const $container = replaceContent($element, data, container, target)
  $container.trigger('xhrml:success')
  $container.trigger('content:loading')
  $container.trigger('content:loaded')
}

function handleRequest($element) {
  if ($element.data('type') !== 'xhrml') { return }

  if (!$element.data('raw-params')) {
    const params = $element.data('params') || ''
    $element.data('raw-params', params)
  }

  const fieldsContainer = $element.data('fields-container')

  if (fieldsContainer) {
    const $fieldsContainer = findContainer($element, fieldsContainer)
    const fields = []
    $fieldsContainer.find(':input').each(function() {
      const name = $(this).data('param-name') || this.name
      if (name) {
        const value = $(this).val()
        fields.push(`${encodeURIComponent(name)}=${encodeURIComponent(value)}`)
      }
    })

    const rawParams = $element.data('raw-params')
    const params = rawParams.split('&').concat(fields).join('&')
    $element.data('params', params)
  }

  $element.data('type', 'html')
  $element.data('xhrml', true)
}

$(function() {
  $(document).on({
    'ajax:before'(event) {
      const $element = $(event.target)
      handleRequest($element)
    },
    'ajax:success'(event, data) {
      const $element = $(event.target)
      handleResponse($element, data)
    },
    'ajax:error'(event, xhr) {
      const $element = $(event.target)
      handleResponse($element, xhr.responseText)
    }
  })
})

$(document).on('ajax:aborted:file', function(event) {
  const $form = $(event.target)
  $(event.target).ajaxSubmit({
    beforeSerialize($f) {
      $f.trigger('ajax:before')
    },
    success(data) {
      $form.trigger('ajax:success', data)
    },
    error(xhr) {
      $form.trigger('ajax:error', xhr)
    }
  })

  return false
})
<commit_msg>Update xhrml.js, add container check<commit_after>// SNIP: 9d6557d3936d0c8700fdedde9eec3026 | xhrml.jsx
// CHANGELOG:
//  - 2019-11-25 支持 target 嵌套
//  - 2018-07-04 添加 replace 属性, 决定是否替换容器
//  - 2018-05-25 优化代码风格
//  - 2018-05-25 添加 fields-container 属性, 支持提交追加字段
//  - 2017-03-11 添加数据载入完成后, 触发 content:loading 事件
//  - 2017-01-24 优化使用 jQuery 发送事件, 而不是原生代码
//  - 2016-08-04 添加数据载入完成后, 触发 content:loaded 事件
//  - 2016-05-16 独立成 javascript 组件
//  - 2015-04-19 后台引入 xhrml

import $ from 'jquery'

function findContainer(element, container, target) {
  let $container = null
  if (container.match(/^#/)) {
    $container = $(container)
  } else {
    $container = $(element).closest(container)
  }

  if (target) {
    return $container.find(target)
  } else {
    return $container
  }
}

function findContent(data, container, target) {
  if (!target) {
    return $(data)
  } else if ($(data).has(container)) {
    return $(data).find(target)
  } else {
    return $(data).find(container).find(target)
  }
}

function replaceContent($element, data, container, target) {
  const $container = findContainer($element, container, target)
  const $data = findContent(data, container, target)

  if ($element.data('replace') || target) {
    $container.replaceWith($data)
    return $data
  } else {
    $container.html($data)
    return $container
  }
}

function handleResponse($element, data) {
  if (!$element.data('xhrml')) { return }
  $element.removeData('xhrml')
  $element.data('type', 'xhrml')

  const selector = $element.data("target")
  const [ container, target ] = selector.replace(" ", "|||").split("|||")
  const $container = replaceContent($element, data, container, target)
  $container.trigger('xhrml:success')
  $container.trigger('content:loading')
  $container.trigger('content:loaded')
}

function handleRequest($element) {
  if ($element.data('type') !== 'xhrml') { return }

  if (!$element.data('raw-params')) {
    const params = $element.data('params') || ''
    $element.data('raw-params', params)
  }

  const fieldsContainer = $element.data('fields-container')

  if (fieldsContainer) {
    const $fieldsContainer = findContainer($element, fieldsContainer)
    const fields = []
    $fieldsContainer.find(':input').each(function() {
      const name = $(this).data('param-name') || this.name
      if (name) {
        const value = $(this).val()
        fields.push(`${encodeURIComponent(name)}=${encodeURIComponent(value)}`)
      }
    })

    const rawParams = $element.data('raw-params')
    const params = rawParams.split('&').concat(fields).join('&')
    $element.data('params', params)
  }

  $element.data('type', 'html')
  $element.data('xhrml', true)
}

$(function() {
  $(document).on({
    'ajax:before'(event) {
      const $element = $(event.target)
      handleRequest($element)
    },
    'ajax:success'(event, data) {
      const $element = $(event.target)
      handleResponse($element, data)
    },
    'ajax:error'(event, xhr) {
      const $element = $(event.target)
      handleResponse($element, xhr.responseText)
    }
  })
})

$(document).on('ajax:aborted:file', function(event) {
  const $form = $(event.target)
  $(event.target).ajaxSubmit({
    beforeSerialize($f) {
      $f.trigger('ajax:before')
    },
    success(data) {
      $form.trigger('ajax:success', data)
    },
    error(xhr) {
      $form.trigger('ajax:error', xhr)
    }
  })

  return false
})
<|endoftext|>


<commit_before>/**
 * Created by isc on 12/05/15.
 */
angular.module('myApp.controllers')
	.controller('EvidenceCtrl', ['$document', '$sce', '$scope', '$http',
		'defaults', '$controller', 'Session', '$rootScope', 'camomileService',

		function ($document, $sce, $scope, $http, defaults, $controller, Session, $rootScope, camomileService) {

			/*import MissPlete from './MissPlete.js';

        	new MissPlete({
            	input: document.querySelector('input[name="entry_input"]'),

            	options: [["Barcelona", "BCN"], ["San Francisco", "SF"]]
        	});*/

			$controller('CommonCtrl', {
				$scope: $scope,
				$http: $http,
				defaults: defaults,
				Session: Session
			});

			$scope.model.incomingQueue = $rootScope.queues.evidenceIn;
			$scope.model.outgoingQueue = $rootScope.queues.evidenceOut;

			$scope.model.q = {};

			$scope.model.user_input = {};

			$scope.model.updateIsDisplayedVideo = function (activate) {
				$scope.model.isDisplayedVideo = activate;
			};

			// initialize page state
			$scope.model.updateIsDisplayedVideo(false);

			var _getVideo = function (id_medium, callback) {

				camomileService.getMedium(id_medium, function (err, medium) {
					callback(err, $sce.trustAsResourceUrl($scope.model.videoPath + '/' + medium.url + '.mp4'));
				});
			};

			// Initializes the data from the queue
			// rename from "initQueueData" to "popQueueElement"
			$scope.model.popQueueElement = function () {

				document.getElementById('videoTest').innerHTML = "";
				// Get queue first element and pop it from the queue
				camomileService.dequeue($scope.model.incomingQueue, function (err, item) {

					if (err) {
						alert(item.error);
						$scope.$apply(function () {
							$scope.model.video = undefined;
							$scope.model.isDisplayedVideo = false;
							$scope.model.updateIsDisplayedVideo(false);
						});

						return;
					}

					//$scope.model.resetTransparentPlan();
					$scope.model.updateIsDisplayedVideo(true);

					if (item.modality === "pronounced") {
						document.getElementById("message").innerHTML = "WARNING: The person name might be pronounced !";
					}

					$scope.model.q = item;
					$scope.model.user_input.person_name = $scope.model.q.person_name;
					$scope.model.initialData = $scope.model.q.person_name;

					// Update the add entry button's status
					$scope.model.updateIsDisplayedVideo($scope.model.user_input.person_name != "");

					async.parallel({
							video: function (callback) {
								_getVideo($scope.model.q.medium_id, callback);
							},
							serverDate: function (callback) {
								camomileService.getDate(function (err, data) {
									callback(null, data.date);
								});
							}
						},
						function (err, results) {
							$scope.model.video = results.video;
							$scope.model.serverDate = results.serverDate;
							$scope.model.clientDate = Date.now();

							$scope.model.restrict_toggle = 2;
							$scope.model.current_time_temp = $scope.model.q.t;
							$scope.model.infbndsec = parseFloat($scope.model.q.t || 0);
							$scope.model.infbndsec-=5.0;
							if ($scope.model.infbndsec < 0) {
								$scope.model.infbndsec = 0;
							}
							$scope.model.supbndsec = parseFloat($scope.model.q.t || 0);
							$scope.model.supbndsec+=5.0;
							if ($scope.model.supbndsec > $scope.model.fullDuration) {
								$scope.model.supbndsec = $scope.model.fullDuration;
							}
							$scope.model.duration = $scope.model.supbndsec - $scope.model.infbndsec;

							$scope.$apply(function () {
								$scope.model.current_time = $scope.model.q.t;
							});

						});
				});
			};

			// Event launched when click on the save button.
			$scope.model.saveQueueElement = function (isEvidence) {

				if (document.getElementById('evidence').src === "") {
					document.getElementById("message").innerHTML = "Please draw a bounding box around the face.";
				}

				var item = {};

				item.log = {};
				item.log.user = Session.username;
				item.log.date = $scope.model.serverDate;
				item.log.duration = Date.now() - $scope.model.clientDate;
				/*camomileService.me(function(callback){
					item.log.user_id = _id;
				});*/

				item.input = {};
				item.input.corpus_id = $scope.model.q.corpus_id;
				item.input.medium_id = $scope.model.q.medium_id;
				item.input.modality = $scope.model.q.modality;
				item.input.person_name = $scope.model.initialData;
				item.input.t = $scope.model.q.t;

				var b_box = {};
				b_box.w = parseFloat(document.getElementById("Wbox").value);
				b_box.h = parseFloat(document.getElementById("Hbox").value);
				b_box.x = parseFloat(document.getElementById("Xbox").value);
				b_box.y = parseFloat(document.getElementById("Ybox").value);

				item.output = {};
				item.output.status = isEvidence;
				if (isEvidence == "yes") {
					item.output.person_name = $scope.model.user_input.person_name;
					item.output.t = $scope.model.current_time;
					item.output.image = document.getElementById('evidence').src;
					item.output.bounding_box = b_box;
				}

				document.getElementById('evidenceImages').style.display = "none";
				document.getElementById('evidence').src = "";
				document.getElementById('draw').children[0].width = document.getElementById('draw').children[0].width;
				document.getElementById("Wbox").value = "";
				document.getElementById("Hbox").value = "";
				document.getElementById("Xbox").value = "";
				document.getElementById("Ybox").value = "";
				document.getElementById("message").innerHTML = "";

				camomileService.enqueue($scope.model.outgoingQueue, item, function (err, data) {

					if (err) {
						console.log("Something went wrong");
					} else {
						$scope.model.popQueueElement();
					}

				});
			};

			$document.on(
				"keydown",
				function (event) {
					var targetID = event.target.id;
					var button_checked = false;
					if (targetID == 'confirm' || targetID == 'cancel') {
						button_checked = true;
					}
					//enter
					if (event.keyCode == 13 && targetID != 'localServerInput') {
						//If the focus is on the check buttons, blur the focus first
						if (button_checked) {
							event.target.blur();
						}
						$scope.$apply(function () {
							$scope.model.saveQueueElement(true);
						});
					}
					//space
					if (event.keyCode == 32 && targetID != "entry_input") {
						if (button_checked) {
							event.target.blur();
						}
						$scope.$apply(function () {
							$scope.model.toggle_play();
						});
					}
					//esc-> skip
					if (event.keyCode == 27) {
						$scope.$apply(function () {
							//skip
							$scope.model.saveQueueElement(false);
						});
					}
					//Left
					if (event.keyCode == 37) {
						$scope.$apply(function () {
							if ($scope.model.current_time - 0.04 > $scope.model.infbndsec) {
								$scope.model.current_time = $scope.model.current_time - 0.04;
							} else {
								$scope.model.current_time = $scope.model.infbndsec;
							}
						});
					}
					//Right
					if (event.keyCode == 39) {
						$scope.$apply(function () {
							if ($scope.model.current_time + 0.04 < $scope.model.supbndsec) {
								$scope.model.current_time = $scope.model.current_time + 0.04;
							} else {
								$scope.model.current_time = $scope.model.supbndsec;
							}
						});
					}
					//Up
					if (event.keyCode == 38) {
						$scope.$apply(function () {
							if ($scope.model.current_time - 1 > $scope.model.infbndsec) {
								$scope.model.current_time = $scope.model.current_time - 1;
							} else {
								$scope.model.current_time = $scope.model.infbndsec;
							}
						});

					} //Down
					if (event.keyCode == 40) {
						$scope.$apply(function () {

							if ($scope.model.current_time + 1 < $scope.model.supbndsec) {
								$scope.model.current_time = $scope.model.current_time + 1;
							} else {
								$scope.model.current_time = $scope.model.supbndsec;
							}
						});
					}
				}
			);

		}
	]);

angular.module('myApp.controllers').directive('drawing', function(){
  return {
    restrict: 'E',
    scope: { localRectangles: '=rectangleList' },
    template: '<canvas class="drawing"></canvas>',
    link: function(scope, element){
    	// There are 3 canvas, one used to determine the zone to copy
    	// another one to extract the image and clip it, the last one to resize the image
      var canvasElement = element.children()[0];
      var ctx = canvasElement.getContext('2d');
      var canvasB = document.getElementById("recup");
      var ctxb = canvasB.getContext('2d');
      var canvasE = document.getElementById("evid");
      var ctxe = canvasE.getContext('2d');

      // The first canvas can be sized at the beginning
      canvasElement.width = document.getElementById("video-container").offsetWidth;
      canvasElement.height = document.getElementById("video-container").offsetHeight;

      // Are we drawing?
      var drawing = false;

      // the last coordinates before the current move
      var centerX;
      var centerY;

      element.children()[0].addEventListener('mousedown', function(event){
        reset();
        startX = event.offsetX;
        startY = event.offsetY;
        document.getElementById("player").pause();

        // begins new line
        ctx.beginPath();

        drawing = true;
      },false);

	  element.children()[0].addEventListener('mousemove', function(event){

        if(drawing){

        //document.getElementById('evid').style.display = "none";
        document.getElementById('evidenceImages').style.display = "none";

          // get current mouse position
          currentX = event.offsetX;
          currentY = event.offsetY;

          if((startX<currentX && startY<currentY) || (startX>currentX && startY>currentY)){
          	if(Math.abs(currentY-startY)<Math.abs(currentX-startX)) currentX = currentY-startY+startX;
          	else currentY = currentX-startX+startY;
          }
          else{
          	if(Math.abs(currentY-startY)<Math.abs(currentX-startX)) currentX = startY-currentY+startX;
          	else currentY = startX-currentX+startY;
    	  }

          // limit all the rectangle within the canvas and draw
          if(currentX >= 0 && currentX <= 360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight && currentY >= 0 && currentY <= 360){
            draw(startX, startY, currentX, currentY);
          }
        }

      },false);

      // canvas reset
      function reset(){
      	// This simple operation reset the canvas
       canvasElement.width = canvasElement.width;
       canvasB.width = canvasB.width;
       canvasE.width = canvasE.width;
      }

      element.children()[0].addEventListener('mouseup', function(event){
        // stop drawing
        drawing = false;
        //document.getElementById('evid').style.display = "";
        document.getElementById('evidenceImages').style.display = "inline-block";
      },false);

      function draw(startX, startY,
                    currentX, currentY, rotate){

        reset();
        var sizeX = currentX - startX;
        var sizeY = currentY - startY;

        ctx.rect(Math.min(startX,currentX),
                 Math.min(startY,currentY),
                 Math.abs(sizeX), Math.abs(sizeY));
        ctx.lineWidth = 3;
        // color gradient
        /*var gradient=ctx.createLinearGradient(Math.min(oppositeX,currentX),Math.min(oppositeY,currentY),Math.max(oppositeX,currentX),Math.max(oppositeY,currentY));
        gradient.addColorStop("0.05","red");
        gradient.addColorStop("0.15","blue");
        gradient.addColorStop("0.25","red");
        gradient.addColorStop("0.35","blue");
        gradient.addColorStop("0.45","red");
        gradient.addColorStop("0.55","blue");
        gradient.addColorStop("0.65","red");
        gradient.addColorStop("0.75","blue");
        gradient.addColorStop("0.85","red");
        gradient.addColorStop("0.95","blue");
        ctx.strokeStyle = gradient;*/
        // color
        ctx.strokeStyle = 'red';
        // draw it
        ctx.stroke();
        // Launch the copy process
        copy(Math.min(startX,currentX),Math.min(startY,currentY),Math.abs(sizeX),Math.abs(sizeY));
        document.getElementById("Xbox").value = Math.min(startX,currentX)/(360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight);
        document.getElementById("Ybox").value = Math.min(startY,currentY)/360;
        document.getElementById("Wbox").value = Math.abs(sizeX)/(360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight);
        document.getElementById("Hbox").value = Math.abs(sizeY)/360;
      }

      function copy(X, Y, sizeX, sizeY){

      	// Get the video source and size the second canvas according to the dimension (16:9 or 4:3)
        var src = document.getElementById('player');
        canvasB.width = 360*src.videoWidth/src.videoHeight;
        canvasB.height = 360;
        // Copy the image
        ctxb.drawImage(src,0,0,canvasB.width,canvasB.height);
        // Clip the image
        var btmp = ctxb.getImageData(X, Y, sizeX, sizeY);
        // Clear the second canvas to put the part of the image we want
        ctxb.clearRect(0,0,canvasB.width,canvasB.height);
        ctxb.putImageData(btmp,0,0);
        // Size of the last canvas
        canvasE.width = sizeX;
        canvasE.height = sizeY;
        // Copy from the second canvas to the third
        ctxe.putImageData(btmp,0,0);
        //dataURI JPEG output
        document.getElementById('evidence').src = canvasE.toDataURL("image/png", 1.0);
      }

    }
  };
});<commit_msg>change condition on message "please draw..." and add a return<commit_after>/**
 * Created by isc on 12/05/15.
 */
angular.module('myApp.controllers')
	.controller('EvidenceCtrl', ['$document', '$sce', '$scope', '$http',
		'defaults', '$controller', 'Session', '$rootScope', 'camomileService',

		function ($document, $sce, $scope, $http, defaults, $controller, Session, $rootScope, camomileService) {

			/*import MissPlete from './MissPlete.js';

        	new MissPlete({
            	input: document.querySelector('input[name="entry_input"]'),

            	options: [["Barcelona", "BCN"], ["San Francisco", "SF"]]
        	});*/

			$controller('CommonCtrl', {
				$scope: $scope,
				$http: $http,
				defaults: defaults,
				Session: Session
			});

			$scope.model.incomingQueue = $rootScope.queues.evidenceIn;
			$scope.model.outgoingQueue = $rootScope.queues.evidenceOut;

			$scope.model.q = {};

			$scope.model.user_input = {};

			$scope.model.updateIsDisplayedVideo = function (activate) {
				$scope.model.isDisplayedVideo = activate;
			};

			// initialize page state
			$scope.model.updateIsDisplayedVideo(false);

			var _getVideo = function (id_medium, callback) {

				camomileService.getMedium(id_medium, function (err, medium) {
					callback(err, $sce.trustAsResourceUrl($scope.model.videoPath + '/' + medium.url + '.mp4'));
				});
			};

			// Initializes the data from the queue
			// rename from "initQueueData" to "popQueueElement"
			$scope.model.popQueueElement = function () {

				document.getElementById('videoTest').innerHTML = "";
				// Get queue first element and pop it from the queue
				camomileService.dequeue($scope.model.incomingQueue, function (err, item) {

					if (err) {
						alert(item.error);
						$scope.$apply(function () {
							$scope.model.video = undefined;
							$scope.model.isDisplayedVideo = false;
							$scope.model.updateIsDisplayedVideo(false);
						});

						return;
					}

					//$scope.model.resetTransparentPlan();
					$scope.model.updateIsDisplayedVideo(true);

					if (item.modality === "pronounced") {
						document.getElementById("message").innerHTML = "WARNING: The person name might be pronounced !";
					}

					$scope.model.q = item;
					$scope.model.user_input.person_name = $scope.model.q.person_name;
					$scope.model.initialData = $scope.model.q.person_name;

					// Update the add entry button's status
					$scope.model.updateIsDisplayedVideo($scope.model.user_input.person_name != "");

					async.parallel({
							video: function (callback) {
								_getVideo($scope.model.q.medium_id, callback);
							},
							serverDate: function (callback) {
								camomileService.getDate(function (err, data) {
									callback(null, data.date);
								});
							}
						},
						function (err, results) {
							$scope.model.video = results.video;
							$scope.model.serverDate = results.serverDate;
							$scope.model.clientDate = Date.now();

							$scope.model.restrict_toggle = 2;
							$scope.model.current_time_temp = $scope.model.q.t;
							$scope.model.infbndsec = parseFloat($scope.model.q.t || 0);
							$scope.model.infbndsec-=5.0;
							if ($scope.model.infbndsec < 0) {
								$scope.model.infbndsec = 0;
							}
							$scope.model.supbndsec = parseFloat($scope.model.q.t || 0);
							$scope.model.supbndsec+=5.0;
							if ($scope.model.supbndsec > $scope.model.fullDuration) {
								$scope.model.supbndsec = $scope.model.fullDuration;
							}
							$scope.model.duration = $scope.model.supbndsec - $scope.model.infbndsec;

							$scope.$apply(function () {
								$scope.model.current_time = $scope.model.q.t;
							});

						});
				});
			};

			// Event launched when click on the save button.
			$scope.model.saveQueueElement = function (isEvidence) {

				if (document.getElementById('evidence').src == "") {
					document.getElementById("message").innerHTML = "Please draw a bounding box around the face.";
					return;
				}

				var item = {};

				item.log = {};
				item.log.user = Session.username;
				item.log.date = $scope.model.serverDate;
				item.log.duration = Date.now() - $scope.model.clientDate;
				/*camomileService.me(function(callback){
					item.log.user_id = _id;
				});*/

				item.input = {};
				item.input.corpus_id = $scope.model.q.corpus_id;
				item.input.medium_id = $scope.model.q.medium_id;
				item.input.modality = $scope.model.q.modality;
				item.input.person_name = $scope.model.initialData;
				item.input.t = $scope.model.q.t;

				var b_box = {};
				b_box.w = parseFloat(document.getElementById("Wbox").value);
				b_box.h = parseFloat(document.getElementById("Hbox").value);
				b_box.x = parseFloat(document.getElementById("Xbox").value);
				b_box.y = parseFloat(document.getElementById("Ybox").value);

				item.output = {};
				item.output.status = isEvidence;
				if (isEvidence == "yes") {
					item.output.person_name = $scope.model.user_input.person_name;
					item.output.t = $scope.model.current_time;
					item.output.image = document.getElementById('evidence').src;
					item.output.bounding_box = b_box;
				}

				document.getElementById('evidenceImages').style.display = "none";
				document.getElementById('evidence').src = "";
				document.getElementById('draw').children[0].width = document.getElementById('draw').children[0].width;
				document.getElementById("Wbox").value = "";
				document.getElementById("Hbox").value = "";
				document.getElementById("Xbox").value = "";
				document.getElementById("Ybox").value = "";
				document.getElementById("message").innerHTML = "";

				camomileService.enqueue($scope.model.outgoingQueue, item, function (err, data) {

					if (err) {
						console.log("Something went wrong");
					} else {
						$scope.model.popQueueElement();
					}

				});
			};

			$document.on(
				"keydown",
				function (event) {
					var targetID = event.target.id;
					var button_checked = false;
					if (targetID == 'confirm' || targetID == 'cancel') {
						button_checked = true;
					}
					//enter
					if (event.keyCode == 13 && targetID != 'localServerInput') {
						//If the focus is on the check buttons, blur the focus first
						if (button_checked) {
							event.target.blur();
						}
						$scope.$apply(function () {
							$scope.model.saveQueueElement(true);
						});
					}
					//space
					if (event.keyCode == 32 && targetID != "entry_input") {
						if (button_checked) {
							event.target.blur();
						}
						$scope.$apply(function () {
							$scope.model.toggle_play();
						});
					}
					//esc-> skip
					if (event.keyCode == 27) {
						$scope.$apply(function () {
							//skip
							$scope.model.saveQueueElement(false);
						});
					}
					//Left
					if (event.keyCode == 37) {
						$scope.$apply(function () {
							if ($scope.model.current_time - 0.04 > $scope.model.infbndsec) {
								$scope.model.current_time = $scope.model.current_time - 0.04;
							} else {
								$scope.model.current_time = $scope.model.infbndsec;
							}
						});
					}
					//Right
					if (event.keyCode == 39) {
						$scope.$apply(function () {
							if ($scope.model.current_time + 0.04 < $scope.model.supbndsec) {
								$scope.model.current_time = $scope.model.current_time + 0.04;
							} else {
								$scope.model.current_time = $scope.model.supbndsec;
							}
						});
					}
					//Up
					if (event.keyCode == 38) {
						$scope.$apply(function () {
							if ($scope.model.current_time - 1 > $scope.model.infbndsec) {
								$scope.model.current_time = $scope.model.current_time - 1;
							} else {
								$scope.model.current_time = $scope.model.infbndsec;
							}
						});

					} //Down
					if (event.keyCode == 40) {
						$scope.$apply(function () {

							if ($scope.model.current_time + 1 < $scope.model.supbndsec) {
								$scope.model.current_time = $scope.model.current_time + 1;
							} else {
								$scope.model.current_time = $scope.model.supbndsec;
							}
						});
					}
				}
			);

		}
	]);

angular.module('myApp.controllers').directive('drawing', function(){
  return {
    restrict: 'E',
    scope: { localRectangles: '=rectangleList' },
    template: '<canvas class="drawing"></canvas>',
    link: function(scope, element){
    	// There are 3 canvas, one used to determine the zone to copy
    	// another one to extract the image and clip it, the last one to resize the image
      var canvasElement = element.children()[0];
      var ctx = canvasElement.getContext('2d');
      var canvasB = document.getElementById("recup");
      var ctxb = canvasB.getContext('2d');
      var canvasE = document.getElementById("evid");
      var ctxe = canvasE.getContext('2d');

      // The first canvas can be sized at the beginning
      canvasElement.width = document.getElementById("video-container").offsetWidth;
      canvasElement.height = document.getElementById("video-container").offsetHeight;

      // Are we drawing?
      var drawing = false;

      // the last coordinates before the current move
      var centerX;
      var centerY;

      element.children()[0].addEventListener('mousedown', function(event){
        reset();
        startX = event.offsetX;
        startY = event.offsetY;
        document.getElementById("player").pause();

        // begins new line
        ctx.beginPath();

        drawing = true;
      },false);

	  element.children()[0].addEventListener('mousemove', function(event){

        if(drawing){

        //document.getElementById('evid').style.display = "none";
        document.getElementById('evidenceImages').style.display = "none";

          // get current mouse position
          currentX = event.offsetX;
          currentY = event.offsetY;

          if((startX<currentX && startY<currentY) || (startX>currentX && startY>currentY)){
          	if(Math.abs(currentY-startY)<Math.abs(currentX-startX)) currentX = currentY-startY+startX;
          	else currentY = currentX-startX+startY;
          }
          else{
          	if(Math.abs(currentY-startY)<Math.abs(currentX-startX)) currentX = startY-currentY+startX;
          	else currentY = startX-currentX+startY;
    	  }

          // limit all the rectangle within the canvas and draw
          if(currentX >= 0 && currentX <= 360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight && currentY >= 0 && currentY <= 360){
            draw(startX, startY, currentX, currentY);
          }
        }

      },false);

      // canvas reset
      function reset(){
      	// This simple operation reset the canvas
       canvasElement.width = canvasElement.width;
       canvasB.width = canvasB.width;
       canvasE.width = canvasE.width;
      }

      element.children()[0].addEventListener('mouseup', function(event){
        // stop drawing
        drawing = false;
        //document.getElementById('evid').style.display = "";
        document.getElementById('evidenceImages').style.display = "inline-block";
      },false);

      function draw(startX, startY,
                    currentX, currentY, rotate){

        reset();
        var sizeX = currentX - startX;
        var sizeY = currentY - startY;

        ctx.rect(Math.min(startX,currentX),
                 Math.min(startY,currentY),
                 Math.abs(sizeX), Math.abs(sizeY));
        ctx.lineWidth = 3;
        // color gradient
        /*var gradient=ctx.createLinearGradient(Math.min(oppositeX,currentX),Math.min(oppositeY,currentY),Math.max(oppositeX,currentX),Math.max(oppositeY,currentY));
        gradient.addColorStop("0.05","red");
        gradient.addColorStop("0.15","blue");
        gradient.addColorStop("0.25","red");
        gradient.addColorStop("0.35","blue");
        gradient.addColorStop("0.45","red");
        gradient.addColorStop("0.55","blue");
        gradient.addColorStop("0.65","red");
        gradient.addColorStop("0.75","blue");
        gradient.addColorStop("0.85","red");
        gradient.addColorStop("0.95","blue");
        ctx.strokeStyle = gradient;*/
        // color
        ctx.strokeStyle = 'red';
        // draw it
        ctx.stroke();
        // Launch the copy process
        copy(Math.min(startX,currentX),Math.min(startY,currentY),Math.abs(sizeX),Math.abs(sizeY));
        document.getElementById("Xbox").value = Math.min(startX,currentX)/(360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight);
        document.getElementById("Ybox").value = Math.min(startY,currentY)/360;
        document.getElementById("Wbox").value = Math.abs(sizeX)/(360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight);
        document.getElementById("Hbox").value = Math.abs(sizeY)/360;
      }

      function copy(X, Y, sizeX, sizeY){

      	// Get the video source and size the second canvas according to the dimension (16:9 or 4:3)
        var src = document.getElementById('player');
        canvasB.width = 360*src.videoWidth/src.videoHeight;
        canvasB.height = 360;
        // Copy the image
        ctxb.drawImage(src,0,0,canvasB.width,canvasB.height);
        // Clip the image
        var btmp = ctxb.getImageData(X, Y, sizeX, sizeY);
        // Clear the second canvas to put the part of the image we want
        ctxb.clearRect(0,0,canvasB.width,canvasB.height);
        ctxb.putImageData(btmp,0,0);
        // Size of the last canvas
        canvasE.width = sizeX;
        canvasE.height = sizeY;
        // Copy from the second canvas to the third
        ctxe.putImageData(btmp,0,0);
        //dataURI JPEG output
        document.getElementById('evidence').src = canvasE.toDataURL("image/png", 1.0);
      }

    }
  };
});<|endoftext|>


<commit_before>'use strict';

angular.module('ddsApp').service('ResultatService', function($http, droitsDescription, CustomizationService) {

    /**
    * OpenFisca test cases separate ressources between two entities: individuals and families.
    * In Mes Aides, we don't care about this separation and want to show eligibilty results for the demandeur only.
    *@param    {Object}  An Openfisca test case. <https://doc.openfisca.fr/openfisca-web-api/input-output-data.html#test-cases>
    *@return   {Object}  A new object containing the ressources of the family and of the individual. The family ressources will be overridden if conflicting.
    */
    function normalizeOpenfiscaRessources(testCase) {
        var individuId = testCase.menages._.personne_de_reference[0];
        return _.merge({}, testCase.menages._, testCase.familles._, testCase.individus.demandeur || testCase.individus[individuId]);
    }

    function valueAt(ressourceId, ressources, period) {
        return ressources[ressourceId] && ressources[ressourceId][period];
    }

    function wasInjected(ressourceId, ressources) {
        return _.reduce(ressources[ressourceId], function(result, value) {
            return result || value;
        }, false);
    }

    function round(amount, aide) {
        if ((aide.type || 'float') != 'float') {
            return amount;
        } else if (! aide.unit && aide.roundToNearest10 !== false && (! aide.roundToNearestCent)) {
            return Math.round(amount / 10) * 10;
        } else if (aide.roundToNearestCent) {
            return Math.round(amount * 100) / 100;
        } else {
            return Math.round(amount);
        }
    }

    function computeEligibleAides(situation, computedRessources, period, customizationId, aidesProvider, injectedAides, isEligible, aide, aideId) {

        if (_.some(situation.individus, function(individu) { return wasInjected(aideId, individu); })) {
            injectedAides.push(aide);
            return;  // the aides were declared, do not re-compute the results
        }

        var value = valueAt(aideId + '_non_calculable', computedRessources, period);

        if ((! value) || value === 'calculable') {
            value = round(valueAt(aideId, computedRessources, period), aide);
        }

        if (isEligible) {
            if (! value) return;

            return _.assign({},
                aide,
                {
                    montant: value,
                    provider: aidesProvider,
                },
                customizationId && aide.customization && aide.customization[customizationId]
            );
        } else {
            if (value) return;

            return _.assign({},
                aide,
                {
                    montant: 0,
                    provider: aidesProvider,
                },
                customizationId && aide.customization && aide.customization[customizationId]
            );
        }
    }

    function computeAides(situation, openfiscaResponse) {
        var period = moment(situation.dateDeValeur).format('YYYY-MM');
        var customizationId = CustomizationService.determineCustomizationId(openfiscaResponse, period);

        var computedRessources = normalizeOpenfiscaRessources(openfiscaResponse);

        var result = {
            eligibleAides: undefined,
            nonEligibleAides: undefined,
            injectedAides: [], // declared by the user
        };

        result.eligibleAides = _.mapValues(droitsDescription, function(aidesProviders) {
            return _.mapValues(aidesProviders, function(aidesProvider) {
                var callback = computeEligibleAides.bind(null, situation, computedRessources, period, customizationId, aidesProvider, result.injectedAides, true);
                var eligibleAides = _.mapValues(aidesProvider.prestations, callback);

                return _.assign({}, aidesProvider, { prestations: _.pickBy(eligibleAides) });
            });
        });

        result.nonEligibleAides = _.mapValues(droitsDescription, function(aidesProviders) {
            return _.mapValues(aidesProviders, function(aidesProvider) {
                var callback = computeEligibleAides.bind(null, situation, computedRessources, period, customizationId, aidesProvider, result.injectedAides, false);
                var eligibleAides = _.mapValues(aidesProvider.prestations, callback);

                return _.assign({}, aidesProvider, { prestations: _.pickBy(eligibleAides) });
            });
        });

        result.eligibleAides.prestationsNationales = _.reduce(result.eligibleAides.prestationsNationales, function(aides, aidesProvider) {
            return _.assign(aides, aidesProvider.prestations);  // flatten all national prestations
        }, {});

        result.nonEligibleAides.prestationsNationales = _.reduce(result.nonEligibleAides.prestationsNationales, function(aides, aidesProvider) {
            return _.assign(aides, aidesProvider.prestations);  // flatten all national prestations
        }, {});

        result.eligibleAides.partenairesLocaux = _.pickBy(result.eligibleAides.partenairesLocaux, function(aidesProvider) {
            return _.keys(aidesProvider.prestations).length;  // exclude partenaires with no eligible prestations
        });

        return {
            droitsEligibles: result.eligibleAides,
            droitsNonEligibles: result.nonEligibleAides,
            droitsInjectes: result.injectedAides,
        };
    }

    function simulate(situation) {
        return $http.get('api/situations/' + situation._id + '/openfisca-response')
            .then(function(OpenfiscaResponse) {
                return OpenfiscaResponse.data;
            }).then(function(openfiscaResponse) {
                return computeAides(situation, openfiscaResponse);
            });
    }

    return {
        _computeAides: computeAides,  // exposed for testing only
        simulate: simulate
    };
});
<commit_msg>Refactor resultatService computeAide<commit_after>'use strict';

angular.module('ddsApp').service('ResultatService', function($http, droitsDescription, CustomizationService) {

    /**
    * OpenFisca test cases separate ressources between two entities: individuals and families.
    * In Mes Aides, we don't care about this separation and want to show eligibilty results for the demandeur only.
    *@param    {Object}  An Openfisca test case. <https://doc.openfisca.fr/openfisca-web-api/input-output-data.html#test-cases>
    *@return   {Object}  A new object containing the ressources of the family and of the individual. The family ressources will be overridden if conflicting.
    */
    function normalizeOpenfiscaRessources(testCase) {
        var individuId = testCase.menages._.personne_de_reference[0];
        return _.merge({}, testCase.menages._, testCase.familles._, testCase.individus.demandeur || testCase.individus[individuId]);
    }

    function valueAt(ressourceId, ressources, period) {
        return ressources[ressourceId] && ressources[ressourceId][period];
    }

    function wasInjected(ressourceId, ressources) {
        return _.reduce(ressources[ressourceId], function(result, value) {
            return result || value;
        }, false);
    }

    function round(amount, aide) {
        if ((aide.type || 'float') != 'float') {
            return amount;
        } else if (! aide.unit && aide.roundToNearest10 !== false && (! aide.roundToNearestCent)) {
            return Math.round(amount / 10) * 10;
        } else if (aide.roundToNearestCent) {
            return Math.round(amount * 100) / 100;
        } else {
            return Math.round(amount);
        }
    }

    function computeAides(situation, openfiscaResponse) {
        var period = moment(situation.dateDeValeur).format('YYYY-MM');
        var customizationId = CustomizationService.determineCustomizationId(openfiscaResponse, period);

        var computedRessources = normalizeOpenfiscaRessources(openfiscaResponse);

        var result = {
            eligibleAides: {},
            nonEligibleAides: {},
            injectedAides: [], // declared by the user
        };

        _.mapValues(droitsDescription, function(aidesProviders, aidesLevel) {
            result.eligibleAides[aidesLevel] = {};
            result.nonEligibleAides[aidesLevel] = {};

            _.mapValues(aidesProviders, function(aidesProvider) {
                _.forEach(aidesProvider.prestations, function(aide, aideId) {
                    if (_.some(situation.individus, function(individu) { return wasInjected(aideId, individu); })) {
                        return result.injectedAides.push(aide);
                    }

                    var value = valueAt(aideId + '_non_calculable', computedRessources, period);

                    if ((! value) || value === 'calculable') {
                        value = round(valueAt(aideId, computedRessources, period), aide);
                    }

                    var dest = (value) ? result.eligibleAides[aidesLevel] : result.nonEligibleAides[aidesLevel];
                    dest[aideId] = _.assign({},
                        aide,
                        {
                            montant: value,
                            provider: aidesProvider,
                        },
                        customizationId && aide.customization && aide.customization[customizationId]
                    );
                });
            });
        });

        result.eligibleAides.partenairesLocaux = _.pickBy(result.eligibleAides.partenairesLocaux, function(aidesProvider) {
            return _.keys(aidesProvider.prestations).length;  // exclude partenaires with no eligible prestations
        });

        return {
            droitsEligibles: result.eligibleAides,
            droitsNonEligibles: result.nonEligibleAides,
            droitsInjectes: result.injectedAides,
        };
    }

    function simulate(situation) {
        return $http.get('api/situations/' + situation._id + '/openfisca-response')
            .then(function(OpenfiscaResponse) {
                return OpenfiscaResponse.data;
            }).then(function(openfiscaResponse) {
                return computeAides(situation, openfiscaResponse);
            });
    }

    return {
        _computeAides: computeAides,  // exposed for testing only
        simulate: simulate
    };
});
<|endoftext|>