<commit_before>const mysleep = require('sleep');
const chai = require('chai');
const parentDir = require('path');
const currentDir = parentDir.dirname(module.filename);
const Connection = require(parentDir.dirname(currentDir) + '/dist/api/connection').Connection
const StateType = require(parentDir.dirname(currentDir) + '/dist/api/api').StateType
const IRecipientInfo = require(parentDir.dirname(currentDir) + '/dist/api/api').IRecipientInfo
const path = parentDir.dirname(currentDir) + "/lib/libcxs.so";
const cxs = require('../dist/index.js')
const expect = chai.expect;
const assert = chai.assert;

const sleep = (time) => new Promise((res) => setTimeout(res, time))

const waitFor = async (predicate) => {
    if (!predicate()) {
        await sleep(1000)
        return waitFor(predicate)
    }
    return predicate()
}

// console.log(release(handle)) // tslint:disable-line
describe('A Connection object with ', function () {
    this.timeout(10000)

    before(function() {
        cxs.init_cxs('ENABLE_TEST_MODE')
    });

    //connection_create tests

    it('valid parameters in create should return success', function () {
        const connection = new Connection(path)
        assert.equal(connection.create({
            id: "234",
            DIDself: "456",
            DIDremote: "0"}), 0)
    })

    it('null param in create should return success', function () {
        const connection = new Connection(path)
        assert.equal(connection.create(null), 0)
    })

// connection_connect tests

    it(' a call to create with no connection created should return unknown error', function () {
        const connection = new Connection(path)
        assert.equal(connection._connect({sms: true}), 1003)
    })

    it(' a call to connect with connection already created should return success', function () {
        const connection = new Connection(path)
        connection.create("connection_connect tests")
        return connection.connect({sms: true})
    })

// connection_get_data tests

    it('a call to get_data where connection exists should return back the connections data', function () {
        const connection = new Connection(path)
        connection.create("dog, cat, man")
        const data = connection.getData()
        const jsonData = JSON.parse(data)
        assert.notEqual(data, null)
        assert.equal(jsonData.handle, connection.connectionHandle)
    })

    it('a call to get_data where connection doesnt exist should return a null value', function () {
        const connection = new Connection(path)
        assert.equal(connection.getData(), null)
    })

    it('a call to get_data where connection was released should return a null value', async function () {
        const connection = new Connection(path)
        assert.equal(connection.create("connection_get_data tests"), 0)

        await connection.connect({sms: true})

        assert.equal(connection.getState(),StateType.OfferSent)

        const data = connection.getData()
        assert.notEqual(data, null)
        assert.equal(connection.release(), 0)

        data = connection.getData()
        assert.equal(data, null)
    })

    // connection_getState tests

    it('call to getState where connection exists should return success', async function () {
        const connection = new Connection(path)
        connection.create("connection_getState tests")
        await connection.connect({sms: true})
        assert.equal(connection.getState(),StateType.OfferSent)
    })

    it('call to getState where no connection exists should have a state value of 0', function () {
        const connection = new Connection(path)
        assert.equal(connection.getState(),StateType.None)
    })

    it('call to get_state where connection exists but not connected should have a state value of 1', function () {
        const connection = new Connection(path)
        connection.create("info2")
        return waitFor(() => connection.getState() === StateType.Initialized)
    })

// connection_release tests

    it('call to connection_release where connection exists should return success', async function () {
        const connection = new Connection(path)
        connection.create("connection_release tests")
        await connection.connect({sms: true})
        assert.equal(connection.release(), 0)
        assert.equal(connection._connect({sms: true}), 1003)
        assert.equal(connection.getData(), null)
    })

    it('call to connection_release with no connection should return unknown error', function () {
        const connection = new Connection(path)
        assert.equal(connection.release(), 1003)
    })

    it('connection and GC deletes object should return null whet get_data is called ', function () {
        this.timeout(30000)
        const connection = new Connection(path)
        connection.create("msg")
        connection._connect({sms: true})
        const getData = connection.RUST_API.cxs_connection_get_data
        const handle = connection.connectionHandle
        assert.notEqual(connection.getData(handle), null)

        delete connection
        global.gc()

        // this will timeout if condition is never met
        // get_data will return "" because the connection object was released
        return waitFor(() => !getData(handle))
    })

})
<commit_msg>Fix<commit_after>const mysleep = require('sleep');
const chai = require('chai');
const parentDir = require('path');
const currentDir = parentDir.dirname(module.filename);
const Connection = require(parentDir.dirname(currentDir) + '/dist/api/connection').Connection
const StateType = require(parentDir.dirname(currentDir) + '/dist/api/api').StateType
const IRecipientInfo = require(parentDir.dirname(currentDir) + '/dist/api/api').IRecipientInfo
const path = parentDir.dirname(currentDir) + "/lib/libcxs.so";
const cxs = require('../dist/index.js')
const expect = chai.expect;
const assert = chai.assert;

const sleep = (time) => new Promise((res) => setTimeout(res, time))

const waitFor = async (predicate) => {
    if (!predicate()) {
        await sleep(1000)
        return waitFor(predicate)
    }
    return predicate()
}

// console.log(release(handle)) // tslint:disable-line
describe('A Connection object with ', function () {
    this.timeout(10000)

    before(function() {
        cxs.init_cxs('ENABLE_TEST_MODE')
    });

    //connection_create tests

    it('valid parameters in create should return success', function () {
        const connection = new Connection(path)
        assert.equal(connection.create({
            id: "234",
            DIDself: "456",
            DIDremote: "0"}), 0)
    })

    it('null param in create should return success', function () {
        const connection = new Connection(path)
        assert.equal(connection.create(null), 0)
    })

// connection_get_data tests

    it('a call to get_data where connection exists should return back the connections data', function () {
        const connection = new Connection(path)
        connection.create("dog, cat, man")
        const data = connection.getData()
        const jsonData = JSON.parse(data)
        assert.notEqual(data, null)
        assert.equal(jsonData.handle, connection.connectionHandle)
    })

    it('a call to get_data where connection doesnt exist should return a null value', function () {
        const connection = new Connection(path)
        assert.equal(connection.getData(), null)
    })

    it('a call to get_data where connection was released should return a null value', async function () {
        const connection = new Connection(path)
        assert.equal(connection.create("connection_get_data tests"), 0)

        await connection.connect({sms: true})

        assert.equal(connection.getState(), StateType.OfferSent)
        assert.notEqual(connection.getData(), null)
        assert.equal(connection.release(), 0)
        assert.equal(connection.getData(), null)
    })

// connection_connect tests

    it(' a call to connect with connection already created should return success', function () {
        const connection = new Connection(path)
        connection.create("connection_connect tests")
        return connection.connect({sms: true})
    })

    it(' a call to create with no connection created should return unknown error', function () {
        const connection = new Connection(path)
        assert.equal(connection._connect({sms: true}), 1003)
    })

    // connection_getState tests

    it('call to getState where connection exists should return success', async function () {
        const connection = new Connection(path)
        connection.create("connection_getState tests")
        await connection.connect({sms: true})
        assert.equal(connection.getState(),StateType.OfferSent)
    })

    it('call to getState where no connection exists should have a state value of 0', function () {
        const connection = new Connection(path)
        assert.equal(connection.getState(),StateType.None)
    })

    it('call to get_state where connection exists but not connected should have a state value of 1', function () {
        const connection = new Connection(path)
        connection.create("info2")
        return waitFor(() => connection.getState() === StateType.Initialized)
    })

// connection_release tests

    it('call to connection_release where connection exists should return success', async function () {
        const connection = new Connection(path)
        connection.create("connection_release tests")
        await connection.connect({sms: true})
        assert.equal(connection.release(), 0)
        assert.equal(connection._connect({sms: true}), 1003)
        assert.equal(connection.getData(), null)
    })

    it('call to connection_release with no connection should return unknown error', function () {
        const connection = new Connection(path)
        assert.equal(connection.release(), 1003)
    })

    it('connection and GC deletes object should return null whet get_data is called ', function () {
        this.timeout(30000)
        const connection = new Connection(path)
        connection.create("msg")
        connection._connect({sms: true})
        const getData = connection.RUST_API.cxs_connection_get_data
        const handle = connection.connectionHandle
        assert.notEqual(connection.getData(handle), null)

        delete connection
        global.gc()

        // this will timeout if condition is never met
        // get_data will return "" because the connection object was released
        return waitFor(() => !getData(handle))
    })

})
<|endoftext|>


<commit_before>/**
 * Functions to build/cache match object
 * */
const config = require('../config');
const async = require('async');
const queries = require('./queries');
const compute = require('../util/compute');
const utility = require('../util/utility');
const constants = require('dotaconstants');
const cassandra = require('../store/cassandra');
const redis = require('../store/redis');
const db = require('../store/db');

const { computeMatchData } = compute;
const { deserialize, buildReplayUrl, isContributor } = utility;

