<commit_before>// Add your custom task options here...
config.init({

  lint: {
    files: ["build/config.js", "app/modules/*.js"]
  },

  concat: {

    // The core library files
    "dist/debug/js/libs.js": [
      "assets/js/libs/jquery.js",
      "assets/js/libs/underscore.js",
      "assets/js/libs/backbone.js"
    ],

    // Application files
    "dist/debug/js/app.js": ["app/*.js", "app/modules/*.js"],

    // Your CSS
    "dist/debug/css/style.css": ["assets/css/*.css"]
  },

  jst: {
    "dist/debug/js/templates.js": ["app/templates/*.html"]
  },

  min: {
    "dist/release/js/libs.js": ["dist/debug/js/libs.js"],
    "dist/release/js/app.js": ["dist/debug/js/app.js"],
    "dist/release/js/templates.js": ["dist/debug/js/templates.js"]
  },

  mincss: {
    "dist/release/css/style.css": ["dist/debug/css/style.css"]
  },

  watch: {
    files: ["assets/**/*", "app/**/*"],
    tasks: "lint:files concat jst"
  }

});

// Run the following tasks...
task.registerTask("default", "lint:files concat jst min mincss");
<commit_msg>updated config comment<commit_after>// This is the main Backbone Boilerplate build configuration file.
//
// This is a JavaScript file, you can define any functions you would like in
// here.
config.init({

  lint: {
    files: ["build/config.js", "app/modules/*.js"]
  },

  concat: {

    // The core library files
    "dist/debug/js/libs.js": [
      "assets/js/libs/jquery.js",
      "assets/js/libs/underscore.js",
      "assets/js/libs/backbone.js"
    ],

    // Application files
    "dist/debug/js/app.js": ["app/*.js", "app/modules/*.js"],

    // Your CSS
    "dist/debug/css/style.css": ["assets/css/*.css"]
  },

  jst: {
    "dist/debug/js/templates.js": ["app/templates/*.html"]
  },

  min: {
    "dist/release/js/libs.js": ["dist/debug/js/libs.js"],
    "dist/release/js/app.js": ["dist/debug/js/app.js"],
    "dist/release/js/templates.js": ["dist/debug/js/templates.js"]
  },

  mincss: {
    "dist/release/css/style.css": ["dist/debug/css/style.css"]
  },

  watch: {
    files: ["assets/**/*", "app/**/*"],
    tasks: "lint:files concat jst"
  }

});

// Run the following tasks...
task.registerTask("default", "lint:files concat jst min mincss");
<|endoftext|>


<commit_before>"use strict";

var extend = require('lodash/extend');
var oo = require('../util/oo');
var EventEmitter = require('../util/EventEmitter');
var TransactionDocument = require('./TransactionDocument');
var DefaultChangeCompressor = require('./DefaultChangeCompressor');
var Selection = require('./Selection');
var DocumentChange = require('./DocumentChange');

var __id__ = 0;

/*
  TODO: Maybe find a suitable name.
  The purpose of this class is to maintain editing related things:
    - selection
    - transactions
    - undo/redo
    - versioning
    - collaborative editing
*/
function DocumentSession(doc, options) {
  DocumentSession.super.apply(this);

  this.__id__ = __id__++;

  options = options || {};
  this.doc = doc;
  this.selection = Selection.nullSelection;

  // the stage is a essentially a clone of this document
  // used to apply a sequence of document operations
  // without touching this document
  this.stage = new TransactionDocument(this.doc, this);
  this.isTransacting = false;

  this.doneChanges = [];
  this.undoneChanges = [];

  this.compressor = options.compressor || new DefaultChangeCompressor();

  // Note: registering twice:
  // 1. once to do internal transformations in case changes are coming
  // in from another session -- this must be done as early as possible
  // 2. to trigger events, such as selection:changed -- this must
  // be done rather late, so that other listeners such as renderers
  // have finished their job already.
  this.doc.connect(this, {
    'document:changed': this.onDocumentChange
  }, { priority: 1000 });

  this.doc.connect(this, {
    'document:changed': this.afterDocumentChange
  }, { priority: -10 });

}

DocumentSession.Prototype = function() {

  this.getDocument = function() {
    return this.doc;
  };

  this.getSelection = function() {
    return this.selection;
  };

  this.setSelection = function(sel) {
    this.selection = sel;
    this.emit('selection:changed', sel, this);
    // For those who are just interested in selection changes
    // done via this method -- as opposed to implicit changes
    // via DocumentChange
    this.emit('selection:changed:explicitly', sel, this);
  };

  this.canUndo = function() {
    return this.doneChanges.length > 0;
  };

  this.canRedo = function() {
    return this.undoneChanges.length > 0;
  };

  this.undo = function() {
    var change = this.doneChanges.pop();
    if (change) {
      this.stage._apply(change);
      this.doc._apply(change);
      this.undoneChanges.push(change.invert());
      this._notifyChangeListeners(change, { 'replay': true });
    } else {
      console.error('No change can be undone.');
    }
  };

  this.redo = function() {
    var change = this.undoneChanges.pop();
    if (change) {
      this.stage._apply(change);
      this.doc._apply(change);
      this.doneChanges.push(change.invert());
      this._notifyChangeListeners(change, { 'replay': true });
    } else {
      console.error('No change can be redone.');
    }
  };

  /**
    Start a transaction to manipulate the document

    @param {function} transformation a function(tx) that performs actions on the transaction document tx

    @example

    ```js
    doc.transaction(function(tx, args) {
      tx.update(...);
      ...
      return {
        selection: newSelection
      };
    })
    ```
  */
  this.transaction = function(transformation, info) {
    /* jshint unused: false */
    if (this.isTransacting) {
      throw new Error('Nested transactions are not supported.');
    }
    this.isTransacting = true;
    this.stage.reset();
    var sel = this.selection;
    info = info || {};
    var change = this.stage._transaction(function(tx) {
      tx.before.selection = sel;
      var args = { selection: sel };
      var result = transformation(tx, args) || {};
      tx.after.selection = result.selection || sel;
      extend(info, tx.info);
    });
    if (change) {
      this.selection = change.after.selection;
      this.isTransacting = false;
      this._commit(change, info);
      this._selectionHasChanged = true;
      return change;
    } else {
      this.isTransacting = false;
    }
  };

  this.onDocumentChange = function(change, info) {
    if (info.session !== this) {
      this.stage._apply(change);
      // rebase the change history
      // TODO: as an optimization we could rebase the history lazily
      DocumentChange.transform(this.doneChanges, change);
      DocumentChange.transform(this.undoneChanges, change);
      // console.log('Transforming selection...', this.__id__);
      this._selectionHasChanged = DocumentChange.transformSelection(this.selection, change);
    } else if (info.replay) {
      var selection = change.after.selection;
      if (selection) {
        this.selection = selection;
        this._selectionHasChanged = true;
      }
    }
  };

  this.afterDocumentChange = function() {
    if (this._selectionHasChanged) {
      // console.log('selection has changed', this.__id__);
      this._selectionHasChanged = false;
      this.emit('selection:changed', this.selection, this);
    }
  };

  this._commit = function(change, info) {
    // apply the change
    change.timestamp = Date.now();
    // TODO: try to find a more explicit way, or a maybe a smarter way
    // to keep the TransactionDocument in sync
    this.doc._apply(change);

    var lastChange = this._getLastChange();
    // try to merge this change with the last to get more natural changes
    // e.g. not every keystroke, but typed words or such.
    var merged = false;
    if (lastChange && !lastChange.isFinal()) {
      if (this.compressor.shouldMerge(lastChange, change)) {
        merged = this.compressor.merge(lastChange, change);
      }
    }
    if (!merged) {
      // push to undo queue and wipe the redo queue
      this.doneChanges.push(change.invert());
    }
    this.undoneChanges = [];
    // console.log('Document._saveTransaction took %s ms', (Date.now() - time));
    // time = Date.now();
    this._notifyChangeListeners(change, info);
  };

  this._notifyChangeListeners = function(change, info) {
    info = info || {};
    info.session = this;
    // TODO: I would like to wrap this with a try catch.
    // however, debugging gets inconvenient as caught exceptions don't trigger a breakpoint
    // by default, and other libraries such as jquery throw noisily.
    this.doc._notifyChangeListeners(change, info);
  };

  this._getLastChange = function() {
    return this.doneChanges[this.doneChanges.length-1];
  };

};

oo.inherit(DocumentSession, EventEmitter);

module.exports = DocumentSession;
<commit_msg>Fix: making sure selection:changed is triggered.<commit_after>"use strict";

var extend = require('lodash/extend');
var oo = require('../util/oo');
var EventEmitter = require('../util/EventEmitter');
var TransactionDocument = require('./TransactionDocument');
var DefaultChangeCompressor = require('./DefaultChangeCompressor');
var Selection = require('./Selection');
var DocumentChange = require('./DocumentChange');

var __id__ = 0;

/*
  TODO: Maybe find a suitable name.
  The purpose of this class is to maintain editing related things:
    - selection
    - transactions
    - undo/redo
    - versioning
    - collaborative editing
*/
function DocumentSession(doc, options) {
  DocumentSession.super.apply(this);

  this.__id__ = __id__++;

  options = options || {};
  this.doc = doc;
  this.selection = Selection.nullSelection;

  // the stage is a essentially a clone of this document
  // used to apply a sequence of document operations
  // without touching this document
  this.stage = new TransactionDocument(this.doc, this);
  this.isTransacting = false;

  this.doneChanges = [];
  this.undoneChanges = [];

  this.compressor = options.compressor || new DefaultChangeCompressor();

  // Note: registering twice:
  // 1. once to do internal transformations in case changes are coming
  // in from another session -- this must be done as early as possible
  // 2. to trigger events, such as selection:changed -- this must
  // be done rather late, so that other listeners such as renderers
  // have finished their job already.
  this.doc.connect(this, {
    'document:changed': this.onDocumentChange
  }, { priority: 1000 });

  this.doc.connect(this, {
    'document:changed': this.afterDocumentChange
  }, { priority: -10 });

}

