<commit_before>import {RequestUtil} from 'mesosphere-shared-reactjs';

import {
  REQUEST_PREVIOUS_SYSTEM_LOG_ERROR,
  REQUEST_PREVIOUS_SYSTEM_LOG_SUCCESS,
  REQUEST_SYSTEM_LOG_ERROR,
  REQUEST_SYSTEM_LOG_SUCCESS,
  REQUEST_SYSTEM_LOG_STREAM_TYPES_ERROR,
  REQUEST_SYSTEM_LOG_STREAM_TYPES_SUCCESS
} from '../constants/ActionTypes';
import AppDispatcher from './AppDispatcher';
import CookieUtils from '../utils/CookieUtils';
import Config from '../config/Config';
import {accumulatedThrottle, getUrl} from '../utils/SystemLogUtil';

/**
 * Implementation of server sent event handling for
 * https://github.com/dcos/dcos-log
 */

const eventThroughPutTime = 500;
// Store of current open connections
const urlToEventSourceMap = {};
const subscriptionIDtoURLMap = {};

function subscribe(url, onMessage, onError) {
  // Unsubscribe if any open connection exists with the same ID
  unsubscribe(url);

  const source = new EventSource(url, {
    withCredentials: Boolean(CookieUtils.getUserMetadata())
  });

  source.addEventListener('message', onMessage, false);
  source.addEventListener('error', onError, false);

  // Store listeners along with EventSource reference, so we can clean up
  urlToEventSourceMap[url] = {
    errorListener: onError,
    messageListener: onMessage,
    source
  };

  return url;
}

function unsubscribe(url) {
  if (!urlToEventSourceMap[url]) {
    return;
  }

  const {errorListener, messageListener, source} = urlToEventSourceMap[url];

  source.removeEventListener('message', messageListener, false);
  source.removeEventListener('error', errorListener, false);

  source.close();

  delete urlToEventSourceMap[url];
}

function parseEvents(eventData) {
  const globalOrigin = global.location.origin;

  return eventData.reduce(function (memo, event) {
    // Only take first argument, which holds the event
    const {data, origin} = event[0] || {};
    if (origin !== globalOrigin) {
      // Ignore events that are not from this origin
      return memo;
    }

    try {
      // Attempt parsing
      const parsedEvent = JSON.parse(data);
      // Append when regular reverse order
      memo.events.push(parsedEvent);
    } catch (error) {
      memo.errors.push(error);
    }

    return memo;
  }, {events: [], errors: []});
}

const SystemLogActions = {
  /**
   * Subscribes to the events stream for logs given the parameters provided
   * @param {String} nodeID ID of the node to retrieve logs from
   * @param {Object} [options] Optional parameters for request
   * @param {String} [options.cursor] ID of the cursor to request entries from
   * @param {String} [options.subscriptionID] ID to emit events to,
   *   if omitted a new one will be created
   * @param {Number} [options.skip_prev] how many entries backwards to look.
   * NB: This _needs_ to be present to start streaming from the bottom!!
   * @param {Number} [options.skip_next] how many entries to look ahead
   * @param {Number} [options.limit] limit how many entries to receive
   * @param {Object} [options.filter] filter parameters to add to URL
   * @param {String} [options.frameworkID] ID for framework to retrieve logs from
   * @param {String} [options.executorID] ID for executor to retrieve logs from
   * @param {String} [options.containerID] ID for container to retrieve logs from
   * @param {String} [options.read_reverse] will read events in reverse order if set to true
   * @return {Symbol} subscriptionID to unsubscribe or resubscribe with
   */
  startTail(nodeID, options = {}) {
    let {subscriptionID, cursor, skip_prev} = options;

    // NB: When subscriptionID is passed from the store and an ongoing stream
    // is open, it will close the connection before opening a new one
    this.stopTail(subscriptionID);

    const url = getUrl(nodeID, options);
    // NB: User can pass `subscriptionID` to associate it with their local data
    // accumulation
    subscriptionID = subscriptionID || Symbol.for(url);

    // Will receive an array of events through the accumulatedThrottle function
    function messageListener(eventData) {
      const {events, errors} = parseEvents(eventData);
      if (errors.length > 0) {
        // Some data was corrupt and could not be parsed
        AppDispatcher.handleServerAction({
          type: REQUEST_SYSTEM_LOG_ERROR,
          data: errors,
          subscriptionID
        });
      }

      // Skip if we are hitting the same cursor as we requested with and we are
      // not looking backwards. This is only relevant for the first item we hit
      if (!skip_prev && events[0] && events[0].cursor === cursor) {
        events.shift();
      }

      // No data to emit
      if (events.length <= 0) {
        return;
      }

      AppDispatcher.handleServerAction({
        type: REQUEST_SYSTEM_LOG_SUCCESS,
        data: events,
        subscriptionID
      });
    }

    const throttledMessageListener = accumulatedThrottle(
      messageListener,
      eventThroughPutTime
    );

    function errorListener(event = {}) {
      AppDispatcher.handleServerAction({
        type: REQUEST_SYSTEM_LOG_ERROR,
        data: event,
        subscriptionID
      });
    }

    subscriptionIDtoURLMap[subscriptionID] = url;

    subscribe(url, throttledMessageListener, errorListener);

    return subscriptionID;
  },

  /**
   * Unsubscribes from the event stream from the given subscriptionID
   * @param {String} subscriptionID ID returned from subscribe function
   */
  stopTail(subscriptionID) {
    if (!subscriptionIDtoURLMap[subscriptionID]) {
      return;
    }

    unsubscribe(subscriptionIDtoURLMap[subscriptionID]);
    delete subscriptionIDtoURLMap[subscriptionID];
  },

  /**
   * Fetches a range of log entries given the parameters provided
   * @param {String} nodeID ID of the node to retrieve logs from
   * @param {Object} [options] Optional parameters for request
   * @param {String} [options.cursor] ID of the cursor to request entries from
   * @param {String} [options.subscriptionID] ID to emit events to,
   *   if omitted a new one will be created
   * @param {Number} [options.skip_prev] how many entries backwards to look
   * @param {Number} [options.skip_next] how many entries to look ahead
   * @param {Number} [options.limit] limit how many entries to receive
   * @param {Object} [options.filter] filter parameters to add to URL
   * @param {String} [options.frameworkID] ID for framework to retrieve logs from
   * @param {String} [options.executorID] ID for executor to retrieve logs from
   * @param {String} [options.containerID] ID for container to retrieve logs from
   */
  fetchRange(nodeID, options = {}) {
    let {limit, subscriptionID} = options;
    const url = getUrl(
      nodeID,
      // Avoiding duplicate events by using read reverse (stream backwards).
      // Connection will close all events are received or have reached the top
      Object.assign(options, {read_reverse: true}),
      false
    );
    // NB: User can pass `subscriptionID` to associate it with their local data
    // accumulation
    subscriptionID = subscriptionID || Symbol.for(url);

    const items = [];

    function messageListener({data, origin} = {}) {
      if (origin !== global.location.origin) {
        // Ignore events that are not from this origin
        return false;
      }

      let parsedData;
      try {
        parsedData = JSON.parse(data);
      } catch (error) {
        AppDispatcher.handleServerAction({
          type: REQUEST_PREVIOUS_SYSTEM_LOG_ERROR,
          data: error,
          subscriptionID
        });
      }

      items.push(parsedData);
    }

    function errorListener(event = {}) {
      const {eventPhase} = event;

      if (eventPhase === EventSource.CLOSED) {
        // Reverse the items, as the come in opposite order
        items.reverse();
        AppDispatcher.handleServerAction({
          type: REQUEST_PREVIOUS_SYSTEM_LOG_SUCCESS,
          data: items,
          firstEntry: items.length < limit,
          subscriptionID
        });
      } else {
        AppDispatcher.handleServerAction({
          type: REQUEST_PREVIOUS_SYSTEM_LOG_ERROR,
          data: event,
          subscriptionID
        });
      }

      unsubscribe(url);
    }

    subscribe(url, messageListener, errorListener);
  },

  fetchStreamTypes(nodeID) {
    RequestUtil.json({
      url: `${Config.logsAPIPrefix}/${nodeID}/logs/v1/fields/STREAM`,
      success(response) {
        AppDispatcher.handleServerAction({
          type: REQUEST_SYSTEM_LOG_STREAM_TYPES_SUCCESS,
          data: response
        });
      },
      error(xhr) {
        AppDispatcher.handleServerAction({
          type: REQUEST_SYSTEM_LOG_STREAM_TYPES_ERROR,
          data: RequestUtil.getErrorFromXHR(xhr),
          xhr
        });
      }
    });
  }
};

module.exports = SystemLogActions;
<commit_msg>Use unshift rather than push and reverse<commit_after>import {RequestUtil} from 'mesosphere-shared-reactjs';

import {
  REQUEST_PREVIOUS_SYSTEM_LOG_ERROR,
  REQUEST_PREVIOUS_SYSTEM_LOG_SUCCESS,
  REQUEST_SYSTEM_LOG_ERROR,
  REQUEST_SYSTEM_LOG_SUCCESS,
  REQUEST_SYSTEM_LOG_STREAM_TYPES_ERROR,
  REQUEST_SYSTEM_LOG_STREAM_TYPES_SUCCESS
} from '../constants/ActionTypes';
import AppDispatcher from './AppDispatcher';
import CookieUtils from '../utils/CookieUtils';
import Config from '../config/Config';
import {accumulatedThrottle, getUrl} from '../utils/SystemLogUtil';

/**
 * Implementation of server sent event handling for
 * https://github.com/dcos/dcos-log
 */

const eventThroughPutTime = 500;
// Store of current open connections
const urlToEventSourceMap = {};
const subscriptionIDtoURLMap = {};

