<commit_before>var util = require("./util")

/*
Callsite name management
*/
var idstack = []
function enterfn(id) { idstack.push(id) }
function leavefn(id) { idstack.pop() }

/*
Enumeration sets new ERP calls to start of domain. Flag for this behavior:
*/
var initEnumerate = false
function startEnumerate() {initEnumerate = true}
function stopEnumerate() {initEnumerate = false}

/*
Variables generated by ERPs
*/
function RandomVariableRecord(name, erp, params, val, logprob, structural, conditioned)
{
	this.name = name
	this.erp = erp
	this.params = params
	this.val = val
	this.logprob = logprob
	this.active = true
	this.structural = structural
	this.conditioned = conditioned
}

RandomVariableRecord.prototype.copy = function copy()
{
	return new RandomVariableRecord(this.name, this.erp, this.params, this.val,
									this.logprob, this.structural, this.conditioned)
}

/*
Execution trace generated by a probabilistic program.
Tracks the random choices made and accumulates probabilities.
*/
function RandomExecutionTrace(computation, init)
{
	init = (init == undefined ? "rejection" : init)
	this.computation = computation
	this.vars = {}
	this.varlist = []
	this.currVarIndex = 0
	this.logprob = 0.0
	this.newlogprob = 0.0
	this.oldlogprob = 0.0
	this.rootframe = null
	this.loopcounters = {}
	this.conditionsSatisfied = false
	this.returnValue = null

	if (init == "rejection") {
		while (!this.conditionsSatisfied)
		{
			this.vars = {}
			this.traceUpdate()
		}
	} else if (init=="enumerate") { //TODO: test
        startEnumerate()
        this.traceUpdate()
        while (!this.conditionsSatisfied) {
            var names = this.freeVarNames()
            var newval = null
            while (newval == null) {
                // if we are out of names it means we're done enumerating with no satisfying execution!
                if (names.length == 0) {throw new Error("No executions satisfy conditions!")}

                //otherwise get next var and increment:
                var varname = names.pop()
                var v = this.getRecord(varname)
                //FIXME: if no nextVal fn, should sample?
                var newval = v.erp.nextVal(v.val, v.params)
                if (newval == null) {
                    v.val = v.erp.nextVal(null, v.params) //get first in domain
                } else {
                    v.val = newval
                }
                v.logprob = v.erp.logprob(v.val, v.params)
            }
        }
        stopEnumerate()
    }
}

RandomExecutionTrace.prototype.deepcopy = function deepcopy()
{
	var newdb = new RandomExecutionTrace(this.computation, false)
	newdb.logprob = this.logprob
	newdb.oldlogprob = this.oldlogprob
	newdb.newlogprob = this.newlogprob
	newdb.conditionsSatisfied = this.conditionsSatisfied
	newdb.returnValue = this.returnValue

	for (var i = 0; i < this.varlist.length; i++)
	{
		var newvar = this.varlist[i].copy()
		newdb.varlist.push(newvar)
		newdb.vars[newvar.name] = newvar
	}

	return newdb
}

RandomExecutionTrace.prototype.freeVarNames = function freeVarNames(structural, nonstructural)
{
	structural = (structural == undefined ? true : structural)
	nonstructural = (nonstructural == undefined ? true : nonstructural)
	var names = []
	for (var name in this.vars)
	{
		var rec = this.vars[name]
		if (!rec.conditioned &&
			((structural && rec.structural) || (nonstructural && !rec.structural)))
			names.push(name)
	}
	return names
}

/*
Names of variables that this trace has that the other does not
*/
RandomExecutionTrace.prototype.varDiff = function varDiff(other)
{
	var arr = []
	for (var name in this.vars)
	{
		if (!other.vars[name])
			arr.push(name)
	}
	return arr
}

/*
Difference in log probability between this trace and the other
due to variables that this one has that the other does not
*/
RandomExecutionTrace.prototype.lpDiff = function lpDiff(other)
{
	return this.varDiff(other)
		.map(function(name) {return this.vars[name].logprob}.bind(this))
		.reduce(function(a,b) {return a+b}, 0)
}

/*
The singleton trace object
*/
var trace = null

/*
Run computation and update this trace accordingly
*/
RandomExecutionTrace.prototype.traceUpdate = function traceUpdate(structureIsFixed)
{
	var origtrace = trace
	trace = this

	this.logprob = 0.0
	this.newlogprob = 0.0
	this.loopcounters = {}
	this.conditionsSatisfied = true
	this.currVarIndex = 0

	// If updating this trace can change the variable structure, then we
	// clear out the flat list of variables beforehand
	if (!structureIsFixed)
		this.varlist.length = 0

	// Mark all variables as inactive; only those reached
	// by the computation will become active
	for (var name in this.vars)
		this.vars[name].active = false

	// Run the computation, creating/looking up random variables
	this.returnValue = this.computation()

	// Clean up
	this.rootframe = null
	this.loopcounters = {}

	// Clear out any random values that are no longer reachable
	var newvars = {}
	this.oldlogprob = 0.0
	for (var name in this.vars)
	{
		var rec = this.vars[name]
		if (!rec.active)
			this.oldlogprob += rec.logprob
		else
			newvars[name] = rec
	}
	this.vars = newvars

	// Reset the original singleton trace
	trace = origtrace
}

/*
Propose a random change to a random variable 'varname'
Returns a new sample trace from the computation and the
forward and reverse probabilities of this proposal
*/
RandomExecutionTrace.prototype.proposeChange = function proposeChange(varname, structureIsFixed)
{
	var nextTrace = this.deepcopy()
	var v = nextTrace.getRecord(varname)
	var propval = v.erp.proposal(v.val, v.params)
	var fwdPropLP = v.erp.logProposalProb(v.val, propval, v.params)
	var rvsPropLP = v.erp.logProposalProb(propval, v.val, v.params)
	v.val = propval
	v.logprob = v.erp.logprob(v.val, v.params)
	nextTrace.traceUpdate(structureIsFixed)
	fwdPropLP += nextTrace.newlogprob
	rvsPropLP += nextTrace.oldlogprob
	return [nextTrace, fwdPropLP, rvsPropLP]
}

/*
Return the current structural name, as determined by the interpreter stack
*/
RandomExecutionTrace.prototype.currentName = function currentName()
{
	var loopnum = this.loopcounters[idstack] || 0
	this.loopcounters[idstack] = loopnum + 1
	return JSON.stringify(idstack) + ":" + loopnum
}

/*
Looks up the value of a random variable.
Creates the variable if it does not already exist
*/
RandomExecutionTrace.prototype.lookup = function lookup(erp, params, isStructural, conditionedValue)
{
	var record = null
	var name = null

	// Try to find the variable (first check the flat list, then do
	// slower structural lookup)
	var varIsInFlatList = this.currVarIndex < this.varlist.length
	if (varIsInFlatList)
		record = this.varlist[this.currVarIndex]
	else
	{
		name = this.currentName()
		record = this.vars[name]
		if (!record || record.erp != erp || record.structural != isStructural)
			record = null
	}

	// If we didn't find the variable, create a new one
	if (!record)
	{
        if (initEnumerate) { // If we are doing ennumeration init new vars to first val in domain:
            var val = erp.nextVal(null, params)
        } else {
            var val = conditionedValue || erp.sample_impl(params)
        }
		var ll = erp.logprob(val, params)
		this.newlogprob += ll
		record = new RandomVariableRecord(name, erp, params, val, ll, isStructural, conditionedValue !== undefined)
		this.vars[name] = record
	}
	// Otherwise, reuse the variable we found, but check if its parameters/conditioning
	// status have changed
	else
	{
		record.conditioned = (conditionedValue != undefined)
		var hasChanges = false
		if (!util.arrayEquals(record.params, params))
		{
			record.params = params
			hasChanges = true
		}
		if (conditionedValue && conditionedValue != record.val)
		{
			record.val = conditionedValue
			record.conditioned = true
			hasChanges = true
		}
		if (hasChanges)
			record.logprob = erp.logprob(record.val, record.params)
	}
	// Finish up and return
	if (!varIsInFlatList)
		this.varlist.push(record)
	this.currVarIndex++
	this.logprob += record.logprob
	record.active = true
	return record.val
}

// Simply retrieve the variable record associated with 'name'
RandomExecutionTrace.prototype.getRecord = function getRecord(name)
{
	return this.vars[name]
}

// Add a new factor into the log-likelihood of this trace
RandomExecutionTrace.prototype.addFactor = function addFactor(num)
{
	this.logprob += num
}

// Condition the trace on the value of a boolean expression
RandomExecutionTrace.prototype.conditionOn = function conditionOn(boolexpr)
{
	this.conditionsSatisfied &= boolexpr
}

// Exported functions for interacting with the global trace

function lookupVariableValue(erp, params, isStructural, conditionedValue)
{
	if (!trace)
	{
		return conditionedValue || erp.sample_impl(params)
	}
	else
	{
		return trace.lookup(erp, params, isStructural, conditionedValue)
	}
}

function newTrace(computation, init)
{
	return new RandomExecutionTrace(computation, init)
}

function factor(num)
{
	if (trace)
		trace.addFactor(num)
}

function condition(boolexpr)
{
	if (trace)
		trace.conditionOn(boolexpr)
}

module.exports =
{
    startEnumerate: startEnumerate,
    stopEnumerate: stopEnumerate,
	enterfn: enterfn,
	leavefn: leavefn,
	lookupVariableValue: lookupVariableValue,
	newTrace: newTrace,
	factor: factor,
	condition: condition
}<commit_msg>fix to enumerate init<commit_after>var util = require("./util")

/*
Callsite name management
*/
var idstack = []
function enterfn(id) { idstack.push(id) }
function leavefn(id) { idstack.pop() }

/*
Enumeration sets new ERP calls to start of domain. Flag for this behavior:
*/
var initEnumerate = false
function startEnumerate() {initEnumerate = true}
function stopEnumerate() {initEnumerate = false}

/*
Variables generated by ERPs
*/
function RandomVariableRecord(name, erp, params, val, logprob, structural, conditioned)
{
	this.name = name
	this.erp = erp
	this.params = params
	this.val = val
	this.logprob = logprob
	this.active = true
	this.structural = structural
	this.conditioned = conditioned
}

RandomVariableRecord.prototype.copy = function copy()
{
	return new RandomVariableRecord(this.name, this.erp, this.params, this.val,
									this.logprob, this.structural, this.conditioned)
}

/*
Execution trace generated by a probabilistic program.
Tracks the random choices made and accumulates probabilities.
*/
function RandomExecutionTrace(computation, init)
{
	init = (init == undefined ? "rejection" : init)
	this.computation = computation
	this.vars = {}
	this.varlist = []
	this.currVarIndex = 0
	this.logprob = 0.0
	this.newlogprob = 0.0
	this.oldlogprob = 0.0
	this.rootframe = null
	this.loopcounters = {}
	this.conditionsSatisfied = false
	this.returnValue = null

	if (init == "rejection") {
		while (!this.conditionsSatisfied)
		{
			this.vars = {}
			this.traceUpdate()
		}
	} else if (init=="enumerate") {
        startEnumerate()
        this.traceUpdate()
        while (!this.conditionsSatisfied) {
            for(v in this.vars){console.log(this.vars[v].val)}
            console.log
            console.log("")

            var names = this.freeVarNames()
            var newval = null
            while (newval == null) {
                // if we are out of names it means we're done enumerating with no satisfying execution!
                if (names.length == 0) {throw new Error("No executions satisfy conditions!")}

                //otherwise get next var and increment:
                var varname = names.pop()
                var v = this.getRecord(varname)
                //FIXME: if no nextVal fn, should sample?
                var newval = v.erp.nextVal(v.val, v.params)
                if (newval == null) {
                    v.val = v.erp.nextVal(null, v.params) //get first in domain
                } else {
                    v.val = newval
                }
                v.logprob = v.erp.logprob(v.val, v.params)
            }
            this.traceUpdate()
        }
        stopEnumerate()
    }
}