DocumentSession.Prototype = function() {

  this.getDocument = function() {
    return this.doc;
  };

  this.getSelection = function() {
    return this.selection;
  };

  this.setSelection = function(sel) {
    this.selection = sel;
    this.emit('selection:changed', sel, this);
    // For those who are just interested in selection changes
    // done via this method -- as opposed to implicit changes
    // via DocumentChange
    this.emit('selection:changed:explicitly', sel, this);
  };

  this.canUndo = function() {
    return this.doneChanges.length > 0;
  };

  this.canRedo = function() {
    return this.undoneChanges.length > 0;
  };

  this.undo = function() {
    var change = this.doneChanges.pop();
    if (change) {
      this.stage._apply(change);
      this.doc._apply(change);
      this.undoneChanges.push(change.invert());
      this._notifyChangeListeners(change, { 'replay': true });
    } else {
      console.error('No change can be undone.');
    }
  };

  this.redo = function() {
    var change = this.undoneChanges.pop();
    if (change) {
      this.stage._apply(change);
      this.doc._apply(change);
      this.doneChanges.push(change.invert());
      this._notifyChangeListeners(change, { 'replay': true });
    } else {
      console.error('No change can be redone.');
    }
  };

  /**
    Start a transaction to manipulate the document

    @param {function} transformation a function(tx) that performs actions on the transaction document tx

    @example

    ```js
    doc.transaction(function(tx, args) {
      tx.update(...);
      ...
      return {
        selection: newSelection
      };
    })
    ```
  */
  this.transaction = function(transformation, info) {
    /* jshint unused: false */
    if (this.isTransacting) {
      throw new Error('Nested transactions are not supported.');
    }
    this.isTransacting = true;
    this.stage.reset();
    var sel = this.selection;
    info = info || {};
    var change = this.stage._transaction(function(tx) {
      tx.before.selection = sel;
      var args = { selection: sel };
      var result = transformation(tx, args) || {};
      tx.after.selection = result.selection || sel;
      extend(info, tx.info);
    });
    if (change) {
      this.selection = change.after.selection;
      this.isTransacting = false;
      this._selectionHasChanged = true;
      this._commit(change, info);
      return change;
    } else {
      this.isTransacting = false;
    }
  };

  this.onDocumentChange = function(change, info) {
    if (info.session !== this) {
      this.stage._apply(change);
      // rebase the change history
      // TODO: as an optimization we could rebase the history lazily
      DocumentChange.transform(this.doneChanges, change);
      DocumentChange.transform(this.undoneChanges, change);
      // console.log('Transforming selection...', this.__id__);
      this._selectionHasChanged = DocumentChange.transformSelection(this.selection, change);
    } else if (info.replay) {
      var selection = change.after.selection;
      if (selection) {
        this.selection = selection;
        this._selectionHasChanged = true;
      }
    }
  };

  this.afterDocumentChange = function() {
    if (this._selectionHasChanged) {
      // console.log('selection has changed', this.__id__);
      this._selectionHasChanged = false;
      this.emit('selection:changed', this.selection, this);
    }
  };

  this._commit = function(change, info) {
    // apply the change
    change.timestamp = Date.now();
    // TODO: try to find a more explicit way, or a maybe a smarter way
    // to keep the TransactionDocument in sync
    this.doc._apply(change);

    var lastChange = this._getLastChange();
    // try to merge this change with the last to get more natural changes
    // e.g. not every keystroke, but typed words or such.
    var merged = false;
    if (lastChange && !lastChange.isFinal()) {
      if (this.compressor.shouldMerge(lastChange, change)) {
        merged = this.compressor.merge(lastChange, change);
      }
    }
    if (!merged) {
      // push to undo queue and wipe the redo queue
      this.doneChanges.push(change.invert());
    }
    this.undoneChanges = [];
    // console.log('Document._saveTransaction took %s ms', (Date.now() - time));
    // time = Date.now();
    this._notifyChangeListeners(change, info);
  };

  this._notifyChangeListeners = function(change, info) {
    info = info || {};
    info.session = this;
    // TODO: I would like to wrap this with a try catch.
    // however, debugging gets inconvenient as caught exceptions don't trigger a breakpoint
    // by default, and other libraries such as jquery throw noisily.
    this.doc._notifyChangeListeners(change, info);
  };

  this._getLastChange = function() {
    return this.doneChanges[this.doneChanges.length-1];
  };

};

oo.inherit(DocumentSession, EventEmitter);

module.exports = DocumentSession;
<|endoftext|>


<commit_before>// General mathematical functions that are used during simulations
function TimeUntilEvent(Probability)
{
	// r=annual probability
	// p=random number between 0 and 1
	// p=r^t
	// p=e^(ln(r)t)
	// t=ln(p)/ln(r)
	return (Math.log(lcg.rand())/Math.log(1-Probability));
}

// Zero matrix
function ZeroMatrix(xsize, ysize){
	ReturnMatrix=[]
	ZeroVector=[];
	for (i=0; i<ysize; i++){
		ZeroVector[i]=0;
	}
	for (i=0; i<xsize; i++){
		ReturnMatrix[i]=ZeroVector.slice();//used to copy array, rather than copy a pointer to the array
	}
	return ReturnMatrix;
}

function MultiplyArr(Array1, Array2){
	if (Array1.length!=Array2.length){
		error("Arrays are incorrect length");
	}
	ArrayResult=new Array(Array1.length);

	for (i=0; i<Array1.length;i++){
		ArrayResult[i]=Array1[i]*Array2[i];
	}

	return ArrayResult;
}

// Event vector
function EventVector(){
	this.Value=[];
	this.Time=[];
	this.NumberOfEvents=0;
}

EventVector.prototype.Set= function (Value, Time){
	if (this.NumberOfEvents>0){
		//Determine if the current time is prior the last time
		if (Time<=this.Time[this.NumberOfEvents-1]){//falls directly on that time, delete because we don't want zero time events
			//Determine where the current event would sit
			Current=this.Get(Time);
			if (Current.Time==Time){//falls directly on that time, delete because we don't want zero time events
				PosToDelete=Current.Pos;
			}else{
				PosToDelete=Current.Pos+1;
			}
			NumToDelete=this.NumberOfEvents-PosToDelete;
			//if there dates after this one, delete all future events
			this.Value.splice(PosToDelete, NumToDelete);
			this.Time.splice(PosToDelete, NumToDelete);
			this.NumberOfEvents=PosToDelete;
		}
	}
	//Add new items to the end of the array
	this.Value.push(Value);
	this.Time.push(Time);
	this.NumberOfEvents++;
};

EventVector.prototype.Get= function (Time){
	//Current.Value=Value at this time
	//Current.Time=Time when this value first started
	//Current.Pos=Position in the array that this time occurred
	var Current={};
	if (this.NumberOfEvents==0){// if no times are set
		Current.Value=Number.NaN;
		Current.Time=Number.NaN;
		Current.Pos=Number.NaN;
		return Current;
	}
	else if (Time<this.Time[0]){ // if before the first one is set
		Current.Value=Number.NaN;
		Current.Time=Number.NaN;
		Current.Pos=-1;//note the negative position indicates the position relative to the zeroth index (i.e. this event occurs prior to i=0)
		return Current;
	}
	else if (this.Time[this.NumberOfEvents-1]<=Time){ // if after the last time
		Current.Value=this.Value[this.NumberOfEvents-1];
		Current.Time=this.Time[this.NumberOfEvents-1];
		Current.Pos=this.NumberOfEvents-1;
		return Current;
	}
	else {//loop through all the middle places (the above should have ensured that there are at least 2 items in the array)
		for (var i=0; i<this.NumberOfEvents-1; i++){
			if (this.Time[i]<=Time&&Time<this.Time[i+1]){
				Current.Value=this.Value[i];
				Current.Time=this.Time[i];
				Current.Pos=i;
				return Current;
			}
		}
	}
}<commit_msg>Adding other vector operations<commit_after>// General mathematical functions that are used during simulations
function TimeUntilEvent(Probability)
{
	// r=annual probability
	// p=random number between 0 and 1
	// p=r^t
	// p=e^(ln(r)t)
	// t=ln(p)/ln(r)
	return (Math.log(lcg.rand())/Math.log(1-Probability));
}

// Zero matrix
function ZeroMatrix(xsize, ysize){
	ReturnMatrix=[]
	ZeroVector=[];
	for (i=0; i<ysize; i++){
		ZeroVector[i]=0;
	}
	for (i=0; i<xsize; i++){
		ReturnMatrix[i]=ZeroVector.slice();//used to copy array, rather than copy a pointer to the array
	}
	return ReturnMatrix;
}

function AddArrays(Array1, Array2){
	if (Array1.length!=Array2.length){
		error("Arrays are incorrect length");
	}
	ArrayResult=new Array(Array1.length);

	for (i=0; i<Array1.length;i++){
		ArrayResult[i]=Array1[i]+Array2[i];
	}
	return ArrayResult;
}

function MinusArrays(Array1, Array2){
	if (Array1.length!=Array2.length){
		error("Arrays are incorrect length");
	}
	ArrayResult=new Array(Array1.length);

	for (i=0; i<Array1.length;i++){
		ArrayResult[i]=Array1[i]-Array2[i];
	}
	return ArrayResult;
}

function MultiplyArrays(Array1, Array2){
	if (Array1.length!=Array2.length){
		error("Arrays are incorrect length");
	}
	ArrayResult=new Array(Array1.length);

	for (i=0; i<Array1.length;i++){
		ArrayResult[i]=Array1[i]*Array2[i];
	}
	return ArrayResult;
}

function DivideArrays(Array1, Array2){
	if (Array1.length!=Array2.length){
		error("Arrays are incorrect length");
	}
	ArrayResult=new Array(Array1.length);

	for (i=0; i<Array1.length;i++){
		ArrayResult[i]=Array1[i]/Array2[i];
	}
	return ArrayResult;
}

// Event vector
function EventVector(){
	this.Value=[];
	this.Time=[];
	this.NumberOfEvents=0;
}

EventVector.prototype.Set= function (Value, Time){
	if (this.NumberOfEvents>0){
		//Determine if the current time is prior the last time
		if (Time<=this.Time[this.NumberOfEvents-1]){//falls directly on that time, delete because we don't want zero time events
			//Determine where the current event would sit
			Current=this.Get(Time);
			if (Current.Time==Time){//falls directly on that time, delete because we don't want zero time events
				PosToDelete=Current.Pos;
			}else{
				PosToDelete=Current.Pos+1;
			}
			NumToDelete=this.NumberOfEvents-PosToDelete;
			//if there dates after this one, delete all future events
			this.Value.splice(PosToDelete, NumToDelete);
			this.Time.splice(PosToDelete, NumToDelete);
			this.NumberOfEvents=PosToDelete;
		}
	}
	//Add new items to the end of the array
	this.Value.push(Value);
	this.Time.push(Time);
	this.NumberOfEvents++;
};

EventVector.prototype.Get= function (Time){
	//Current.Value=Value at this time
	//Current.Time=Time when this value first started
	//Current.Pos=Position in the array that this time occurred
	var Current={};
	if (this.NumberOfEvents==0){// if no times are set
		Current.Value=Number.NaN;
		Current.Time=Number.NaN;
		Current.Pos=Number.NaN;
		return Current;
	}
	else if (Time<this.Time[0]){ // if before the first one is set
		Current.Value=Number.NaN;
		Current.Time=Number.NaN;
		Current.Pos=-1;//note the negative position indicates the position relative to the zeroth index (i.e. this event occurs prior to i=0)
		return Current;
	}
	else if (this.Time[this.NumberOfEvents-1]<=Time){ // if after the last time
		Current.Value=this.Value[this.NumberOfEvents-1];
		Current.Time=this.Time[this.NumberOfEvents-1];
		Current.Pos=this.NumberOfEvents-1;
		return Current;
	}
	else {//loop through all the middle places (the above should have ensured that there are at least 2 items in the array)
		for (var i=0; i<this.NumberOfEvents-1; i++){
			if (this.Time[i]<=Time&&Time<this.Time[i+1]){
				Current.Value=this.Value[i];
				Current.Time=this.Time[i];
				Current.Pos=i;
				return Current;
			}
		}
	}
}<|endoftext|>


<commit_before>'use strict';