function subscribe(url, onMessage, onError) {
  // Unsubscribe if any open connection exists with the same ID
  unsubscribe(url);

  const source = new EventSource(url, {
    withCredentials: Boolean(CookieUtils.getUserMetadata())
  });

  source.addEventListener('message', onMessage, false);
  source.addEventListener('error', onError, false);

  // Store listeners along with EventSource reference, so we can clean up
  urlToEventSourceMap[url] = {
    errorListener: onError,
    messageListener: onMessage,
    source
  };

  return url;
}

function unsubscribe(url) {
  if (!urlToEventSourceMap[url]) {
    return;
  }

  const {errorListener, messageListener, source} = urlToEventSourceMap[url];

  source.removeEventListener('message', messageListener, false);
  source.removeEventListener('error', errorListener, false);

  source.close();

  delete urlToEventSourceMap[url];
}

function parseEvents(eventData) {
  const globalOrigin = global.location.origin;

  return eventData.reduce(function (memo, event) {
    // Only take first argument, which holds the event
    const {data, origin} = event[0] || {};
    if (origin !== globalOrigin) {
      // Ignore events that are not from this origin
      return memo;
    }

    try {
      // Attempt parsing
      const parsedEvent = JSON.parse(data);
      // Append when regular reverse order
      memo.events.push(parsedEvent);
    } catch (error) {
      memo.errors.push(error);
    }

    return memo;
  }, {events: [], errors: []});
}

const SystemLogActions = {
  /**
   * Subscribes to the events stream for logs given the parameters provided
   * @param {String} nodeID ID of the node to retrieve logs from
   * @param {Object} [options] Optional parameters for request
   * @param {String} [options.cursor] ID of the cursor to request entries from
   * @param {String} [options.subscriptionID] ID to emit events to,
   *   if omitted a new one will be created
   * @param {Number} [options.skip_prev] how many entries backwards to look.
   * NB: This _needs_ to be present to start streaming from the bottom!!
   * @param {Number} [options.skip_next] how many entries to look ahead
   * @param {Number} [options.limit] limit how many entries to receive
   * @param {Object} [options.filter] filter parameters to add to URL
   * @param {String} [options.frameworkID] ID for framework to retrieve logs from
   * @param {String} [options.executorID] ID for executor to retrieve logs from
   * @param {String} [options.containerID] ID for container to retrieve logs from
   * @param {String} [options.read_reverse] will read events in reverse order if set to true
   * @return {Symbol} subscriptionID to unsubscribe or resubscribe with
   */
  startTail(nodeID, options = {}) {
    let {subscriptionID, cursor, skip_prev} = options;

    // NB: When subscriptionID is passed from the store and an ongoing stream
    // is open, it will close the connection before opening a new one
    this.stopTail(subscriptionID);

    const url = getUrl(nodeID, options);
    // NB: User can pass `subscriptionID` to associate it with their local data
    // accumulation
    subscriptionID = subscriptionID || Symbol.for(url);

    // Will receive an array of events through the accumulatedThrottle function
    function messageListener(eventData) {
      const {events, errors} = parseEvents(eventData);
      if (errors.length > 0) {
        // Some data was corrupt and could not be parsed
        AppDispatcher.handleServerAction({
          type: REQUEST_SYSTEM_LOG_ERROR,
          data: errors,
          subscriptionID
        });
      }

      // Skip if we are hitting the same cursor as we requested with and we are
      // not looking backwards. This is only relevant for the first item we hit
      if (!skip_prev && events[0] && events[0].cursor === cursor) {
        events.shift();
      }

      // No data to emit
      if (events.length <= 0) {
        return;
      }

      AppDispatcher.handleServerAction({
        type: REQUEST_SYSTEM_LOG_SUCCESS,
        data: events,
        subscriptionID
      });
    }

    const throttledMessageListener = accumulatedThrottle(
      messageListener,
      eventThroughPutTime
    );

    function errorListener(event = {}) {
      AppDispatcher.handleServerAction({
        type: REQUEST_SYSTEM_LOG_ERROR,
        data: event,
        subscriptionID
      });
    }

    subscriptionIDtoURLMap[subscriptionID] = url;

    subscribe(url, throttledMessageListener, errorListener);

    return subscriptionID;
  },

  /**
   * Unsubscribes from the event stream from the given subscriptionID
   * @param {String} subscriptionID ID returned from subscribe function
   */
  stopTail(subscriptionID) {
    if (!subscriptionIDtoURLMap[subscriptionID]) {
      return;
    }

    unsubscribe(subscriptionIDtoURLMap[subscriptionID]);
    delete subscriptionIDtoURLMap[subscriptionID];
  },

  /**
   * Fetches a range of log entries given the parameters provided
   * @param {String} nodeID ID of the node to retrieve logs from
   * @param {Object} [options] Optional parameters for request
   * @param {String} [options.cursor] ID of the cursor to request entries from
   * @param {String} [options.subscriptionID] ID to emit events to,
   *   if omitted a new one will be created
   * @param {Number} [options.skip_prev] how many entries backwards to look
   * @param {Number} [options.skip_next] how many entries to look ahead
   * @param {Number} [options.limit] limit how many entries to receive
   * @param {Object} [options.filter] filter parameters to add to URL
   * @param {String} [options.frameworkID] ID for framework to retrieve logs from
   * @param {String} [options.executorID] ID for executor to retrieve logs from
   * @param {String} [options.containerID] ID for container to retrieve logs from
   */
  fetchRange(nodeID, options = {}) {
    let {limit, subscriptionID} = options;
    const url = getUrl(
      nodeID,
      // Avoiding duplicate events by using read reverse (stream backwards).
      // Connection will close all events are received or have reached the top
      Object.assign(options, {read_reverse: true}),
      false
    );
    // NB: User can pass `subscriptionID` to associate it with their local data
    // accumulation
    subscriptionID = subscriptionID || Symbol.for(url);

    const items = [];

    function messageListener({data, origin} = {}) {
      if (origin !== global.location.origin) {
        // Ignore events that are not from this origin
        return false;
      }

      let parsedData;
      try {
        parsedData = JSON.parse(data);
      } catch (error) {
        AppDispatcher.handleServerAction({
          type: REQUEST_PREVIOUS_SYSTEM_LOG_ERROR,
          data: error,
          subscriptionID
        });
      }

      // Unshift items as the come in opposite order
      items.unshift(parsedData);
    }

    function errorListener(event = {}) {
      const {eventPhase} = event;

      if (eventPhase === EventSource.CLOSED) {
        AppDispatcher.handleServerAction({
          type: REQUEST_PREVIOUS_SYSTEM_LOG_SUCCESS,
          data: items,
          firstEntry: items.length < limit,
          subscriptionID
        });
      } else {
        AppDispatcher.handleServerAction({
          type: REQUEST_PREVIOUS_SYSTEM_LOG_ERROR,
          data: event,
          subscriptionID
        });
      }

      unsubscribe(url);
    }

    subscribe(url, messageListener, errorListener);
  },

  fetchStreamTypes(nodeID) {
    RequestUtil.json({
      url: `${Config.logsAPIPrefix}/${nodeID}/logs/v1/fields/STREAM`,
      success(response) {
        AppDispatcher.handleServerAction({
          type: REQUEST_SYSTEM_LOG_STREAM_TYPES_SUCCESS,
          data: response
        });
      },
      error(xhr) {
        AppDispatcher.handleServerAction({
          type: REQUEST_SYSTEM_LOG_STREAM_TYPES_ERROR,
          data: RequestUtil.getErrorFromXHR(xhr),
          xhr
        });
      }
    });
  }
};

module.exports = SystemLogActions;
<|endoftext|>


<commit_before>Session.set('initialLoad', true);

l=function(s){
  console.log(s);
}

// HELPERS
getSetting = function(setting){
  var settings=Settings.find().fetch()[0];
  if(settings){
    return settings[setting];
  }
  return '';
}
clearSeenErrors = function(){
  Errors.update({seen:true}, {$set: {show:false}}, {multi:true});
}
// SUBSCRIPTIONS

// ** Errors **
// Local (client-only) collection

Errors = new Meteor.Collection(null);

// ** Settings **

Settings = new Meteor.Collection('settings');
Meteor.subscribe('settings', function(){

  // runs once on site load
  analyticsInit();
  Session.set('settingsLoaded',true);
});

// ** Categories **

Categories = new Meteor.Collection('categories');
Meteor.subscribe('categories');

// ** Users **

Meteor.subscribe('currentUser');
Meteor.subscribe('allUsers');

// ** Notifications **
// Only load if user is logged in

Notifications = new Meteor.Collection('notifications');
if(Meteor.userId() != null){
  Meteor.subscribe('notifications');
}

// ** Posts **
// We have a few subscriptions here, for the various ways we load posts
//
// The advantage is that
//   a) we can change pages a lot quicker
//     XXX: and we can animate between them (todo)
//   b) we know when an individual page is ready

Posts = new Meteor.Collection('posts');

STATUS_PENDING=1;
STATUS_APPROVED=2;
STATUS_REJECTED=3;

var queryFind = function(status, slug){
  console.log('calling queryFind')
  var find = {};

  // build find query starting with the status
  switch(status){
    case STATUS_APPROVED:
      find = {
        $or: [
          {status: {$exists : false}},
          {status: STATUS_APPROVED}
        ]
      };
    break;
    case STATUS_PENDING:
      find = {status: STATUS_PENDING}
    break;
    case STATUS_REJECTED:
      find = {status: STATUS_REJECTED}
    break;
  }

  // if a category slug is defined, modify selector

  // DOESN'T WORK FOR SOME REASON
  if(slug){
    console.log('category slug: ', slug);
    find={
      $and : [
        find,
        {'categories.slug': slug}
      ]
    };
  }
  // console.log(find)
  return find;
}

var sortBy = function(sortProperty){
  var sortBy = {sort: {sticky: -1}};
  sortBy.sort[sortProperty] = -1;
  return sortBy;
}