function getMatchData(matchId, cb) {
  cassandra.execute('SELECT * FROM matches where match_id = ?', [Number(matchId)], {
    prepare: true,
    fetchSize: 1,
    autoPage: true,
  }, (err, result) => {
    if (err) {
      return cb(err);
    }
    result = result.rows.map(m => deserialize(m));
    return cb(err, result[0]);
  });
}

function getPlayerMatchData(matchId, cb) {
  cassandra.execute('SELECT * FROM player_matches where match_id = ?', [Number(matchId)], {
    prepare: true,
    fetchSize: 24,
    autoPage: true,
  }, (err, result) => {
    if (err) {
      return cb(err);
    }
    result = result.rows.map(m => deserialize(m));
    // get personanames
    return async.map(result, (r, cb) => {
      db.raw(`
        SELECT personaname, name, last_login
        FROM players
        LEFT JOIN notable_players
        ON players.account_id = notable_players.account_id
        WHERE players.account_id = ?
      `, [r.account_id]).asCallback((err, names) => {
        if (err) {
          return cb(err);
        }
        return cb(err, Object.assign({}, r, names.rows[0]));
      });
    }, cb);
  });
}

function getMatch(matchId, cb) {
  if (!matchId || Number.isNaN(Number(matchId)) || Number(matchId) <= 0) {
    return cb();
  }

  return getMatchData(matchId, (err, match) => {
    if (err) {
      return cb(err);
    } else if (!match) {
      return cb();
    }
    return async.parallel({
      players(cb) {
        getPlayerMatchData(matchId, (err, players) => {
          if (err) {
            return cb(err);
          }
          return async.map(players, (p, cb) => {
            // match-level columns
            p.radiant_win = match.radiant_win;
            p.start_time = match.start_time;
            p.duration = match.duration;
            p.cluster = match.cluster;
            p.lobby_type = match.lobby_type;
            p.game_mode = match.game_mode;
            p.isContributor = isContributor(p.account_id);
            computeMatchData(p);
            db.first().from('rank_tier').where({ account_id: p.account_id || null }).asCallback((err, row) => {
              p.rank_tier = row ? row.rating : null;
              cb(err, p);
            });
          }, cb);
        });
      },
      gcdata(cb) {
        db.first().from('match_gcdata').where({
          match_id: matchId,
        }).asCallback(cb);
      },
      cosmetics(cb) {
        async.map(Object.keys(match.cosmetics || {}), (itemId, cb) => {
          db.first().from('cosmetics').where({
            item_id: itemId,
          }).asCallback(cb);
        }, (err, cosmetics) => {
          if (err) {
            return cb(err);
          }
          return cb(err, cosmetics.filter(c => c));
        });
      },
      prodata(cb) {
        db.first(['radiant_team_id', 'dire_team_id', 'leagueid'])
          .from('matches')
          .where({
            match_id: matchId,
          }).asCallback((err, result) => {
            if (err) {
              return cb(err);
            }
            if (!result) {
              return cb(null, {});
            }
            return async.parallel({
              league: cb => db.first().from('leagues').where({
                leagueid: result.leagueid,
              }).asCallback(cb),
              radiant_team: cb => db.first().from('teams').where({
                team_id: result.radiant_team_id,
              }).asCallback(cb),
              dire_team: cb => db.first().from('teams').where({
                team_id: result.dire_team_id,
              }).asCallback(cb),
            }, cb);
          });
      },
    }, (err, result) => {
      if (err) {
        return cb(err);
      }
      match = Object.assign({}, match, result.gcdata, result.prodata, {
        players: result.players,
      });
      // Assign cosmetics to each player
      if (result.cosmetics) {
        match.players.forEach((p) => {
          const hero = constants.heroes[p.hero_id] || {};
          p.cosmetics = result.cosmetics.filter(c => match.cosmetics[c.item_id] === p.player_slot &&
            (!c.used_by_heroes || c.used_by_heroes === hero.name));
        });
      }
      computeMatchData(match);
      if (match.replay_salt) {
        match.replay_url = buildReplayUrl(match.match_id, match.cluster, match.replay_salt);
      }
      return queries.getMatchBenchmarks(match, err => cb(err, match));
    });
  });
}

function buildMatch(matchId, cb) {
  const key = `match:${matchId}`;
  redis.get(key, (err, reply) => {
    if (err) {
      return cb(err);
    } else if (reply) {
      // console.log(`Cache hit for match ${matchId}`);
      const match = JSON.parse(reply);
      return cb(err, match);
    }
    // console.log(`Cache miss for match ${matchId}`);
    return getMatch(matchId, (err, match) => {
      if (err) {
        return cb(err);
      }
      if (!match) {
        return cb();
      }
      if (match.version && config.ENABLE_MATCH_CACHE) {
        return redis.setex(key, config.MATCH_CACHE_SECONDS, JSON.stringify(match), (err) => {
          if (err) {
            console.error(err);
          }
          return cb(null, match);
        });
      }
      return cb(err, match);
    });
  });
}

module.exports = buildMatch;
<commit_msg>Update buildMatch.js<commit_after>/**
 * Functions to build/cache match object
 * */
const config = require('../config');
const async = require('async');
const queries = require('./queries');
const compute = require('../util/compute');
const utility = require('../util/utility');
const constants = require('dotaconstants');
const cassandra = require('../store/cassandra');
const redis = require('../store/redis');
const db = require('../store/db');

const { computeMatchData } = compute;
const { deserialize, buildReplayUrl, isContributor } = utility;

function getMatchData(matchId, cb) {
  cassandra.execute('SELECT * FROM matches where match_id = ?', [Number(matchId)], {
    prepare: true,
    fetchSize: 1,
    autoPage: true,
  }, (err, result) => {
    if (err) {
      return cb(err);
    }
    result = result.rows.map(m => deserialize(m));
    return cb(err, result[0]);
  });
}

function getPlayerMatchData(matchId, cb) {
  cassandra.execute('SELECT * FROM player_matches where match_id = ?', [Number(matchId)], {
    prepare: true,
    fetchSize: 24,
    autoPage: true,
  }, (err, result) => {
    if (err) {
      return cb(err);
    }
    result = result.rows.map(m => deserialize(m));
    // get personanames
    return async.map(result, (r, cb) => {
      db.raw(`
        SELECT personaname, name, last_login
        FROM players
        LEFT JOIN notable_players
        ON players.account_id = notable_players.account_id
        WHERE players.account_id = ?
      `, [r.account_id]).asCallback((err, names) => {
        if (err) {
          return cb(err);
        }
        return cb(err, Object.assign({}, r, names.rows[0]));
      });
    }, cb);
  });
}

function getMatch(matchId, cb) {
  if (!matchId || Number.isNaN(Number(matchId)) || Number(matchId) <= 0) {
    return cb();
  }

  return getMatchData(matchId, (err, match) => {
    if (err) {
      return cb(err);
    } else if (!match) {
      return cb();
    }
    return async.parallel({
      players(cb) {
        getPlayerMatchData(matchId, (err, players) => {
          if (err) {
            return cb(err);
          }
          return async.map(players, (p, cb) => {
            // match-level columns
            p.radiant_win = match.radiant_win;
            p.start_time = match.start_time;
            p.duration = match.duration;
            p.cluster = match.cluster;
            p.lobby_type = match.lobby_type;
            p.game_mode = match.game_mode;
            p.is_contributor = isContributor(p.account_id);
            computeMatchData(p);
            db.first().from('rank_tier').where({ account_id: p.account_id || null }).asCallback((err, row) => {
              p.rank_tier = row ? row.rating : null;
              cb(err, p);
            });
          }, cb);
        });
      },
      gcdata(cb) {
        db.first().from('match_gcdata').where({
          match_id: matchId,
        }).asCallback(cb);
      },
      cosmetics(cb) {
        async.map(Object.keys(match.cosmetics || {}), (itemId, cb) => {
          db.first().from('cosmetics').where({
            item_id: itemId,
          }).asCallback(cb);
        }, (err, cosmetics) => {
          if (err) {
            return cb(err);
          }
          return cb(err, cosmetics.filter(c => c));
        });
      },
      prodata(cb) {
        db.first(['radiant_team_id', 'dire_team_id', 'leagueid'])
          .from('matches')
          .where({
            match_id: matchId,
          }).asCallback((err, result) => {
            if (err) {
              return cb(err);
            }
            if (!result) {
              return cb(null, {});
            }
            return async.parallel({
              league: cb => db.first().from('leagues').where({
                leagueid: result.leagueid,
              }).asCallback(cb),
              radiant_team: cb => db.first().from('teams').where({
                team_id: result.radiant_team_id,
              }).asCallback(cb),
              dire_team: cb => db.first().from('teams').where({
                team_id: result.dire_team_id,
              }).asCallback(cb),
            }, cb);
          });
      },
    }, (err, result) => {
      if (err) {
        return cb(err);
      }
      match = Object.assign({}, match, result.gcdata, result.prodata, {
        players: result.players,
      });
      // Assign cosmetics to each player
      if (result.cosmetics) {
        match.players.forEach((p) => {
          const hero = constants.heroes[p.hero_id] || {};
          p.cosmetics = result.cosmetics.filter(c => match.cosmetics[c.item_id] === p.player_slot &&
            (!c.used_by_heroes || c.used_by_heroes === hero.name));
        });
      }
      computeMatchData(match);
      if (match.replay_salt) {
        match.replay_url = buildReplayUrl(match.match_id, match.cluster, match.replay_salt);
      }
      return queries.getMatchBenchmarks(match, err => cb(err, match));
    });
  });
}