RandomExecutionTrace.prototype.deepcopy = function deepcopy()
{
	var newdb = new RandomExecutionTrace(this.computation, false)
	newdb.logprob = this.logprob
	newdb.oldlogprob = this.oldlogprob
	newdb.newlogprob = this.newlogprob
	newdb.conditionsSatisfied = this.conditionsSatisfied
	newdb.returnValue = this.returnValue

	for (var i = 0; i < this.varlist.length; i++)
	{
		var newvar = this.varlist[i].copy()
		newdb.varlist.push(newvar)
		newdb.vars[newvar.name] = newvar
	}

	return newdb
}

RandomExecutionTrace.prototype.freeVarNames = function freeVarNames(structural, nonstructural)
{
	structural = (structural == undefined ? true : structural)
	nonstructural = (nonstructural == undefined ? true : nonstructural)
	var names = []
	for (var name in this.vars)
	{
		var rec = this.vars[name]
		if (!rec.conditioned &&
			((structural && rec.structural) || (nonstructural && !rec.structural)))
			names.push(name)
	}
	return names
}

/*
Names of variables that this trace has that the other does not
*/
RandomExecutionTrace.prototype.varDiff = function varDiff(other)
{
	var arr = []
	for (var name in this.vars)
	{
		if (!other.vars[name])
			arr.push(name)
	}
	return arr
}

/*
Difference in log probability between this trace and the other
due to variables that this one has that the other does not
*/
RandomExecutionTrace.prototype.lpDiff = function lpDiff(other)
{
	return this.varDiff(other)
		.map(function(name) {return this.vars[name].logprob}.bind(this))
		.reduce(function(a,b) {return a+b}, 0)
}

/*
The singleton trace object
*/
var trace = null

/*
Run computation and update this trace accordingly
*/
RandomExecutionTrace.prototype.traceUpdate = function traceUpdate(structureIsFixed)
{
	var origtrace = trace
	trace = this

	this.logprob = 0.0
	this.newlogprob = 0.0
	this.loopcounters = {}
	this.conditionsSatisfied = true
	this.currVarIndex = 0

	// If updating this trace can change the variable structure, then we
	// clear out the flat list of variables beforehand
	if (!structureIsFixed)
		this.varlist.length = 0

	// Mark all variables as inactive; only those reached
	// by the computation will become active
	for (var name in this.vars)
		this.vars[name].active = false

	// Run the computation, creating/looking up random variables
	this.returnValue = this.computation()

	// Clean up
	this.rootframe = null
	this.loopcounters = {}

	// Clear out any random values that are no longer reachable
	var newvars = {}
	this.oldlogprob = 0.0
	for (var name in this.vars)
	{
		var rec = this.vars[name]
		if (!rec.active)
			this.oldlogprob += rec.logprob
		else
			newvars[name] = rec
	}
	this.vars = newvars

	// Reset the original singleton trace
	trace = origtrace
}

/*
Propose a random change to a random variable 'varname'
Returns a new sample trace from the computation and the
forward and reverse probabilities of this proposal
*/
RandomExecutionTrace.prototype.proposeChange = function proposeChange(varname, structureIsFixed)
{
	var nextTrace = this.deepcopy()
	var v = nextTrace.getRecord(varname)
	var propval = v.erp.proposal(v.val, v.params)
	var fwdPropLP = v.erp.logProposalProb(v.val, propval, v.params)
	var rvsPropLP = v.erp.logProposalProb(propval, v.val, v.params)
	v.val = propval
	v.logprob = v.erp.logprob(v.val, v.params)
	nextTrace.traceUpdate(structureIsFixed)
	fwdPropLP += nextTrace.newlogprob
	rvsPropLP += nextTrace.oldlogprob
	return [nextTrace, fwdPropLP, rvsPropLP]
}

/*
Return the current structural name, as determined by the interpreter stack
*/
RandomExecutionTrace.prototype.currentName = function currentName()
{
	var loopnum = this.loopcounters[idstack] || 0
	this.loopcounters[idstack] = loopnum + 1
	return JSON.stringify(idstack) + ":" + loopnum
}

/*
Looks up the value of a random variable.
Creates the variable if it does not already exist
*/
RandomExecutionTrace.prototype.lookup = function lookup(erp, params, isStructural, conditionedValue)
{
	var record = null
	var name = null

	// Try to find the variable (first check the flat list, then do
	// slower structural lookup)
	var varIsInFlatList = this.currVarIndex < this.varlist.length
	if (varIsInFlatList)
		record = this.varlist[this.currVarIndex]
	else
	{
		name = this.currentName()
		record = this.vars[name]
		if (!record || record.erp != erp || record.structural != isStructural)
			record = null
	}

	// If we didn't find the variable, create a new one
	if (!record)
	{
        if (initEnumerate) { // If we are doing ennumeration init new vars to first val in domain:
            var val = erp.nextVal(null, params)
        } else {
            var val = conditionedValue || erp.sample_impl(params)
        }
		var ll = erp.logprob(val, params)
		this.newlogprob += ll
		record = new RandomVariableRecord(name, erp, params, val, ll, isStructural, conditionedValue !== undefined)
		this.vars[name] = record
	}
	// Otherwise, reuse the variable we found, but check if its parameters/conditioning
	// status have changed
	else
	{
		record.conditioned = (conditionedValue != undefined)
		var hasChanges = false
		if (!util.arrayEquals(record.params, params))
		{
			record.params = params
			hasChanges = true
		}
		if (conditionedValue && conditionedValue != record.val)
		{
			record.val = conditionedValue
			record.conditioned = true
			hasChanges = true
		}
		if (hasChanges)
			record.logprob = erp.logprob(record.val, record.params)
	}
	// Finish up and return
	if (!varIsInFlatList)
		this.varlist.push(record)
	this.currVarIndex++
	this.logprob += record.logprob
	record.active = true
	return record.val
}

// Simply retrieve the variable record associated with 'name'
RandomExecutionTrace.prototype.getRecord = function getRecord(name)
{
	return this.vars[name]
}

// Add a new factor into the log-likelihood of this trace
RandomExecutionTrace.prototype.addFactor = function addFactor(num)
{
	this.logprob += num
}

// Condition the trace on the value of a boolean expression
RandomExecutionTrace.prototype.conditionOn = function conditionOn(boolexpr)
{
	this.conditionsSatisfied &= boolexpr
}

// Exported functions for interacting with the global trace

function lookupVariableValue(erp, params, isStructural, conditionedValue)
{
	if (!trace)
	{
		return conditionedValue || erp.sample_impl(params)
	}
	else
	{
		return trace.lookup(erp, params, isStructural, conditionedValue)
	}
}

function newTrace(computation, init)
{
	return new RandomExecutionTrace(computation, init)
}

function factor(num)
{
	if (trace)
		trace.addFactor(num)
}

function condition(boolexpr)
{
	if (trace)
		trace.conditionOn(boolexpr)
}

module.exports =
{
    startEnumerate: startEnumerate,
    stopEnumerate: stopEnumerate,
	enterfn: enterfn,
	leavefn: leavefn,
	lookupVariableValue: lookupVariableValue,
	newTrace: newTrace,
	factor: factor,
	condition: condition
}<|endoftext|>


<commit_before>import React from 'react';
import Chartist from 'chartist';

export default class Chart extends React.Component {
  componentDidMount() {
    const {type, data, options = {}, responsiveOptions = []} = this.props;

    this.chartist = new Chartist[type](React.findDOMNode(this), data, options, responsiveOptions);
  }

  componentWillReceiveProps(newProps) {
    const {data, options = {}} = newProps;

    this.chartist.update(data, options, true);
  }

  componentWillUnmount() {
    this.chartist.detach();
  }

  render() {
    return

;
  }
}

Chart.propTypes = {
  type: React.PropTypes.string.isRequired,
  ratio: React.PropTypes.string,
  data: React.PropTypes.shape({
    labels: React.PropTypes.array.isRequired,
    series: React.PropTypes.array.isRequired
  }),
  options: React.PropTypes.object,
  responsiveOptions: React.PropTypes.array
};
<commit_msg>Combine chart creation and update logics<commit_after>import React from 'react';
import Chartist from 'chartist';

export default class Chart extends React.Component {
  componentDidMount() {
    this.updateChart(this.props);
  }

  componentWillReceiveProps(newProps) {
    this.updateChart(newProps);
  }

  componentWillUnmount() {
    this.chartist.detach();
  }

  render() {
    return

;
  }

  updateChart(props) {
    const {type, data, options = {}, responsiveOptions = []} = props;

    this.chartist ? this.chartist.update(data, options, true) :
    data.series ? this.chartist = new Chartist[type](React.findDOMNode(this), data, options, responsiveOptions) :
    null;
  }
}

Chart.propTypes = {
  type: React.PropTypes.string.isRequired,
  ratio: React.PropTypes.string,
  data: React.PropTypes.shape({
    labels: React.PropTypes.array.isRequired,
    series: React.PropTypes.array.isRequired
  }),
  options: React.PropTypes.object,
  responsiveOptions: React.PropTypes.array
};
<|endoftext|>


<commit_before>import { debug }                from '../utils/debug';
import { EventEmitter }         from 'events';
import { Observable }           from 'rxjs/Observable';

export class MiniDroneService extends EventEmitter {

    constructor() {
        super();
        this.drone = null;
        this.cmdService = null;
        this.ftpGetService = null;
        this.ftpHandlingService = null;
        this.cmdObservable = null;
        this.ftpObservable = null;
        this.noble = require('noble');
    }

    startScanning() {
        return new Promise((resolve, reject) => {
            try {
                this.noble.on('scanStart', () => {
                    debug('scanning devices...');
                    resolve("success");
                });

                this.noble.on('stateChange', (state) => {
                    try {
                        (state === 'poweredOn') ? this.noble.startScanning() : this.noble.stopScanning();
                    } catch(e) {
                        reject(e);
                    }
                });
            } catch (e) {
                reject(e);
            }
        });
    }

    stopScanning() {
        return new Promise((resolve, reject) => {
            try {
                this.noble.on('scanStop', () => {
                    debug('scanning stopped...');
                    resolve("success");
                });

                this.noble.stopScanning();
            } catch (e) {
                reject(e);
            }
        });
    }

    discoverDevice(droneIdentifier) {
        return new Promise((resolve, reject) => {
            try {
                this.noble.on('discover', (peripheral) => {
                    if ((peripheral.advertisement.localName &&
                        peripheral.advertisement.localName.includes(droneIdentifier)) ||
                        peripheral.advertisement.uuid === droneIdentifier) {
                        debug('peripheral discovered: '+ peripheral.advertisement.localName +
                            ' at promixity: ' + peripheral.rssi);
                        resolve(peripheral);
                    }
                });
            } catch (e) {
                reject(e);
            }
        });
    }

    connect(peripheral) {
        return new Promise((resolve, reject) => {
            let self = this;
            try {
                peripheral.on('connect', function() {
                    debug('handshake completed...');
                    self.drone = peripheral;
                    resolve("success");
                });

                peripheral.connect();
            } catch (e) {
                reject(e);
            }
        });
    }

    updateProximity() {
        return new Promise((resolve, reject) => {
            try {
                this.drone.on('rssiUpdate', function(rssi) {
                    debug("proximity updated to: " + rssi);
                    resolve("success");
                });

                this.drone.updateRssi();
            } catch (e) {
                reject(e);
            }
        });
    }

    discoverServices() {
        return new Promise((resolve, reject) => {
            try {
                this.drone.on('servicesDiscover', function(services) {
                    debug('services found: ' + services);
                    resolve(services);
                });

                this.drone.discoverServices();
            } catch (e) {
                reject(e);
            }
        });
    }

    discoverCharacteristics(services) {
        return new Promise((resolve, reject) => {
            try {
                let ids = [],
                    chars = [];
                services.forEach((service, idx, array) => {
                    service.on('characteristicsDiscover', function(characteristics) {
                        debug('characteristics found: ' + characteristics);
                        chars = chars.concat(characteristics);
                        ids.push(idx);

                        if (ids.length === array.length) {
                            resolve(chars);
                        }
                    });
                    service.discoverCharacteristics();
                })

            } catch (e) {
                reject(e);
            }
        });
    }