var postListSubscription = function(find, options, per_page) {
  console.log('calling postListSubscription')
  var handle = Meteor.subscribeWithPagination('paginatedPosts', find, options, per_page);
  handle.fetch = function() {
    return limitDocuments(Posts.find(find, options), handle.loaded());
  }
  return handle;
}

var FIND_APPROVED = function() {
  console.log('calling FIND_APPROVED');
  return queryFind(STATUS_APPROVED, Session.get('categorySlug'));
}
var FIND_PENDING = function() {
  return queryFind(STATUS_PENDING, Session.get('categorySlug'));
}

topPostsHandle = postListSubscription(FIND_APPROVED, sortBy('score'), 10);
newPostsHandle = postListSubscription(FIND_APPROVED, sortBy('submitted'), 10);
bestPostsHandle = postListSubscription(FIND_APPROVED, sortBy('baseScore'), 10);
pendingPostsHandle = postListSubscription(FIND_PENDING, sortBy('createdAt'), 10);

// digest subscriptions
DIGEST_PRELOADING = 3;
var digestHandles = {}
var dateHash = function(mDate) {
  return mDate.format('DD-MM-YYYY');
}
var currentMDateForDigest = function() {
  return moment(Session.get('currentDate')).startOf('day');
}
currentDigestHandle = function() {
  return digestHandles[dateHash(currentMDateForDigest())];
}

// we use autorun here, because we DON'T want meteor to automatically
// unsubscribe for us
Meteor.autorun(function() {
  var daySubscription = function(mDate) {
    console.log('calling daySubscription')
    var find = _.extend({
        submitted: {
          $gte: mDate.startOf('day').valueOf(),
          $lt: mDate.endOf('day').valueOf()
        }
      }, FIND_APPROVED);
    // note: the digest is ranked by baseScore and not score because we want the posts with the most votes of the day
    // independantly of age
    var options = {sort: {baseScore: -1}};

    // we aren't ever going to paginate this sub, but we'll use pSub
    // so we have a reactive loading() function
    // (grr... https://github.com/meteor/meteor/pull/273)
    return postListSubscription(find, options, 50);
  };

  // take it to the start of the day.
  var mDate = currentMDateForDigest();
  var firstDate = moment(mDate).subtract('days', DIGEST_PRELOADING);
  var lastDate = moment(mDate).add('days', DIGEST_PRELOADING);

  // first unsubscribe all the subscriptions that fall outside of our current range
  _.each(digestHandles, function(handle, hash) {
    var mDate = moment(hash, 'DD-MM-YYYY');
    if (mDate < firstDate || mDate > lastDate) {
      // console.log('unsubscribing digest for ' + mDate.toString())
      handle.stop();
      delete digestHandles[dateHash(mDate)];
    }
  });

  // set up a sub for each day for the DIGEST_PRELOADING days before and after
  // but we want to be smart about it --
  for (mDate = firstDate; mDate < lastDate; mDate.add('days',1 )) {
    if (! digestHandles[dateHash(mDate)]) {
      // console.log('subscribing digest for ' + mDate.toString());
      digestHandles[dateHash(mDate)] = daySubscription(mDate);
    }
  }
});

// ** Comments **
// Collection depends on selectedPostId and selectedCommentId session variable

Session.set('selectedPostId', null);
Comments = new Meteor.Collection('comments');
Meteor.autosubscribe(function() {
  var query = { $or : [ { post : Session.get('selectedPostId') } , { _id : Session.get('selectedCommentId') } ] };
  Meteor.subscribe('comments', query, function() {
    Session.set('commentReady', true);
  });
});
<commit_msg>simplifying and refactoring app.js code<commit_after>Session.set('initialLoad', true);

l=function(s){
  console.log(s);
}

// HELPERS
getSetting = function(setting){
  var settings=Settings.find().fetch()[0];
  if(settings){
    return settings[setting];
  }
  return '';
}
clearSeenErrors = function(){
  Errors.update({seen:true}, {$set: {show:false}}, {multi:true});
}
// SUBSCRIPTIONS

// ** Errors **
// Local (client-only) collection

Errors = new Meteor.Collection(null);

// ** Settings **

Settings = new Meteor.Collection('settings');
Meteor.subscribe('settings', function(){

  // runs once on site load
  analyticsInit();
  Session.set('settingsLoaded',true);
});

// ** Categories **

Categories = new Meteor.Collection('categories');
Meteor.subscribe('categories');

// ** Users **

Meteor.subscribe('currentUser');
Meteor.subscribe('allUsers');

// ** Notifications **
// Only load if user is logged in

Notifications = new Meteor.Collection('notifications');
if(Meteor.userId() != null){
  Meteor.subscribe('notifications');
}

// ** Posts **
// We have a few subscriptions here, for the various ways we load posts
//
// The advantage is that
//   a) we can change pages a lot quicker
//     XXX: and we can animate between them (todo)
//   b) we know when an individual page is ready

Posts = new Meteor.Collection('posts');

STATUS_PENDING=1;
STATUS_APPROVED=2;
STATUS_REJECTED=3;

var findPosts = function(status){
  console.log('calling findPosts')
  var find = {};

  // build find query starting with the status
  switch(status){
    case STATUS_APPROVED:
      find = {
        $or: [
          {status: {$exists : false}},
          {status: STATUS_APPROVED}
        ]
      };
    break;
    case STATUS_PENDING:
      find = {status: STATUS_PENDING}
    break;
    case STATUS_REJECTED:
      find = {status: STATUS_REJECTED}
    break;
  }

  // if a category slug is defined, modify selector

  if(slug = Session.get('categorySlug')){
    console.log('category slug: ', slug);
    find={
      $and : [
        find,
        {'categories.slug': slug}
      ]
    };
  }
  // console.log(find)
  return find;
}

var sortPosts = function(sortProperty){
  var sort = {sort: {sticky: -1}};
  sort.sort[sortProperty] = -1;
  return sort;
}

var postListSubscription = function(find, options, per_page) {
  console.log('calling postListSubscription')
  var handle = Meteor.subscribeWithPagination('paginatedPosts', find, options, per_page);
  handle.fetch = function() {
    return limitDocuments(Posts.find(find, options), handle.loaded());
  }
  return handle;
}

topPostsHandle =      postListSubscription(findPosts(STATUS_APPROVED), sortPosts('score'), 10);
newPostsHandle =      postListSubscription(findPosts(STATUS_APPROVED), sortPosts('submitted'), 10);
bestPostsHandle =     postListSubscription(findPosts(STATUS_APPROVED), sortPosts('baseScore'), 10);
pendingPostsHandle =  postListSubscription(findPosts(STATUS_PENDING), sortPosts('createdAt'), 10);

// digest subscriptions
DIGEST_PRELOADING = 3;
var digestHandles = {}
var dateHash = function(mDate) {
  return mDate.format('DD-MM-YYYY');
}
var currentMDateForDigest = function() {
  return moment(Session.get('currentDate')).startOf('day');
}
currentDigestHandle = function() {
  return digestHandles[dateHash(currentMDateForDigest())];
}

// we use autorun here, because we DON'T want meteor to automatically
// unsubscribe for us
Meteor.autorun(function() {
  var daySubscription = function(mDate) {
    console.log('calling daySubscription')
    var find = _.extend({
        submitted: {
          $gte: mDate.startOf('day').valueOf(),
          $lt: mDate.endOf('day').valueOf()
        }
      }, findPosts(STATUS_APPROVED));
    // note: the digest is ranked by baseScore and not score because we want the posts with the most votes of the day
    // independantly of age
    var options = {sort: {baseScore: -1}};

    // we aren't ever going to paginate this sub, but we'll use pSub
    // so we have a reactive loading() function
    // (grr... https://github.com/meteor/meteor/pull/273)
    return postListSubscription(find, options, 50);
  };

  // take it to the start of the day.
  var mDate = currentMDateForDigest();
  var firstDate = moment(mDate).subtract('days', DIGEST_PRELOADING);
  var lastDate = moment(mDate).add('days', DIGEST_PRELOADING);

  // first unsubscribe all the subscriptions that fall outside of our current range
  _.each(digestHandles, function(handle, hash) {
    var mDate = moment(hash, 'DD-MM-YYYY');
    if (mDate < firstDate || mDate > lastDate) {
      // console.log('unsubscribing digest for ' + mDate.toString())
      handle.stop();
      delete digestHandles[dateHash(mDate)];
    }
  });

  // set up a sub for each day for the DIGEST_PRELOADING days before and after
  // but we want to be smart about it --
  for (mDate = firstDate; mDate < lastDate; mDate.add('days',1 )) {
    if (! digestHandles[dateHash(mDate)]) {
      // console.log('subscribing digest for ' + mDate.toString());
      digestHandles[dateHash(mDate)] = daySubscription(mDate);
    }
  }
});

// ** Comments **
// Collection depends on selectedPostId and selectedCommentId session variable

Session.set('selectedPostId', null);
Comments = new Meteor.Collection('comments');
Meteor.autosubscribe(function() {
  var query = { $or : [ { post : Session.get('selectedPostId') } , { _id : Session.get('selectedCommentId') } ] };
  Meteor.subscribe('comments', query, function() {
    Session.set('commentReady', true);
  });
});
<|endoftext|>


<commit_before>/********************************************************************************************************
 * Name: UML to YANG Mapping Tool
 * Copyright 2015 CAICT (China Academy of Information and Communication Technology (former China Academy of Telecommunication Research)). All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License").
 *
 * This tool is developed according to the mapping rules defined in onf2015.261_Mapping_Gdls_UML-YANG.08 by OpenNetworkFoundation(ONF) IMP group.
 *
 * file: \model\OpenModelObject.js
 *
 * The above copyright information should be included in all distribution, reproduction or derivative works of this software.
 *
 ****************************************************************************************************/