let mongoose = require('mongoose');
require('mongoose-double')(mongoose);

var SchemaTypes = mongoose.Schema.Types;

// Defining producer schema - similar as EF code first for db entry
let producerSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true,
        unique: true
    },
    description: {
        type: String,
        required: true
    },
    type: {
        type: String,
        required: true,
        lowercase: true
        // enum: [Array]
    },
    mainProducts: {
        type: Array,
        required: true
    },
    telephone: {
        type: String
    },
    email: {
        type: String,
        required: true,
        lowercase: true,
        match: /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
    },
    addressLongitude: {
        type: SchemaTypes.Double
    },
    addressLatitude: {
        type: SchemaTypes.Double
    },
    userId: {
        type: String,
        required: true
    },
    isDeleted: {
        type: Boolean,
        required: true
    },
    logo: {
        type: Array
    }
});

mongoose.model('Producer', producerSchema);
<commit_msg>Location more<commit_after>'use strict';

let mongoose = require('mongoose');
require('mongoose-double')(mongoose);

var SchemaTypes = mongoose.Schema.Types;

// Defining producer schema - similar as EF code first for db entry
let producerSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true,
        unique: true
    },
    description: {
        type: String,
        required: true
    },
    type: {
        type: String,
        required: true,
        lowercase: true
        // enum: [Array]
    },
    mainProducts: {
        type: Array,
        required: true
    },
    telephone: {
        type: String
    },
    email: {
        type: String,
        required: true,
        lowercase: true,
        match: /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
    },
    addressLongitude: {
        type: String
    },
    addressLatitude: {
        type: String
    },
    userId: {
        type: String,
        required: true
    },
    isDeleted: {
        type: Boolean,
        required: true
    },
    logo: {
        type: Array
    }
});

mongoose.model('Producer', producerSchema);
<|endoftext|>


<commit_before>import React, { Component } from 'react'

import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableHighlight,
  NativeModules,
  requireNativeComponent,
  Alert,
  Dimensions,
  Button,
  DeviceEventEmitter,
  Platform,
  PixelRatio,
  PermissionsAndroid
} from 'react-native'

var RNFS = require('react-native-fs')

var ReactNative = require('react-native')
import IMUI from 'aurora-imui-react-native'
var InputView = IMUI.ChatInput
var MessageListView = IMUI.MessageList
const AuroraIController = IMUI.AuroraIMUIController
const window = Dimensions.get('window')
const getInputTextEvent = "getInputText"
const MessageListDidLoadEvent = "IMUIMessageListDidLoad"

var themsgid = 1

function constructNormalMessage() {

  var message = {}
  message.msgId = themsgid.toString()
  themsgid += 1
  message.status = "send_going"
  message.isOutgoing = true
  var date = new Date()
  message.timeString = date.getHours() + ":" + date.getMinutes()
  var user = {
    userId: "",
    displayName: "replace your nickname",
    avatarPath: "images"
  }

  if (Platform.OS === "ios") {
    user.avatarPath = RNFS.MainBundlePath + '/default_header.png'
  }

  message.fromUser = user

  return message
}

class CustomVew extends Component {
  constructor(props) {
    super(props);
    this.state = {
    };
  }
  render() {
    return (<img src={`${RNFS.MainBundlePath}/default_header.png`}>)
  }
}

export default class TestRNIMUI extends Component {
  constructor(props) {
    super(props);
    let initHeight;
    if (Platform.OS === "ios") {
      initHeight = 86
    } else {
      initHeight = 100
    }
    this.state = {
      inputLayoutHeight: initHeight,
      messageListLayout: {flex: 1, width: window.width, margin: 0},
      inputViewLayout: { width: window.width, height: initHeight, },
      isAllowPullToRefresh: true,
      navigationBar: {}
    }

    this.updateLayout = this.updateLayout.bind(this);
  }

  componentDidMount() {
    AuroraIController.compressImage({path: "/storage/emulated/0/DCIM/Camera/IMG_20180305_164154.jpg", compressionQuality: 0.5}, (result) => {
      console.log(JSON.stringify(result))
      var message = constructNormalMessage()
      message.mediaPath = result.thumbPath
      message.msgType = "image"
      AuroraIController.appendMessages([message])
    })
    this.resetMenu()
    AuroraIController.addMessageListDidLoadListener(() => {
      this.getHistoryMessage()
    });
  }

  getHistoryMessage() {
    var messages = []
    for (var i = 0; i < 1; i++) {
      // var message = constructNormalMessage()
      // message.msgType = "text"
      // message.text = "" + i
      // if (i%2 == 0)  {
      //   message.isOutgoing = false
      // }
      var message = constructNormalMessage()
      message.msgType = 'custom'

      if (Platform.OS === "ios") {
        message.content = `

This is a custom message.

        `
      } else {
        message.content = '
This is a custom message.
\
        '
      }

      var eventMessage = constructNormalMessage()
      eventMessage.msgType = "event"
      eventMessage.text = 'fsadfad'

      message.contentSize = { 'height': 100, 'width': 200 }
      message.extras = { "extras": "fdfsf" }
      AuroraIController.appendMessages([message,eventMessage])
      AuroraIController.scrollToBottom(true)

      AuroraIController.insertMessagesToTop([message])
    }
  }

  onInputViewSizeChange = (size) => {
    console.log("height: " + size.height + " width: " + size.width)
    if (this.state.inputLayoutHeight != size.height) {
      this.setState({
        inputLayoutHeight: size.height,
        inputViewLayout: { width: window.width, height: size.height },
        messageListLayout: { flex:1, width: window.width, margin: 0 }
      })
    }
  }

  componentWillUnmount() {
    AuroraIController.removeMessageListDidLoadListener(MessageListDidLoadEvent)
  }

  resetMenu() {
    if (Platform.OS === "android") {
      this.refs["ChatInput"].showMenu(false)
      this.setState({
        messageListLayout: { flex: 1, width: window.width, margin: 0 },
        navigationBar: { height: 64, justifyContent: 'center' },
      })
      this.forceUpdate();
    } else {
      AuroraIController.hidenFeatureView(true)
    }
  }

  onTouchEditText = () => {
    this.refs["ChatInput"].showMenu(false)
    this.setState({
      inputViewLayout: { width: window.width, height: this.state.inputLayoutHeight }
    })
    // if (this.state.shouldExpandMenuContainer) {
    //   console.log("on touch input, expend menu")
    //   this.expendMenu()
    // }
  }

  onFullScreen = () => {
    console.log("on full screen")
    this.setState({
      messageListLayout: { flex: 0, width: 0, height: 0 },
      inputViewLayout: { flex:1, width: window.width, height: window.height },
      navigationBar: { height: 0 }
    })
  }

  onRecoverScreen = () => {
    this.setState({
      messageListLayout: { flex: 1, width: window.width, margin: 0 },
      inputViewLayout: { flex: 0, width: window.width, height: this.state.inputLayoutHeight },
      navigationBar: { height: 64, justifyContent: 'center' }
    })
  }

  onAvatarClick = (message) => {
    Alert.alert()
    AuroraIController.removeMessage(message.msgId)
  }

  onMsgClick = (message) => {
    console.log(message)
    Alert.alert("message", JSON.stringify(message))
  }

  onMsgLongClick = (message) => {
    Alert.alert('message bubble on long press', 'message bubble on long press')
  }

  onStatusViewClick = (message) => {
    message.status = 'send_succeed'
    AuroraIController.updateMessage(message)
  }

  onBeginDragMessageList = () => {
    this.resetMenu()
    AuroraIController.hidenFeatureView(true)
  }

  onTouchMsgList = () => {
    AuroraIController.hidenFeatureView(true)
  }

  onPullToRefresh = () => {
    console.log("on pull to refresh")
    var messages = []
    for (var i = 0; i < 14; i++) {
      var message = constructNormalMessage()
      // if (index%2 == 0) {
      message.msgType = "text"
      message.text = "" + i
      // }

      if (i % 3 == 0) {
        message.msgType = "event"
        message.text = "" + i
      }

      AuroraIController.insertMessagesToTop([message])
    }
    AuroraIController.insertMessagesToTop(messages)
    if (Platform.OS === 'android') {
      this.refs["MessageList"].refreshComplete()
    }

  }

  onSendText = (text) => {
    var message = constructNormalMessage()
    var evenmessage = constructNormalMessage()

    message.msgType = 'text'
    message.text = text

    AuroraIController.appendMessages([message])
  }

  onTakePicture = (media) => {
    console.log("media " + JSON.stringify(media))
    var message = constructNormalMessage()
    message.msgType = 'image'
    message.mediaPath = media.mediaPath
    AuroraIController.appendMessages([message])
    this.resetMenu()
    AuroraIController.scrollToBottom(true)
  }

  onStartRecordVoice = (e) => {
    console.log("on start record voice")
  }

  onFinishRecordVoice = (mediaPath, duration) => {
    var message = constructNormalMessage()
    message.msgType = "voice"
    message.mediaPath = mediaPath
    message.timeString = "safsdfa"
    message.duration = duration
    AuroraIController.appendMessages([message])
    console.log("on start record voice")
  }

  onCancelRecordVoice = () => {
    console.log("on cancel record voice")
  }

  onStartRecordVideo = () => {
    console.log("on start record video")
  }

  onFinishRecordVideo = (video) => {
    var message = constructNormalMessage()
    message.msgType = "video"
    message.mediaPath = video.mediaPath
    message.duration = video.duration
    AuroraIController.appendMessages([message])
  }

  onSendGalleryFiles = (mediaFiles) => {
    /**
     * WARN: This callback will return original image,
     * if insert it directly will high memory usage and blocking UI。
     * You should crop the picture before insert to messageList。
     *
     * WARN: 这里返回的是原图，直接插入大会话列表会很大且耗内存.
     * 应该做裁剪操作后再插入到 messageListView 中，
     * 一般的 IM SDK 会提供裁剪操作，或者开发者手动进行裁剪。
     *
     * 代码用例不做裁剪操作。
     */
    Alert.alert('fas',JSON.stringify(mediaFiles))
    for (index in mediaFiles) {
      var message = constructNormalMessage()
      if (mediaFiles[index].mediaType == "image") {
        message.msgType = "image"
      } else {
        message.msgType = "video"
        message.duration = mediaFiles[index].duration
      }

      message.mediaPath = mediaFiles[index].mediaPath
      message.timeString = "8:00"
      AuroraIController.appendMessages([message])
      AuroraIController.scrollToBottom(true)
    }

    this.resetMenu()
  }

  onSwitchToMicrophoneMode = () => {
    AuroraIController.scrollToBottom(true)
  }

  onSwitchToEmojiMode = () => {
    AuroraIController.scrollToBottom(true)
  }
  onSwitchToGalleryMode = () => {
    AuroraIController.scrollToBottom(true)
  }

  onSwitchToCameraMode = () => {
    AuroraIController.scrollToBottom(true)
  }

  onShowKeyboard = (keyboard_height) => {
  }

  updateLayout(layout) {
    this.setState({ inputViewLayout: layout })
  }

  onInitPress() {
    console.log('on click init push ');
    this.updateAction();
  }