    identifyCharacteristics(characteristics) {
        return new Promise((resolve, reject) => {
            try {
                let cmdChars = characteristics.filter((char) => char.uuid.indexOf("fa") >= 0),
                    notifyChars = characteristics.filter((char) => char.uuid.indexOf("fb") >= 0),
                    ftpChars = characteristics.filter((char) => char.uuid.indexOf("fd2") >= 0);

                this.cmdService = cmdChars[10];
                this.cmdObservable = this.createObservable(notifyChars);
                this.ftpGetService = ftpChars[1];
                this.ftpHandlingService = ftpChars[2];
                this.ftpObservable = this.createObservable(ftpChars);

                this.subscribeToNotify(notifyChars).then(() => {
                    this.subscribeToNotify(ftpChars).then(() => {
                        resolve('success');
                    }).catch(e => {
                        reject(e);
                    });
                }).catch(e => {
                    reject(e);
                });
            } catch (e) {
                reject(e);
            }
        });
    }

    subscribeToNotify(characteristics) {
        return new Promise((resolve, reject) => {
            try {
                let ids = [];
                characteristics.forEach((char, idx, array) => {
                    char.on('notify', function(state) {
                        // debug('on -> notify: ' + this.uuid + ': ' + state);

                        ids.push(idx);
                        if (ids.length === array.length) {
                            debug('subscribed to characteristics...');
                            resolve('success');
                        }
                    });

                    char.notify(true);
                });
            } catch (e) {
                reject(e);
            }
        });
    }

    createObservable(characteristics) {
        return Observable
                .create(observer => {
                    debug('Creating observable...');
                    characteristics.forEach((char) => {
                        char.on('data', function (data) {
                            let arr = Array.prototype.slice.call(data, 0);
                            observer.next(arr.join('+'));
                        });
                    });

                    return function () {
                        debug('observable disposed');
                    }
                });

    }

    sendNavCommand(buffer) {
        return new Promise((resolve, reject) => {
            try {
                debug('Sending Command...');
                this.cmdService.write(buffer, false);
                resolve("success");
            } catch (e) {
                reject(e);
            }
        });
    }

    sendFTPCommand(buffer, thruGetService) {
        return new Promise((resolve, reject) => {
            try {
                if (thruGetService) {
                    this.ftpGetService.write(buffer, false);
                } else {
                    this.ftpHandlingService.write(buffer, false);
                }
                resolve("success");
            } catch (e) {
                reject(e);
            }
        });
    }

    disconnect() {
        return new Promise((resolve, reject) => {
            try {
                debug('disconnecting drone...')
                this.drone.disconnect();
                resolve("success");
            } catch (e) {
                reject(e);
            }
        });
    }
}
<commit_msg>Code cleanup.<commit_after>import { debug }                from '../utils/debug';
import { Observable }           from 'rxjs/Observable';

export class MiniDroneService {

    constructor() {
        this.drone = null;
        this.cmdService = null;
        this.ftpGetService = null;
        this.ftpHandlingService = null;
        this.cmdObservable = null;
        this.ftpObservable = null;
        this.noble = require('noble');
    }

    startScanning() {
        return new Promise((resolve, reject) => {
            try {
                this.noble.on('scanStart', () => {
                    debug('scanning devices...');
                    resolve("success");
                });

                this.noble.on('stateChange', (state) => {
                    try {
                        (state === 'poweredOn') ? this.noble.startScanning() : this.noble.stopScanning();
                    } catch(e) {
                        reject(e);
                    }
                });
            } catch (e) {
                reject(e);
            }
        });
    }

    stopScanning() {
        return new Promise((resolve, reject) => {
            try {
                this.noble.on('scanStop', () => {
                    debug('scanning stopped...');
                    resolve("success");
                });

                this.noble.stopScanning();
            } catch (e) {
                reject(e);
            }
        });
    }

    discoverDevice(droneIdentifier) {
        return new Promise((resolve, reject) => {
            try {
                this.noble.on('discover', (peripheral) => {
                    if ((peripheral.advertisement.localName &&
                        peripheral.advertisement.localName.includes(droneIdentifier)) ||
                        peripheral.advertisement.uuid === droneIdentifier) {
                        debug('peripheral discovered: '+ peripheral.advertisement.localName +
                            ' at promixity: ' + peripheral.rssi);
                        resolve(peripheral);
                    }
                });
            } catch (e) {
                reject(e);
            }
        });
    }

    connect(peripheral) {
        return new Promise((resolve, reject) => {
            let self = this;
            try {
                peripheral.on('connect', function() {
                    debug('handshake completed...');
                    self.drone = peripheral;
                    resolve("success");
                });

                peripheral.connect();
            } catch (e) {
                reject(e);
            }
        });
    }

    updateProximity() {
        return new Promise((resolve, reject) => {
            try {
                this.drone.on('rssiUpdate', function(rssi) {
                    debug("proximity updated to: " + rssi);
                    resolve("success");
                });

                this.drone.updateRssi();
            } catch (e) {
                reject(e);
            }
        });
    }

    discoverServices() {
        return new Promise((resolve, reject) => {
            try {
                this.drone.on('servicesDiscover', function(services) {
                    debug('services found: ' + services);
                    resolve(services);
                });

                this.drone.discoverServices();
            } catch (e) {
                reject(e);
            }
        });
    }

    discoverCharacteristics(services) {
        return new Promise((resolve, reject) => {
            try {
                let ids = [],
                    chars = [];
                services.forEach((service, idx, array) => {
                    service.on('characteristicsDiscover', function(characteristics) {
                        debug('characteristics found: ' + characteristics);
                        chars = chars.concat(characteristics);
                        ids.push(idx);

                        if (ids.length === array.length) {
                            resolve(chars);
                        }
                    });
                    service.discoverCharacteristics();
                })

            } catch (e) {
                reject(e);
            }
        });
    }

    identifyCharacteristics(characteristics) {
        return new Promise((resolve, reject) => {
            try {
                let cmdChars = characteristics.filter((char) => char.uuid.indexOf("fa") >= 0),
                    notifyChars = characteristics.filter((char) => char.uuid.indexOf("fb") >= 0),
                    ftpChars = characteristics.filter((char) => char.uuid.indexOf("fd2") >= 0);

                this.cmdService = cmdChars[10];
                this.cmdObservable = this.createObservable(notifyChars);
                this.ftpGetService = ftpChars[1];
                this.ftpHandlingService = ftpChars[2];
                this.ftpObservable = this.createObservable(ftpChars);

                this.subscribeToNotify(notifyChars).then(() => {
                    this.subscribeToNotify(ftpChars).then(() => {
                        resolve('success');
                    }).catch(e => {
                        reject(e);
                    });
                }).catch(e => {
                    reject(e);
                });
            } catch (e) {
                reject(e);
            }
        });
    }

    subscribeToNotify(characteristics) {
        return new Promise((resolve, reject) => {
            try {
                let ids = [];
                characteristics.forEach((char, idx, array) => {
                    char.on('notify', function(state) {
                        // debug('on -> notify: ' + this.uuid + ': ' + state);

                        ids.push(idx);
                        if (ids.length === array.length) {
                            debug('subscribed to characteristics...');
                            resolve('success');
                        }
                    });

                    char.notify(true);
                });
            } catch (e) {
                reject(e);
            }
        });
    }

    createObservable(characteristics) {
        return Observable
                .create(observer => {
                    debug('Creating observable...');
                    characteristics.forEach((char) => {
                        char.on('data', function (data) {
                            let arr = Array.prototype.slice.call(data, 0);
                            observer.next(arr.join('+'));
                        });
                    });

                    return function () {
                        debug('observable disposed');
                    }
                });

    }

    sendNavCommand(buffer) {
        return new Promise((resolve, reject) => {
            try {
                debug('Sending Command...');
                this.cmdService.write(buffer, false);
                resolve("success");
            } catch (e) {
                reject(e);
            }
        });
    }

    sendFTPCommand(buffer, thruGetService) {
        return new Promise((resolve, reject) => {
            try {
                if (thruGetService) {
                    this.ftpGetService.write(buffer, false);
                } else {
                    this.ftpHandlingService.write(buffer, false);
                }
                resolve("success");
            } catch (e) {
                reject(e);
            }
        });
    }

    disconnect() {
        return new Promise((resolve, reject) => {
            try {
                debug('disconnecting drone...')
                this.drone.disconnect();
                resolve("success");
            } catch (e) {
                reject(e);
            }
        });
    }
}
<|endoftext|>


<commit_before>"use strict";
/* Util */
var console = (window.console = window.console || {});

function Material(params) {
	this.initialised = false;
	var modules = params && params.hasOwnProperty("modules") ? params.modules : null;
	this.init(modules);
}
Material.prototype.init = function(modules) {
	if (this.initialised) return;
	if (!modules) {
		Dialog.init();
		Responsive.init();
		SideMenu.init();
		Ripple.init();
	}
	else {
		for (var i = 0, len = modules.length; i < len; i++) {
			var module = modules[i];
			if (!window.hasOwnProperty(module) || !window[module].hasOwnProperty("init") || !window[module].isMaterialModule) {
				console.warn("[material.init] Module not found");
				return;
			}
			window[module].init();
		}
	}
	this.initialised = true;
};

/* Responsive code */
var Responsive = {
	initialised: false,
	isMaterialModule: true,
	constructor: Responsive,
	init: function() {
		if (this.initialised) return;
		this.onResize();
		window.addEventListener("resize", this.onResize.bind(this));
		this.initialised = true;
	},
	onResize: function() {
		var width     = window.innerWidth,
		    oldDevice = this.device;
		if (width > 1000) {
			this.device = "desktop";
		}
		else if (width > 450) {
			this.device = "tablet";
		}
		else {
			this.device = "phone";
		}
		document.body.classList.remove(oldDevice);
		document.body.classList.add(this.device);
	},
	addResizeHandler: function(handler) {
		window.addEventListener("resize", handler);
	},
	removeResizeHandler: function(handler) {
		window.removeEventListener("resize", handler);
	}
};

/* Theme code */
var Theme = {
	isMaterialModule: true,
	toggle: function(element) {
		var el = element || document.body;
		if (el.classList.contains("dark-theme")) {
			el.classList.remove("dark-theme");
		}
		else {
			el.classList.add("dark-theme");
		}
	},
	setTheme: function(theme, element) {
		var el = element || document.body;
		switch (theme) {
			case "light":
				el.classList.remove("dark-theme");
				break;
			case "dark":
				el.classList.add("dark-theme");
				break;
			default:
				console.log("[Theme.setTheme] Unknown theme : " + theme);
				break;
		}
	}
};

/* SideMenu code */
var SideMenu = {
	initialised: false,
	isMaterialModule: true,
	constructor: SideMenu,
	init: function(params) {
		if (this.initialised) return;
		this.createOverlay();
		if (params && params.overlay) {
			this.setOverlay(params.overlay);
		}
		this.overlay.addEventListener("click", function() {
			var sidemenus = document.querySelectorAll(".sidemenu");
			for (var i = 0, len = sidemenus.length; i < len; i++) {
				var sidemenu = sidemenus[i];
				if (!sidemenu.hidden && (!sidemenu.classList.contains("sidebar") || (typeof Responsive == "undefined" || Responsive.device !== "desktop"))) {
					this.hide(sidemenu);
				}
			}
		}.bind(this));
		if (typeof Responsive != "undefined") {
			Responsive.addResizeHandler(this.onResize.bind(this));
		}
		this.onResize();
		this.initialised = true;
	},
	createOverlay: function() {
		if (document.querySelector(".sidemenu-overlay")) {
			this.overlay = document.querySelectorAll(".sidemenu-overlay")[0];
			return;
		}
		var overlay = document.createElement("div");
		overlay.className = "overlay sidemenu-overlay";
		overlay.hidden = true;
		overlay.setAttribute("id", "mf_overlay_" + Math.floor(Math.random() * 100000));
		document.body.appendChild(overlay);
		this.overlay = overlay;
	},
	toggle: function(sm) {
		if (!sm.classList.contains("sidebar") || (typeof Responsive == "undefined" || Responsive.device !== "desktop")) {
			this.overlay.hidden = !sm.hidden;
		}
		sm.hidden = !sm.hidden;
	},
	show: function(sm) {
		if (!sm.classList.contains("sidebar") || (typeof Responsive == "undefined" || Responsive.device !== "desktop")) {
			this.overlay.hidden = false;
		}
		sm.hidden = false;
	},
	hide: function(sm) {
		this.overlay.hidden = true;
		sm.hidden = true;
	},
	onResize: function() {
		var sidebars = document.querySelectorAll(".sidebar");
		for (var i = 0, len = sidebars.length; i < len; i++) {
			if (Responsive.device == "desktop") {
				this.show(sidebars[i]);
			}
			else {
				this.hide(sidebars[i]);
			}
		}
	}
};