function OpenModelObject(id, type, vr, cond, sup, inv, avcNot, dNot, cNot, passBR, opex, opid, ato, key, units, fileName){
    this.id = id;
    this.type = type;
    this.valueRange = vr;
    this.condition = cond;
    this.status;
    this.support = sup;
    this.isInvariant = inv;
    this.key = key;
    this.attributeValueChangeNotification = avcNot;
    this.objectDeletionNotification = dNot;
    this.objectCreationNotification = cNot;
    this.passedByReference = passBR;
    this["operation exceptions"] = opex;
    this["isOperationIdempotent"] = opid;
    this["isAtomic"] = ato;
    this.units = units;
    this.fileName = fileName;
}
module.exports=OpenModelObject;<commit_msg>handling integers<commit_after>/********************************************************************************************************
 * Name: UML to YANG Mapping Tool
 * Copyright 2015 CAICT (China Academy of Information and Communication Technology (former China Academy of Telecommunication Research)). All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License").
 *
 * This tool is developed according to the mapping rules defined in onf2015.261_Mapping_Gdls_UML-YANG.08 by OpenNetworkFoundation(ONF) IMP group.
 *
 * file: \model\OpenModelObject.js
 *
 * The above copyright information should be included in all distribution, reproduction or derivative works of this software.
 *
 ****************************************************************************************************/
function OpenModelObject(id, type, vr, cond, sup, inv, avcNot, dNot, cNot, passBR, opex, opid, ato, key, units, fileName, unsigned, bitLength){
    this.id = id;
    this.type = type;
    this.valueRange = vr;
    this.condition = cond;
    this.status;
    this.support = sup;
    this.isInvariant = inv;
    this.key = key;
    this.attributeValueChangeNotification = avcNot;
    this.objectDeletionNotification = dNot;
    this.objectCreationNotification = cNot;
    this.passedByReference = passBR;
    this["operation exceptions"] = opex;
    this["isOperationIdempotent"] = opid;
    this["isAtomic"] = ato;
    this.units = units;
    this.fileName = fileName;
    this.unsigned = unsigned;
    this.bitLength = bitLength;
}
module.exports=OpenModelObject;<|endoftext|>


<commit_before>// LICENSE : MIT
"use strict";
import {testValid, testInvalid} from "./test-util";
import {TextLintCore} from "textlint";
const describe = (typeof global.describe === "function") ? global.describe : function (text, method) {
    return method.apply(this);
};

const it = (typeof global.it === "function") ? global.it : function (text, method) {
    return method.apply(this);
};

export default class TextLintTester {
    testValidPattern(ruleName, rule, valid) {
        let text = valid.text || valid;
        let options = valid.options || {};
        var textlint = new TextLintCore();
        textlint.setupRules({
            [ruleName]: rule
        }, {
            [ruleName]: options
        });
        it(text, ()=> {
            testValid(textlint, text);
        });
    }

    testInvalidPattern(ruleName, rule, invalid) {
        let text = invalid.text;
        let options = invalid.options || {};
        let errors = invalid.errors;
        var textlint = new TextLintCore();
        textlint.setupRules({
            [ruleName]: rule
        }, {
            [ruleName]: options
        });
        it(text, ()=> {
            testInvalid(textlint, text, errors);
        });
    }

    testState(ruleName, rule, valid, invliad) {
        let validListNoOptions = valid.filter(state => {
            return state.options === undefined;
        });
        let invalidListNoOptions = invliad.filter(state => {
            return state.options === undefined;
        });
        if (validListNoOptions.length === 0 || invalidListNoOptions.length === 0) {
            return;
        }
        it(`should reset state each time`, function () {
            // invalid -> valid using same textlint instance
            // it test that finish invalid test and should reset rule stat
            var textlint = new TextLintCore();
            textlint.setupRules({
                [ruleName]: rule
            }, {
                [ruleName]: true
            });
            invalidListNoOptions.forEach(state => {
                let text = state.text;
                testInvalid(textlint, text, state.errors)
            });
            try {
                validListNoOptions.forEach(state => {
                    let text = state.text || state;
                    testValid(textlint, text);
                });
            } catch (e) {
                throw new Error(`${ruleName} should reset own state each time.

export default function(context){
    var state = {};
    return {
        [context.Syntax.Document](){
            state = {};// reset state each time
        }
        // ...
    }
}
                `);
            }
        });
    }

    /**
     * run test for textlint rule.
     * @param {string} ruleName ruleName is name of thee rule
     * @param {Function} rule rule is the function of rule
     * @param {string[]|object[]} valid
     * @param {object[]} invalid
     */
    run(ruleName, rule, {valid=[], invalid=[]}) {
        describe(ruleName, ()=> {
            invalid.forEach(state => {
                this.testInvalidPattern(ruleName, rule, state);
            });
            valid.forEach(state => {
                this.testValidPattern(ruleName, rule, state);
            });
            this.testState(ruleName, rule, valid, invalid);
        });
    }
}<commit_msg>docs(tester): show original error object<commit_after>// LICENSE : MIT
"use strict";
import {testValid, testInvalid} from "./test-util";
import {TextLintCore} from "textlint";
const describe = (typeof global.describe === "function") ? global.describe : function (text, method) {
    return method.apply(this);
};

const it = (typeof global.it === "function") ? global.it : function (text, method) {
    return method.apply(this);
};

export default class TextLintTester {
    testValidPattern(ruleName, rule, valid) {
        let text = valid.text || valid;
        let options = valid.options || {};
        var textlint = new TextLintCore();
        textlint.setupRules({
            [ruleName]: rule
        }, {
            [ruleName]: options
        });
        it(text, ()=> {
            testValid(textlint, text);
        });
    }

    testInvalidPattern(ruleName, rule, invalid) {
        let text = invalid.text;
        let options = invalid.options || {};
        let errors = invalid.errors;
        var textlint = new TextLintCore();
        textlint.setupRules({
            [ruleName]: rule
        }, {
            [ruleName]: options
        });
        it(text, ()=> {
            testInvalid(textlint, text, errors);
        });
    }

    testState(ruleName, rule, valid, invliad) {
        let validListNoOptions = valid.filter(state => {
            return state.options === undefined;
        });
        let invalidListNoOptions = invliad.filter(state => {
            return state.options === undefined;
        });
        if (validListNoOptions.length === 0 || invalidListNoOptions.length === 0) {
            return;
        }
        it(`should reset state each time`, function () {
            // invalid -> valid using same textlint instance
            // it test that finish invalid test and should reset rule stat
            var textlint = new TextLintCore();
            textlint.setupRules({
                [ruleName]: rule
            }, {
                [ruleName]: true
            });
            try {
                invalidListNoOptions.forEach(state => {
                    let text = state.text;
                    testInvalid(textlint, text, state.errors)
                });
                validListNoOptions.forEach(state => {
                    let text = state.text || state;
                    testValid(textlint, text);
                });
            } catch (e) {
                throw new Error(`${ruleName} should reset own state each time.

export default function(context){
    var state = {};
    return {
        [context.Syntax.Document](){
            state = {};// reset state each time
        }
        // ...
    }
}
                `);
                console.error(e.message);
            }
        });
    }

    /**
     * run test for textlint rule.
     * @param {string} ruleName ruleName is name of thee rule
     * @param {Function} rule rule is the function of rule
     * @param {string[]|object[]} valid
     * @param {object[]} invalid
     */
    run(ruleName, rule, {valid=[], invalid=[]}) {
        describe(ruleName, ()=> {
            invalid.forEach(state => {
                this.testInvalidPattern(ruleName, rule, state);
            });
            valid.forEach(state => {
                this.testValidPattern(ruleName, rule, state);
            });
            this.testState(ruleName, rule, valid, invalid);
        });
    }
}<|endoftext|>


<commit_before>Chat = (function() {
  'use strict';

  function randomString()  {
    return ('' + Math.random()).substr(2, 4);
  }

  var Chat = function(socket) {
    this.socket = socket;
  };

  /*
  Chat.prototype.createMessage = function(text, nick, room) {
    var clientTime = Date.now();
    var message = {
      sender: nick,
      room: room,
      text: text,
      clientTime: clientTime,
      clientId: clientTime + '-' + randomString(),
    };
    return message;
  };
  */

  Chat.prototype.sendMessage = function(message) {
    this.socket.emit('message', message);
  };

  /*
  Chat.prototype.changeRoom = function(room) {
    this.socket.emit('join', {
      newRoom: room
    });
  };
  */

  /*
  Chat.prototype.processCommand = function(command) {
    var words = command.split(' ');
    var command = words[0]
                  .substring(1, words[0].length)
                  .toLowerCase();
    var message = false;

    switch(command) {
      case 'join':
        words.shift();
        var room = words.join(' ');
        //this.changeRoom(room);
        break;
      case 'nick':
        words.shift();
        var name = words.join(' ');
        this.socket.emit('set-name', name);
        break;
      default:
        message = 'Unrecognized command.';
        break;
    };

    return message;
  };
  */

  return Chat;
})();
<commit_msg>rm obsolete jrm obsolete jss<commit_after><|endoftext|>


<commit_before>function load_parents(mass2motif_id,motif_name,vo_id) {

    current_pos = 0

    //clear the existing svg (if it exists)
    d3.select('#load_text').remove()
    d3.select("#frag_graph_titlebar_svg").remove();
    d3.select("#frag_graph_svg").remove();
    d3.select('#frag_graph_svg').remove()

    // var url = '/basicviz/get_parents/' + mass2motif_id + '/' + vo_id + '/';

    d3.json(url,function(error,total_dataset) {
        if (error) throw error;
        key = null
        plot_parent(total_dataset,motif_name)
        $('#message').fadeOut('fast');
    });

}

function load_parent(url) {
    current_pos = 0
    d3.json(url,function(error,total_dataset) {
    if (error) throw error;
    key = total_dataset[0][1]
    console.log(key)
    plot_parent(total_dataset[0][0],"")
    $('#message').fadeOut('fast');
    });

}