  onClickSelectAlbum = () => {
    console.log("on click select album")
  }

  render() {
    return (
      <View style={styles.container}>
        <View style={this.state.navigationBar}
          ref="NavigatorView">
          <Button
            style={styles.sendCustomBtn}
            title="Custom Message"
            onPress={() => {
              if (Platform.OS === 'ios') {
                var message = constructNormalMessage()
                message.msgType = 'custom'
                message.content = `

This is a custom message.

                `
                console.log(message.content)
                message.contentSize = { 'height': 100, 'width': 200 }
                message.extras = { "extras": "fdfsf" }
                AuroraIController.appendMessages([message])
                AuroraIController.scrollToBottom(true)
              } else {
                var message = constructNormalMessage()
                message.msgType = "custom"
                message.msgId = "10"
                message.status = "send_going"
                message.isOutgoing = true
                message.content = `

This is a custom message.

                `
                message.contentSize = { 'height': 400, 'width': 400 }
                message.extras = { "extras": "fdfsf" }
                var user = {
                  userId: "1",
                  displayName: "",
                  avatarPath: ""
                }
                user.displayName = "0001"
                user.avatarPath = "ironman"
                message.fromUser = user
                AuroraIController.appendMessages([message]);
              }
            }}>
          </Button>
        </View>
        <MessageListView style={this.state.messageListLayout}
          ref="MessageList"
          isAllowPullToRefresh={false}
          onAvatarClick={this.onAvatarClick}
          onMsgClick={this.onMsgClick}
          onStatusViewClick={this.onStatusViewClick}
          onTouchMsgList={this.onTouchMsgList}
          onTapMessageCell={this.onTapMessageCell}
          onBeginDragMessageList={this.onBeginDragMessageList}
          onPullToRefresh={this.onPullToRefresh}
          avatarSize={{ width: 50, height: 50 }}
          avatarCornerRadius={60}
          messageListBackgroundColor={"#f3f3f3"}
          sendBubbleTextSize={18}
          sendBubbleTextColor={"#000000"}
          sendBubblePadding={{ left: 10, top: 10, right: 15, bottom: 10 }}
          datePadding={{ left: 5, top: 5, right: 5, bottom: 5 }}
          dateBackgroundColor={"#39ef23"}
          isAllowPullToRefresh={true}
        />
        <InputView style={this.state.inputViewLayout}
          ref="ChatInput"
          menuContainerHeight={this.state.menuContainerHeight}
          isDismissMenuContainer={this.state.isDismissMenuContainer}
          onSendText={this.onSendText}
          onTakePicture={this.onTakePicture}
          onStartRecordVoice={this.onStartRecordVoice}
          onFinishRecordVoice={this.onFinishRecordVoice}
          onCancelRecordVoice={this.onCancelRecordVoice}
          onStartRecordVideo={this.onStartRecordVideo}
          onFinishRecordVideo={this.onFinishRecordVideo}
          onSendGalleryFiles={this.onSendGalleryFiles}
          onSwitchToEmojiMode={this.onSwitchToEmojiMode}
          onSwitchToMicrophoneMode={this.onSwitchToMicrophoneMode}
          onSwitchToGalleryMode={this.onSwitchToGalleryMode}
          onSwitchToCameraMode={this.onSwitchToCameraMode}
          onShowKeyboard={this.onShowKeyboard}
          onTouchEditText={this.onTouchEditText}
          onFullScreen={this.onFullScreen}
          onRecoverScreen={this.onRecoverScreen}
          onSizeChange={this.onInputViewSizeChange}
          showSelectAlbumBtn={true}
          onClickSelectAlbum={this.onClickSelectAlbum}
          galleryScale={0.6}//default = 0.5
          compressionQuality={0.6}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  sendCustomBtn: {

  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  inputView: {
    backgroundColor: 'green',
    width: window.width,
    height: 100,
  },
  btnStyle: {
    marginTop: 10,
    borderWidth: 1,
    borderColor: '#3e83d7',
    borderRadius: 8,
    backgroundColor: '#3e83d7'
  }
});

<commit_msg>update demo<commit_after>import React, { Component } from 'react'

import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableHighlight,
  NativeModules,
  requireNativeComponent,
  Alert,
  Dimensions,
  Button,
  DeviceEventEmitter,
  Platform,
  PixelRatio,
  PermissionsAndroid
} from 'react-native'

var RNFS = require('react-native-fs')

var ReactNative = require('react-native')
import IMUI from 'aurora-imui-react-native'
var InputView = IMUI.ChatInput
var MessageListView = IMUI.MessageList
const AuroraIController = IMUI.AuroraIMUIController
const window = Dimensions.get('window')
const getInputTextEvent = "getInputText"
const MessageListDidLoadEvent = "IMUIMessageListDidLoad"

var themsgid = 1

function constructNormalMessage() {

  var message = {}
  message.msgId = themsgid.toString()
  themsgid += 1
  message.status = "send_going"
  message.isOutgoing = true
  var date = new Date()
  message.timeString = date.getHours() + ":" + date.getMinutes()
  var user = {
    userId: "",
    displayName: "replace your nickname",
    avatarPath: "images"
  }

  if (Platform.OS === "ios") {
    user.avatarPath = RNFS.MainBundlePath + '/default_header.png'
  }

  message.fromUser = user

  return message
}

class CustomVew extends Component {
  constructor(props) {
    super(props);
    this.state = {
    };
  }
  render() {
    return (<img src={`${RNFS.MainBundlePath}/default_header.png`}>)
  }
}

export default class TestRNIMUI extends Component {
  constructor(props) {
    super(props);
    let initHeight;
    if (Platform.OS === "ios") {
      initHeight = 86
    } else {
      initHeight = 100
    }
    this.state = {
      inputLayoutHeight: initHeight,
      messageListLayout: {flex: 1, width: window.width, margin: 0},
      inputViewLayout: { width: window.width, height: initHeight, },
      isAllowPullToRefresh: true,
      navigationBar: {}
    }

    this.updateLayout = this.updateLayout.bind(this);
  }

  componentDidMount() {
    AuroraIController.compressImage({path: "/storage/emulated/0/DCIM/Camera/IMG_20180305_164154.jpg", compressionQuality: 0.5}, (result) => {
      console.log(JSON.stringify(result))
      var message = constructNormalMessage()
      message.mediaPath = result.thumbPath
      message.msgType = "image"
      AuroraIController.appendMessages([message])
    })
    this.resetMenu()
    AuroraIController.addMessageListDidLoadListener(() => {
      this.getHistoryMessage()
    });
  }

  getHistoryMessage() {
    var messages = []
    for (var i = 0; i < 1; i++) {
      // var message = constructNormalMessage()
      // message.msgType = "text"
      // message.text = "" + i
      // if (i%2 == 0)  {
      //   message.isOutgoing = false
      // }
      var message = constructNormalMessage()
      message.msgType = 'custom'

      if (Platform.OS === "ios") {
        message.content = `

This is a custom message.

        `
      } else {
        message.content = '
This is a custom message.
\
        '
      }

      var eventMessage = constructNormalMessage()
      eventMessage.msgType = "event"
      eventMessage.text = 'fsadfad'

      message.contentSize = { 'height': 100, 'width': 200 }
      message.extras = { "extras": "fdfsf" }
      AuroraIController.appendMessages([message,eventMessage])
      AuroraIController.scrollToBottom(true)

      AuroraIController.insertMessagesToTop([message])
    }
  }

  onInputViewSizeChange = (size) => {
    console.log("height: " + size.height + " width: " + size.width)
    if (this.state.inputLayoutHeight != size.height) {
      this.setState({
        inputLayoutHeight: size.height,
        inputViewLayout: { width: window.width, height: size.height },
        messageListLayout: { flex:1, width: window.width, margin: 0 }
      })
    }
  }

  componentWillUnmount() {
    AuroraIController.removeMessageListDidLoadListener(MessageListDidLoadEvent)
  }

  resetMenu() {
    if (Platform.OS === "android") {
      this.refs["ChatInput"].showMenu(false)
      this.setState({
        messageListLayout: { flex: 1, width: window.width, margin: 0 },
        navigationBar: { height: 64, justifyContent: 'center' },
      })
      this.forceUpdate();
    } else {
      AuroraIController.hidenFeatureView(true)
    }
  }

  onTouchEditText = () => {
    this.refs["ChatInput"].showMenu(false)
    this.setState({
      inputViewLayout: { width: window.width, height: this.state.inputLayoutHeight }
    })
    // if (this.state.shouldExpandMenuContainer) {
    //   console.log("on touch input, expend menu")
    //   this.expendMenu()
    // }
  }

  onFullScreen = () => {
    console.log("on full screen")
    this.setState({
      messageListLayout: { flex: 0, width: 0, height: 0 },
      inputViewLayout: { flex:1, width: window.width, height: window.height },
      navigationBar: { height: 0 }
    })
  }

  onRecoverScreen = () => {
    this.setState({
      messageListLayout: { flex: 1, width: window.width, margin: 0 },
      inputViewLayout: { flex: 0, width: window.width, height: this.state.inputLayoutHeight },
      navigationBar: { height: 64, justifyContent: 'center' }
    })
  }

  onAvatarClick = (message) => {
    Alert.alert()
    AuroraIController.removeMessage(message.msgId)
  }

  onMsgClick = (message) => {
    console.log(message)
    Alert.alert("message", JSON.stringify(message))
  }

  onMsgLongClick = (message) => {
    Alert.alert('message bubble on long press', 'message bubble on long press')
  }

  onStatusViewClick = (message) => {
    message.status = 'send_succeed'
    AuroraIController.updateMessage(message)
  }

  onBeginDragMessageList = () => {
    this.resetMenu()
    AuroraIController.hidenFeatureView(true)
  }

  onTouchMsgList = () => {
    AuroraIController.hidenFeatureView(true)
  }

  onPullToRefresh = () => {
    console.log("on pull to refresh")
    var messages = []
    for (var i = 0; i < 14; i++) {
      var message = constructNormalMessage()
      // if (index%2 == 0) {
      message.msgType = "text"
      message.text = "" + i
      // }

      if (i % 3 == 0) {
        message.msgType = "event"
        message.text = "" + i
      }

      AuroraIController.insertMessagesToTop([message])
    }
    AuroraIController.insertMessagesToTop(messages)
    if (Platform.OS === 'android') {
      this.refs["MessageList"].refreshComplete()
    }

  }

  onSendText = (text) => {
    var message = constructNormalMessage()
    var evenmessage = constructNormalMessage()

    message.msgType = 'text'
    message.text = text

    AuroraIController.appendMessages([message])
  }

  onTakePicture = (media) => {
    console.log("media " + JSON.stringify(media))
    var message = constructNormalMessage()
    message.msgType = 'image'
    message.mediaPath = media.mediaPath
    AuroraIController.appendMessages([message])
    this.resetMenu()
    AuroraIController.scrollToBottom(true)
  }

  onStartRecordVoice = (e) => {
    console.log("on start record voice")
  }

  onFinishRecordVoice = (mediaPath, duration) => {
    var message = constructNormalMessage()
    message.msgType = "voice"
    message.mediaPath = mediaPath
    message.timeString = "safsdfa"
    message.duration = duration
    AuroraIController.appendMessages([message])
    console.log("on start record voice")
  }