/* Dialog code */
var Dialog = {
	initialised: false,
	isMaterialModule: true,
	constructor: Dialog,
	init: function() {
		if (this.initialised) return;
		this.createOverlay();
		var buttons = document.querySelectorAll(".dialog-confirm, .dialog-close");
		for (var i = 0, len = buttons.length; i < len; i++) {
			buttons[i].addEventListener("click", this.hideCurrentDialog.bind(this));
		}
		this.initialised = true;
	},
	createOverlay: function() {
		if (document.querySelector(".dialog-overlay")) {
			this.overlay = document.querySelectorAll(".dialog-overlay")[0];
			return;
		}
		var overlay = document.createElement("div");
		overlay.className = "overlay dialog-overlay";
		overlay.hidden = true;
		overlay.setAttribute("id", "mf_overlay_" + Math.floor(Math.random() * 100000));
		document.body.appendChild(overlay);
		this.overlay = overlay;
	},
	show: function(dialog) {
		this.overlay.hidden = false;
		dialog.hidden = false;
	},
	hide: function(dialog) {
		this.overlay.hidden = true;
		dialog.hidden = true;
	},
	toggle: function(dialog) {
		this.overlay.hidden = !dialog.hidden;
		dialog.hidden = !dialog.hidden;
	},
	getCurrentDialog: function() {
		return document.querySelector(".dialog:not([hidden])");
	},
	hideCurrentDialog: function() {
		this.hide(this.getCurrentDialog());
	}
};

/* Ripple code */
var Ripple = {
	isMaterialModule: true,
	initialised: false,
	constructor : Ripple,
	init: function() {
		if(this.initialised) return;
		// var rippleitems = document.querySelectorAll(".button:not(.no-ripple):not([ripple='none']), .fab:not(.no-ripple):not([ripple='none']), [ripple]:not([ripple='none']), .ripple");
		// for (var i = 0; i < rippleitems.length; i++) {
		// 	rippleitems[i].addEventListener("mousedown", this.onClick, false);
		// 	rippleitems[i].addEventListener("touchstart", this.onClick, false);
		// }
		// Hack to enable :active state on iOS
		document.addEventListener("touchstart", function() {}, false);
		this.initialised = true;
	},
	onClick: function(event) {
		/* FIXME : This needs fixing */
		var x     = event.pageX - this.offsetLeft - (this.clientWidth / 2),
		    y     = event.pageY - this.offsetTop - (this.clientHeight / 2),
		    style = document.createElement("style"),
		    id    = "data-mf-ripple_" + Math.floor(Math.random() * 1000000),
		    value = Math.floor(Math.random() * 1000000);
		this.setAttribute(id, value);
		style.innerHTML = "[" + id + "='" + value + "']::after {\n"+
		                  "left: " + x + "px;\n"+
		                  "top: " + y + "px;}";
		document.body.appendChild(style);
		setTimeout(function() {
			style.remove();
			this.removeAttribute(id);
		}.bind(this), 2000);
	}
};
<commit_msg>FancyHeader rework<commit_after>"use strict";
/* Util */
var console = (window.console = window.console || {});

function Material(params) {
	this.initialised = false;
	var modules = params && params.hasOwnProperty("modules") ? params.modules : null;
	this.init(modules);
}
Material.prototype.init = function(modules) {
	if (this.initialised) return;
	if (!modules) {
		Dialog.init();
		Responsive.init();
		SideMenu.init();
		Ripple.init();
	}
	else {
		for (var i = 0, len = modules.length; i < len; i++) {
			var module = modules[i];
			if (!window.hasOwnProperty(module) || !window[module].hasOwnProperty("init") || !window[module].isMaterialModule) {
				console.warn("[material.init] Module not found");
				return;
			}
			window[module].init();
		}
	}
	this.initialised = true;
};

/* Responsive code */
var Responsive = {
	initialised: false,
	isMaterialModule: true,
	constructor: Responsive,
	init: function() {
		if (this.initialised) return;
		this.onResize();
		window.addEventListener("resize", this.onResize.bind(this));
		this.initialised = true;
	},
	onResize: function() {
		var width     = window.innerWidth,
		    oldDevice = this.device;
		if (width > 1000) {
			this.device = "desktop";
		}
		else if (width > 450) {
			this.device = "tablet";
		}
		else {
			this.device = "phone";
		}
		document.body.classList.remove(oldDevice);
		document.body.classList.add(this.device);
	},
	addResizeHandler: function(handler) {
		window.addEventListener("resize", handler);
	},
	removeResizeHandler: function(handler) {
		window.removeEventListener("resize", handler);
	}
};

/* Theme code */
var Theme = {
	isMaterialModule: true,
	toggle: function(element) {
		var el = element || document.body;
		if (el.classList.contains("dark-theme")) {
			el.classList.remove("dark-theme");
		}
		else {
			el.classList.add("dark-theme");
		}
	},
	setTheme: function(theme, element) {
		var el = element || document.body;
		switch (theme) {
			case "light":
				el.classList.remove("dark-theme");
				break;
			case "dark":
				el.classList.add("dark-theme");
				break;
			default:
				console.log("[Theme.setTheme] Unknown theme : " + theme);
				break;
		}
	}
};

/* SideMenu code */
var SideMenu = {
	initialised: false,
	isMaterialModule: true,
	constructor: SideMenu,
	init: function(params) {
		if (this.initialised) return;
		this.createOverlay();
		if (params && params.overlay) {
			this.setOverlay(params.overlay);
		}
		this.overlay.addEventListener("click", function() {
			var sidemenus = document.querySelectorAll(".sidemenu");
			for (var i = 0, len = sidemenus.length; i < len; i++) {
				var sidemenu = sidemenus[i];
				if (!sidemenu.hidden && (!sidemenu.classList.contains("sidebar") || (typeof Responsive == "undefined" || Responsive.device !== "desktop"))) {
					this.hide(sidemenu);
				}
			}
		}.bind(this));
		if (typeof Responsive != "undefined") {
			Responsive.addResizeHandler(this.onResize.bind(this));
		}
		this.onResize();
		this.initialised = true;
	},
	createOverlay: function() {
		if (document.querySelector(".sidemenu-overlay")) {
			this.overlay = document.querySelectorAll(".sidemenu-overlay")[0];
			return;
		}
		var overlay = document.createElement("div");
		overlay.className = "overlay sidemenu-overlay";
		overlay.hidden = true;
		overlay.setAttribute("id", "mf_overlay_" + Math.floor(Math.random() * 100000));
		document.body.appendChild(overlay);
		this.overlay = overlay;
	},
	toggle: function(sm) {
		if (!sm.classList.contains("sidebar") || (typeof Responsive == "undefined" || Responsive.device !== "desktop")) {
			this.overlay.hidden = !sm.hidden;
		}
		sm.hidden = !sm.hidden;
	},
	show: function(sm) {
		if (!sm.classList.contains("sidebar") || (typeof Responsive == "undefined" || Responsive.device !== "desktop")) {
			this.overlay.hidden = false;
		}
		sm.hidden = false;
	},
	hide: function(sm) {
		this.overlay.hidden = true;
		sm.hidden = true;
	},
	onResize: function() {
		var sidebars = document.querySelectorAll(".sidebar");
		for (var i = 0, len = sidebars.length; i < len; i++) {
			if (Responsive.device == "desktop") {
				this.show(sidebars[i]);
			}
			else {
				this.hide(sidebars[i]);
			}
		}
	}
};

/* Dialog code */
var Dialog = {
	initialised: false,
	isMaterialModule: true,
	constructor: Dialog,
	init: function() {
		if (this.initialised) return;
		this.createOverlay();
		var buttons = document.querySelectorAll(".dialog-confirm, .dialog-close");
		for (var i = 0, len = buttons.length; i < len; i++) {
			buttons[i].addEventListener("click", this.hideCurrentDialog.bind(this));
		}
		this.initialised = true;
	},
	createOverlay: function() {
		if (document.querySelector(".dialog-overlay")) {
			this.overlay = document.querySelectorAll(".dialog-overlay")[0];
			return;
		}
		var overlay = document.createElement("div");
		overlay.className = "overlay dialog-overlay";
		overlay.hidden = true;
		overlay.setAttribute("id", "mf_overlay_" + Math.floor(Math.random() * 100000));
		document.body.appendChild(overlay);
		this.overlay = overlay;
	},
	show: function(dialog) {
		this.overlay.hidden = false;
		dialog.hidden = false;
	},
	hide: function(dialog) {
		this.overlay.hidden = true;
		dialog.hidden = true;
	},
	toggle: function(dialog) {
		this.overlay.hidden = !dialog.hidden;
		dialog.hidden = !dialog.hidden;
	},
	getCurrentDialog: function() {
		return document.querySelector(".dialog:not([hidden])");
	},
	hideCurrentDialog: function() {
		this.hide(this.getCurrentDialog());
	}
};

/* Ripple code */
var Ripple = {
	isMaterialModule: true,
	initialised: false,
	constructor : Ripple,
	init: function() {
		if(this.initialised) return;
		// var rippleitems = document.querySelectorAll(".button:not(.no-ripple):not([ripple='none']), .fab:not(.no-ripple):not([ripple='none']), [ripple]:not([ripple='none']), .ripple");
		// for (var i = 0; i < rippleitems.length; i++) {
		// 	rippleitems[i].addEventListener("mousedown", this.onClick, false);
		// 	rippleitems[i].addEventListener("touchstart", this.onClick, false);
		// }
		// Hack to enable :active state on iOS
		document.addEventListener("touchstart", function() {}, false);
		this.initialised = true;
	},
	onClick: function(event) {
		/* FIXME : This needs fixing */
		var x     = event.pageX - this.offsetLeft - (this.clientWidth / 2),
		    y     = event.pageY - this.offsetTop - (this.clientHeight / 2),
		    style = document.createElement("style"),
		    id    = "data-mf-ripple_" + Math.floor(Math.random() * 1000000),
		    value = Math.floor(Math.random() * 1000000);
		this.setAttribute(id, value);
		style.innerHTML = "[" + id + "='" + value + "']::after {\n"+
		                  "left: " + x + "px;\n"+
		                  "top: " + y + "px;}";
		document.body.appendChild(style);
		setTimeout(function() {
			style.remove();
			this.removeAttribute(id);
		}.bind(this), 2000);
	}
};