function plot_parent(total_dataset,motif_name) {

    if(current_pos < 0) {
        current_pos = 0
    }
    if(current_pos > total_dataset.length-1) {
        current_pos = total_dataset.length-1
    }

    var parent_mass = total_dataset[current_pos][0][0]
    var parent_intensity = total_dataset[current_pos][0][1]
    var parent_name = total_dataset[current_pos][0][2]
    var parent_annotation = total_dataset[current_pos][0][3]
    var dataset = total_dataset[current_pos][1]
    var max_mass = d3.max(dataset,function(d) {return d[0]+50})

    if (max_mass < parent_mass) {
        max_mass = parent_mass + 50;
    }

    var total_width = 900
    var total_height = 500
    var plot_width = 700
    var plot_height = 300
    var ver_margin = 30
    var hor_margin = 50
    var head_height = 50

    var n_parents = total_dataset.length
    n_parents -= 1

    //clear the existing svg (if it exists)
    d3.select('#load_text').remove()
    d3.select("#frag_graph_titlebar_svg").remove();
    d3.select("#frag_graph_svg").remove();

    var frag_graph_titlebar_svg = d3.select("svg")
       .append("svg")
            .attr("width",plot_width)
            .attr("height",head_height)
            .attr("id","frag_graph_titlebar_svg")
    frag_graph_titlebar_svg.append("rect")
        .attr("width","98%")
        .attr("height","98%")
        .attr("x","10")
        .attr("stroke","black")
        .attr("fill","#F2F2F2");

    if (key != null) {
        var keybox = d3.select("svg")
            .append("svg")
                .attr("width",plot_width)
                .attr("height",140)
                .attr("id","key_box_svg")
                .attr("x",0)
                .attr("y",360)
        keybox.append("rect")
            .attr("width","98%")
            .attr("height","98%")
            .attr("x","10")
            .attr("stroke","black")
            .attr("fill","#F2F2F2");
        keylines = keybox.selectAll("lines")
                    .data(key)
                    .enter()
                    .append("line");
        keylines.attr("x1",50)
                 .attr("x2",300)
                 .attr("y1",function(d,i) {return 20 + 20*i;})
                 .attr("y2",function(d,i) {return 20 + 20*i;})
                 .attr("stroke",function(d) {return d[1];})
                 .attr("stroke-width",5);
        keytext = keybox.selectAll("text")
            .data(key)
            .enter()
            .append("text");
        keytext.attr("x",310)
                 .attr("y",function(d,i) {return 20 + 20*i;})
                .text(function(d) {return d[0];});
    };
    var nextbut = frag_graph_titlebar_svg.append("g")
        .attr("cursor","pointer")
        .on("click",function () {current_pos += 1;plot_parent(total_dataset,motif_name)})

    nextbut.append("rect")
                .attr("height",30)
                .attr("width",70)
                .attr("x",plot_width-100)
                .attr("y",9)
                .attr("stroke","black")
                .attr("fill","#CCAAAA")
    nextbut.append("text")
                .attr("x",plot_width-90)
                .attr("y",30)
                .text("Next")
                .attr("font-family","sans-serif")
                .attr("font-size","14px")

    var prevbut = frag_graph_titlebar_svg.append("g")
        .attr("cursor","pointer")
        .on("click",function () {current_pos -= 1;plot_parent(total_dataset,motif_name)})

    prevbut.append("rect")
                .attr("height",30)
                .attr("width",70)
                .attr("x",30)
                .attr("y",9)
                .attr("stroke","black")
                .attr("fill","#CCAAAA")
    prevbut.append("text")
                .attr("x",40)
                .attr("y",30)
                .text("Previous")
                .attr("font-family","sans-serif")
                .attr("font-size","14px")

    frag_graph_titlebar_svg.append("text")
                .attr("x",plot_width-500)
                .attr("y",40)
                .attr("font-family","sans-serif")
                .attr("font-size","14px")
                .text("Parent: " + parent_name + ", " + parent_annotation + "  (" + (current_pos+1) + "/" + (n_parents+1) + ")")
    frag_graph_titlebar_svg.append("text")
                .attr("x",plot_width-500)
                .attr("y",20)
                .text(motif_name)

    var frag_graph_svg = d3.select("svg")
               .append("svg")
                    .attr("width",plot_width)
                    .attr("height",plot_height)
                    .attr("y",head_height)
                    .attr("id","frag_graph_svg")

    // Create the line objects
    lines = frag_graph_svg.selectAll("line")
            .data(dataset)
            .enter()
            .append("line")
            .on("click",function(d) {
                console.log(d);
            })

    // Axis scale objects
    var xScale = d3.scale.linear()
    xScale.domain([0, max_mass])
    xScale.range([ hor_margin,plot_width-hor_margin])
    var yScale = d3.scale.linear()
    yScale.domain([0,d3.max(dataset,function(d) {return d[3];})])
    yScale.range([plot_height-ver_margin,ver_margin])

    // Set the line attributes
    lines.attr("x1",function(d) {return xScale(d[0])})
          .attr("x2",function(d) {return xScale(d[1])})
          .attr("y1",function(d) {return yScale(d[2])})
          .attr("y2",function(d) {return yScale(d[3])})
          .attr("stroke",function(d) {return d[5]})
          .attr("stroke-width",2)
        .attr("stroke-dasharray",function(d) {if(d[4]==1) {return "0.0";} else {return "5.5";}})
        .on("mouseover",function(d) {

            d3.select(this)
                // .attr("stroke","green")
                .attr("stroke-width",4);
                    var xPos = parseFloat(d3.select(this).attr("x1"))
            var yPos = parseFloat(d3.select(this).attr("y2"))

            frag_graph_svg.append("text")
                .attr("id","tooltip")
                .attr("x",xPos-50)
                .attr("y",yPos-5)
                .attr("font-family","sans-serif")
                .attr("font-size","12px")
                .attr("font-weight","bold")
                .text(d[6])

        })
        .on("mouseout",function() {
            d3.select(this)
                .transition()
                .duration(250)
                // .attr("stroke",d[5])
                .attr("stroke-width",2);
            d3.select("#tooltip").remove()
            // d3.select("#lossline").remove()
            // d3.select("#losstext").remove()
        });

     // Axes
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient("bottom");
    frag_graph_svg.append("g")
        .attr("class", "axis")
        .attr("transform", "translate(0," + (plot_height-ver_margin) + ")")
        .call(xAxis);

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient("left")
    frag_graph_svg.append("g")
        .attr("class","axis")
        .attr("transform","translate(" + hor_margin + ",0)")
        .call(yAxis)

    // Axes labels
    frag_graph_svg.append("text")
        .text("Mass")
        .attr("x",plot_width/2)
        .attr("y",plot_height)
        .attr("class","axis-label")

    frag_graph_svg.append("text")
        .text("Relative Intensity")
        .attr("x",0)
        .attr("y",0)
        .attr("class","axis-label")
        .attr("transform","translate(10," + (30+plot_height/2) + ")rotate(-90)");

    frag_graph_svg.append("line")
        .attr("x1",xScale(parent_mass))
        .attr("x2",xScale(parent_mass))
        .attr("y1",plot_height-ver_margin)
        .attr("y2",yScale(parent_intensity))
        .attr("stroke","blue")
        .attr("stroke-width",3)

    frag_graph_svg.append("text")
        .text("Parent Ion (" + parent_mass.toFixed(4) + ")")
        .attr("class","axis-label")
        .attr("transform","translate("+ (xScale(parent_mass)-5) + "," + (50+plot_height/2) + ")rotate(-90)")

};<commit_msg>fixed iss 5<commit_after>function load_parents(mass2motif_id,motif_name,vo_id) {

    current_pos = 0

    //clear the existing svg (if it exists)
    d3.select('#load_text').remove()
    d3.select("#frag_graph_titlebar_svg").remove();
    d3.select("#frag_graph_svg").remove();
    d3.select('#frag_graph_svg').remove()

    var url = '/basicviz/get_parents/' + mass2motif_id + '/' + vo_id + '/';

    d3.json(url,function(error,total_dataset) {
        if (error) throw error;
        key = null
        plot_parent(total_dataset,motif_name)
        $('#message').fadeOut('fast');
    });

}

function load_parent(url) {
    current_pos = 0
    d3.json(url,function(error,total_dataset) {
    if (error) throw error;
    key = total_dataset[0][1]
    console.log(key)
    plot_parent(total_dataset[0][0],"")
    $('#message').fadeOut('fast');
    });

}