function buildMatch(matchId, cb) {
  const key = `match:${matchId}`;
  redis.get(key, (err, reply) => {
    if (err) {
      return cb(err);
    } else if (reply) {
      // console.log(`Cache hit for match ${matchId}`);
      const match = JSON.parse(reply);
      return cb(err, match);
    }
    // console.log(`Cache miss for match ${matchId}`);
    return getMatch(matchId, (err, match) => {
      if (err) {
        return cb(err);
      }
      if (!match) {
        return cb();
      }
      if (match.version && config.ENABLE_MATCH_CACHE) {
        return redis.setex(key, config.MATCH_CACHE_SECONDS, JSON.stringify(match), (err) => {
          if (err) {
            console.error(err);
          }
          return cb(null, match);
        });
      }
      return cb(err, match);
    });
  });
}

module.exports = buildMatch;
<|endoftext|>


<commit_before>L.Marker.include({
	showLabel: function () {
		if (this._label && this._map) {
			this._label.setLatLng(this._latlng);
			this._map.showLabel(this._label);
		}

		return this;
	},

	hideLabel: function () {
		if (this._label) {
			this._label.close();
		}
		return this;
	},

	bindLabel: function (content, options) {
		if (!this._label) {
			this
				.on('mouseover', this.showLabel, this)
				.on('mouseout', this.hideLabel, this);

			if (L.Browser.touch) {
				this.on('click', this.showLabel, this);
			}

		}

		this._label = new L.Label(options, this)
			.setContent(content);

		return this;
	},

	unbindLabel: function () {
		if (this._label) {
			this._label = null;
			this
				.off('mouseover', this.showLabel)
				.off('mouseout', this.hideLabel);

			if (L.Browser.touch) {
				this.of('click', this.showLabel);
			}

		}
		return this;
	},

	updateLabelContent: function (content) {
		if (this._label) {
			this._label.setContent(content);
		}
	}
});<commit_msg>Added support for non-revealing labels.<commit_after>L.Marker.include({
	showLabel: function () {
		if (this._label && this._map) {
			this._label.setLatLng(this._latlng);
			this._map.showLabel(this._label);
		}

		return this;
	},

	hideLabel: function () {
		if (this._label) {
			this._label.close();
		}
		return this;
	},

	bindLabel: function (content, options) {
		options = options || {};

		if (!this._label && !options.nohide) {
			this
				.on('mouseover', this.showLabel, this)
				.on('mouseout', this.hideLabel, this);

			if (L.Browser.touch) {
				this.on('click', this.showLabel, this);
			}
			this._haslabelHandlers = true;
		}

		this._label = new L.Label(options, this)
			.setContent(content);

		return this;
	},

	unbindLabel: function () {
		if (this._label) {
			this._label = null;

			if (this._haslabelHandlers) {
				this
					.off('mouseover', this.showLabel)
					.off('mouseout', this.hideLabel);

				if (L.Browser.touch) {
					this.of('click', this.showLabel);
				}
			}

			this._haslabelHandlers = false;
		}
		return this;
	},

	updateLabelContent: function (content) {
		if (this._label) {
			this._label.setContent(content);
		}
	}
});<|endoftext|>


<commit_before><commit_msg>Update redux.js<commit_after><|endoftext|>


<commit_before>"use strict";

var assert = require('assert');

var createAccountFrom = function(str) {
  if (isValidAccountNumber(str)) {
    var AccountNumber = function() {

    };

    return new AccountNumber();
  } else {

    return undefined;
  }
};

var isValidAccountNumber = function(str) {
  if (!str) {
    return false;
  }

  var lines = str.split('\n');
  if (lines.length !== 4) {
    return false;
  }

  return lines[0].length === 27 &&
         lines[1].length === 27 &&
         lines[2].length === 27;
};

describe('bank', function() {

  var useCase1 = ' _  _  _  _  _  _  _  _  _ \n' +
                 '| || || || || || || || || |\n' +
                 '|_||_||_||_||_||_||_||_||_|\n' +
                 '';

  describe('input format', function() {
    it("consists of four lines", function() {
      var input = useCase1;
      assert.equal(4, input.split('\n').length);
    });

    it("each line consists of 27 characters", function() {
      var input = useCase1;
      var lines = input.split('\n');
      for(var i=0;i<3;++i) {
        assert.equal(27, lines[i].length);
      }
    });

    it("describes validility", function() {
      assert(isValidAccountNumber(useCase1));
    });
  });

  describe('account numbers', function() {
    it('is not created from a invalid input format', function() {
      assert.equal(undefined, createAccountFrom('12345'));
      assert.equal(undefined, createAccountFrom());
    });

    it('is created from a valid input format', function() {
      assert(createAccountFrom(useCase1));
    });
  });

  describe('number', function() {
    it('zero string', function() {
      var zero = ' _ \n' +
                 '| |\n' +
                 '|_|\n';

      var num = new Num(zero);
      assert.equal(0, num.value());
    });
  });
});
<commit_msg>refactor to function]<commit_after>"use strict";

var assert = require('assert');

var createAccountFrom = function(str) {
  if (isValidAccountNumber(str)) {
    var AccountNumber = function() {

    };

    return new AccountNumber();
  } else {

    return undefined;
  }
};

var isValidAccountNumber = function(str) {
  if (!str) {
    return false;
  }

  var lines = str.split('\n');
  if (lines.length !== 4) {
    return false;
  }

  return lines[0].length === 27 &&
         lines[1].length === 27 &&
         lines[2].length === 27;
};

describe('bank', function() {

  var useCase1 = ' _  _  _  _  _  _  _  _  _ \n' +
                 '| || || || || || || || || |\n' +
                 '|_||_||_||_||_||_||_||_||_|\n' +
                 '';

  describe('input format', function() {
    it("consists of four lines", function() {
      var input = useCase1;
      assert.equal(4, input.split('\n').length);
    });

    it("each line consists of 27 characters", function() {
      var input = useCase1;
      var lines = input.split('\n');
      for(var i=0;i<3;++i) {
        assert.equal(27, lines[i].length);
      }
    });

    it("describes validility", function() {
      assert(isValidAccountNumber(useCase1));
    });
  });

  describe('account numbers', function() {
    it('is not created from a invalid input format', function() {
      assert.equal(undefined, createAccountFrom('12345'));
      assert.equal(undefined, createAccountFrom());
    });

    it('is created from a valid input format', function() {
      assert(createAccountFrom(useCase1));
    });
  });

  describe('number', function() {
    it('zero string', function() {
      var zero = ' _ \n' +
                 '| |\n' +
                 '|_|\n';

      var num = createNumber(zero);
      assert.equal(0, num.value());
    });
  });
});
<|endoftext|>