  onCancelRecordVoice = () => {
    console.log("on cancel record voice")
  }

  onStartRecordVideo = () => {
    console.log("on start record video")
  }

  onFinishRecordVideo = (video) => {
    var message = constructNormalMessage()
    message.msgType = "video"
    message.mediaPath = video.mediaPath
    message.duration = video.duration
    AuroraIController.appendMessages([message])
  }

  onSendGalleryFiles = (mediaFiles) => {
    /**
     * WARN: This callback will return original image,
     * if insert it directly will high memory usage and blocking UI。
     * You should crop the picture before insert to messageList。
     *
     * WARN: 这里返回的是原图，直接插入大会话列表会很大且耗内存.
     * 应该做裁剪操作后再插入到 messageListView 中，
     * 一般的 IM SDK 会提供裁剪操作，或者开发者手动进行裁剪。
     *
     * 代码用例不做裁剪操作。
     */
    Alert.alert('fas',JSON.stringify(mediaFiles))
    for (index in mediaFiles) {
      var message = constructNormalMessage()
      if (mediaFiles[index].mediaType == "image") {
        message.msgType = "image"
      } else {
        message.msgType = "video"
        message.duration = mediaFiles[index].duration
      }

      message.mediaPath = mediaFiles[index].mediaPath
      message.timeString = "8:00"
      AuroraIController.appendMessages([message])
      AuroraIController.scrollToBottom(true)
    }

    this.resetMenu()
  }

  onSwitchToMicrophoneMode = () => {
    AuroraIController.scrollToBottom(true)
  }

  onSwitchToEmojiMode = () => {
    AuroraIController.scrollToBottom(true)
  }
  onSwitchToGalleryMode = () => {
    AuroraIController.scrollToBottom(true)
  }

  onSwitchToCameraMode = () => {
    AuroraIController.scrollToBottom(true)
  }

  onShowKeyboard = (keyboard_height) => {
  }

  updateLayout(layout) {
    this.setState({ inputViewLayout: layout })
  }

  onInitPress() {
    console.log('on click init push ');
    this.updateAction();
  }

  onClickSelectAlbum = () => {
    console.log("on click select album")
  }