function plot_parent(total_dataset,motif_name) {

    if(current_pos < 0) {
        current_pos = 0
    }
    if(current_pos > total_dataset.length-1) {
        current_pos = total_dataset.length-1
    }

    var parent_mass = total_dataset[current_pos][0][0]
    var parent_intensity = total_dataset[current_pos][0][1]
    var parent_name = total_dataset[current_pos][0][2]
    var parent_annotation = total_dataset[current_pos][0][3]
    var dataset = total_dataset[current_pos][1]
    var max_mass = d3.max(dataset,function(d) {return d[0]+50})

    if (max_mass < parent_mass) {
        max_mass = parent_mass + 50;
    }

    var total_width = 900
    var total_height = 500
    var plot_width = 700
    var plot_height = 300
    var ver_margin = 30
    var hor_margin = 50
    var head_height = 50

    var n_parents = total_dataset.length
    n_parents -= 1

    //clear the existing svg (if it exists)
    d3.select('#load_text').remove()
    d3.select("#frag_graph_titlebar_svg").remove();
    d3.select("#frag_graph_svg").remove();

    var frag_graph_titlebar_svg = d3.select("svg")
       .append("svg")
            .attr("width",plot_width)
            .attr("height",head_height)
            .attr("id","frag_graph_titlebar_svg")
    frag_graph_titlebar_svg.append("rect")
        .attr("width","98%")
        .attr("height","98%")
        .attr("x","10")
        .attr("stroke","black")
        .attr("fill","#F2F2F2");

    if (key != null) {
        var keybox = d3.select("svg")
            .append("svg")
                .attr("width",plot_width)
                .attr("height",140)
                .attr("id","key_box_svg")
                .attr("x",0)
                .attr("y",360)
        keybox.append("rect")
            .attr("width","98%")
            .attr("height","98%")
            .attr("x","10")
            .attr("stroke","black")
            .attr("fill","#F2F2F2");
        keylines = keybox.selectAll("lines")
                    .data(key)
                    .enter()
                    .append("line");
        keylines.attr("x1",50)
                 .attr("x2",300)
                 .attr("y1",function(d,i) {return 20 + 20*i;})
                 .attr("y2",function(d,i) {return 20 + 20*i;})
                 .attr("stroke",function(d) {return d[1];})
                 .attr("stroke-width",5);
        keytext = keybox.selectAll("text")
            .data(key)
            .enter()
            .append("text");
        keytext.attr("x",310)
                 .attr("y",function(d,i) {return 20 + 20*i;})
                .text(function(d) {return d[0];});
    };
    var nextbut = frag_graph_titlebar_svg.append("g")
        .attr("cursor","pointer")
        .on("click",function () {current_pos += 1;plot_parent(total_dataset,motif_name)})

    nextbut.append("rect")
                .attr("height",30)
                .attr("width",70)
                .attr("x",plot_width-100)
                .attr("y",9)
                .attr("stroke","black")
                .attr("fill","#CCAAAA")
    nextbut.append("text")
                .attr("x",plot_width-90)
                .attr("y",30)
                .text("Next")
                .attr("font-family","sans-serif")
                .attr("font-size","14px")

    var prevbut = frag_graph_titlebar_svg.append("g")
        .attr("cursor","pointer")
        .on("click",function () {current_pos -= 1;plot_parent(total_dataset,motif_name)})

    prevbut.append("rect")
                .attr("height",30)
                .attr("width",70)
                .attr("x",30)
                .attr("y",9)
                .attr("stroke","black")
                .attr("fill","#CCAAAA")
    prevbut.append("text")
                .attr("x",40)
                .attr("y",30)
                .text("Previous")
                .attr("font-family","sans-serif")
                .attr("font-size","14px")

    frag_graph_titlebar_svg.append("text")
                .attr("x",plot_width-500)
                .attr("y",40)
                .attr("font-family","sans-serif")
                .attr("font-size","14px")
                .text("Parent: " + parent_name + ", " + parent_annotation + "  (" + (current_pos+1) + "/" + (n_parents+1) + ")")
    frag_graph_titlebar_svg.append("text")
                .attr("x",plot_width-500)
                .attr("y",20)
                .text(motif_name)

    var frag_graph_svg = d3.select("svg")
               .append("svg")
                    .attr("width",plot_width)
                    .attr("height",plot_height)
                    .attr("y",head_height)
                    .attr("id","frag_graph_svg")

    // Create the line objects
    lines = frag_graph_svg.selectAll("line")
            .data(dataset)
            .enter()
            .append("line")
            .on("click",function(d) {
                console.log(d);
            })

    // Axis scale objects
    var xScale = d3.scale.linear()
    xScale.domain([0, max_mass])
    xScale.range([ hor_margin,plot_width-hor_margin])
    var yScale = d3.scale.linear()
    yScale.domain([0,d3.max(dataset,function(d) {return d[3];})])
    yScale.range([plot_height-ver_margin,ver_margin])

    // Set the line attributes
    lines.attr("x1",function(d) {return xScale(d[0])})
          .attr("x2",function(d) {return xScale(d[1])})
          .attr("y1",function(d) {return yScale(d[2])})
          .attr("y2",function(d) {return yScale(d[3])})
          .attr("stroke",function(d) {return d[5]})
          .attr("stroke-width",2)
        .attr("stroke-dasharray",function(d) {if(d[4]==1) {return "0.0";} else {return "5.5";}})
        .on("mouseover",function(d) {

            d3.select(this)
                // .attr("stroke","green")
                .attr("stroke-width",4);
                    var xPos = parseFloat(d3.select(this).attr("x1"))
            var yPos = parseFloat(d3.select(this).attr("y2"))

            frag_graph_svg.append("text")
                .attr("id","tooltip")
                .attr("x",xPos-50)
                .attr("y",yPos-5)
                .attr("font-family","sans-serif")
                .attr("font-size","12px")
                .attr("font-weight","bold")
                .text(d[6])

        })
        .on("mouseout",function() {
            d3.select(this)
                .transition()
                .duration(250)
                // .attr("stroke",d[5])
                .attr("stroke-width",2);
            d3.select("#tooltip").remove()
            // d3.select("#lossline").remove()
            // d3.select("#losstext").remove()
        });

     // Axes
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient("bottom");
    frag_graph_svg.append("g")
        .attr("class", "axis")
        .attr("transform", "translate(0," + (plot_height-ver_margin) + ")")
        .call(xAxis);

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient("left")
    frag_graph_svg.append("g")
        .attr("class","axis")
        .attr("transform","translate(" + hor_margin + ",0)")
        .call(yAxis)

    // Axes labels
    frag_graph_svg.append("text")
        .text("Mass")
        .attr("x",plot_width/2)
        .attr("y",plot_height)
        .attr("class","axis-label")

    frag_graph_svg.append("text")
        .text("Relative Intensity")
        .attr("x",0)
        .attr("y",0)
        .attr("class","axis-label")
        .attr("transform","translate(10," + (30+plot_height/2) + ")rotate(-90)");

    frag_graph_svg.append("line")
        .attr("x1",xScale(parent_mass))
        .attr("x2",xScale(parent_mass))
        .attr("y1",plot_height-ver_margin)
        .attr("y2",yScale(parent_intensity))
        .attr("stroke","blue")
        .attr("stroke-width",3)

    frag_graph_svg.append("text")
        .text("Parent Ion (" + parent_mass.toFixed(4) + ")")
        .attr("class","axis-label")
        .attr("transform","translate("+ (xScale(parent_mass)-5) + "," + (50+plot_height/2) + ")rotate(-90)")

};<|endoftext|>