<commit_before>(function(window, vjs, vast) {
  'use strict';

  var extend = function(obj) {
      var arg, i, k;
      for (i = 1; i < arguments.length; i++) {
        arg = arguments[i];
        for (k in arg) {
          if (arg.hasOwnProperty(k)) {
            obj[k] = arg[k];
          }
        }
      }
      return obj;
    },

    defaults = {
      // seconds before skip button shows, negative values to disable skip button altogether
      skip: 5,
      remainTxt: 'Skip in %d ...',
      skipTxt: 'Skip'
    },

    Vast = function (player, settings) {

      // return vast plugin
      return {
        createSourceObjects: function (media_files) {
          var sourcesByFormat = {}, i, j, tech;
          var techOrder = player.options().techOrder;
          for (i = 0, j = techOrder.length; i < j; i++) {
            var techName = techOrder[i].charAt(0).toUpperCase() + techOrder[i].slice(1);
            tech = window.videojs[techName];

            // Check if the current tech is defined before continuing
            if (!tech) {
              continue;
            }

            // Check if the browser supports this technology
            if (tech.isSupported()) {
              // Loop through each source object
              for (var a = 0, b = media_files.length; a < b; a++) {
                var media_file = media_files[a];
                var source = {type:media_file.mimeType, src:media_file.fileURL};
                // Check if source can be played with this technology
                if (tech.canPlaySource(source)) {
                  if (sourcesByFormat[techOrder[i]] === undefined) {
                    sourcesByFormat[techOrder[i]] = [];
                  }
                  sourcesByFormat[techOrder[i]].push({
                    type:media_file.mimeType,
                    src: media_file.fileURL,
                    width: media_file.width,
                    height: media_file.height
                  });
                }
              }
            }
          }
          // Create sources in preferred format order
          var sources = [];
          for (j = 0; j < techOrder.length; j++) {
            tech = techOrder[j];
            if (sourcesByFormat[tech] !== undefined) {
              for (i = 0; i < sourcesByFormat[tech].length; i++) {
                sources.push(sourcesByFormat[tech][i]);
              }
            }
          }
          return sources;
        },

        getContent: function () {

          // query vast url given in settings
          vast.client.get(settings.url, function(response) {
            if (response) {
              // we got a response, deal with it
              for (var adIdx = 0; adIdx < response.ads.length; adIdx++) {
                var ad = response.ads[adIdx];
                player.vast.companion = undefined;
                for (var creaIdx = 0; creaIdx < ad.creatives.length; creaIdx++) {
                  var creative = ad.creatives[creaIdx], foundCreative = false, foundCompanion = false;
                  if (creative.type === "linear" && !foundCreative) {

                    if (creative.mediaFiles.length) {

                      player.vast.sources = player.vast.createSourceObjects(creative.mediaFiles);

                      if (!player.vast.sources.length) {
                        player.trigger('adscanceled');
                        return;
                      }

                      player.vastTracker = new vast.tracker(ad, creative);

                      foundCreative = true;
                    }

                  } else if (creative.type === "companion" && !foundCompanion) {

                    player.vast.companion = creative;

                    foundCompanion = true;

                  }
                }

                if (player.vastTracker) {
                  // vast tracker and content is ready to go, trigger event
                  player.trigger('vast-ready');
                  break;
                } else {
                  // Inform ad server we can't find suitable media file for this ad
                  vast.util.track(ad.errorURLTemplates, {ERRORCODE: 403});
                }
              }
            } else {
              player.trigger('contentplay');
            }

            if (!player.vastTracker) {
              // No pre-roll, start video
              player.trigger('adscanceled');
            }
          });
        },

        setupEvents: function() {

          var errorOccurred = false,
            canplayFn = function() {
              player.vastTracker.load();
            },
            timeupdateFn = function() {
              if (isNaN(player.vastTracker.assetDuration)) {
                player.vastTracker.assetDuration = player.duration();
              }
              player.vastTracker.setProgress(player.currentTime());
            },
            pauseFn = function() {
              player.vastTracker.setPaused(true);
              player.one('play', function(){
                player.vastTracker.setPaused(false);
              });
            },
            errorFn = function() {
              // Inform ad server we couldn't play the media file for this ad
              vast.util.track(player.vastTracker.ad.errorURLTemplates, {ERRORCODE: 405});
              errorOccurred = true;
              player.trigger('ended');
            };

          player.on('canplay', canplayFn);
          player.on('timeupdate', timeupdateFn);
          player.on('pause', pauseFn);
          player.on('error', errorFn);

          player.one('vast-preroll-removed', function() {
            player.off('canplay', canplayFn);
            player.off('timeupdate', timeupdateFn);
            player.off('pause', pauseFn);
            player.off('error', errorFn);
            if (!errorOccurred) {
              player.vastTracker.complete();
            }
          });
        },

        preroll: function() {
          player.ads.startLinearAdMode();
          player.vast.showControls = player.controls();
          if (player.vast.showControls) {
            player.controls(false);
          }

          // load linear ad sources and start playing them
          player.src(player.vast.sources);

          var clickthrough;
          if (player.vastTracker.clickThroughURLTemplate) {
            clickthrough = vast.util.resolveURLTemplates(
              [player.vastTracker.clickThroughURLTemplate],
              {
                CACHEBUSTER: Math.round(Math.random() * 1.0e+10),
                CONTENTPLAYHEAD: player.vastTracker.progressFormated()
              }
            )[0];
          }

          var blocker = document.createElement("div");
          blocker.className = "vast-blocker";
          blocker.onclick = function() {
            if (player.paused()) {
              player.play();
              return false;
            }
            var clicktrackers = player.vastTracker.clickTrackingURLTemplate;
            if (clicktrackers) {
              player.vastTracker.trackURLs([clicktrackers]);
            }

            if(player.currentTime() > 1) {
              player.trigger("adclick");
              window.open(clickthrough || "#", '_blank');
            }
          };
          player.vast.blocker = blocker;
          player.el().insertBefore(blocker, player.controlBar.el());

          var skipButton = window.document.createElement("div");
          skipButton.className = "vast-skip-button";
          if (settings.skip < 0) {
            skipButton.style.display = "none";
          }
          player.vast.skipButton = skipButton;
          player.el().appendChild(skipButton);

          player.on("timeupdate", player.vast.timeupdate);

          skipButton.onclick = function(e) {
            if((' ' + player.vast.skipButton.className + ' ').indexOf(' enabled ') >= 0) {
              player.vastTracker.skip();
              player.vast.tearDown();
            }
            if(window.Event.prototype.stopPropagation !== undefined) {
              e.stopPropagation();
            } else {
              return false;
            }
          };

          player.vast.setupEvents();

          player.one('ended', player.vast.tearDown);

          player.trigger('vast-preroll-ready');
        },

        tearDown: function() {
          // remove preroll buttons
          player.vast.skipButton.parentNode.removeChild(player.vast.skipButton);
          player.vast.blocker.parentNode.removeChild(player.vast.blocker);

          // remove vast-specific events
          player.off('timeupdate', player.vast.timeupdate);
          player.off('ended', player.vast.tearDown);

          // end ad mode
          player.ads.endLinearAdMode();

          // show player controls for video
          if (player.vast.showControls) {
            player.controls(true);
          }

          player.trigger('vast-preroll-removed');
        },

        timeupdate: function(e) {
          player.loadingSpinner.el().style.display = "none";
          var timeLeft = Math.ceil(settings.skip - player.currentTime());
          if(timeLeft > 0) {
            player.vast.skipButton.innerHTML = settings.remainTxt.replace('%d', timeLeft); //'Skip in ' + timeLeft + "..."
          } else {
            if((' ' + player.vast.skipButton.className + ' ').indexOf(' enabled ') === -1){
              player.vast.skipButton.className += " enabled";
              player.vast.skipButton.innerHTML = settings.skipTxt;
            }
          }
        }
      };

    },

    vastPlugin = function(options) {
      var player = this;
      var settings = extend({}, defaults, options || {});

      // check that we have the ads plugin
      if (player.ads === undefined) {
        window.console.error('vast video plugin requires videojs-contrib-ads, vast plugin not initialized');
        return null;
      }

      // set up vast plugin, then set up events here
      player.vast = new Vast(player, settings);

      player.on('vast-ready', function () {
        // vast is prepared with content, set up ads and trigger ready function
        player.trigger('adsready');
      });

      player.on('vast-preroll-ready', function () {
        // start playing preroll, note: this should happen this way no matter what, even if autoplay
        //  has been disabled since the preroll function shouldn't run until the user/autoplay has
        //  caused the main video to trigger this preroll function
        player.play();
      });

      player.on('vast-preroll-removed', function () {
        // preroll done or removed, start playing the actual video
        player.play();
      });

      player.on('contentupdate', function(){
        // videojs-ads triggers this when src changes
        player.vast.getContent(settings.url);
      });

      player.on('readyforpreroll', function() {
        // if we don't have a vast url, just bail out
        if (!settings.url) {
          player.trigger('adscanceled');
          return null;
        }
        // set up and start playing preroll
        player.vast.preroll();
      });

      // make an ads request immediately so we're ready when the viewer hits "play"
      if (player.currentSrc()) {
        player.vast.getContent(settings.url);
      }

      // return player to allow this plugin to be chained
      return player;
    };

  vjs.plugin('vast', vastPlugin);

}(window, videojs, DMVAST));
<commit_msg>add addskipped event<commit_after>(function(window, vjs, vast) {
  'use strict';

  var extend = function(obj) {
      var arg, i, k;
      for (i = 1; i < arguments.length; i++) {
        arg = arguments[i];
        for (k in arg) {
          if (arg.hasOwnProperty(k)) {
            obj[k] = arg[k];
          }
        }
      }
      return obj;
    },

    defaults = {
      // seconds before skip button shows, negative values to disable skip button altogether
      skip: 5,
      remainTxt: 'Skip in %d ...',
      skipTxt: 'Skip'
    },

    Vast = function (player, settings) {

      // return vast plugin
      return {
        createSourceObjects: function (media_files) {
          var sourcesByFormat = {}, i, j, tech;
          var techOrder = player.options().techOrder;
          for (i = 0, j = techOrder.length; i < j; i++) {
            var techName = techOrder[i].charAt(0).toUpperCase() + techOrder[i].slice(1);
            tech = window.videojs[techName];

            // Check if the current tech is defined before continuing
            if (!tech) {
              continue;
            }

            // Check if the browser supports this technology
            if (tech.isSupported()) {
              // Loop through each source object
              for (var a = 0, b = media_files.length; a < b; a++) {
                var media_file = media_files[a];
                var source = {type:media_file.mimeType, src:media_file.fileURL};
                // Check if source can be played with this technology
                if (tech.canPlaySource(source)) {
                  if (sourcesByFormat[techOrder[i]] === undefined) {
                    sourcesByFormat[techOrder[i]] = [];
                  }
                  sourcesByFormat[techOrder[i]].push({
                    type:media_file.mimeType,
                    src: media_file.fileURL,
                    width: media_file.width,
                    height: media_file.height
                  });
                }
              }
            }
          }
          // Create sources in preferred format order
          var sources = [];
          for (j = 0; j < techOrder.length; j++) {
            tech = techOrder[j];
            if (sourcesByFormat[tech] !== undefined) {
              for (i = 0; i < sourcesByFormat[tech].length; i++) {
                sources.push(sourcesByFormat[tech][i]);
              }
            }
          }
          return sources;
        },

        getContent: function () {

          // query vast url given in settings
          vast.client.get(settings.url, function(response) {
            if (response) {
              // we got a response, deal with it
              for (var adIdx = 0; adIdx < response.ads.length; adIdx++) {
                var ad = response.ads[adIdx];
                player.vast.companion = undefined;
                for (var creaIdx = 0; creaIdx < ad.creatives.length; creaIdx++) {
                  var creative = ad.creatives[creaIdx], foundCreative = false, foundCompanion = false;
                  if (creative.type === "linear" && !foundCreative) {

                    if (creative.mediaFiles.length) {

                      player.vast.sources = player.vast.createSourceObjects(creative.mediaFiles);

                      if (!player.vast.sources.length) {
                        player.trigger('adscanceled');
                        return;
                      }

                      player.vastTracker = new vast.tracker(ad, creative);

                      foundCreative = true;
                    }

                  } else if (creative.type === "companion" && !foundCompanion) {

                    player.vast.companion = creative;

                    foundCompanion = true;

                  }
                }

                if (player.vastTracker) {
                  // vast tracker and content is ready to go, trigger event
                  player.trigger('vast-ready');
                  break;
                } else {
                  // Inform ad server we can't find suitable media file for this ad
                  vast.util.track(ad.errorURLTemplates, {ERRORCODE: 403});
                }
              }
            } else {
              player.trigger('contentplay');
            }

            if (!player.vastTracker) {
              // No pre-roll, start video
              player.trigger('adscanceled');
            }
          });
        },

        setupEvents: function() {

          var errorOccurred = false,
            canplayFn = function() {
              player.vastTracker.load();
            },
            timeupdateFn = function() {
              if (isNaN(player.vastTracker.assetDuration)) {
                player.vastTracker.assetDuration = player.duration();
              }
              player.vastTracker.setProgress(player.currentTime());
            },
            pauseFn = function() {
              player.vastTracker.setPaused(true);
              player.one('play', function(){
                player.vastTracker.setPaused(false);
              });
            },
            errorFn = function() {
              // Inform ad server we couldn't play the media file for this ad
              vast.util.track(player.vastTracker.ad.errorURLTemplates, {ERRORCODE: 405});
              errorOccurred = true;
              player.trigger('ended');
            };

          player.on('canplay', canplayFn);
          player.on('timeupdate', timeupdateFn);
          player.on('pause', pauseFn);
          player.on('error', errorFn);

          player.one('vast-preroll-removed', function() {
            player.off('canplay', canplayFn);
            player.off('timeupdate', timeupdateFn);
            player.off('pause', pauseFn);
            player.off('error', errorFn);
            if (!errorOccurred) {
              player.vastTracker.complete();
            }
          });
        },

        preroll: function() {
          player.ads.startLinearAdMode();
          player.vast.showControls = player.controls();
          if (player.vast.showControls) {
            player.controls(false);
          }

          // load linear ad sources and start playing them
          player.src(player.vast.sources);

          var clickthrough;
          if (player.vastTracker.clickThroughURLTemplate) {
            clickthrough = vast.util.resolveURLTemplates(
              [player.vastTracker.clickThroughURLTemplate],
              {
                CACHEBUSTER: Math.round(Math.random() * 1.0e+10),
                CONTENTPLAYHEAD: player.vastTracker.progressFormated()
              }
            )[0];
          }

          var blocker = document.createElement("div");
          blocker.className = "vast-blocker";
          blocker.onclick = function() {
            if (player.paused()) {
              player.play();
              return false;
            }
            var clicktrackers = player.vastTracker.clickTrackingURLTemplate;
            if (clicktrackers) {
              player.vastTracker.trackURLs([clicktrackers]);
            }

            if(player.currentTime() > 1) {
              player.trigger("adclick");
              window.open(clickthrough || "#", '_blank');
            }
          };
          player.vast.blocker = blocker;
          player.el().insertBefore(blocker, player.controlBar.el());

          var skipButton = window.document.createElement("div");
          skipButton.className = "vast-skip-button";
          if (settings.skip < 0) {
            skipButton.style.display = "none";
          }
          player.vast.skipButton = skipButton;
          player.el().appendChild(skipButton);

          player.on("timeupdate", player.vast.timeupdate);

          skipButton.onclick = function(e) {
            if((' ' + player.vast.skipButton.className + ' ').indexOf(' enabled ') >= 0) {
              player.trigger('adskipped');
              player.vastTracker.skip();
              player.vast.tearDown();
            }
            if(window.Event.prototype.stopPropagation !== undefined) {
              e.stopPropagation();
            } else {
              return false;
            }
          };

          player.vast.setupEvents();

          player.one('ended', player.vast.tearDown);

          player.trigger('vast-preroll-ready');
        },

        tearDown: function() {
          // remove preroll buttons
          player.vast.skipButton.parentNode.removeChild(player.vast.skipButton);
          player.vast.blocker.parentNode.removeChild(player.vast.blocker);

          // remove vast-specific events
          player.off('timeupdate', player.vast.timeupdate);
          player.off('ended', player.vast.tearDown);

          // end ad mode
          player.ads.endLinearAdMode();

          // show player controls for video
          if (player.vast.showControls) {
            player.controls(true);
          }

          player.trigger('vast-preroll-removed');
        },

        timeupdate: function(e) {
          player.loadingSpinner.el().style.display = "none";
          var timeLeft = Math.ceil(settings.skip - player.currentTime());
          if(timeLeft > 0) {
            player.vast.skipButton.innerHTML = settings.remainTxt.replace('%d', timeLeft); //'Skip in ' + timeLeft + "..."
          } else {
            if((' ' + player.vast.skipButton.className + ' ').indexOf(' enabled ') === -1){
              player.vast.skipButton.className += " enabled";
              player.vast.skipButton.innerHTML = settings.skipTxt;
            }
          }
        }
      };

    },

    vastPlugin = function(options) {
      var player = this;
      var settings = extend({}, defaults, options || {});

      // check that we have the ads plugin
      if (player.ads === undefined) {
        window.console.error('vast video plugin requires videojs-contrib-ads, vast plugin not initialized');
        return null;
      }

      // set up vast plugin, then set up events here
      player.vast = new Vast(player, settings);

      player.on('vast-ready', function () {
        // vast is prepared with content, set up ads and trigger ready function
        player.trigger('adsready');
      });

      player.on('vast-preroll-ready', function () {
        // start playing preroll, note: this should happen this way no matter what, even if autoplay
        //  has been disabled since the preroll function shouldn't run until the user/autoplay has
        //  caused the main video to trigger this preroll function
        player.play();
      });

      player.on('vast-preroll-removed', function () {
        // preroll done or removed, start playing the actual video
        player.play();
      });

      player.on('contentupdate', function(){
        // videojs-ads triggers this when src changes
        player.vast.getContent(settings.url);
      });

      player.on('readyforpreroll', function() {
        // if we don't have a vast url, just bail out
        if (!settings.url) {
          player.trigger('adscanceled');
          return null;
        }
        // set up and start playing preroll
        player.vast.preroll();
      });

      // make an ads request immediately so we're ready when the viewer hits "play"
      if (player.currentSrc()) {
        player.vast.getContent(settings.url);
      }

      // return player to allow this plugin to be chained
      return player;
    };

  vjs.plugin('vast', vastPlugin);

}(window, videojs, DMVAST));
<|endoftext|>