  render() {
    return (
      <View style={styles.container}>
        <View style={this.state.navigationBar}
          ref="NavigatorView">
          <Button
            style={styles.sendCustomBtn}
            title="Custom Message"
            onPress={() => {
              if (Platform.OS === 'ios') {
                var message = constructNormalMessage()
                message.msgType = 'custom'
                message.content = `

This is a custom message.

                `
                console.log(message.content)
                message.contentSize = { 'height': 100, 'width': 200 }
                message.extras = { "extras": "fdfsf" }
                AuroraIController.appendMessages([message])
                AuroraIController.scrollToBottom(true)
              } else {
                var message = constructNormalMessage()
                message.msgType = "custom"
                message.msgId = "10"
                message.status = "send_going"
                message.isOutgoing = true
                message.content = `

This is a custom message.

                `
                message.contentSize = { 'height': 400, 'width': 400 }
                message.extras = { "extras": "fdfsf" }
                var user = {
                  userId: "1",
                  displayName: "",
                  avatarPath: ""
                }
                user.displayName = "0001"
                user.avatarPath = "ironman"
                message.fromUser = user
                AuroraIController.appendMessages([message]);
              }
            }}>
          </Button>
        </View>
        <MessageListView style={this.state.messageListLayout}
          ref="MessageList"
          isAllowPullToRefresh={true}
          onAvatarClick={this.onAvatarClick}
          onMsgClick={this.onMsgClick}
          onStatusViewClick={this.onStatusViewClick}
          onTouchMsgList={this.onTouchMsgList}
          onTapMessageCell={this.onTapMessageCell}
          onBeginDragMessageList={this.onBeginDragMessageList}
          onPullToRefresh={this.onPullToRefresh}
          avatarSize={{ width: 50, height: 50 }}
          avatarCornerRadius={60}
          messageListBackgroundColor={"#f3f3f3"}
          sendBubbleTextSize={18}
          sendBubbleTextColor={"#000000"}
          sendBubblePadding={{ left: 10, top: 10, right: 15, bottom: 10 }}
          datePadding={{ left: 5, top: 5, right: 5, bottom: 5 }}
          dateBackgroundColor={"#39ef23"}
        />
        <InputView style={this.state.inputViewLayout}
          ref="ChatInput"
          menuContainerHeight={this.state.menuContainerHeight}
          isDismissMenuContainer={this.state.isDismissMenuContainer}
          onSendText={this.onSendText}
          onTakePicture={this.onTakePicture}
          onStartRecordVoice={this.onStartRecordVoice}
          onFinishRecordVoice={this.onFinishRecordVoice}
          onCancelRecordVoice={this.onCancelRecordVoice}
          onStartRecordVideo={this.onStartRecordVideo}
          onFinishRecordVideo={this.onFinishRecordVideo}
          onSendGalleryFiles={this.onSendGalleryFiles}
          onSwitchToEmojiMode={this.onSwitchToEmojiMode}
          onSwitchToMicrophoneMode={this.onSwitchToMicrophoneMode}
          onSwitchToGalleryMode={this.onSwitchToGalleryMode}
          onSwitchToCameraMode={this.onSwitchToCameraMode}
          onShowKeyboard={this.onShowKeyboard}
          onTouchEditText={this.onTouchEditText}
          onFullScreen={this.onFullScreen}
          onRecoverScreen={this.onRecoverScreen}
          onSizeChange={this.onInputViewSizeChange}
          showSelectAlbumBtn={true}
          onClickSelectAlbum={this.onClickSelectAlbum}
          galleryScale={0.6}//default = 0.5
          compressionQuality={0.6}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  sendCustomBtn: {

  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  inputView: {
    backgroundColor: 'green',
    width: window.width,
    height: 100,
  },
  btnStyle: {
    marginTop: 10,
    borderWidth: 1,
    borderColor: '#3e83d7',
    borderRadius: 8,
    backgroundColor: '#3e83d7'
  }
});

<|endoftext|>


<commit_before>exports.BattleScripts = {
	init: function() {
		for (var i in this.data.Pokedex) {
			if (!i === 'shedinja') this.data.Pokedex[i].baseStats.hp = 160 - this.data.Pokedex[i].baseStats.hp;
			this.data.Pokedex[i].baseStats.atk = 160 - this.data.Pokedex[i].baseStats.atk;
			this.data.Pokedex[i].baseStats.def = 160 - this.data.Pokedex[i].baseStats.def;
			this.data.Pokedex[i].baseStats.spa = 160 - this.data.Pokedex[i].baseStats.spa;
			this.data.Pokedex[i].baseStats.spd = 160 - this.data.Pokedex[i].baseStats.spd;
		}
	}
};<commit_msg>Negative meta mod fix<commit_after>exports.BattleScripts = {
	init: function() {
		for (var i in this.data.Pokedex) {
			var hp = 160 - this.data.Pokedex[i].baseStats.hp;
			var atk = 160 - this.data.Pokedex[i].baseStats.atk;
			var def = 160 - this.data.Pokedex[i].baseStats.def;
			var spa = 160 - this.data.Pokedex[i].baseStats.spa;
			var spd = 160 - this.data.Pokedex[i].baseStats.spd;
			var spe = 160 - this.data.Pokedex[i].baseStats.spe;
			this.data.Pokedex[i].baseStats.hp = (hp > 5)? (i === 'shedinja')? 1 : hp : 5;
			this.data.Pokedex[i].baseStats.atk = (atk > 5)? atk : 5;
			this.data.Pokedex[i].baseStats.def = (def > 5)? def : 5;
			this.data.Pokedex[i].baseStats.spa = (spa > 5)? spa : 5;
			this.data.Pokedex[i].baseStats.spd = (spd > 5)? spd : 5;
			this.data.Pokedex[i].baseStats.spd = (spe > 5)? spe : 5;
		}
	}
};<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
//  Copyright (C) 2013  The IPython Development Team
//
//  Distributed under the terms of the BSD License.  The full license is in
//  the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------

//============================================================================
// Comm and CommManager bases
//============================================================================
/**
 * Base Comm classes
 * @module IPython
 * @namespace IPython
 * @submodule comm
 */

var IPython = (function (IPython) {
    "use strict";

    //-----------------------------------------------------------------------
    // CommManager class
    //-----------------------------------------------------------------------

    var CommManager = function (kernel) {
        this.comms = {};
        this.targets = {};
        if (kernel !== undefined) {
            this.init_kernel(kernel);
        }
    };

    CommManager.prototype.init_kernel = function (kernel) {
        // connect the kernel, and register message handlers
        this.kernel = kernel;
        var msg_types = ['comm_open', 'comm_msg', 'comm_close'];
        for (var i = 0; i < msg_types.length; i++) {
            var msg_type = msg_types[i];
            kernel.register_iopub_handler(msg_type, $.proxy(this[msg_type], this));
        }
    };

    CommManager.prototype.new_comm = function (target_name, data, callbacks, metadata, comm_id) {
        // Create a new Comm, register it, and open its Kernel-side counterpart
        // Mimics the auto-registration in `Comm.__init__` in the IPython Comm
        var comm = new Comm(target_name, comm_id);
        this.register_comm(comm);
        comm.open(data, callbacks, metadata);
        return comm;
    };

    CommManager.prototype.register_target = function (target_name, f) {
        // Register a target function for a given target name
        this.targets[target_name] = f;
    };

    CommManager.prototype.unregister_target = function (target_name, f) {
        // Unregister a target function for a given target name
        delete this.targets[target_name];
    };

    CommManager.prototype.register_comm = function (comm) {
        // Register a comm in the mapping
        this.comms[comm.comm_id] = comm;
        comm.kernel = this.kernel;
        return comm.comm_id;
    };

    CommManager.prototype.unregister_comm = function (comm_id) {
        // Remove a comm from the mapping
        delete this.comms[comm_id];
    };

    // comm message handlers

    CommManager.prototype.comm_open = function (msg) {
        var content = msg.content;
        var f = this.targets[content.target_name];
        if (f === undefined) {
            console.log("No such target registered: ", content.target_name);
            console.log("Available targets are: ", this.targets);
            return;
        }
        var comm = new Comm(content.target_name, content.comm_id);
        this.register_comm(comm);
        try {
            f(comm, msg);
        } catch (e) {
            console.log("Exception opening new comm:", e, msg);
            comm.close();
            this.unregister_comm(comm);
        }
    };

    CommManager.prototype.comm_close = function (msg) {
        var content = msg.content;
        var comm = this.comms[content.comm_id];
        if (comm === undefined) {
            return;
        }
        delete this.comms[content.comm_id];
        try {
            comm.handle_close(msg);
        } catch (e) {
            console.log("Exception closing comm: ", e, msg);
        }
    };

    CommManager.prototype.comm_msg = function (msg) {
        var content = msg.content;
        var comm = this.comms[content.comm_id];
        if (comm === undefined) {
            return;
        }
        try {
            comm.handle_msg(msg);
        } catch (e) {
            console.log("Exception handling comm msg: ", e, msg);
        }
    };

    //-----------------------------------------------------------------------
    // Comm base class
    //-----------------------------------------------------------------------

    var Comm = function (target_name, comm_id) {
        this.target_name = target_name;
        this.comm_id = comm_id || IPython.utils.uuid();
        this._msg_callback = this._close_callback = null;
    };

    // methods for sending messages
    Comm.prototype.open = function (data, callbacks, metadata) {
        var content = {
            comm_id : this.comm_id,
            target_name : this.target_name,
            data : data || {},
        };
        return this.kernel.send_shell_message("comm_open", content, callbacks, metadata);
    };

    Comm.prototype.send = function (data, callbacks, metadata) {
        var content = {
            comm_id : this.comm_id,
            data : data || {},
        };
        return this.kernel.send_shell_message("comm_msg", content, callbacks, metadata);
    };

    Comm.prototype.close = function (data, callbacks, metadata) {
        var content = {
            comm_id : this.comm_id,
            data : data || {},
        };
        return this.kernel.send_shell_message("comm_close", content, callbacks, metadata);
    };

    // methods for registering callbacks for incoming messages
    Comm.prototype._register_callback = function (key, callback) {
        this['_' + key + '_callback'] = callback;
    };

    Comm.prototype.on_msg = function (callback) {
        this._register_callback('msg', callback);
    };

    Comm.prototype.on_close = function (callback) {
        this._register_callback('close', callback);
    };

    // methods for handling incoming messages

    Comm.prototype._maybe_callback = function (key, msg) {
        var callback = this['_' + key + '_callback'];
        if (callback) callback(msg);
    };

    Comm.prototype.handle_msg = function (msg) {
        this._maybe_callback('msg', msg);
    };

    Comm.prototype.handle_close = function (msg) {
        this._maybe_callback('close', msg);
    };

    IPython.CommManager = CommManager;
    IPython.Comm = Comm;

    return IPython;

}(IPython));

<commit_msg>catch errors in comm callbacks<commit_after>//----------------------------------------------------------------------------
//  Copyright (C) 2013  The IPython Development Team
//
//  Distributed under the terms of the BSD License.  The full license is in
//  the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------

//============================================================================
// Comm and CommManager bases
//============================================================================
/**
 * Base Comm classes
 * @module IPython
 * @namespace IPython
 * @submodule comm
 */

var IPython = (function (IPython) {
    "use strict";

    //-----------------------------------------------------------------------
    // CommManager class
    //-----------------------------------------------------------------------

    var CommManager = function (kernel) {
        this.comms = {};
        this.targets = {};
        if (kernel !== undefined) {
            this.init_kernel(kernel);
        }
    };

    CommManager.prototype.init_kernel = function (kernel) {
        // connect the kernel, and register message handlers
        this.kernel = kernel;
        var msg_types = ['comm_open', 'comm_msg', 'comm_close'];
        for (var i = 0; i < msg_types.length; i++) {
            var msg_type = msg_types[i];
            kernel.register_iopub_handler(msg_type, $.proxy(this[msg_type], this));
        }
    };

    CommManager.prototype.new_comm = function (target_name, data, callbacks, metadata, comm_id) {
        // Create a new Comm, register it, and open its Kernel-side counterpart
        // Mimics the auto-registration in `Comm.__init__` in the IPython Comm
        var comm = new Comm(target_name, comm_id);
        this.register_comm(comm);
        comm.open(data, callbacks, metadata);
        return comm;
    };

    CommManager.prototype.register_target = function (target_name, f) {
        // Register a target function for a given target name
        this.targets[target_name] = f;
    };

    CommManager.prototype.unregister_target = function (target_name, f) {
        // Unregister a target function for a given target name
        delete this.targets[target_name];
    };

    CommManager.prototype.register_comm = function (comm) {
        // Register a comm in the mapping
        this.comms[comm.comm_id] = comm;
        comm.kernel = this.kernel;
        return comm.comm_id;
    };

    CommManager.prototype.unregister_comm = function (comm_id) {
        // Remove a comm from the mapping
        delete this.comms[comm_id];
    };

    // comm message handlers

    CommManager.prototype.comm_open = function (msg) {
        var content = msg.content;
        var f = this.targets[content.target_name];
        if (f === undefined) {
            console.log("No such target registered: ", content.target_name);
            console.log("Available targets are: ", this.targets);
            return;
        }
        var comm = new Comm(content.target_name, content.comm_id);
        this.register_comm(comm);
        try {
            f(comm, msg);
        } catch (e) {
            console.log("Exception opening new comm:", e, msg);
            comm.close();
            this.unregister_comm(comm);
        }
    };

    CommManager.prototype.comm_close = function (msg) {
        var content = msg.content;
        var comm = this.comms[content.comm_id];
        if (comm === undefined) {
            return;
        }
        delete this.comms[content.comm_id];
        try {
            comm.handle_close(msg);
        } catch (e) {
            console.log("Exception closing comm: ", e, msg);
        }
    };

    CommManager.prototype.comm_msg = function (msg) {
        var content = msg.content;
        var comm = this.comms[content.comm_id];
        if (comm === undefined) {
            return;
        }
        try {
            comm.handle_msg(msg);
        } catch (e) {
            console.log("Exception handling comm msg: ", e, msg);
        }
    };

    //-----------------------------------------------------------------------
    // Comm base class
    //-----------------------------------------------------------------------

    var Comm = function (target_name, comm_id) {
        this.target_name = target_name;
        this.comm_id = comm_id || IPython.utils.uuid();
        this._msg_callback = this._close_callback = null;
    };

    // methods for sending messages
    Comm.prototype.open = function (data, callbacks, metadata) {
        var content = {
            comm_id : this.comm_id,
            target_name : this.target_name,
            data : data || {},
        };
        return this.kernel.send_shell_message("comm_open", content, callbacks, metadata);
    };

    Comm.prototype.send = function (data, callbacks, metadata) {
        var content = {
            comm_id : this.comm_id,
            data : data || {},
        };
        return this.kernel.send_shell_message("comm_msg", content, callbacks, metadata);
    };

    Comm.prototype.close = function (data, callbacks, metadata) {
        var content = {
            comm_id : this.comm_id,
            data : data || {},
        };
        return this.kernel.send_shell_message("comm_close", content, callbacks, metadata);
    };

    // methods for registering callbacks for incoming messages
    Comm.prototype._register_callback = function (key, callback) {
        this['_' + key + '_callback'] = callback;
    };

    Comm.prototype.on_msg = function (callback) {
        this._register_callback('msg', callback);
    };

    Comm.prototype.on_close = function (callback) {
        this._register_callback('close', callback);
    };

    // methods for handling incoming messages

    Comm.prototype._maybe_callback = function (key, msg) {
        var callback = this['_' + key + '_callback'];
        if (callback) {
            try {
                callback(msg);
            } catch (e) {
                console.log("Exception in Comm callback", e, msg);
            }
        }
    };

    Comm.prototype.handle_msg = function (msg) {
        this._maybe_callback('msg', msg);
    };

    Comm.prototype.handle_close = function (msg) {
        this._maybe_callback('close', msg);
    };

    IPython.CommManager = CommManager;
    IPython.Comm = Comm;

    return IPython;

}(IPython));

<|endoftext|>


<commit_before>/*
 * AuthVerifier.jsm
 *
 * Authentication Verifier.
 *
 * Version: 1.0.1 (10 December 2014)
 *
 * Copyright (c) 2014 Philippe Lieser
 *
 * This software is licensed under the terms of the MIT License.
 *
 * The above copyright and license notice shall be
 * included in all copies or substantial portions of the Software.
 */

// options for JSHint
/* jshint strict:true, moz:true, smarttabs:true, unused:true */
/* global Components, Services, Task */
/* global Logging, ARHParser */
/* global dkimStrings, exceptionToStr, getDomainFromAddr, tryGetFormattedString, DKIM_InternalError */
/* exported EXPORTED_SYMBOLS, AuthVerifier */

"use strict";

const module_version = "1.0.1";

var EXPORTED_SYMBOLS = [
	"AuthVerifier"
];

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");

Cu.import("resource://dkim_verifier/logging.jsm");
Cu.import("resource://dkim_verifier/helper.jsm");
Cu.import("resource://dkim_verifier/MsgReader.jsm");
Cu.import("resource://dkim_verifier/ARHParser.jsm");
let DKIM = {};
Cu.import("resource://dkim_verifier/dkimPolicy.jsm", DKIM);
Cu.import("resource://dkim_verifier/dkimVerifier.jsm", DKIM);

const PREF_BRANCH = "extensions.dkim_verifier.";

let log = Logging.getLogger("AuthVerifier");
let prefs = Services.prefs.getBranch(PREF_BRANCH);

var AuthVerifier = {
	get version() { return module_version; },

	/**
	 * @typedef {Object} AuthResult
	 * @property {String} version
	 *           result version ("2.0")
	 * @property {AuthResultDKIM[]} dkim
	 * @property {ARHResinfo[]} [spf]
	 * @property {ARHResinfo[]} [dmarc]
	 */

	/**
	 * @typedef {Object} AuthResultDKIM
	 * @extends dkimSigResultV2
	 * @property {Number} res_num
	 *           10: SUCCESS
	 *           20: TEMPFAIL
	 *           30: PERMFAIL
	 *           35: PERMFAIL treat as no sig
	 *           40: no sig
	 * @property {String} result_str
	 *           localized result string
	 * @property {String[]} [warnings_str]
	 *           localized warnings
	 */

	/**
	 * Verifies the authentication of the msg.
	 *
	 * @param {nsIMsgDBHdr} msgHdr
	 * @param {String} [msgURI=""] Required if msg is external.
	 * @return {Promise<AuthResult>}
	 */
	verify: function _authVerifier_verify(msgHdr, msgURI) {
		var promise = Task.spawn(function () {
			// check for saved AuthResult
			let authResult = loadAuthResult(msgHdr);
			if (authResult) {
				throw new Task.Result(authResult);
			}

			// get msgURI if not specified
			if (!msgURI) {
				msgURI = msgHdr.folder.getUriForMsg(msgHdr);
			}

			// create msg object
			let msg = yield DKIM.Verifier.createMsg(msgURI);

			// read Authentication-Results header
			authResult = getARHResult(msg);

			if (!authResult) {
				// verify DKIM signatures
				let dkimResultV2 = yield DKIM.Verifier.verify2(msg);
				authResult = {
					version: "2.0",
					dkim: dkimResultV2.signatures.map(dkimSigResultV2_to_AuthResultDKIM),
				};
			}

			// save AuthResult
			saveAuthResult(msgHdr, authResult);

			throw new Task.Result(authResult);
		});
		promise.then(null, function onReject(exception) {
			log.warn(exceptionToStr(exception));
		});
		return promise;
	},

	/**
	 * Resets the stored authentication result of the msg.
	 *
	 * @param {nsIMsgDBHdr} msgHdr
	 * @return {Promise<Undefined>}
	 */
	resetResult: function _authVerifier_resetResult(msgHdr) {
		var promise = Task.spawn(function () {
			saveAuthResult(msgHdr, "");
		});
		promise.then(null, function onReject(exception) {
			log.warn(exceptionToStr(exception));
		});
		return promise;
	},
};

/**
 * Get the Authentication-Results header as an AuthResult.
 *
 * @param {Object} msg
 * @return {AuthResult|Null}
 */
function getARHResult(msg) {
	if (!prefs.getBoolPref("arh.read") ||
	    !msg.headerFields.has("authentication-results")) {
		return null;
	}

	// get DKIM, SPF and DMARC res
	let arhDKIM = [];
	let arhSPF = [];
	let arhDMARC = [];
	for (let i = 0; i < msg.headerFields.get("authentication-results").length; i++) {
		let arh;
		try {
			arh = ARHParser.parse(msg.headerFields.get("authentication-results")[i]);
		} catch (exception) {
			log.error(exceptionToStr(exception));
			continue;
		}
		arhDKIM = arhDKIM.concat(arh.resinfo.filter(function (element) {
			return element.method === "dkim";
		}));
		arhSPF = arhSPF.concat(arh.resinfo.filter(function (element) {
			return element.method === "spf";
		}));
		arhDMARC = arhDMARC.concat(arh.resinfo.filter(function (element) {
			return element.method === "dmarc";
		}));
	}

	// convert DKIM results
	let dkimSigResults = arhDKIM.map(arhDKIM_to_dkimSigResultV2);

	// check for signature existents
	DKIM.Verifier.checkForSignatureExsistens(msg, dkimSigResults);

	// check SDID and AUID of DKIM results
	for (let i = 0; i < dkimSigResults.length; i++) {
		if (dkimSigResults[i].result === "SUCCESS") {
			try {
				DKIM.Policy.checkSDID(
					msg.DKIMSignPolicy.sdid,
					msg.from,
					dkimSigResults[i].sdid,
					dkimSigResults[i].auid,
					dkimSigResults[i].warnings
				);
			} catch(exception) {
				dkimSigResults[i] = DKIM.Verifier.handleExeption(
					exception,
					msg,
					{d: dkimSigResults[i].sdid, i: dkimSigResults[i].auid}
				);
			}
		}
	}

	// sort signatures
	DKIM.Verifier.sortSignatures(msg, dkimSigResults);

	let authResult = {
		version: "2.0",
		dkim: dkimSigResults.map(dkimSigResultV2_to_AuthResultDKIM),
		spf: arhSPF,
		dmarc: arhDMARC,
	};
	return authResult;
}

/**
 * Save authentication result
 *
 * @param {nsIMsgDBHdr} msgHdr
 * @param {AuthResult} authResult
 */
function saveAuthResult(msgHdr, authResult) {
	if (prefs.getBoolPref("saveResult")) {
		// don't save result if message is external
		if (!msgHdr.folder) {
			log.debug("result not saved because message is external");
			return;
		}

		if (authResult === "") {
			// reset result
			log.debug("reset AuthResult result");
			msgHdr.setStringProperty("dkim_verifier@pl-result", "");
		} else if (authResult.dkim[0].result === "TEMPFAIL") {
			// don't save result if DKIM result is a TEMPFAIL
			log.debug("result not saved because DKIM result is a TEMPFAIL");
		} else {
			log.debug("save AuthResult result");
			msgHdr.setStringProperty("dkim_verifier@pl-result", JSON.stringify(authResult));
		}
	}
}

/**
 * Get saved authentication result
 *
 * @param {nsIMsgDBHdr} msgHdr
 * @return {AuthResult|Null} authResult
 */
function loadAuthResult(msgHdr) {
	if (prefs.getBoolPref("saveResult")) {
		// don't read result if message is external
		if (!msgHdr.folder) {
			return null;
		}

		let authResult = msgHdr.getStringProperty("dkim_verifier@pl-result");

		if (authResult !== "") {
			log.debug("AuthResult result found: "+authResult);

			authResult = JSON.parse(authResult);

			if (authResult.version.match(/^[0-9]+/)[0] === "1") {
				// old dkimResultV1 (AuthResult version 1)
				let res = {
					version: "2.0",
					dkim: [dkimSigResultV2_to_AuthResultDKIM(
						dkimResultV1_to_dkimSigResultV2(authResult))],
				};
				return res;
			}
			if (authResult.version.match(/^[0-9]+/)[0] === "2") {
				// AuthResult version 2
				return authResult;
			}

			throw new DKIM_InternalError("AuthResult result has wrong Version (" +
				authResult.version + ")");
		}
	}

	return null;
}

/**
 * Convert DKIM ARHresinfo to dkimResult
 *
 * @param {ARHresinfo} arhDKIM
 * @return {dkimSigResultV2}
 */
function arhDKIM_to_dkimSigResultV2(arhDKIM) {
	let dkimSigResult = {};
	dkimSigResult.version = "2.0";
	switch (arhDKIM.result) {
		case "none":
			dkimSigResult.result = "none";
			break;
		case "pass":
			dkimSigResult.result = "SUCCESS";
			dkimSigResult.warnings = [];
			let sdid = arhDKIM.propertys.header.d;
			let auid = arhDKIM.propertys.header.i;
			if (sdid || auid) {
				if (!sdid) {
					sdid = getDomainFromAddr(auid);
				} else if (!auid) {
					auid = "@" + sdid;
				}
				dkimSigResult.sdid = sdid;
				dkimSigResult.auid = auid;
			}
			break;
		case "fail":
		case "policy":
		case "neutral":
		case "permerror":
			dkimSigResult.result = "PERMFAIL";
			if (arhDKIM.reason) {
				dkimSigResult.errorType = arhDKIM.reason;
			} else {
				dkimSigResult.errorType = "";
			}
			break;
		case "temperror":
			dkimSigResult.result = "TEMPFAIL";
			if (arhDKIM.reason) {
				dkimSigResult.errorType = arhDKIM.reason;
			} else {
				dkimSigResult.errorType = "";
			}
			break;
		default:
			throw new DKIM_InternalError("invalid dkim result in arh: " +
				arhDKIM.result);
	}
	return dkimSigResult;
}

/**
 * Convert dkimResultV1 to dkimSigResultV2
 *
 * @param {dkimResultV1} dkimResult
 * @return {dkimSigResultV2}
 */
function dkimResultV1_to_dkimSigResultV2(dkimResultV1) {
	let dkimSigResultV2 = {
		version: "2.0",
		result: dkimResultV1.result,
		sdid: dkimResultV1.SDID,
		selector: dkimResultV1.selector,
		errorType: dkimResultV1.errorType,
		hideFail: dkimResultV1.hideFail,
	};
	if (dkimResultV1.warnings) {
		dkimSigResultV2.warnings = dkimResultV1.warnings.map(
			function (w) {
				if (w === "DKIM_POLICYERROR_WRONG_SDID") {
					return {name: w, params: [dkimResultV1.shouldBeSignedBy]};
				}
				return {name: w};
			}
		);
	}
	if (dkimResultV1.errorType === "DKIM_POLICYERROR_WRONG_SDID" ||
	    dkimResultV1.errorType === "DKIM_POLICYERROR_MISSING_SIG") {
		dkimSigResultV2.errorStrParams = [dkimResultV1.shouldBeSignedBy];
	}
	return dkimSigResultV2;
}

/**
 * Convert dkimSigResultV2 to AuthResultDKIM
 *
 * @param {dkimSigResultV2} dkimSigResult
 * @return {AuthResultDKIM}
 * @throws DKIM_InternalError
 */
function dkimSigResultV2_to_AuthResultDKIM(dkimSigResult) {
	let authResultDKIM = dkimSigResult;
	switch(dkimSigResult.result) {
		case "SUCCESS":
			authResultDKIM.res_num = 10;
			authResultDKIM.result_str = dkimStrings.getFormattedString("SUCCESS",
				[dkimSigResult.sdid]);
			authResultDKIM.warnings_str = dkimSigResult.warnings.map(function(e) {
				return tryGetFormattedString(dkimStrings, e.name, e.params) || e.name;
			});
			break;
		case "TEMPFAIL":
			authResultDKIM.res_num = 20;
			authResultDKIM.result_str =
				tryGetFormattedString(dkimStrings, dkimSigResult.errorType,
					dkimSigResult.errorStrParams) ||
				dkimSigResult.errorType ||
				dkimStrings.getString("DKIM_INTERNALERROR_NAME");
			break;
		case "PERMFAIL":
			if (dkimSigResult.hideFail) {
				authResultDKIM.res_num = 35;
			} else {
				authResultDKIM.res_num = 30;
			}
			let errorMsg =
				tryGetFormattedString(dkimStrings, dkimSigResult.errorType,
					dkimSigResult.errorStrParams) ||
				dkimSigResult.errorType;
			if (errorMsg) {
				authResultDKIM.result_str = dkimStrings.getFormattedString("PERMFAIL",
					[errorMsg]);
			} else {
				authResultDKIM.result_str = dkimStrings.getString("PERMFAIL_NO_REASON");
			}
			break;
		case "none":
			authResultDKIM.res_num = 40;
			authResultDKIM.result_str = dkimStrings.getString("NOSIG");
			break;
		default:
			throw new DKIM_InternalError("unkown result: " + dkimSigResult.result);
	}

	return authResultDKIM;
}
<commit_msg>ARHParser.jsm: continue verification if there is no DKIM result in the ARH header<commit_after>/*
 * AuthVerifier.jsm
 *
 * Authentication Verifier.
 *
 * Version: 1.0.1 (10 December 2014)
 *
 * Copyright (c) 2014 Philippe Lieser
 *
 * This software is licensed under the terms of the MIT License.
 *
 * The above copyright and license notice shall be
 * included in all copies or substantial portions of the Software.
 */

// options for JSHint
/* jshint strict:true, moz:true, smarttabs:true, unused:true */
/* global Components, Services, Task */
/* global Logging, ARHParser */
/* global dkimStrings, exceptionToStr, getDomainFromAddr, tryGetFormattedString, DKIM_InternalError */
/* exported EXPORTED_SYMBOLS, AuthVerifier */

"use strict";

const module_version = "1.0.1";

var EXPORTED_SYMBOLS = [
	"AuthVerifier"
];

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");

Cu.import("resource://dkim_verifier/logging.jsm");
Cu.import("resource://dkim_verifier/helper.jsm");
Cu.import("resource://dkim_verifier/MsgReader.jsm");
Cu.import("resource://dkim_verifier/ARHParser.jsm");
let DKIM = {};
Cu.import("resource://dkim_verifier/dkimPolicy.jsm", DKIM);
Cu.import("resource://dkim_verifier/dkimVerifier.jsm", DKIM);

const PREF_BRANCH = "extensions.dkim_verifier.";

let log = Logging.getLogger("AuthVerifier");
let prefs = Services.prefs.getBranch(PREF_BRANCH);

var AuthVerifier = {
	get version() { return module_version; },

	/**
	 * @typedef {Object} AuthResult
	 * @property {String} version
	 *           result version ("2.0")
	 * @property {AuthResultDKIM[]} dkim
	 * @property {ARHResinfo[]} [spf]
	 * @property {ARHResinfo[]} [dmarc]
	 */

	/**
	 * @typedef {Object} AuthResultDKIM
	 * @extends dkimSigResultV2
	 * @property {Number} res_num
	 *           10: SUCCESS
	 *           20: TEMPFAIL
	 *           30: PERMFAIL
	 *           35: PERMFAIL treat as no sig
	 *           40: no sig
	 * @property {String} result_str
	 *           localized result string
	 * @property {String[]} [warnings_str]
	 *           localized warnings
	 */

	/**
	 * Verifies the authentication of the msg.
	 *
	 * @param {nsIMsgDBHdr} msgHdr
	 * @param {String} [msgURI=""] Required if msg is external.
	 * @return {Promise<AuthResult>}
	 */
	verify: function _authVerifier_verify(msgHdr, msgURI) {
		var promise = Task.spawn(function () {
			// check for saved AuthResult
			let authResult = loadAuthResult(msgHdr);
			if (authResult) {
				throw new Task.Result(authResult);
			}

			// get msgURI if not specified
			if (!msgURI) {
				msgURI = msgHdr.folder.getUriForMsg(msgHdr);
			}

			// create msg object
			let msg = yield DKIM.Verifier.createMsg(msgURI);

			// read Authentication-Results header
			authResult = getARHResult(msg);

			if (!authResult || authResult.dkim.length === 0) {
				// verify DKIM signatures
				let dkimResultV2 = yield DKIM.Verifier.verify2(msg);
				authResult = {
					version: "2.0",
					dkim: dkimResultV2.signatures.map(dkimSigResultV2_to_AuthResultDKIM),
				};
			}

			// save AuthResult
			saveAuthResult(msgHdr, authResult);

			throw new Task.Result(authResult);
		});
		promise.then(null, function onReject(exception) {
			log.warn(exceptionToStr(exception));
		});
		return promise;
	},

	/**
	 * Resets the stored authentication result of the msg.
	 *
	 * @param {nsIMsgDBHdr} msgHdr
	 * @return {Promise<Undefined>}
	 */
	resetResult: function _authVerifier_resetResult(msgHdr) {
		var promise = Task.spawn(function () {
			saveAuthResult(msgHdr, "");
		});
		promise.then(null, function onReject(exception) {
			log.warn(exceptionToStr(exception));
		});
		return promise;
	},
};

/**
 * Get the Authentication-Results header as an AuthResult.
 *
 * @param {Object} msg
 * @return {AuthResult|Null}
 */
function getARHResult(msg) {
	if (!prefs.getBoolPref("arh.read") ||
	    !msg.headerFields.has("authentication-results")) {
		return null;
	}

	// get DKIM, SPF and DMARC res
	let arhDKIM = [];
	let arhSPF = [];
	let arhDMARC = [];
	for (let i = 0; i < msg.headerFields.get("authentication-results").length; i++) {
		let arh;
		try {
			arh = ARHParser.parse(msg.headerFields.get("authentication-results")[i]);
		} catch (exception) {
			log.error(exceptionToStr(exception));
			continue;
		}
		arhDKIM = arhDKIM.concat(arh.resinfo.filter(function (element) {
			return element.method === "dkim";
		}));
		arhSPF = arhSPF.concat(arh.resinfo.filter(function (element) {
			return element.method === "spf";
		}));
		arhDMARC = arhDMARC.concat(arh.resinfo.filter(function (element) {
			return element.method === "dmarc";
		}));
	}

	// convert DKIM results
	let dkimSigResults = arhDKIM.map(arhDKIM_to_dkimSigResultV2);

	// check SDID and AUID of DKIM results
	for (let i = 0; i < dkimSigResults.length; i++) {
		if (dkimSigResults[i].result === "SUCCESS") {
			try {
				DKIM.Policy.checkSDID(
					msg.DKIMSignPolicy.sdid,
					msg.from,
					dkimSigResults[i].sdid,
					dkimSigResults[i].auid,
					dkimSigResults[i].warnings
				);
			} catch(exception) {
				dkimSigResults[i] = DKIM.Verifier.handleExeption(
					exception,
					msg,
					{d: dkimSigResults[i].sdid, i: dkimSigResults[i].auid}
				);
			}
		}
	}

	// sort signatures
	DKIM.Verifier.sortSignatures(msg, dkimSigResults);

	let authResult = {
		version: "2.0",
		dkim: dkimSigResults.map(dkimSigResultV2_to_AuthResultDKIM),
		spf: arhSPF,
		dmarc: arhDMARC,
	};
	return authResult;
}

/**
 * Save authentication result
 *
 * @param {nsIMsgDBHdr} msgHdr
 * @param {AuthResult} authResult
 */
function saveAuthResult(msgHdr, authResult) {
	if (prefs.getBoolPref("saveResult")) {
		// don't save result if message is external
		if (!msgHdr.folder) {
			log.debug("result not saved because message is external");
			return;
		}

		if (authResult === "") {
			// reset result
			log.debug("reset AuthResult result");
			msgHdr.setStringProperty("dkim_verifier@pl-result", "");
		} else if (authResult.dkim[0].result === "TEMPFAIL") {
			// don't save result if DKIM result is a TEMPFAIL
			log.debug("result not saved because DKIM result is a TEMPFAIL");
		} else {
			log.debug("save AuthResult result");
			msgHdr.setStringProperty("dkim_verifier@pl-result", JSON.stringify(authResult));
		}
	}
}

/**
 * Get saved authentication result
 *
 * @param {nsIMsgDBHdr} msgHdr
 * @return {AuthResult|Null} authResult
 */
function loadAuthResult(msgHdr) {
	if (prefs.getBoolPref("saveResult")) {
		// don't read result if message is external
		if (!msgHdr.folder) {
			return null;
		}

		let authResult = msgHdr.getStringProperty("dkim_verifier@pl-result");

		if (authResult !== "") {
			log.debug("AuthResult result found: "+authResult);

			authResult = JSON.parse(authResult);

			if (authResult.version.match(/^[0-9]+/)[0] === "1") {
				// old dkimResultV1 (AuthResult version 1)
				let res = {
					version: "2.0",
					dkim: [dkimSigResultV2_to_AuthResultDKIM(
						dkimResultV1_to_dkimSigResultV2(authResult))],
				};
				return res;
			}
			if (authResult.version.match(/^[0-9]+/)[0] === "2") {
				// AuthResult version 2
				return authResult;
			}

			throw new DKIM_InternalError("AuthResult result has wrong Version (" +
				authResult.version + ")");
		}
	}

	return null;
}

/**
 * Convert DKIM ARHresinfo to dkimResult
 *
 * @param {ARHresinfo} arhDKIM
 * @return {dkimSigResultV2}
 */
function arhDKIM_to_dkimSigResultV2(arhDKIM) {
	let dkimSigResult = {};
	dkimSigResult.version = "2.0";
	switch (arhDKIM.result) {
		case "none":
			dkimSigResult.result = "none";
			break;
		case "pass":
			dkimSigResult.result = "SUCCESS";
			dkimSigResult.warnings = [];
			let sdid = arhDKIM.propertys.header.d;
			let auid = arhDKIM.propertys.header.i;
			if (sdid || auid) {
				if (!sdid) {
					sdid = getDomainFromAddr(auid);
				} else if (!auid) {
					auid = "@" + sdid;
				}
				dkimSigResult.sdid = sdid;
				dkimSigResult.auid = auid;
			}
			break;
		case "fail":
		case "policy":
		case "neutral":
		case "permerror":
			dkimSigResult.result = "PERMFAIL";
			if (arhDKIM.reason) {
				dkimSigResult.errorType = arhDKIM.reason;
			} else {
				dkimSigResult.errorType = "";
			}
			break;
		case "temperror":
			dkimSigResult.result = "TEMPFAIL";
			if (arhDKIM.reason) {
				dkimSigResult.errorType = arhDKIM.reason;
			} else {
				dkimSigResult.errorType = "";
			}
			break;
		default:
			throw new DKIM_InternalError("invalid dkim result in arh: " +
				arhDKIM.result);
	}
	return dkimSigResult;
}

/**
 * Convert dkimResultV1 to dkimSigResultV2
 *
 * @param {dkimResultV1} dkimResult
 * @return {dkimSigResultV2}
 */
function dkimResultV1_to_dkimSigResultV2(dkimResultV1) {
	let dkimSigResultV2 = {
		version: "2.0",
		result: dkimResultV1.result,
		sdid: dkimResultV1.SDID,
		selector: dkimResultV1.selector,
		errorType: dkimResultV1.errorType,
		hideFail: dkimResultV1.hideFail,
	};
	if (dkimResultV1.warnings) {
		dkimSigResultV2.warnings = dkimResultV1.warnings.map(
			function (w) {
				if (w === "DKIM_POLICYERROR_WRONG_SDID") {
					return {name: w, params: [dkimResultV1.shouldBeSignedBy]};
				}
				return {name: w};
			}
		);
	}
	if (dkimResultV1.errorType === "DKIM_POLICYERROR_WRONG_SDID" ||
	    dkimResultV1.errorType === "DKIM_POLICYERROR_MISSING_SIG") {
		dkimSigResultV2.errorStrParams = [dkimResultV1.shouldBeSignedBy];
	}
	return dkimSigResultV2;
}

/**
 * Convert dkimSigResultV2 to AuthResultDKIM
 *
 * @param {dkimSigResultV2} dkimSigResult
 * @return {AuthResultDKIM}
 * @throws DKIM_InternalError
 */
function dkimSigResultV2_to_AuthResultDKIM(dkimSigResult) {
	let authResultDKIM = dkimSigResult;
	switch(dkimSigResult.result) {
		case "SUCCESS":
			authResultDKIM.res_num = 10;
			authResultDKIM.result_str = dkimStrings.getFormattedString("SUCCESS",
				[dkimSigResult.sdid]);
			authResultDKIM.warnings_str = dkimSigResult.warnings.map(function(e) {
				return tryGetFormattedString(dkimStrings, e.name, e.params) || e.name;
			});
			break;
		case "TEMPFAIL":
			authResultDKIM.res_num = 20;
			authResultDKIM.result_str =
				tryGetFormattedString(dkimStrings, dkimSigResult.errorType,
					dkimSigResult.errorStrParams) ||
				dkimSigResult.errorType ||
				dkimStrings.getString("DKIM_INTERNALERROR_NAME");
			break;
		case "PERMFAIL":
			if (dkimSigResult.hideFail) {
				authResultDKIM.res_num = 35;
			} else {
				authResultDKIM.res_num = 30;
			}
			let errorMsg =
				tryGetFormattedString(dkimStrings, dkimSigResult.errorType,
					dkimSigResult.errorStrParams) ||
				dkimSigResult.errorType;
			if (errorMsg) {
				authResultDKIM.result_str = dkimStrings.getFormattedString("PERMFAIL",
					[errorMsg]);
			} else {
				authResultDKIM.result_str = dkimStrings.getString("PERMFAIL_NO_REASON");
			}
			break;
		case "none":
			authResultDKIM.res_num = 40;
			authResultDKIM.result_str = dkimStrings.getString("NOSIG");
			break;
		default:
			throw new DKIM_InternalError("unkown result: " + dkimSigResult.result);
	}

	return authResultDKIM;
}
<|endoftext|>