<commit_before>var Kc = Kc || {};
Kc.Global = Kc.Global || {};
(function (namespace, $) {
    // set all modals to static behavior (clicking out does not close)
    $.fn.modal.Constructor.DEFAULTS.backdrop = "static";
})(Kc.Global, jQuery);<commit_msg>[KRACOEUS-8479] Convert non-full date to full date on loss of focus in js<commit_after>var Kc = Kc || {};
Kc.Global = Kc.Global || {};
(function (namespace, $) {
    // set all modals to static behavior (clicking out does not close)
    $.fn.modal.Constructor.DEFAULTS.backdrop = "static";

    $(document).on("ready", function(){
        // date conversion for date fields to full leading 0 - for days and months and to full year dates
        $(document).on("blur", ".uif-dateControl", function(){
            var dateFormat = $.datepicker._defaults.dateFormat;
            var date = $(this).val();
            if (!date) {
                return;
            }

            date = date.replace(/-/g, "/");

            if (date && (date.match(/\//g) || []).length === 2) {

                // find the expected position and value of year in the string based on date format
                var year;
                if (dateFormat.indexOf("y") === 0) {
                    year = date.substr(0, date.indexOf("/"));
                }
                else {
                    year = date.substr(date.lastIndexOf("/") + 1, date.length - 1);
                }

                // when year is length of 2 append the first 2 numbers of the current full year (ie 14 -> 2014)
                if (year.length === 2) {
                    var currentDate = new Date();
                    year = currentDate.getFullYear().toString().substr(0,2) + year;
                }

                var dateObj = new Date(date);
                if (isNaN(dateObj.valueOf())) {
                    // not valid abandon conversion
                    return;
                }

                dateObj.setFullYear(year);

                var formattedDate = $.datepicker.formatDate(dateFormat, dateObj);
                $(this).val(formattedDate);
            }
        });
    });
})(Kc.Global, jQuery);<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright (c) 2015, Institute for Pervasive Computing, ETH Zurich.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file is part of the OMA LWM2M DevKit.
 *******************************************************************************/
/**
 * \file Main script file for the LWM2M DevKit.
 *
 * \author Matthias Kovatsch <kovatsch@inf.ethz.ch>
 */

Lwm2mDevKit.InformationReporting = { };

Lwm2mDevKit.InformationReporting.entry = function(msg) {
	this.message = msg;
};

Lwm2mDevKit.InformationReporting.entry.prototype = {
	message : null,
	timer : null,
	number : 1,
	last : 0,
	lastValue : null
};

Lwm2mDevKit.InformationReporting.relations = { };

Lwm2mDevKit.InformationReporting.handleObserve = function(message) {

	let token = message.getToken(true);
	let path = message.getUriPath();
	let entry = Lwm2mDevKit.InformationReporting.relations[token];
	let operation = 'Notify';

	let pmax = Lwm2mDevKit.InformationReporting.getAttribute(path, 'pmax');

	if (entry) {
		if (entry.timer) window.clearTimeout(entry.timer);
	} else {
		Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Observe on '+ message.getUriPath());
		operation = 'Observe';
		entry = new Lwm2mDevKit.InformationReporting.entry(message);
		Lwm2mDevKit.InformationReporting.addRelationRow(message);

		if (message.reply.getContentFormat()==Lwm2mDevKit.Copper.CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_TEXT) {
			entry.lastValue = message.reply.getPayloadText();
		}
	}

	// enable pmin
	entry.last = Date.now();
	// enable pmax Notify
	entry.timer = window.setTimeout(
			function() {
				Lwm2mDevKit.InformationReporting.notify(path);
			}, pmax*1000);

	document.getElementById('reporting_relations_'+token).setAttribute('label', entry.number);
	message.reply.setObserve(entry.number++);
	Lwm2mDevKit.logOperationReporting(operation, path, "Success", message.reply);
	Lwm2mDevKit.InformationReporting.relations[token] = entry;
};

Lwm2mDevKit.InformationReporting.notify = function(path) {

	for (let token in Lwm2mDevKit.InformationReporting.relations) {
		let entry = Lwm2mDevKit.InformationReporting.relations[token];

		if (entry.message.getUriPath()==path) {

			// notify is the last tutorial action
			Lwm2mDevKit.Tooltips.finish = true;
			Lwm2mDevKit.Tooltips.nextStep();

			let pmin = Lwm2mDevKit.InformationReporting.getAttribute(path, 'pmin');
			let current = Date.now() - entry.last;

			if (current < pmin*1000) {
				if (entry.timer) window.clearTimeout(entry.timer);
				entry.timer = window.setTimeout(
						function() {
							Lwm2mDevKit.InformationReporting.notify(path);
						}, pmin*1000 - current);
				Lwm2mDevKit.InformationReporting.relations[token] = entry;

				Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Postponing Notify for pmin='+ pmin);
			} else {

				Lwm2mDevKit.DeviceManagement.handleRead(entry.message);

				// conditional observe
				if (entry.lastValue!==null) {

					let lt = Number( Lwm2mDevKit.InformationReporting.getAttribute(path, 'lt') );
					let gt = Number( Lwm2mDevKit.InformationReporting.getAttribute(path, 'gt') );
					let st = Number( Lwm2mDevKit.InformationReporting.getAttribute(path, 'st') );
					let pl = entry.message.reply.getPayloadText();

					if (lt && gt && (Number(pl)>lt || Number(pl)<gt)) {
						Lwm2mDevKit.logEvent('Dropping Notify for ' + path + ': value='+pl+', gt='+ gt+', lt='+lt);
						Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Dropping Notify for gt='+ gt + ' and lt='+ lt);
						return;
					} else if (lt && Number(pl)>lt) {
						Lwm2mDevKit.logEvent('Dropping Notify for ' + path + ': value='+pl+', lt='+lt);
						Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Dropping Notify for lt='+ lt);
						return;
					} else if (gt && Number(pl)<gt) {
						Lwm2mDevKit.logEvent('Dropping Notify for ' + path + ': value='+pl+', gt='+ gt);
						Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Dropping Notify for gt='+ gt);
						return;
					}
					if (st && Math.abs( Number(entry.lastValue) - Number(pl) ) < st) {
						Lwm2mDevKit.logEvent('Dropping Notify for ' + path + ': value='+pl+', last='+entry.lastValue+', step='+ st);
						Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Dropping Notify for st='+ st);
						return;
					}

					entry.lastValue = pl;
				}

				entry.message.reply.setType(Lwm2mDevKit.Copper.MSG_TYPE_CON);
				entry.message.reply.setTID(null);
				entry.message.reply.setCode(Lwm2mDevKit.Copper.CODE_2_04_CHANGED);
				Lwm2mDevKit.coapEndpoint.send(entry.message.reply);

				let value = '';
				if (entry.message.reply.isPrintable()) value = ": " +  entry.message.reply.getPayloadText();
				Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Notify for '+ path + value);
			}
		}
	}
};

Lwm2mDevKit.InformationReporting.cancel = function(cancel, message) {
	for (let token in Lwm2mDevKit.InformationReporting.relations) {
		if (token==cancel) {
			let entry = Lwm2mDevKit.InformationReporting.relations[token];
			window.clearTimeout( entry.timer );

			let rows = document.getElementById('reporting_relations');
			rows.removeChild( document.getElementById('reporting_relation_'+cancel) );

			delete Lwm2mDevKit.InformationReporting.relations[token];

			Lwm2mDevKit.logOperationReporting("Cancel", entry.message.getUriPath(), "Success", message);
			Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Cancel for '+ entry.message.getUriPath());
			return;
		}
	}
	Lwm2mDevKit.logWarning("Observe relation "+cancel+" not found");
};

Lwm2mDevKit.InformationReporting.cancelManually = function(event) {

	if (event.key!='Del') return;

	let rows = document.getElementById('reporting_relations');
	if (!rows.selectedItem) return;
	Lwm2mDevKit.InformationReporting.cancel( rows.selectedItem.token );
};

Lwm2mDevKit.InformationReporting.cancelAll = function() {

	for (let token in Lwm2mDevKit.InformationReporting.relations) {
		let entry = Lwm2mDevKit.InformationReporting.relations[token];
		if (entry.timer) window.clearTimeout(entry.timer);

		let rows = document.getElementById('reporting_relations');
		rows.removeChild( document.getElementById('reporting_relation_'+token) );

		delete Lwm2mDevKit.InformationReporting.relations[token];
	}
};

Lwm2mDevKit.InformationReporting.getAttribute = function(path, attrib) {

	let temp = path.split('/');
	let obj = temp[0];
	let ins = temp[1];
	let res = temp[2];

	if (Lwm2mDevKit.client.attributes[obj]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][ins]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][ins][res]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][ins][res][attrib]!==undefined) {
		return Lwm2mDevKit.client.attributes[obj][ins][res][attrib];
	}
	if (Lwm2mDevKit.client.attributes[obj]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][ins]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][ins][attrib]!==undefined) {
		return Lwm2mDevKit.client.attributes[obj][ins][attrib];
	}
	if (Lwm2mDevKit.client.attributes[obj]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][attrib]!==undefined) {
		return Lwm2mDevKit.client.attributes[obj][attrib];
	}

	if (attrib=='pmin') return Lwm2mDevKit.client.instances[1][1][2];
	if (attrib=='pmax') return Lwm2mDevKit.client.instances[1][1][3];
};

Lwm2mDevKit.InformationReporting.addRelationRow = function(message) {

	let rows = document.getElementById('reporting_relations');
	let token = message.getToken(true);

	var item = document.createElement('listitem');
	item.setAttribute('id', 'reporting_relation_'+token);
	item.token = token;

	var cell = document.createElement('listcell');
	cell.setAttribute('label', token);
	item.appendChild(cell);

	cell = document.createElement('listcell');
	cell.setAttribute('label', message.getUriPath());
	item.appendChild(cell);

	cell = document.createElement('listcell');
	cell.setAttribute('id', 'reporting_relations_'+token);
	cell.setAttribute('label', 1);
	item.appendChild(cell);

	rows.appendChild( item );

	//rows.ensureElementIsVisible(item);
};
<commit_msg>Now propagates notify to parent observes.<commit_after>/*******************************************************************************
 * Copyright (c) 2015, Institute for Pervasive Computing, ETH Zurich.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file is part of the OMA LWM2M DevKit.
 *******************************************************************************/
/**
 * \file Main script file for the LWM2M DevKit.
 *
 * \author Matthias Kovatsch <kovatsch@inf.ethz.ch>
 */

Lwm2mDevKit.InformationReporting = { };

Lwm2mDevKit.InformationReporting.entry = function(msg) {
	this.message = msg;
};

Lwm2mDevKit.InformationReporting.entry.prototype = {
	message : null,
	timer : null,
	number : 1,
	last : 0,
	lastValue : null
};

Lwm2mDevKit.InformationReporting.relations = { };

Lwm2mDevKit.InformationReporting.handleObserve = function(message) {

	let token = message.getToken(true);
	let path = message.getUriPath();
	let entry = Lwm2mDevKit.InformationReporting.relations[token];
	let operation = 'Notify';

	let pmax = Lwm2mDevKit.InformationReporting.getAttribute(path, 'pmax');

	if (entry) {
		if (entry.timer) window.clearTimeout(entry.timer);
	} else {
		Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Observe on '+ message.getUriPath());
		operation = 'Observe';
		entry = new Lwm2mDevKit.InformationReporting.entry(message);
		Lwm2mDevKit.InformationReporting.addRelationRow(message);

		if (message.reply.getContentFormat()==Lwm2mDevKit.Copper.CONTENT_TYPE_APPLICATION_VND_OMA_LWM2M_TEXT) {
			entry.lastValue = message.reply.getPayloadText();
		}
	}

	// enable pmin
	entry.last = Date.now();
	// enable pmax Notify
	entry.timer = window.setTimeout(
			function() {
				Lwm2mDevKit.InformationReporting.notify(path);
			}, pmax*1000);

	document.getElementById('reporting_relations_'+token).setAttribute('label', entry.number);
	message.reply.setObserve(entry.number++);
	Lwm2mDevKit.logOperationReporting(operation, path, "Success", message.reply);
	Lwm2mDevKit.InformationReporting.relations[token] = entry;
};