/* FancyHeader Experimental
  Example usage - demo.js:
  FancyHeader.init({
	header:       document.querySelector(".toolbar"),
	scrollTarget: document.querySelector(".main-content")
  });
*/
var FancyHeader = {
	header: null,
	scrollTarget: null,
	state: "show",
	initialised: false,
	isMaterialModule: false,
	constructor: FancyHeader,
	init: function(options) {
		if (this.initialised) return;
		//Little Setup?
		if (options.header === null || options.scrollTarget === null) {
			console.warn("You need to Setup a Header and Scroll-Target(window or obj) at least!");
			return;
		}
		this.header = options.header;
		this.scrollTarget = options.scrollTarget;
		//Needs another attempt
		this.header.style.position = "fixed";
		this.header.style.width = "100%";
		//Fix for Paddings
		var headerHeight = Math.max(this.header.scrollHeight, this.header.offsetHeight, this.header.clientHeight);
		var sections = document.querySelectorAll(".navigation-section");
		for (var i = 0, len = sections.length; i < len; i++) {
			sections[i].style.paddingTop = headerHeight + "px";
		}
		this.lastY = this.scrollTarget.scrollY;
		this.scrollTarget.addEventListener("scroll", this.update.bind(this), false);
		this.initialised = true;
	},
	hide: function() {
		if (this.state == "hide") return;
		this.header.classList.toggle("hide");
		this.state = "hide";
	},
	show: function() {
		if (this.state == "show") return;
		this.header.classList.toggle("hide");
		this.state = "show";
	},
	getY: function(cb) {
		cb((this.scrollTarget.pageYOffset !== undefined) ? this.scrollTarget.pageYOffset
		: (this.scrollTarget.scrollTop !== undefined) ? this.scrollTarget.scrollTop
		: (document.documentElement || document.body.parentNode || document.body).scrollTop);
	},
	update: function() {
		var self = this;
		this.getY(function(y) {
			var direction = y > self.lastY ? "down" : "up";
			if (direction == "down") {
				self.hide();
			}
			else if (direction == "up") {
				self.show();
			}
			self.lastY = y;
		});
	}
};
<|endoftext|>