<commit_before>(function(){

    // Datawrapper.Dataset
    // -------------------

    //
    var Dataset = Datawrapper.Dataset = function(options) {
        _.extend(options, {
            type: 'delimited'
        });
        this.__options = options;

    };

    _.extend(Dataset.prototype, {

        _initialize: function() {
            var me = this,
                opts = me.__options;
        },

        _fetchDelimited: function(callbacks) {
            var me = this,
                opts = me.__options;

            if (opts.url !== undefined) {
                if (me.__lastUrl == opts.url) {
                    // use cached data
                    loaded(me.__rawData);
                } else {
                    // load data from url
                    $.ajax({
                        url: opts.url,
                        method: 'GET',
                        dataType: "text", // NOTE (edouard): Without that jquery try to parse the content and return a Document
                        success: function(raw) {
                            me._delimtedLoaded(raw);
                            if (_.isFunction(callbacks.success)) {
                                callbacks.success();
                            }
                        }
                    });
                }
            }
        },

        _delimtedLoaded: function(raw, callbacks) {
            var me = this, opts = me.__options;
            me.__rawData = raw;
            // parse data
            var parser = new Datawrapper.Parsers.Delimited(opts),
                data = parser.parse(raw);
            me._processData(data);
            me.__data = data;
            me.__loaded = true;
        },

        _processData: function(data) {
            var me = this,
                numParser = new NumberParser();
            me.__seriesByName = {};
            // at first we teach the parser all numbers we have
            _.each(data.series, function(s) {
                me.__seriesByName[s.name] = s;
                s._min = function() {
                    //console.warn('series._min() is deprecated, use series.min instead.');
                    return s.min;
                };
                s._max = function() {
                    //console.warn('series._max() is deprecated, use series.max instead.');
                    return s.max;
                };
                _.each(s.data, function(number) {
                    numParser.learn(number);
                });
            });
            // then we let parse the numbers
            _.each(data.series, function(s) {
                s.min = Number.MAX_VALUE;
                s.max = -Number.MAX_VALUE;
                s.total = 0;
                _.each(s.data, function(number, i) {
                    s.data[i] = numParser.parse(number);
                    if (!isNaN(s.data[i])) {
                        s.min = Math.min(s.min, s.data[i]);
                        s.max = Math.max(s.max, s.data[i]);
                        s.total += s.data[i];
                    }
                });
                // store copy of original data in origdata
                s.origdata = s.data.slice();
            });
        },

        // PUBLIC API

        /*
         * loads a new dataset
         */
        fetch: function(callbacks) {
            var me = this, opts = me.__options;

            if (opts.type == "delimited") {
                me._fetchDelimited(callbacks);
            }
        },

        /*
         *
         */
        fetchRaw: function() {
            var me = this, opts = me.__options;
            if (opts.type == "delimited") {
                me._delimtedLoaded(opts.rawData);
            }
        },

        /*
         * returns either a single series by name or index, or a list of
         * all series, if no parameter x is given
         */
        series: function(x) {
            var me = this;
            if (_.isString(x)) {
                // single series by name
                if (me.__seriesByName[x] !== undefined) return me.__seriesByName[x];
                throw 'No series found with that name: "'+x+'"';
            }
            if (x !== undefined) {
                // single series by index
                if (me.__data.series[x] !== undefined) return me.__data.series[x];
                throw 'No series found with that index: '+x;
            }
            return this.__data.series;
        },

        hasRowNames: function() {
            return this.__data.rowNames !== undefined;
        },

        numRows: function() {
            return this.__data.series[0].data.length;
        },

        eachRow: function(func) {
            var i;
            for (i=0; i<this.numRows(); i++) {
                func(i);
            }
        },

        eachSeries: function(func) {
            _.each(this.series(), func);
        },

        rowNames: function() {
            return this.__data.rowNames;
        },

        rowName: function(i) {
            return this.__data.rowNames[i];
        },

        rowNameLabel: function() {
            return this.__data.rowNameLabel !== undefined ? this.__data.rowNameLabel : '';
        },

        /*
         * removes every row except the one with index i
         * and updates min, max and total of each series
         */
        filterRows: function(rows) {
            this.eachSeries(function(s) {
                var d = [];
                s.total = 0;
                s.min = Number.MAX_VALUE;
                s.max = Number.MAX_VALUE*-1;
                _.each(rows, function(i) {
                    d.push(s.origdata[i]);
                    s.total += s.origdata[i];
                    s.min = Math.min(s.min, s.origdata[i]);
                    s.max = Math.max(s.max, s.origdata[i]);
                });
                s.data = d;
            });
        }
    });

    var NumberParser = function() {
        this.__numbers = [];
        this.__knownFormats = {
            '-.': /^[\-\.]?[0-9]+(\.[0-9]+)?$/,
            '-,': /^[\-,]?[0-9]+(,[0-9]+)?$/,
            ',.': /^[0-9]{1,3}(,[0-9]{3})(\.[0-9]+)?$/,
            '.,': /^[0-9]{1,3}(\.[0-9]{3})(,[0-9]+)?$/,
            ' .': /^[0-9]{1,3}( [0-9]{3})(\.[0-9]+)?$/,
            ' ,': /^[0-9]{1,3}( [0-9]{3})(,[0-9]+)?$/
        };
    };

    _.extend(NumberParser.prototype, {

        // get some input numbers
        learn: function(number) {
            this.__numbers.push(number);
        },

        // test all numbers against certain
        _getFormat: function() {
            var me = this,
                matches = {},
                bestMatch = ['', 0];
            _.each(me.__numbers, function(n) {
                _.each(me.__knownFormats, function(regex, fmt) {
                    if (matches[fmt] === undefined) matches[fmt] = 0;
                    if (regex.test(n)) {
                        matches[fmt] += 1;
                        if (matches[fmt] > bestMatch[1]) {
                            bestMatch[0] = fmt;
                            bestMatch[1] = matches[fmt];
                        }
                    }
                });
            });
            return bestMatch[0];
        },

        parse: function(raw) {
            var me = this,
                number = raw,
                fmt = this.__format;
            if (raw === null || raw === undefined || raw === '') return 'n/a';
            if (fmt === undefined) {
                fmt = this.__format = this._getFormat();
            }
            // clean number
            if (fmt[0] == ',' || fmt[0] == '.' || fmt[0] == ' ') {
                // remove kilo seperator
                number = number.replace(fmt[0], '');
            }
            if (fmt[1] != '.') {
                // replace decimal char w/ point
                number = number.replace(fmt[1], '.');
            }
            number = Number(number);
            return isNaN(number) ? raw : number;
        }
    });

}).call(this);<commit_msg>dataset now supports parsing of hierarchical structures<commit_after>(function(){

    // Datawrapper.Dataset
    // -------------------

    //
    var Dataset = Datawrapper.Dataset = function(options) {
        _.extend(options, {
            type: 'delimited'
        });
        this.__options = options;

    };

    _.extend(Dataset.prototype, {

        _initialize: function() {
            var me = this,
                opts = me.__options;
        },

        _fetchDelimited: function(callbacks) {
            var me = this,
                opts = me.__options;

            if (opts.url !== undefined) {
                if (me.__lastUrl == opts.url) {
                    // use cached data
                    loaded(me.__rawData);
                } else {
                    // load data from url
                    $.ajax({
                        url: opts.url,
                        method: 'GET',
                        dataType: "text", // NOTE (edouard): Without that jquery try to parse the content and return a Document
                        success: function(raw) {
                            me._delimtedLoaded(raw);
                            if (_.isFunction(callbacks.success)) {
                                callbacks.success();
                            }
                        }
                    });
                }
            }
        },

        _delimtedLoaded: function(raw, callbacks) {
            var me = this, opts = me.__options;
            me.__rawData = raw;
            // parse data
            var parser = new Datawrapper.Parsers.Delimited(opts),
                data = parser.parse(raw);
            me._processData(data);
            me.__data = data;
            me.__loaded = true;
        },

        _processData: function(data) {
            var me = this,
                numParser = new NumberParser();
            me.__seriesByName = {};
            // at first we teach the parser all numbers we have
            _.each(data.series, function(s) {
                me.__seriesByName[s.name] = s;
                s._min = function() {
                    //console.warn('series._min() is deprecated, use series.min instead.');
                    return s.min;
                };
                s._max = function() {
                    //console.warn('series._max() is deprecated, use series.max instead.');
                    return s.max;
                };
                _.each(s.data, function(number) {
                    numParser.learn(number);
                });
            });
            // then we let parse the numbers
            _.each(data.series, function(s) {
                s.min = Number.MAX_VALUE;
                s.max = -Number.MAX_VALUE;
                s.total = 0;
                _.each(s.data, function(number, i) {
                    s.data[i] = numParser.parse(number);
                    if (!isNaN(s.data[i])) {
                        s.min = Math.min(s.min, s.data[i]);
                        s.max = Math.max(s.max, s.data[i]);
                        s.total += s.data[i];
                    }
                });
                // store copy of original data in origdata
                s.origdata = s.data.slice();
            });
        },

        // PUBLIC API

        /*
         * loads a new dataset
         */
        fetch: function(callbacks) {
            var me = this, opts = me.__options;

            if (opts.type == "delimited") {
                me._fetchDelimited(callbacks);
            }
        },

        /*
         *
         */
        fetchRaw: function() {
            var me = this, opts = me.__options;
            if (opts.type == "delimited") {
                me._delimtedLoaded(opts.rawData);
            }
        },

        /*
         * returns either a single series by name or index, or a list of
         * all series, if no parameter x is given
         */
        series: function(x) {
            var me = this;
            if (_.isString(x)) {
                // single series by name
                if (me.__seriesByName[x] !== undefined) return me.__seriesByName[x];
                throw 'No series found with that name: "'+x+'"';
            }
            if (x !== undefined) {
                // single series by index
                if (me.__data.series[x] !== undefined) return me.__data.series[x];
                throw 'No series found with that index: '+x;
            }
            return this.__data.series;
        },

        hasRowNames: function() {
            return this.__data.rowNames !== undefined;
        },

        numRows: function() {
            return this.__data.series[0].data.length;
        },

        eachRow: function(func) {
            var i;
            for (i=0; i<this.numRows(); i++) {
                func(i);
            }
        },

        eachSeries: function(func) {
            _.each(this.series(), func);
        },

        rowNames: function() {
            return this.__data.rowNames;
        },

        rowName: function(i) {
            return this.__data.rowNames[i];
        },

        rowNameLabel: function() {
            return this.__data.rowNameLabel !== undefined ? this.__data.rowNameLabel : '';
        },

        /*
         * removes every row except the one with index i
         * and updates min, max and total of each series
         */
        filterRows: function(rows) {
            this.eachSeries(function(s) {
                var d = [];
                s.total = 0;
                s.min = Number.MAX_VALUE;
                s.max = Number.MAX_VALUE*-1;
                _.each(rows, function(i) {
                    d.push(s.origdata[i]);
                    s.total += s.origdata[i];
                    s.min = Math.min(s.min, s.origdata[i]);
                    s.max = Math.max(s.max, s.origdata[i]);
                });
                s.data = d;
            });
        },

        /*
         * returns a tree data structure from this dataset
         */
        parseTree: function(row) {
            var tree = { children: [], depth: 0 };
            this.eachSeries(function(s) {
                var parts = s.name.split('>');
                var node = tree;
                _.each(parts, function(p, i) {
                    parts[i] = p = p.trim();
                    var found = false;
                    _.each(node.children, function(c) {
                        if (c.name.trim() == p) {
                            node = c;
                            found = true;
                            return false;
                        }
                    });
                    if (!found) { // child not found, create new one
                        var n = { name: p, children: [], _series: s, _row: 0, depth: i+1 };
                        if (i == parts.length-1) n.value = s.data[row];
                        node.children.push(n);
                        node = n;
                    }
                });
            });
            return tree;
        }
    });

    var NumberParser = function() {
        this.__numbers = [];
        this.__knownFormats = {
            '-.': /^[\-\.]?[0-9]+(\.[0-9]+)?$/,
            '-,': /^[\-,]?[0-9]+(,[0-9]+)?$/,
            ',.': /^[0-9]{1,3}(,[0-9]{3})(\.[0-9]+)?$/,
            '.,': /^[0-9]{1,3}(\.[0-9]{3})(,[0-9]+)?$/,
            ' .': /^[0-9]{1,3}( [0-9]{3})(\.[0-9]+)?$/,
            ' ,': /^[0-9]{1,3}( [0-9]{3})(,[0-9]+)?$/
        };
    };

    _.extend(NumberParser.prototype, {

        // get some input numbers
        learn: function(number) {
            this.__numbers.push(number);
        },

        // test all numbers against certain
        _getFormat: function() {
            var me = this,
                matches = {},
                bestMatch = ['', 0];
            _.each(me.__numbers, function(n) {
                _.each(me.__knownFormats, function(regex, fmt) {
                    if (matches[fmt] === undefined) matches[fmt] = 0;
                    if (regex.test(n)) {
                        matches[fmt] += 1;
                        if (matches[fmt] > bestMatch[1]) {
                            bestMatch[0] = fmt;
                            bestMatch[1] = matches[fmt];
                        }
                    }
                });
            });
            return bestMatch[0];
        },

        parse: function(raw) {
            var me = this,
                number = raw,
                fmt = this.__format;
            if (raw === null || raw === undefined || raw === '') return 'n/a';
            if (fmt === undefined) {
                fmt = this.__format = this._getFormat();
            }
            // clean number
            if (fmt[0] == ',' || fmt[0] == '.' || fmt[0] == ' ') {
                // remove kilo seperator
                number = number.replace(fmt[0], '');
            }
            if (fmt[1] != '.') {
                // replace decimal char w/ point
                number = number.replace(fmt[1], '.');
            }
            number = Number(number);
            return isNaN(number) ? raw : number;
        }

    });

}).call(this);<|endoftext|>