Lwm2mDevKit.InformationReporting.notify = function(path) {

	for (let token in Lwm2mDevKit.InformationReporting.relations) {
		let entry = Lwm2mDevKit.InformationReporting.relations[token];
		let opath = entry.message.getUriPath();

		// same path or shorter path (actually ending with EOF
		if (opath==path || ( path.startsWith(opath) && (path[opath.length]=='/' || path[opath.length]===undefined) )) {

			Lwm2mDevKit.logEvent("Notify for "+path+" triggering "+token+ " ("+opath+")");

			// notify is the last tutorial action
			Lwm2mDevKit.Tooltips.finish = true;
			Lwm2mDevKit.Tooltips.nextStep();

			let pmin = Lwm2mDevKit.InformationReporting.getAttribute(opath, 'pmin');
			let current = Date.now() - entry.last;

			if (current < pmin*1000) {

				if (entry.timer) window.clearTimeout(entry.timer);
				entry.timer = window.setTimeout(
						function() {
							Lwm2mDevKit.InformationReporting.notify(opath);
						}, pmin*1000 - current);
				Lwm2mDevKit.InformationReporting.relations[token] = entry;

				Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Postponing Notify for pmin='+ pmin);

			} else {

				Lwm2mDevKit.DeviceManagement.handleRead(entry.message);

				// conditional observe
				if (opath==path && entry.lastValue!==null) {

					let lt = Number( Lwm2mDevKit.InformationReporting.getAttribute(path, 'lt') );
					let gt = Number( Lwm2mDevKit.InformationReporting.getAttribute(path, 'gt') );
					let st = Number( Lwm2mDevKit.InformationReporting.getAttribute(path, 'st') );
					let pl = entry.message.reply.getPayloadText();

					if (lt && gt && (Number(pl)>lt || Number(pl)<gt)) {
						Lwm2mDevKit.logEvent('Dropping Notify for ' + path + ': value='+pl+', gt='+ gt+', lt='+lt);
						Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Dropping Notify for gt='+ gt + ' and lt='+ lt);
						return;
					} else if (lt && Number(pl)>lt) {
						Lwm2mDevKit.logEvent('Dropping Notify for ' + path + ': value='+pl+', lt='+lt);
						Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Dropping Notify for lt='+ lt);
						return;
					} else if (gt && Number(pl)<gt) {
						Lwm2mDevKit.logEvent('Dropping Notify for ' + path + ': value='+pl+', gt='+ gt);
						Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Dropping Notify for gt='+ gt);
						return;
					}
					if (st && Math.abs( Number(entry.lastValue) - Number(pl) ) < st) {
						Lwm2mDevKit.logEvent('Dropping Notify for ' + path + ': value='+pl+', last='+entry.lastValue+', step='+ st);
						Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Dropping Notify for st='+ st);
						return;
					}

					entry.lastValue = pl;
				}

				entry.message.reply.setType(Lwm2mDevKit.Copper.MSG_TYPE_CON);
				entry.message.reply.setTID(null);
				entry.message.reply.setCode(Lwm2mDevKit.Copper.CODE_2_04_CHANGED);
				Lwm2mDevKit.coapEndpoint.send(entry.message.reply);

				let value = '';
				if (entry.message.reply.isPrintable()) value = ": " +  entry.message.reply.getPayloadText();
				Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Notify for '+ opath + value);
			}
		}
	}
};

Lwm2mDevKit.InformationReporting.cancel = function(cancel, message) {
	for (let token in Lwm2mDevKit.InformationReporting.relations) {
		if (token==cancel) {
			let entry = Lwm2mDevKit.InformationReporting.relations[token];
			window.clearTimeout( entry.timer );

			let rows = document.getElementById('reporting_relations');
			rows.removeChild( document.getElementById('reporting_relation_'+cancel) );

			delete Lwm2mDevKit.InformationReporting.relations[token];

			Lwm2mDevKit.logOperationReporting("Cancel", entry.message.getUriPath(), "Success", message);
			Lwm2mDevKit.popup(Lwm2mDevKit.hostname+':'+Lwm2mDevKit.port, 'Cancel for '+ entry.message.getUriPath());
			return;
		}
	}
	Lwm2mDevKit.logWarning("Observe relation "+cancel+" not found");
};

Lwm2mDevKit.InformationReporting.cancelManually = function(event) {

	if (event.key!='Del') return;

	let rows = document.getElementById('reporting_relations');
	if (!rows.selectedItem) return;
	Lwm2mDevKit.InformationReporting.cancel( rows.selectedItem.token );
};

Lwm2mDevKit.InformationReporting.cancelAll = function() {

	for (let token in Lwm2mDevKit.InformationReporting.relations) {
		let entry = Lwm2mDevKit.InformationReporting.relations[token];
		if (entry.timer) window.clearTimeout(entry.timer);

		let rows = document.getElementById('reporting_relations');
		rows.removeChild( document.getElementById('reporting_relation_'+token) );

		delete Lwm2mDevKit.InformationReporting.relations[token];
	}
};

Lwm2mDevKit.InformationReporting.getAttribute = function(path, attrib) {

	let temp = path.split('/');
	let obj = temp[0];
	let ins = temp[1];
	let res = temp[2];

	if (Lwm2mDevKit.client.attributes[obj]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][ins]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][ins][res]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][ins][res][attrib]!==undefined) {
		return Lwm2mDevKit.client.attributes[obj][ins][res][attrib];
	}
	if (Lwm2mDevKit.client.attributes[obj]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][ins]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][ins][attrib]!==undefined) {
		return Lwm2mDevKit.client.attributes[obj][ins][attrib];
	}
	if (Lwm2mDevKit.client.attributes[obj]!==undefined &&
		Lwm2mDevKit.client.attributes[obj][attrib]!==undefined) {
		return Lwm2mDevKit.client.attributes[obj][attrib];
	}

	if (attrib=='pmin') return Lwm2mDevKit.client.instances[1][1][2];
	if (attrib=='pmax') return Lwm2mDevKit.client.instances[1][1][3];
};

Lwm2mDevKit.InformationReporting.addRelationRow = function(message) {

	let rows = document.getElementById('reporting_relations');
	let token = message.getToken(true);

	var item = document.createElement('listitem');
	item.setAttribute('id', 'reporting_relation_'+token);
	item.token = token;

	var cell = document.createElement('listcell');
	cell.setAttribute('label', token);
	item.appendChild(cell);

	cell = document.createElement('listcell');
	cell.setAttribute('label', message.getUriPath());
	item.appendChild(cell);

	cell = document.createElement('listcell');
	cell.setAttribute('id', 'reporting_relations_'+token);
	cell.setAttribute('label', 1);
	item.appendChild(cell);

	rows.appendChild( item );

	//rows.ensureElementIsVisible(item);
};
<|endoftext|>


<commit_before>
/**
 * Manager for pending transactions
 */

var Transaction = require('./transaction').Transaction;

function TransactionQueue() {
  this._queue         = [ ];
  this._idCache       = { };
  this._sequenceCache = { };
  this._save          = void(0);
};

TransactionQueue.prototype.save = function() {
  if (typeof this._save !== 'function') return;

  this._save(this._queue.map(function(tx) {
    return {
      tx_json: tx.tx_json,
      submittedIDs: tx.submittedIDs
    }
  }));
};

/**
 * Store received (validated) sequence
 */

TransactionQueue.prototype.addReceivedSequence = function(sequence) {
  this._sequenceCache[sequence] = true;
};

/**
 * Store received (validated) ID transaction
 */

TransactionQueue.prototype.addReceivedId = function(id, transaction) {
  this._idCache[id] = transaction;
};

/**
 * Get received (validated) transaction by ID
 */

TransactionQueue.prototype.getReceived = function(id) {
  return this._idCache[id];
};

/**
 * Check that sequence number has been consumed by a validated
 * transaction
 */

TransactionQueue.prototype.hasSequence = function(sequence) {
  return this._sequenceCache[sequence] || false;
};

/**
 * Get a submitted transaction by ID. Transactions
 * may have multiple associated IDs.
 */

TransactionQueue.prototype.getSubmission = function(id, callback) {
  var result = false;

  for (var i=0, tx; tx=this._queue[i]; i++) {
    if (~tx.submittedIDs.indexOf(id)) {
      result = tx;
      break;
    }
  }

  return result;
};

/**
 * Remove a transaction from the queue
 */

TransactionQueue.prototype.remove = function(tx) {
  // ND: We are just removing the Transaction by identity
  var i = this._queue.length;

  while (i--) {
    if (this._queue[i] === tx) {
      this._queue.splice(i, 1);
      break;
    }
  }

  this.save();
};

TransactionQueue.prototype.push = function(tx) {
  this._queue.push(tx);
  this.save();
};

TransactionQueue.prototype.forEach = function(fn) {
  this._queue.forEach(fn);
};

TransactionQueue.prototype.length = function() {
  return this._queue.length;
};

exports.TransactionQueue = TransactionQueue;
<commit_msg>Clear caches when queue empties<commit_after>
/**
 * Manager for pending transactions
 */

var Transaction = require('./transaction').Transaction;

function TransactionQueue() {
  var self = this;

  this._queue         = [ ];
  this._idCache       = { };
  this._sequenceCache = { };
  this._save          = void(0);
};

TransactionQueue.prototype.clearCache = function() {
  this._idCache       = { };
  this._sequenceCache = { };
};

TransactionQueue.prototype.save = function() {
  if (typeof this._save !== 'function') return;

  this._save(this._queue.map(function(tx) {
    return {
      tx_json: tx.tx_json,
      submittedIDs: tx.submittedIDs
    }
  }));
};

/**
 * Store received (validated) sequence
 */

TransactionQueue.prototype.addReceivedSequence = function(sequence) {
  this._sequenceCache[sequence] = true;
};

/**
 * Store received (validated) ID transaction
 */

TransactionQueue.prototype.addReceivedId = function(id, transaction) {
  this._idCache[id] = transaction;
};

/**
 * Get received (validated) transaction by ID
 */

TransactionQueue.prototype.getReceived = function(id) {
  return this._idCache[id];
};

/**
 * Check that sequence number has been consumed by a validated
 * transaction
 */

TransactionQueue.prototype.hasSequence = function(sequence) {
  return this._sequenceCache[sequence] || false;
};

/**
 * Get a submitted transaction by ID. Transactions
 * may have multiple associated IDs.
 */

TransactionQueue.prototype.getSubmission = function(id, callback) {
  var result = false;

  for (var i=0, tx; tx=this._queue[i]; i++) {
    if (~tx.submittedIDs.indexOf(id)) {
      result = tx;
      break;
    }
  }

  return result;
};

/**
 * Remove a transaction from the queue
 */

TransactionQueue.prototype.remove = function(tx) {
  // ND: We are just removing the Transaction by identity
  var i = this._queue.length;

  while (i--) {
    if (this._queue[i] === tx) {
      this._queue.splice(i, 1);
      break;
    }
  }

  if (!this._queue.length) {
    this.clearCache();
  }

  this.save();
};

TransactionQueue.prototype.push = function(tx) {
  this._queue.push(tx);
  this.save();
};

TransactionQueue.prototype.forEach = function(fn) {
  this._queue.forEach(fn);
};

TransactionQueue.prototype.length = function() {
  return this._queue.length;
};

exports.TransactionQueue = TransactionQueue;
<|endoftext|>