<commit_before>define(['js/debug', 'js/events', 'js/styles'], function (debug, events, styles) {
  var mentions = []
    , processedMentions = []
    , $mentionsPanel
    , $mentionsDropdown
    , mentionsCount = { total: 0, unread: 0 }
    , firstRun = true;

  function getStream() {
    var api = new Ext.data.HttpProxy({ url:'/ui/as_append3' });
    api.doRequest('read', null, {
      aggregateByDays: true,
      aggregatedRescheduleChanges: true,
      //appendContext: "{2:1400176884004}",
      filterAuthorMe: false,
      filterByDeltaTypes: "[comment]",
      filterEditedByMe: false,
      filterFollowedByMe: true,
      filterResponsibleMe: false,
      loadDepthLimit: 10,
      loadLimit: 100,
      massActionsEnabled: true,
      noPeep: true,
      onlyAfterTimeLastRead: false,
      onlyUnread: false,
      parentFolderId: null,
      scanLimit: 200,
    }, { read: handleMentionStreamData }, function(){});
  }

  function getComments(taskId, accountId) {
    var api = new Ext.data.HttpProxy({ url:'/ui/as_get_stream_for_entity' });
    api.doRequest('read', null, {
      loadDepthLimit: 5,
      onlyAfterTimeLastRead: false,
      taskId: taskId,
      accountId: accountId,
      parentFolderId: null,
      aggregateByDays: true,
      aggregatedRescheduleChanges: true,
      massActionsEnabled: true,
      loadLimit: 10,
      noPeep: true,
      scanLimit: 200,
      markAsRead: false,
      filterAuthorMe: false,
      filterByDeltaTypes: "[comment]",
      filterEditedByMe: false,
      filterFollowedByMe: true,
      filterResponsibleMe: false,
      onlyUnread: false,
    }, { read: handleMentionStreamData }, function(){});
  }

  function handleMentionStreamData(response) {
    if (response.status !== 200) {
      debug.error('Failed to get stream data', arguments);
      // We don't need to go any farther, so return an empty function
      return { success: function(){} };
    }

    var data = JSON.parse(response.responseText)
      , userId = $wrike.user.getUid()
      , yourMentions = [];

    // Loop through each update and each comment, looking for the current user being mentioned
    $(data.data.stream).each(function (streamIndex, streamUpdate) {
      $(streamUpdate.agentries).each(function (agentriesIndex, comment) {
        if (comment.comment.text.indexOf('') !== -1) {
          // Skip comments that we've already processed
          if ($.inArray(comment.id, processedMentions) !== -1) { return; }

          processedMentions.push(comment.id);
          var task = streamUpdate;
          delete task.agentries;
          yourMentions.push({ task: task, comment: comment });
          mentionsCount.total++;
          if (comment.isRead !== true) { mentionsCount.unread++; }
        }
      });
    });

    if (yourMentions.length === 0) { return { success: function(){} }; }

    // If this is not our first run, emit an event for any new mentions
    if (firstRun === true) { firstRun = false; }
    else { events.emitEvent('mention', yourMentions); }

    mentions = mentions.concat(yourMentions);
    // Sort mentions in reverse chronological order
    mentions.sort(function (a, b) { return b.comment.timepoint - a.comment.timepoint; });
    renderMentions();

    // We don't need to go any farther, so return an empty function
    return { success: function(){} };
  }

  function commentAdded(comment) {
    var tasksProcessed = [];
    $(comment.ids).each(function (i, taskId) {
      if ($.inArray(taskId, tasksProcessed) !== -1) { return; }
      tasksProcessed.push(taskId);
      getComments(taskId, comment.accountId);
    });
  }
  events.addListener('task.comment', commentAdded);

  function renderPanel() {
    $mentionsPanel = $(/*jshint multistr: true */ '\

\

\
    Mentions - Can\'t click links yet. Find the task yourself!\

\

\

\

\

\

\

\

\

\
    ').hide();
    $('body').append($mentionsPanel);
  }

  function renderMentions() {
    var $mentionsContainer = $mentionsPanel.find('.stream-view-template-target').empty()
      , $mention
      , lastMention;

    $(mentions).each(function (i, mention) {
      var data = {
        commentAuthor: $wrike.user(mention.comment.entryUid).data(),
        taskAuthor: $wrike.user(mention.task.uid).data(),
        firstResponsible: $wrike.user(mention.task.responsibles[0]).data(),
        timestamp: new Date(mention.comment.timepoint),
      };
      if (mention.task.started === null || mention.task.finished === null) {
        data.taskStart = data.taskEnd = null;
        data.taskLength = 0;
      } else {
        data.taskStart = new Date(mention.task.started);
        data.taskEnd = new Date(mention.task.finished);
        data.taskLength = Math.ceil((data.taskEnd - data.taskStart) / 86400 / 1000);
      }

      // If this is the same task as the last one, group the comments together
      if (typeof lastMention !== 'undefined' && lastMention.task.id === mention.task.id) {
        $mention.find('.comments').append(renderComment(mention.comment, data));
        return;
      }

      $mention = $(/*jshint multistr: true */ '\

\

\

\

\

\

\

\

\
        ' + mention.task.responsibles.length + '\

\

\

\

\

\
        ' + mention.task.text + '\
        \
          \
          [\
        \

\

\
        \
          ' + ((data.taskLength !== 0) ? ('Planned for ' + data.taskStart.toLocaleDateString() + ' – ' + data.taskEnd.toLocaleDateString() + ' (' + data.taskLength + 'd)') : 'Backlogged') + '\
             \
        \

\

\

\

' + renderComment(mention.comment, data) + '
\

\
      ');

      var folders = [];
      $(mention.task.parentFolders).each(function (i, folderId) {
        var folder = $w.folders.getById(folderId);

        // Skip any folders that we don't have access to
        if (typeof folder === 'undefined') { return; }

        var $folderLink = $('' + folder.data.title + '');

        $folderLink.click(function() { $wspace.History.openFolder({ id: folder.id }); });
        if (folders.length !== 0) { $folderLink.prepend(', '); }

        folders.push($folderLink);
      });
      $mention.find('.details .parent-folders').append(folders).append(']');
      $mentionsContainer.append($mention);
      lastMention = mention;
    });

    renderMentionsDropdown();
  }

  function renderComment(comment, data) {
    var commentHtml = /*jshint multistr: true */ '\

\

\
    ' + data.timestamp.toLocaleDateString() + ' at ' + data.timestamp.toLocaleTimeString() + '\

\

\

\

\

\

\

\

\
        \
          ' + data.commentAuthor.fullName + '\
          \
        \

\
          \
            ' + comment.comment.text + '\
          \

\

\

\

\

';
    return commentHtml;
  }

  function renderMentionsDropdown() {
    var mentionsHtml = 'Mentions (' + mentionsCount.total + ') ' +
          '
' + mentionsCount.unread + '
';
    if (typeof $mentionsDropdown === 'undefined') {
      $mentionsDropdown = $(/*jshint multistr: true */ '\
\
  ' + mentionsHtml + '\
\
      ');

      $mentionsDropdown.click(function () {
        $mentionsPanel.toggle();
        mentionsCount.unread = 0;
        renderMentionsDropdown();
      });

      $('.wrike_header_links').prepend($mentionsDropdown);
    } else {
      $mentionsDropdown.find('.mentions').html(mentionsHtml);
    }
  }

  styles.addStyle('mentions', /*jshint multistr: true */ '\
    .wspace_header_mentions .count {\
      display: inline-block;\
      background: red;\
      line-height: 16px;\
      background-color: #dc0d17;\
      background-image: -webkit-gradient(linear, center top, center bottom, from(#fa3c45), to(#dc0d17));\
      background-image: -webkit-linear-gradient(#fa3c45, #dc0d17);\
      color: #fff;\
      min-height: 13px;\
      padding: 1px 5px;\
      text-shadow: 0 -1px 0 rgba(0, 0, 0, .4);\
      -webkit-border-radius: 2px;\
      -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .7);\
      margin-left: 8px;\
    }\
    .wspace_header_mentions .count.hidden { display: none; }\
  ');

  renderPanel();
  getStream();

  return {
    mentions: mentions,
  };
});
<commit_msg>Make mentions dropdown links respond to clicks<commit_after>define(['js/debug', 'js/events', 'js/styles'], function (debug, events, styles) {
  var mentions = []
    , processedMentions = []
    , $mentionsPanel
    , $mentionsDropdown
    , mentionsCount = { total: 0, unread: 0 }
    , firstRun = true;

  function getStream() {
    var api = new Ext.data.HttpProxy({ url:'/ui/as_append3' });
    api.doRequest('read', null, {
      aggregateByDays: true,
      aggregatedRescheduleChanges: true,
      //appendContext: "{2:1400176884004}",
      filterAuthorMe: false,
      filterByDeltaTypes: "[comment]",
      filterEditedByMe: false,
      filterFollowedByMe: true,
      filterResponsibleMe: false,
      loadDepthLimit: 10,
      loadLimit: 100,
      massActionsEnabled: true,
      noPeep: true,
      onlyAfterTimeLastRead: false,
      onlyUnread: false,
      parentFolderId: null,
      scanLimit: 200,
    }, { read: handleMentionStreamData }, function(){});
  }

  function getComments(taskId, accountId) {
    var api = new Ext.data.HttpProxy({ url:'/ui/as_get_stream_for_entity' });
    api.doRequest('read', null, {
      loadDepthLimit: 5,
      onlyAfterTimeLastRead: false,
      taskId: taskId,
      accountId: accountId,
      parentFolderId: null,
      aggregateByDays: true,
      aggregatedRescheduleChanges: true,
      massActionsEnabled: true,
      loadLimit: 10,
      noPeep: true,
      scanLimit: 200,
      markAsRead: false,
      filterAuthorMe: false,
      filterByDeltaTypes: "[comment]",
      filterEditedByMe: false,
      filterFollowedByMe: true,
      filterResponsibleMe: false,
      onlyUnread: false,
    }, { read: handleMentionStreamData }, function(){});
  }

  function handleMentionStreamData(response) {
    if (response.status !== 200) {
      debug.error('Failed to get stream data', arguments);
      // We don't need to go any farther, so return an empty function
      return { success: function(){} };
    }

    var data = JSON.parse(response.responseText)
      , userId = $wrike.user.getUid()
      , yourMentions = [];

    // Loop through each update and each comment, looking for the current user being mentioned
    $(data.data.stream).each(function (streamIndex, streamUpdate) {
      $(streamUpdate.agentries).each(function (agentriesIndex, comment) {
        if (comment.comment.text.indexOf('') !== -1) {
          // Skip comments that we've already processed
          if ($.inArray(comment.id, processedMentions) !== -1) { return; }

          processedMentions.push(comment.id);
          var task = streamUpdate;
          delete task.agentries;
          yourMentions.push({ task: task, comment: comment });
          mentionsCount.total++;
          if (comment.isRead !== true) { mentionsCount.unread++; }
        }
      });
    });

    if (yourMentions.length === 0) { return { success: function(){} }; }

    // If this is not our first run, emit an event for any new mentions
    if (firstRun === true) { firstRun = false; }
    else { events.emitEvent('mention', yourMentions); }

    mentions = mentions.concat(yourMentions);
    // Sort mentions in reverse chronological order
    mentions.sort(function (a, b) { return b.comment.timepoint - a.comment.timepoint; });
    renderMentions();

    // We don't need to go any farther, so return an empty function
    return { success: function(){} };
  }

  function commentAdded(comment) {
    var tasksProcessed = [];
    $(comment.ids).each(function (i, taskId) {
      if ($.inArray(taskId, tasksProcessed) !== -1) { return; }
      tasksProcessed.push(taskId);
      getComments(taskId, comment.accountId);
    });
  }
  events.addListener('task.comment', commentAdded);

  function renderPanel() {
    $mentionsPanel = $(/*jshint multistr: true */ '\

\

\
    Mentions\

\

\

\

\

\

\

\

\

\
    ').hide();
    $('body').append($mentionsPanel);
  }

  function renderMentions() {
    var $mentionsContainer = $mentionsPanel.find('.stream-view-template-target').empty()
      , $mention
      , lastMention;

    $(mentions).each(function (i, mention) {
      var data = {
        commentAuthor: $wrike.user(mention.comment.entryUid).data(),
        taskAuthor: $wrike.user(mention.task.uid).data(),
        firstResponsible: $wrike.user(mention.task.responsibles[0]).data(),
        timestamp: new Date(mention.comment.timepoint),
      };
      if (mention.task.started === null || mention.task.finished === null) {
        data.taskStart = data.taskEnd = null;
        data.taskLength = 0;
      } else {
        data.taskStart = new Date(mention.task.started);
        data.taskEnd = new Date(mention.task.finished);
        data.taskLength = Math.ceil((data.taskEnd - data.taskStart) / 86400 / 1000);
      }

      // If this is the same task as the last one, group the comments together
      if (typeof lastMention !== 'undefined' && lastMention.task.id === mention.task.id) {
        $mention.find('.comments').append(renderComment(mention.comment, data));
        return;
      }

      $mention = $(/*jshint multistr: true */ '\

\

\

\

\

\

\

\

\
        ' + mention.task.responsibles.length + '\

\

\

\

\

\
        ' + mention.task.text + '\
        \
          \
          [\
        \

\

\
        \
          ' + ((data.taskLength !== 0) ? ('Planned for ' + data.taskStart.toLocaleDateString() + ' – ' + data.taskEnd.toLocaleDateString() + ' (' + data.taskLength + 'd)') : 'Backlogged') + '\
             \
        \

\

\

\

' + renderComment(mention.comment, data) + '
\

\
      ');

      var folders = [];
      $(mention.task.parentFolders).each(function (i, folderId) {
        var folder = $w.folders.getById(folderId);

        // Skip any folders that we don't have access to
        if (typeof folder === 'undefined') { return; }

        var $folderLink = $('' + folder.data.title + '');

        $folderLink.click(function() { $wspace.History.openFolder({ id: folder.id }); });
        if (folders.length !== 0) { $folderLink.prepend(', '); }

        folders.push($folderLink);
      });
      $mention.find('.details .parent-folders').append(folders).append(']');

      // Make the entire task item launch the overlay when clicked
      $mention.click(function() {
        $wrike.bus.fireEvent('overlay.task.selected', mention.task.id);
      });

      $mentionsContainer.append($mention);
      lastMention = mention;
    });

    // Make all usernames clickable
    $wrike.contact.AvatarFactory.xAddOnClickListener(Ext.fly('powerwrike-mentions-list'), ["stream-user-id", "x-user-avatar"]);

    renderMentionsDropdown();
  }

  function renderComment(comment, data) {
    var commentHtml = /*jshint multistr: true */ '\

\

\
    ' + data.timestamp.toLocaleDateString() + ' at ' + data.timestamp.toLocaleTimeString() + '\

\

\

\

\

\

\

\

\
        \
          ' + data.commentAuthor.fullName + '\
          \
        \

\
          \
            ' + comment.comment.text + '\
          \

\

\

\

\

';
    return commentHtml;
  }

  function renderMentionsDropdown() {
    var mentionsHtml = 'Mentions (' + mentionsCount.total + ') ' +
          '
' + mentionsCount.unread + '
';
    if (typeof $mentionsDropdown === 'undefined') {
      $mentionsDropdown = $(/*jshint multistr: true */ '\
\
  ' + mentionsHtml + '\
\
      ');

      $mentionsDropdown.click(function () {
        $mentionsPanel.toggle();
        mentionsCount.unread = 0;
        renderMentionsDropdown();
      });

      $('.wrike_header_links').prepend($mentionsDropdown);
    } else {
      $mentionsDropdown.find('.mentions').html(mentionsHtml);
    }
  }

  styles.addStyle('mentions', /*jshint multistr: true */ '\
    .wspace_header_mentions .count {\
      display: inline-block;\
      background: red;\
      line-height: 16px;\
      background-color: #dc0d17;\
      background-image: -webkit-gradient(linear, center top, center bottom, from(#fa3c45), to(#dc0d17));\
      background-image: -webkit-linear-gradient(#fa3c45, #dc0d17);\
      color: #fff;\
      min-height: 13px;\
      padding: 1px 5px;\
      text-shadow: 0 -1px 0 rgba(0, 0, 0, .4);\
      -webkit-border-radius: 2px;\
      -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .7);\
      margin-left: 8px;\
    }\
    .wspace_header_mentions .count.hidden { display: none; }\
  ');

  renderPanel();
  getStream();

  return {
    mentions: mentions,
  };
});
<|endoftext|>


<commit_before>export default function kineticsService() {
    return {
        getVelocity(accelArray) {
            let newArray = [];
            accelArray.forEach((element, index, array) => {
                if (index === (array.length - 1)) return;
                let time = Date.parse(array[index + 1].date) - Date.parse(element.date);
                let velocity = (1 / 2) * (array[index + 1].acceleration + element.acceleration) * time;
                newArray.push({time,velocity});
            });
            return new Promise((resolve, reject) => {
                resolve(newArray);
            });
        },
        getDistance(velArray) {
            let newArray = [];
            velArray.forEach((element, index, array) => {
                if (index === (array.length - 1)) return;
                let time = array[index + 1].time - element.time;
                let distance = (1 / 2) * (array[index + 1].velocity + element.velocity) * time;
                newArray.push({time,distance});
            });
            return new Promise((resolve, reject) => {
                resolve(newArray);
            });
        },
        totalDistance(distArray) {
            console.log('distArr: ', distArray);
            return distArray.reduce((acc, curr) => { return acc.distance + curr.distance; });
        }
    };
};
<commit_msg>fixed kinetic services so it gives distance...but they're nonsensical due to gravity<commit_after>export default function kineticsService() {
    return {
        getVelocity(accelArray) {
            let newArray = [];
            let timeStamp = 0;
            accelArray.forEach((element, index, array) => {
                if (index === (array.length - 1)) return;
                let time = ( Date.parse(array[index + 1].date) - Date.parse(element.date) ) / 1000; // because the return values are in ms
                timeStamp += time;
                let velocity = (1 / 2) * (array[index + 1].acceleration + element.acceleration) * time;
                newArray.push({time,timeStamp,velocity});
            });
            return new Promise((resolve, reject) => {
                resolve(newArray);
            });
        },
        getDistance(velArray) {
            let newArray = [];
            let timeStamp = 0;
            velArray.forEach((element, index, array) => {
                if (index === (array.length - 1)) return;
                let time = (array[index + 1].time + element.time) / 2;
                timeStamp += time;
                let distance = (1 / 2) * (array[index + 1].velocity + element.velocity) * time;
                newArray.push({time,timeStamp,distance});
            });
            return new Promise((resolve, reject) => {
                resolve(newArray);
            });
        },
        totalDistance(distArray) {
            console.log('distArr: ', distArray);
            return distArray.reduce((acc, curr) => {
                return acc + curr.distance;
            }, 0);
        }
    };
};
<|endoftext|>


<commit_before>
// グローバル変数
var localStorageFlg = true;

var initializeStatus = 0;
var loadingStatus = true;
var diffStatus = true;

var dateList = new Array();

var rankingMode = 0;

var initDate;
var initDate2;
var exitDate2;
var exitDate;

// 定数
LOCAL_STORAGE_HISTORY_KEY = "osuRankingDiaryHistoryV1";

$(function() {

  // ----------------------------------------------------------------
  // 初期化
  initializeORD();

  $(document).ajaxSuccess(function() {
    initializeORD();
  });

  // ----------------------------------------------------------------
  // ローカルストレージ対応判定
  if(!localStorage) {
    console.log('"Local Storage" is unsupported. Data can not be saved.');
    console.log('"ローカルストレージ"機能に対応していません。データを保存することができません。');

    localStorageFlg = false;

    $("#action-save").remove();
    $("#action-load").remove();
    $("#action-reset").remove();
  }

  // ----------------------------------------------------------------
  // トップまでのスクロール
  $(document).on('click', '#pagetop', function() {
    // console.log("Scroll to Top");
    $('body,html').animate({scrollTop:0}, 500);
  });

  // ----------------------------------------------------------------
  // タイトル
  $(document).on('click', '#title', function() {
    // console.log("Click Title");

    location.reload();

  });

  // ----------------------------------------------------------------
  // ローカルストレージを初期化
  $(document).on('click', '#action-reset', function() {
    // console.log("Click Reset action");

    showConfirmDialog("ローカルストレージの初期化", "
ローカルストレージに保存されている内容を全て初期化します。
よろしいですか？
", initializeLocalStorage)
  });

  // ----------------------------------------------------------------
  // View difference columnを変更
  $(document).on("change", "#view-column", function() {
    console.log("Change Vire difference column: " + $(this).prop("checked"));

    diffStatus = toggleBoolean(diffStatus);

    var checkViewColumn = $(this).prop("checked");

    if (checkViewColumn) {
      // 変動を表示
      $("#setting-date-area > #difference-date").removeClass("display-none");
      $("#exit-date").attr("min", initDate2);
      fixRankDate(0);

    } else {
      // 変動を非表示
      $("#setting-date-area > #difference-date").addClass("display-none");
      $("#exit-date").attr("min", initDate);

    }

    $(".change-value, .difference-of-above").each(function(i, element) {
      if (checkViewColumn) {
        $(element).removeClass("display-none");

      } else {
        $(element).addClass("display-none");

      }
    });

  });

  // ----------------------------------------------------------------
  // init-date を変更
  $(document).on("change", "#init-date", function() {
    fixRankDate(0);

  });

  // ----------------------------------------------------------------
  // exit-date を変更
  $(document).on("change", "#exit-date", function() {
    fixRankDate(1);

  });

  // ----------------------------------------------------------------
  // init-rank を変更
  $(document).on("change", "#init-rank", function() {
    fixRank(0);

  });

  // ----------------------------------------------------------------
  // exit-rank を変更
  $(document).on("change", "#exit-rank", function() {
    fixRank(1);

  });

});

// ----------------------------------------------------------------
// Functions

// ----------------------------------------------------------------
// osu! Ranking Diary 初期化
function initializeORD(){

  switch (initializeStatus) {
    case 0:
      // ajax
      searchDateList();

      break;
    case 1:

      $("#init-date").val(initDate);
      $("#exit-date").val(exitDate);
      $("#init-rank").val(1);
      $("#exit-rank").val(100);

      // tooltip をつける

      $("#view-column-label").tooltip({placement: "left"});

      $("#init-date").attr("title", "" + initDate + " ～ " + exitDate2);
      $("#exit-date").attr("title", "" + initDate + " ～ " + exitDate);

      $("#init-date").tooltip();
      $("#exit-date").tooltip();

      $("#init-rank").tooltip();
      $("#exit-rank").tooltip();

      toggleLoading();

      break;
  }

  initializeStatus++;

}

// ----------------------------------------------------------------
// 日付一覧を取得
function searchDateList(){
  $.ajax({
    url: "ruby/getRankListDates.rb",
    success: function(data, dataType) {
      var i = 0;

      // グローバル変数に改行区切りで分割して、最後の空白削除
      dateList = data.split('\n');
      dateList.pop();

      // 日付リスト回す
      $(dateList).each(function(i, date) {
        dateList[i] = date.trim();
        date = dateList[i];
        // console.log("dateList: " + i + "/" + dateList.length + ": " + date);

        if (i === 0) {
          initDate = date;
          initDate2 = initDate2 || date;
        }
        if (i === 1) {
          initDate2 = date;
        }
        if (i === dateList.length - 2) {
          exitDate2 = date;
        }
        if (i === dateList.length - 1) {
          exitDate = date;
          exitDate2 = exitDate2 || date;
        }

      });

      $("#init-date").attr("min", initDate);
      $("#exit-date").attr("min", initDate2);
      $("#init-date").attr("max", exitDate2);
      $("#exit-date").attr("max", exitDate);

    },
    error: function(XMLHttpRequest, textStatus, errorThrown) {
      console.log("Error: ajax: " + textStatus);
    }
  });

}

// ----------------------------------------------------------------
// 日付を変更したとき、もう一方の日付を修正
function fixRankDate(_id) {
  // 日付が許容値を超えていたら修正
  var initDateValLocal = $("#init-date").val();
  var initDateMaxLocal = $("#init-date").attr("max");
  var initDateMinLocal = $("#init-date").attr("min");
  var exitDateValLocal = $("#exit-date").val();
  var exitDateMaxLocal = $("#exit-date").attr("max");
  var exitDateMinLocal = $("#exit-date").attr("min");

  if (initDateValLocal > initDateMaxLocal) {
    $("#init-date").val($("#init-date").attr("max"));
  }
  if (initDateValLocal < initDateMinLocal) {
    $("#init-date").val($("#init-date").attr("min"));
  }

  if (exitDateValLocal > exitDateMaxLocal) {
    $("#exit-date").val($("#exit-date").attr("max"));
  }
  if (exitDateValLocal < exitDateMinLocal) {
    $("#exit-date").val($("#exit-date").attr("min"));
  }

  // もう一方の日付を超えたとき、もう一方を修正
  if (diffStatus) {
    var initDateLocal = new Date($("#init-date").val());
    var exitDateLocal = new Date($("#exit-date").val());

    if (initDateLocal >= exitDateLocal) {
      if (_id === 0) {
        initDateLocal.setDate(initDateLocal.getDate() + 1);
        $("#exit-date").val(getDateString(initDateLocal, "%Y-%m-%d"));
      } else if (_id === 1) {
        exitDateLocal.setDate(exitDateLocal.getDate() - 1);
        $("#init-date").val(getDateString(exitDateLocal, "%Y-%m-%d"));
      }
    }
  }

}

// ----------------------------------------------------------------
// ランクを変更したとき、もう一方のランクを修正
function fixRank(_id) {
  // ランクが許容値を超えていたら修正
  var initRankValLocal = 1 * $("#init-rank").val();
  var initRankMaxLocal = 1 * $("#init-rank").attr("max");
  var initRankMinLocal = 1 * $("#init-rank").attr("min");
  var exitRankValLocal = 1 * $("#exit-rank").val();
  var exitRankMaxLocal = 1 * $("#exit-rank").attr("max");
  var exitRankMinLocal = 1 * $("#exit-rank").attr("min");

  if (initRankValLocal > initRankMaxLocal) {
    $("#init-rank").val($("#init-rank").attr("max"));
    console.log("teetetet");
  }
  if (initRankValLocal < initRankMinLocal) {
    $("#init-rank").val($("#init-rank").attr("min"));
    console.log("teetetet");
  }

  if (exitRankValLocal > exitRankMaxLocal) {
    $("#exit-rank").val($("#exit-rank").attr("max"));
    console.log("teetetet");
  }
  if (exitRankValLocal < exitRankMinLocal) {
    $("#exit-rank").val($("#exit-rank").attr("min"));
    console.log("teetetet");
  }

  // もう一方のランクを超えたとき、もう一方を修正
  initRankValLocal = 1 * $("#init-rank").val();
  exitRankValLocal = 1 * $("#exit-rank").val();
  if (initRankValLocal >= exitRankValLocal) {
    if (_id === 0) {
      $("#exit-rank").val((initRankValLocal + 1).toString());
    } else if (_id === 1) {
      $("#init-rank").val((exitRankValLocal - 1).toString());
    }
  }

}

// ----------------------------------------------------------------
// Loading表記の切り替え
// _status:
//  true: loading
//  false: main
function toggleLoading(_status){
  if (_status === null) {
    loadingStatus = _status;

  } else {
    loadingStatus = toggleBoolean(loadingStatus);

  }

  if (loadingStatus) {
    $("#loading").removeClass("display-none");
    $("#main").addClass("display-none");

  } else {
    $("#main").removeClass("display-none");
    $("#loading").addClass("display-none");

  }
}

// ----------------------------------------------------------------
// Dateオブジェクトからゼロ埋めした日付文字列を生成
// _date: new Date()
//  Dateオブジェクト
// _format: '%Y/%m/%d %H:%M:%S'
//  %Y: 年4桁
//  %y: 年2桁
//  %m: 月
//  %d: 日
//  %H: 時
//  %M: 分
//  %S: 秒
function getDateString(_date, _format){
  var date = _date || new Date();
  var dateString = _format || '%Y/%m/%d %H:%M:%S';

  if (dateString.indexOf('%Y') >= 0) {
    dateString = dateString.replace('%Y', ("000" + _date.getFullYear()).slice(-4));
  }
  if (dateString.indexOf('%y') >= 0) {
    dateString = dateString.replace('%y', ("0" + _date.getFullYear()).slice(-2));
  }
  if (dateString.indexOf('%m') >= 0) {
    dateString = dateString.replace('%m', ("0" + (_date.getMonth() + 1)).slice(-2));
  }
  if (dateString.indexOf('%d') >= 0) {
    dateString = dateString.replace('%d', ("0" + _date.getDate()).slice(-2));
  }
  if (dateString.indexOf('%H') >= 0) {
    dateString = dateString.replace('%H', ("0" + _date.getHours()).slice(-2));
  }
  if (dateString.indexOf('%M') >= 0) {
    dateString = dateString.replace('%M', ("0" + _date.getMinutes()).slice(-2));
  }
  if (dateString.indexOf('%S') >= 0) {
    dateString = dateString.replace('%S', ("0" + _date.getSeconds()).slice(-2));
  }
  return dateString;
}

// ----------------------------------------------------------------
// ローカルストレージの初期化
function initializeLocalStorage(_initializeFlg) {

  // var initializeFlg = _initializeFlg || true;
  // で初期値与えようとすると false がきたとき true を持ってくるから使えない

  var initializeFlg = _initializeFlg;
  if (initializeFlg === null) {
    initializeFlg = true;
  }

  if (initializeFlg) {
    console.log("LocalStorage Reset");
    localStorage.clear();

  }
}

// ----------------------------------------------------------------
// ローカルストレージを更新
function updateHistory(_mode, _initDate, _exitDate, _initRank, _exitRank){

  var arrayOfHistoryValue;

  var modeLocal = _mode || rankingMode;
  var initDateLocal = _initDate || $("#init-date").val();
  var exitDateLocal = _exitDate || $("#exit-date").val();
  var initRankLocal = _initRank || $("#init-rank").val();
  var exitRankLocal = _exitRank || $("#exit-rank").val();

  // 履歴に追加
  var localStorageActiveKey = modeLocal + ":" + initDateLocal ":" + exitDateLocal ":" + initRankLocal ":" + exitRankLocal;
  var localStorageHistoryValue = localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY);
  console.log(LOCAL_STORAGE_HISTORY_KEY + " -> " + localStorageHistoryValue);

  // 履歴が存在する場合は整形
  if (localStorageHistoryValue != null) {
    localStorageHistoryValue = localStorageHistoryValue.replace(/\s+/g, "");
    arrayOfHistoryValue = localStorageHistoryValue.split(",");
  }

  localStorageHistoryValue = localStorageActiveKey;

  if (arrayOfHistoryValue != null) {
    for (var i = 0; i < arrayOfHistoryValue.length; i++) {
      if (arrayOfHistoryValue[i] === localStorageActiveKey) {
        continue;
      }
      localStorageHistoryValue += ", " + arrayOfHistoryValue[i];

    }
  }

  console.log(LOCAL_STORAGE_HISTORY_KEY + " <- " + localStorageHistoryValue);
  localStorage.setItem(LOCAL_STORAGE_HISTORY_KEY, localStorageHistoryValue);

}

// ----------------------------------------------------------------
// 通常モーダルウィンドウ
function showDialog(_dialogTitle, _dialogContent) {
  var dialogTitle = _dialogTitle || "タイトル";
  var dialogContent = _dialogContent || "内容";

  // モーダルウィンドウを表示
  $("#modalDialog").html(dialogContent);
  $("#modalDialog").dialog({
    modal: true,
    title: dialogTitle
  });
}

// ----------------------------------------------------------------
// 確認モーダルウィンドウ
function showConfirmDialog(_dialogTitle, _dialogContent, _callbackFunction) {
  var dialogTitle = _dialogTitle || "確認";
  var dialogContent = _dialogContent || "内容";
  var callbackFunction = _callbackFunction || function(){};

  // モーダルウィンドウを表示
  $("#modalConfirmDialog").html(dialogContent);
  $("#modalConfirmDialog").dialog({
    modal: true,
    title: dialogTitle,
    buttons: {
      "OK": function() {
        callbackFunction(true);
        $(this).dialog("close");
      },
      "キャンセル": function() {
        callbackFunction(false);
        $(this).dialog("close");
      }
    }
  });
}

// ----------------------------------------------------------------
// true false をスイッチ
function toggleBoolean(_bool) {
  return !_bool;
}
<commit_msg>[fix] Fix function updateHistory<commit_after>
// グローバル変数
var localStorageFlg = true;

var initializeStatus = 0;
var loadingStatus = true;
var diffStatus = true;

var dateList = new Array();

var rankingMode = 0;

var initDate;
var initDate2;
var exitDate2;
var exitDate;

// 定数
LOCAL_STORAGE_HISTORY_KEY = "osuRankingDiaryHistoryV1";

$(function() {

  // ----------------------------------------------------------------
  // 初期化
  initializeORD();

  $(document).ajaxSuccess(function() {
    initializeORD();
  });

  // ----------------------------------------------------------------
  // ローカルストレージ対応判定
  if(!localStorage) {
    console.log('"Local Storage" is unsupported. Data can not be saved.');
    console.log('"ローカルストレージ"機能に対応していません。データを保存することができません。');

    localStorageFlg = false;

    $("#action-save").remove();
    $("#action-load").remove();
    $("#action-reset").remove();
  }

  // ----------------------------------------------------------------
  // トップまでのスクロール
  $(document).on('click', '#pagetop', function() {
    // console.log("Scroll to Top");
    $('body,html').animate({scrollTop:0}, 500);
  });

  // ----------------------------------------------------------------
  // タイトル
  $(document).on('click', '#title', function() {
    // console.log("Click Title");

    location.reload();

  });

  // ----------------------------------------------------------------
  // ローカルストレージを初期化
  $(document).on('click', '#action-reset', function() {
    // console.log("Click Reset action");

    showConfirmDialog("ローカルストレージの初期化", "
ローカルストレージに保存されている内容を全て初期化します。
よろしいですか？
", initializeLocalStorage)
  });

  // ----------------------------------------------------------------
  // View difference columnを変更
  $(document).on("change", "#view-column", function() {
    console.log("Change Vire difference column: " + $(this).prop("checked"));

    diffStatus = toggleBoolean(diffStatus);

    var checkViewColumn = $(this).prop("checked");

    if (checkViewColumn) {
      // 変動を表示
      $("#setting-date-area > #difference-date").removeClass("display-none");
      $("#exit-date").attr("min", initDate2);
      fixRankDate(0);

    } else {
      // 変動を非表示
      $("#setting-date-area > #difference-date").addClass("display-none");
      $("#exit-date").attr("min", initDate);

    }

    $(".change-value, .difference-of-above").each(function(i, element) {
      if (checkViewColumn) {
        $(element).removeClass("display-none");

      } else {
        $(element).addClass("display-none");

      }
    });

  });

  // ----------------------------------------------------------------
  // init-date を変更
  $(document).on("change", "#init-date", function() {
    fixRankDate(0);

  });

  // ----------------------------------------------------------------
  // exit-date を変更
  $(document).on("change", "#exit-date", function() {
    fixRankDate(1);

  });

  // ----------------------------------------------------------------
  // init-rank を変更
  $(document).on("change", "#init-rank", function() {
    fixRank(0);

  });

  // ----------------------------------------------------------------
  // exit-rank を変更
  $(document).on("change", "#exit-rank", function() {
    fixRank(1);

  });

});

// ----------------------------------------------------------------
// Functions

// ----------------------------------------------------------------
// osu! Ranking Diary 初期化
function initializeORD(){

  switch (initializeStatus) {
    case 0:
      // ajax
      searchDateList();

      break;
    case 1:

      $("#init-date").val(initDate);
      $("#exit-date").val(exitDate);
      $("#init-rank").val(1);
      $("#exit-rank").val(100);

      // tooltip をつける

      $("#view-column-label").tooltip({placement: "left"});

      $("#init-date").attr("title", "" + initDate + " ～ " + exitDate2);
      $("#exit-date").attr("title", "" + initDate + " ～ " + exitDate);

      $("#init-date").tooltip();
      $("#exit-date").tooltip();

      $("#init-rank").tooltip();
      $("#exit-rank").tooltip();

      toggleLoading();

      break;
  }

  initializeStatus++;

}

// ----------------------------------------------------------------
// 日付一覧を取得
function searchDateList(){
  $.ajax({
    url: "ruby/getRankListDates.rb",
    success: function(data, dataType) {
      var i = 0;

      // グローバル変数に改行区切りで分割して、最後の空白削除
      dateList = data.split('\n');
      dateList.pop();

      // 日付リスト回す
      $(dateList).each(function(i, date) {
        dateList[i] = date.trim();
        date = dateList[i];
        // console.log("dateList: " + i + "/" + dateList.length + ": " + date);

        if (i === 0) {
          initDate = date;
          initDate2 = initDate2 || date;
        }
        if (i === 1) {
          initDate2 = date;
        }
        if (i === dateList.length - 2) {
          exitDate2 = date;
        }
        if (i === dateList.length - 1) {
          exitDate = date;
          exitDate2 = exitDate2 || date;
        }

      });

      $("#init-date").attr("min", initDate);
      $("#exit-date").attr("min", initDate2);
      $("#init-date").attr("max", exitDate2);
      $("#exit-date").attr("max", exitDate);

    },
    error: function(XMLHttpRequest, textStatus, errorThrown) {
      console.log("Error: ajax: " + textStatus);
    }
  });

}

// ----------------------------------------------------------------
// 日付を変更したとき、もう一方の日付を修正
function fixRankDate(_id) {
  // 日付が許容値を超えていたら修正
  var initDateValLocal = $("#init-date").val();
  var initDateMaxLocal = $("#init-date").attr("max");
  var initDateMinLocal = $("#init-date").attr("min");
  var exitDateValLocal = $("#exit-date").val();
  var exitDateMaxLocal = $("#exit-date").attr("max");
  var exitDateMinLocal = $("#exit-date").attr("min");

  if (initDateValLocal > initDateMaxLocal) {
    $("#init-date").val($("#init-date").attr("max"));
  }
  if (initDateValLocal < initDateMinLocal) {
    $("#init-date").val($("#init-date").attr("min"));
  }

  if (exitDateValLocal > exitDateMaxLocal) {
    $("#exit-date").val($("#exit-date").attr("max"));
  }
  if (exitDateValLocal < exitDateMinLocal) {
    $("#exit-date").val($("#exit-date").attr("min"));
  }

  // もう一方の日付を超えたとき、もう一方を修正
  if (diffStatus) {
    var initDateLocal = new Date($("#init-date").val());
    var exitDateLocal = new Date($("#exit-date").val());

    if (initDateLocal >= exitDateLocal) {
      if (_id === 0) {
        initDateLocal.setDate(initDateLocal.getDate() + 1);
        $("#exit-date").val(getDateString(initDateLocal, "%Y-%m-%d"));
      } else if (_id === 1) {
        exitDateLocal.setDate(exitDateLocal.getDate() - 1);
        $("#init-date").val(getDateString(exitDateLocal, "%Y-%m-%d"));
      }
    }
  }

}

// ----------------------------------------------------------------
// ランクを変更したとき、もう一方のランクを修正
function fixRank(_id) {
  // ランクが許容値を超えていたら修正
  var initRankValLocal = 1 * $("#init-rank").val();
  var initRankMaxLocal = 1 * $("#init-rank").attr("max");
  var initRankMinLocal = 1 * $("#init-rank").attr("min");
  var exitRankValLocal = 1 * $("#exit-rank").val();
  var exitRankMaxLocal = 1 * $("#exit-rank").attr("max");
  var exitRankMinLocal = 1 * $("#exit-rank").attr("min");

  if (initRankValLocal > initRankMaxLocal) {
    $("#init-rank").val($("#init-rank").attr("max"));
    console.log("teetetet");
  }
  if (initRankValLocal < initRankMinLocal) {
    $("#init-rank").val($("#init-rank").attr("min"));
    console.log("teetetet");
  }

  if (exitRankValLocal > exitRankMaxLocal) {
    $("#exit-rank").val($("#exit-rank").attr("max"));
    console.log("teetetet");
  }
  if (exitRankValLocal < exitRankMinLocal) {
    $("#exit-rank").val($("#exit-rank").attr("min"));
    console.log("teetetet");
  }

  // もう一方のランクを超えたとき、もう一方を修正
  initRankValLocal = 1 * $("#init-rank").val();
  exitRankValLocal = 1 * $("#exit-rank").val();
  if (initRankValLocal >= exitRankValLocal) {
    if (_id === 0) {
      $("#exit-rank").val((initRankValLocal + 1).toString());
    } else if (_id === 1) {
      $("#init-rank").val((exitRankValLocal - 1).toString());
    }
  }

}

// ----------------------------------------------------------------
// Loading表記の切り替え
// _status:
//  true: loading
//  false: main
function toggleLoading(_status){
  if (_status === null) {
    loadingStatus = _status;

  } else {
    loadingStatus = toggleBoolean(loadingStatus);

  }

  if (loadingStatus) {
    $("#loading").removeClass("display-none");
    $("#main").addClass("display-none");

  } else {
    $("#main").removeClass("display-none");
    $("#loading").addClass("display-none");

  }
}

// ----------------------------------------------------------------
// Dateオブジェクトからゼロ埋めした日付文字列を生成
// _date: new Date()
//  Dateオブジェクト
// _format: '%Y/%m/%d %H:%M:%S'
//  %Y: 年4桁
//  %y: 年2桁
//  %m: 月
//  %d: 日
//  %H: 時
//  %M: 分
//  %S: 秒
function getDateString(_date, _format){
  var date = _date || new Date();
  var dateString = _format || '%Y/%m/%d %H:%M:%S';

  if (dateString.indexOf('%Y') >= 0) {
    dateString = dateString.replace('%Y', ("000" + _date.getFullYear()).slice(-4));
  }
  if (dateString.indexOf('%y') >= 0) {
    dateString = dateString.replace('%y', ("0" + _date.getFullYear()).slice(-2));
  }
  if (dateString.indexOf('%m') >= 0) {
    dateString = dateString.replace('%m', ("0" + (_date.getMonth() + 1)).slice(-2));
  }
  if (dateString.indexOf('%d') >= 0) {
    dateString = dateString.replace('%d', ("0" + _date.getDate()).slice(-2));
  }
  if (dateString.indexOf('%H') >= 0) {
    dateString = dateString.replace('%H', ("0" + _date.getHours()).slice(-2));
  }
  if (dateString.indexOf('%M') >= 0) {
    dateString = dateString.replace('%M', ("0" + _date.getMinutes()).slice(-2));
  }
  if (dateString.indexOf('%S') >= 0) {
    dateString = dateString.replace('%S', ("0" + _date.getSeconds()).slice(-2));
  }
  return dateString;
}

// ----------------------------------------------------------------
// ローカルストレージの初期化
function initializeLocalStorage(_initializeFlg) {

  // var initializeFlg = _initializeFlg || true;
  // で初期値与えようとすると false がきたとき true を持ってくるから使えない

  var initializeFlg = _initializeFlg;
  if (initializeFlg === null) {
    initializeFlg = true;
  }

  if (initializeFlg) {
    console.log("LocalStorage Reset");
    localStorage.clear();

  }
}

// ----------------------------------------------------------------
// ローカルストレージの履歴を更新
function updateHistory(_mode, _initDate, _exitDate, _initRank, _exitRank){

  var arrayOfHistoryValue;

  var modeLocal = _mode || rankingMode;
  var initDateLocal = _initDate || $("#init-date").val();
  var exitDateLocal = _exitDate || $("#exit-date").val();
  var initRankLocal = _initRank || $("#init-rank").val();
  var exitRankLocal = _exitRank || $("#exit-rank").val();

  // 履歴に追加
  var localStorageActiveKey = modeLocal + ":" + initDateLocal + ":" + exitDateLocal + ":" + initRankLocal + ":" + exitRankLocal;
  var localStorageHistoryValue = localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY);
  console.log(LOCAL_STORAGE_HISTORY_KEY + " -> " + localStorageHistoryValue);

  // 履歴が存在する場合は整形
  if (localStorageHistoryValue != null) {
    localStorageHistoryValue = localStorageHistoryValue.replace(/\s+/g, "");
    arrayOfHistoryValue = localStorageHistoryValue.split(",");
  }

  localStorageHistoryValue = localStorageActiveKey;

  if (arrayOfHistoryValue != null) {
    for (var i = 0; i < arrayOfHistoryValue.length; i++) {
      if (arrayOfHistoryValue[i] === localStorageActiveKey) {
        continue;
      }
      localStorageHistoryValue += ", " + arrayOfHistoryValue[i];

    }
  }

  console.log(LOCAL_STORAGE_HISTORY_KEY + " <- " + localStorageHistoryValue);
  localStorage.setItem(LOCAL_STORAGE_HISTORY_KEY, localStorageHistoryValue);

}

// ----------------------------------------------------------------
// 通常モーダルウィンドウ
function showDialog(_dialogTitle, _dialogContent) {
  var dialogTitle = _dialogTitle || "タイトル";
  var dialogContent = _dialogContent || "内容";

  // モーダルウィンドウを表示
  $("#modalDialog").html(dialogContent);
  $("#modalDialog").dialog({
    modal: true,
    title: dialogTitle
  });
}

// ----------------------------------------------------------------
// 確認モーダルウィンドウ
function showConfirmDialog(_dialogTitle, _dialogContent, _callbackFunction) {
  var dialogTitle = _dialogTitle || "確認";
  var dialogContent = _dialogContent || "内容";
  var callbackFunction = _callbackFunction || function(){};

  // モーダルウィンドウを表示
  $("#modalConfirmDialog").html(dialogContent);
  $("#modalConfirmDialog").dialog({
    modal: true,
    title: dialogTitle,
    buttons: {
      "OK": function() {
        callbackFunction(true);
        $(this).dialog("close");
      },
      "キャンセル": function() {
        callbackFunction(false);
        $(this).dialog("close");
      }
    }
  });
}

// ----------------------------------------------------------------
// true false をスイッチ
function toggleBoolean(_bool) {
  return !_bool;
}
<|endoftext|>