<commit_before>// Legacy  get rid of this.
// Used wrongly in textWidget.js
// Stub it out until we fix this.
function ComparisonSaveAnnotations() {}

// Record the viewer into the current note and save into the database.
function SaveView() {
  var note = NOTES_WIDGET.GetCurrentNote();
        note.SnapShotCallback();
  NOTES_WIDGET.SaveCallback();
}

//==============================================================================
// Create and manage the menu to edit dual views.

function ShowViewEditMenu(x, y) {
    // Viewers have independent annotation visibility (which could be annoying.
    var viewer = EVENT_MANAGER.CurrentViewer;
    if ( ! viewer) { return; }

    var color = "#A0A0A0";
    if (viewer.WidgetList.length > 0) {
      color = "#000000";
    }

    $('#viewEditMenu').css({'top': y-15, 'left':x-15}).show();
}

function ShowViewerEditMenu(viewer) {
    EVENT_MANAGER.CurrentViewer = viewer;
    var viewport = viewer.GetViewport();
    $('#viewEditMenu').css({'top': viewport[1]+viewport[3]-180,
                            'left': viewport[0]+viewport[2]-230})
                      .show();
}

function InitViewEditMenus() {
    // Create the menu of edit options.
    $('
').appendTo('body').css({
        'background-color': 'white',
        'border-style': 'solid',
        'border-width': '1px',
        'border-radius': '5px',
        'position': 'absolute',
        'top' : '35px',
        'left' : '35px',
        'z-index': '2',
        'color': '#303030',
        'font-size': '20px'
    }).attr('id', 'viewEditMenu').hide()
      .mouseleave(function(){$(this).fadeOut();});

    var viewEditSelector = $('
');
    viewEditSelector.appendTo('#viewEditMenu')
             .attr('id', 'viewEditSelector')
             .css({'width': '100%', 'list-style-type':'none'});
    $('
').appendTo(viewEditSelector)
             .text("Load Slide")
             .click(function(){ShowViewBrowser();});
    if (EDIT) {
      $('
').appendTo(viewEditSelector)
               .text("Save View")
               .click(function(){SaveView();});
    }
    $('
').appendTo(viewEditSelector)
             .text("Slide Info")
             .click(function(){ShowSlideInformation();});

    // Test for showing coverage of view histor.
    $('
').appendTo(viewEditSelector)
             .text("History Mask")
             .click(function(){VIEWER1.MainView.DrawHistory();});

    // Hack until we have some sort of scale.
    $('
').appendTo(viewEditSelector)
             .attr('id', 'dualViewCopyZoom')
             .text("Copy Zoom")
             .hide()
             .click(function(){CopyZoom();});
    $('
').appendTo(viewEditSelector)
             .text("Flip Horizontal")
             .click(function(){FlipHorizontal();});

    // Create a selection list of sessions.
    $('
').appendTo('body').css({
        'background-color': 'white',
        'border-style': 'solid',
        'border-width': '1px',
        'border-radius': '5px',
        'position': 'absolute',
        'top' : '35px',
        'left' : '35px',
        'width' : '500px',
        'height' : '700px',
        'overflow': 'auto',
        'z-index': '2',
        'color': '#303030',
        'font-size': '20px'
    }).attr('id', 'sessionMenu').hide()
        .mouseleave(function(){$(this).fadeOut();});
    $('
').appendTo('#sessionMenu').attr('id', 'sessionMenuSelector');

    // Create a selector for views.
    $('
').appendTo('body').css({
        'background-color': 'white',
        'border-style': 'solid',
        'border-width': '1px',
        'border-radius': '5px',
        'position': 'absolute',
        'top' : '135px',
        'left' : '135px',
        'width' : '500px',
        'height' : '700px',
        'overflow': 'auto',
        'z-index': '2',
        'color': '#303030',
        'font-size': '20px'
    }).attr('id', 'viewMenu').hide()
        .mouseleave(function(){$(this).fadeOut();});
    $('
').appendTo('#viewMenu').attr('id', 'viewMenuSelector'); // <select> for drop down

    $('
').appendTo('body').css({
        'background-color': 'white',
        'border-style': 'solid',
        'border-width': '1px',
        'border-radius': '5px',
        'position': 'absolute',
        'top' : '30%',
        'left' : '30%',
        'width': '40%',
        'height': '40%',
        'z-index': '2',
        'color': '#303030',
        'font-size': '20px'
    }).attr('id', 'slideInformation').hide()
      .mouseleave(function(){$(this).fadeOut();});
}

function CopyZoom() {
  $('#viewEditMenu').hide();
  var viewer = EVENT_MANAGER.CurrentViewer;
  if ( ! viewer) { return; }

  var cam = viewer.GetCamera();
  var copyCam;
  if (viewer == VIEWER1) {
    var copyCam = VIEWER2.GetCamera();
  } else {
    var copyCam = VIEWER1.GetCamera();
  }

  viewer.AnimateCamera(cam.GetFocalPoint(), cam.Roll, copyCam.Height);
}

function ShowSlideInformation() {
  $('#viewEditMenu').hide();
  var viewer = EVENT_MANAGER.CurrentViewer;
  if ( ! viewer) { return; }

  imageObj = viewer.MainView.Section.Caches[0].Image;

  $('#slideInformation')
    .html("File Name: " + imageObj.filename
          + "
Dimensions: " + imageObj.dimensions[0] + ", "
                               + imageObj.dimensions[1]
          + "
Levels: " + imageObj.levels)
    .show();
}

function ShowSlideInformation() {
  $('#viewEditMenu').hide();
  var viewer = EVENT_MANAGER.CurrentViewer;
  if ( ! viewer) { return; }

  imageObj = viewer.MainView.Section.Caches[0].Image;

  $('#slideInformation')
    .html("File Name: " + imageObj.filename
          + "
Dimensions: " + imageObj.dimensions[0] + ", "
                               + imageObj.dimensions[1]
          + "
Levels: " + imageObj.levels)
    .show();
}

// Mirror image
function FlipHorizontal() {
    $('#viewEditMenu').hide();
    // When the circle button is pressed, create the widget.
    var viewer = EVENT_MANAGER.CurrentViewer;
    if ( ! viewer) { return; }

    var cam = viewer.GetCamera();
    viewer.ToggleMirror();
    viewer.SetCamera(cam.GetFocalPoint(), cam.GetRotation()+180.0, cam.Height);
    RecordState();
}

function SessionAdvance() {
// I do not have the session id and it is hard to get!
//    $.get(SESSIONS_URL+"?json=true&sessid="+$(obj).attr('sessid')+"&sessdb="+$(obj).attr('sessdb'),
//          function(data,status){
//            if (status == "success") {
//              ShowViewMenuAjax(data);
//            } else { alert("ajax failed."); }
//          });
}

function SessionAdvanceAjax() {
}

<commit_msg>Make the view menu disappear after save<commit_after>// Legacy  get rid of this.
// Used wrongly in textWidget.js
// Stub it out until we fix this.
function ComparisonSaveAnnotations() {}

// Record the viewer into the current note and save into the database.
function SaveView() {
  var note = NOTES_WIDGET.GetCurrentNote();
        note.SnapShotCallback();
  NOTES_WIDGET.SaveCallback();
  $('#viewEditMenu').hide();
}

//==============================================================================
// Create and manage the menu to edit dual views.

function ShowViewEditMenu(x, y) {
    // Viewers have independent annotation visibility (which could be annoying.
    var viewer = EVENT_MANAGER.CurrentViewer;
    if ( ! viewer) { return; }

    var color = "#A0A0A0";
    if (viewer.WidgetList.length > 0) {
      color = "#000000";
    }

    $('#viewEditMenu').css({'top': y-15, 'left':x-15}).show();
}

function ShowViewerEditMenu(viewer) {
    EVENT_MANAGER.CurrentViewer = viewer;
    var viewport = viewer.GetViewport();
    $('#viewEditMenu').css({'top': viewport[1]+viewport[3]-180,
                            'left': viewport[0]+viewport[2]-230})
                      .show();
}

function InitViewEditMenus() {
    // Create the menu of edit options.
    $('
').appendTo('body').css({
        'background-color': 'white',
        'border-style': 'solid',
        'border-width': '1px',
        'border-radius': '5px',
        'position': 'absolute',
        'top' : '35px',
        'left' : '35px',
        'z-index': '2',
        'color': '#303030',
        'font-size': '20px'
    }).attr('id', 'viewEditMenu').hide()
      .mouseleave(function(){$(this).fadeOut();});

    var viewEditSelector = $('
');
    viewEditSelector.appendTo('#viewEditMenu')
             .attr('id', 'viewEditSelector')
             .css({'width': '100%', 'list-style-type':'none'});
    $('
').appendTo(viewEditSelector)
             .text("Load Slide")
             .click(function(){ShowViewBrowser();});
    if (EDIT) {
      $('
').appendTo(viewEditSelector)
               .text("Save View")
               .click(function(){SaveView();});
    }
    $('
').appendTo(viewEditSelector)
             .text("Slide Info")
             .click(function(){ShowSlideInformation();});

    // Test for showing coverage of view histor.
    $('
').appendTo(viewEditSelector)
             .text("History Mask")
             .click(function(){VIEWER1.MainView.DrawHistory();});

    // Hack until we have some sort of scale.
    $('
').appendTo(viewEditSelector)
             .attr('id', 'dualViewCopyZoom')
             .text("Copy Zoom")
             .hide()
             .click(function(){CopyZoom();});
    $('
').appendTo(viewEditSelector)
             .text("Flip Horizontal")
             .click(function(){FlipHorizontal();});

    // Create a selection list of sessions.
    $('
').appendTo('body').css({
        'background-color': 'white',
        'border-style': 'solid',
        'border-width': '1px',
        'border-radius': '5px',
        'position': 'absolute',
        'top' : '35px',
        'left' : '35px',
        'width' : '500px',
        'height' : '700px',
        'overflow': 'auto',
        'z-index': '2',
        'color': '#303030',
        'font-size': '20px'
    }).attr('id', 'sessionMenu').hide()
        .mouseleave(function(){$(this).fadeOut();});
    $('
').appendTo('#sessionMenu').attr('id', 'sessionMenuSelector');

    // Create a selector for views.
    $('
').appendTo('body').css({
        'background-color': 'white',
        'border-style': 'solid',
        'border-width': '1px',
        'border-radius': '5px',
        'position': 'absolute',
        'top' : '135px',
        'left' : '135px',
        'width' : '500px',
        'height' : '700px',
        'overflow': 'auto',
        'z-index': '2',
        'color': '#303030',
        'font-size': '20px'
    }).attr('id', 'viewMenu').hide()
        .mouseleave(function(){$(this).fadeOut();});
    $('
').appendTo('#viewMenu').attr('id', 'viewMenuSelector'); // <select> for drop down

    $('
').appendTo('body').css({
        'background-color': 'white',
        'border-style': 'solid',
        'border-width': '1px',
        'border-radius': '5px',
        'position': 'absolute',
        'top' : '30%',
        'left' : '30%',
        'width': '40%',
        'height': '40%',
        'z-index': '2',
        'color': '#303030',
        'font-size': '20px'
    }).attr('id', 'slideInformation').hide()
      .mouseleave(function(){$(this).fadeOut();});
}

function CopyZoom() {
  $('#viewEditMenu').hide();
  var viewer = EVENT_MANAGER.CurrentViewer;
  if ( ! viewer) { return; }

  var cam = viewer.GetCamera();
  var copyCam;
  if (viewer == VIEWER1) {
    var copyCam = VIEWER2.GetCamera();
  } else {
    var copyCam = VIEWER1.GetCamera();
  }

  viewer.AnimateCamera(cam.GetFocalPoint(), cam.Roll, copyCam.Height);
}

function ShowSlideInformation() {
  $('#viewEditMenu').hide();
  var viewer = EVENT_MANAGER.CurrentViewer;
  if ( ! viewer) { return; }

  imageObj = viewer.MainView.Section.Caches[0].Image;

  $('#slideInformation')
    .html("File Name: " + imageObj.filename
          + "
Dimensions: " + imageObj.dimensions[0] + ", "
                               + imageObj.dimensions[1]
          + "
Levels: " + imageObj.levels)
    .show();
}

function ShowSlideInformation() {
  $('#viewEditMenu').hide();
  var viewer = EVENT_MANAGER.CurrentViewer;
  if ( ! viewer) { return; }

  imageObj = viewer.MainView.Section.Caches[0].Image;

  $('#slideInformation')
    .html("File Name: " + imageObj.filename
          + "
Dimensions: " + imageObj.dimensions[0] + ", "
                               + imageObj.dimensions[1]
          + "
Levels: " + imageObj.levels)
    .show();
}

// Mirror image
function FlipHorizontal() {
    $('#viewEditMenu').hide();
    // When the circle button is pressed, create the widget.
    var viewer = EVENT_MANAGER.CurrentViewer;
    if ( ! viewer) { return; }

    var cam = viewer.GetCamera();
    viewer.ToggleMirror();
    viewer.SetCamera(cam.GetFocalPoint(), cam.GetRotation()+180.0, cam.Height);
    RecordState();
}

function SessionAdvance() {
// I do not have the session id and it is hard to get!
//    $.get(SESSIONS_URL+"?json=true&sessid="+$(obj).attr('sessid')+"&sessdb="+$(obj).attr('sessdb'),
//          function(data,status){
//            if (status == "success") {
//              ShowViewMenuAjax(data);
//            } else { alert("ajax failed."); }
//          });
}

function SessionAdvanceAjax() {
}

<|endoftext|>