<commit_before>/* global FB, $ */

/**
 * This class implements authentication against facebook
 * connect using the Facebook SDK.
 */

import Provider from 'torii/providers/base';
import {configurable} from 'torii/configuration';

var fbPromise;

function fbLoad(settings){
  if (fbPromise) { return fbPromise; }

  var original = window.fbAsyncInit;
  fbPromise = new Ember.RSVP.Promise(function(resolve, reject){
    window.fbAsyncInit = function(){
      FB.init(settings);
      Ember.run(null, resolve);
    };
    $.getScript('//connect.facebook.net/en_US/all.js');
  }).then(function(){
    window.fbAsyncInit = original;
  });

  return fbPromise;
}

function fbLogin(scope){
  return new Ember.RSVP.Promise(function(resolve, reject){
    FB.login(function(response){
      if (response.authResponse) {
        Ember.run(null, resolve, response.authResponse);
      } else {
        Ember.run(null, reject, response.status);
      }
    }, { scope: scope });
  });
}

function fbNormalize(response){
  return {
    userId: response.userID,
    accessToken: response.accessToken
  };
}

var Facebook = Provider.extend({

  // Required settings:
  name:  'facebook-connect',
  scope: configurable('scope', 'email'),
  appId: configurable('appId'),

  // API:
  //
  open: function(){
    var scope = this.get('scope');

    return fbLoad( this.settings() )
      .then(function(){
        return fbLogin(scope);
      })
      .then(fbNormalize);
  },

  settings: function(){
    return {
      status: true,
      cookie: true,
      xfbml: false,
      appId: this.get('appId')
    };
  },

  // Load Facebook's script eagerly, so that the window.open
  // in FB.login will be part of the same JS frame as the
  // click itself.
  loadFbLogin: function(){
    fbLoad( this.settings() );
  }.on('init')

});

export default Facebook;
<commit_msg>Updated Facebook SDK<commit_after>/* global FB, $ */

/**
 * This class implements authentication against facebook
 * connect using the Facebook SDK.
 */

import Provider from 'torii/providers/base';
import {configurable} from 'torii/configuration';

var fbPromise;

function fbLoad(settings){
  if (fbPromise) { return fbPromise; }

  var original = window.fbAsyncInit;
  fbPromise = new Ember.RSVP.Promise(function(resolve, reject){
    window.fbAsyncInit = function(){
      FB.init(settings);
      Ember.run(null, resolve);
    };
    $.getScript('//connect.facebook.net/en_US/sdk.js');
  }).then(function(){
    window.fbAsyncInit = original;
  });

  return fbPromise;
}

function fbLogin(scope){
  return new Ember.RSVP.Promise(function(resolve, reject){
    FB.login(function(response){
      if (response.authResponse) {
        Ember.run(null, resolve, response.authResponse);
      } else {
        Ember.run(null, reject, response.status);
      }
    }, { scope: scope });
  });
}

function fbNormalize(response){
  return {
    userId: response.userID,
    accessToken: response.accessToken
  };
}

var Facebook = Provider.extend({

  // Required settings:
  name:  'facebook-connect',
  scope: configurable('scope', 'email'),
  appId: configurable('appId'),

  // API:
  //
  open: function(){
    var scope = this.get('scope');

    return fbLoad( this.settings() )
      .then(function(){
        return fbLogin(scope);
      })
      .then(fbNormalize);
  },

  settings: function(){
    return {
      status: true,
      cookie: true,
      xfbml: false,
      version: 'v2.0',
      appId: this.get('appId')
    };
  },

  // Load Facebook's script eagerly, so that the window.open
  // in FB.login will be part of the same JS frame as the
  // click itself.
  loadFbLogin: function(){
    fbLoad( this.settings() );
  }.on('init')

});

export default Facebook;
<|endoftext|>


<commit_before>// @flow

import React, { useState } from 'react';
import EditableValue from './EditableValue';
import Button from '../Button';
import ButtonIcon from '../ButtonIcon';
import { getMetaValueLabel } from '../utils';
import { meta } from '../../../hydration';
import styles from './KeyValue.css';

type OverrideValueFn = (path: Array<string | number>, value: any) => void;

type KeyValueProps = {|
  depth: number,
  name: string,
  overrideValueFn?: ?OverrideValueFn,
  path?: Array<any>,
  value: any,
|};

export default function KeyValue({
  depth,
  name,
  overrideValueFn,
  path = [],
  value,
}: KeyValueProps) {
  const [open, setOpen] = useState(false);

  const handleToggle = () => {
    setOpen(prevOpen => !prevOpen);
  };

  const dataType = typeof value;
  const isSimpleType =
    dataType === 'number' ||
    dataType === 'string' ||
    dataType === 'boolean' ||
    value == null;

  const paddingLeft = `${depth * 0.75}rem`;

  let children = null;
  if (isSimpleType) {
    let displayValue = value;
    if (dataType === 'string') {
      displayValue = `"${value}"`;
    } else if (dataType === 'boolean') {
      displayValue = value ? 'true' : 'false';
    } else if (value === null) {
      displayValue = 'null';
    } else if (value === undefined) {
      displayValue = 'undefined';
    }

    const nameClassName =
      typeof overrideValueFn === 'function' ? styles.EditableName : styles.Name;

    children = (

        {name}
        {typeof overrideValueFn === 'function' ? (
          <EditableValue
            dataType={dataType}
            overrideValueFn={overrideValueFn}
            path={path}
            value={value}
          />
        ) : (
          {displayValue}
        )}

    );
  } else if (value.hasOwnProperty(meta.type)) {
    // TODO Is this type even necessary? Can we just drop it?
    children = (

        {name}
        {getMetaValueLabel(value)}

    );
  } else {
    const opener = (
      <Button className={styles.Opener} onClick={handleToggle}>
        <ButtonIcon type={open ? 'up' : 'down'} />
      </Button>
    );

    if (Array.isArray(value)) {
      children = open
        ? value.map((innerValue, index) => (
            <KeyValue
              key={index}
              depth={depth + 1}
              name={index}
              overrideValueFn={overrideValueFn}
              path={path.concat(index)}
              value={value[index]}
            />
          ))
        : [];
      children.unshift(
        <div
          key={`${depth}-root`}
          className={styles.Item}
          style={{ paddingLeft }}
        >
          {value.length > 0 && opener}
          {name}
          Array

      );
    } else {
      children = open
        ? // $FlowFixMe "Missing type annotation for U" whatever that means
          Object.entries(value).map(([name, value]) => (
            <KeyValue
              key={name}
              depth={depth + 1}
              name={name}
              overrideValueFn={overrideValueFn}
              path={path.concat(name)}
              value={value}
            />
          ))
        : [];
      children.unshift(
        <div
          key={`${depth}-root`}
          className={styles.Item}
          style={{ paddingLeft }}
        >
          {Object.entries(value).length > 0 && opener}
          {name}
          Object

      );
    }
  }

  return children;
}
<commit_msg>Fix flow type<commit_after>// @flow

import React, { useState } from 'react';
import type { Element } from 'react';
import EditableValue from './EditableValue';
import Button from '../Button';
import ButtonIcon from '../ButtonIcon';
import { getMetaValueLabel } from '../utils';
import { meta } from '../../../hydration';
import styles from './KeyValue.css';

type OverrideValueFn = (path: Array<string | number>, value: any) => void;

type KeyValueProps = {|
  depth: number,
  name: string,
  overrideValueFn?: ?OverrideValueFn,
  path?: Array<any>,
  value: any,
|};

export default function KeyValue({
  depth,
  name,
  overrideValueFn,
  path = [],
  value,
}: KeyValueProps) {
  const [open, setOpen] = useState(false);

  const handleToggle = () => {
    setOpen(prevOpen => !prevOpen);
  };

  const dataType = typeof value;
  const isSimpleType =
    dataType === 'number' ||
    dataType === 'string' ||
    dataType === 'boolean' ||
    value == null;

  const paddingLeft = `${depth * 0.75}rem`;

  let children = null;
  if (isSimpleType) {
    let displayValue = value;
    if (dataType === 'string') {
      displayValue = `"${value}"`;
    } else if (dataType === 'boolean') {
      displayValue = value ? 'true' : 'false';
    } else if (value === null) {
      displayValue = 'null';
    } else if (value === undefined) {
      displayValue = 'undefined';
    }

    const nameClassName =
      typeof overrideValueFn === 'function' ? styles.EditableName : styles.Name;

    children = (

        {name}
        {typeof overrideValueFn === 'function' ? (
          <EditableValue
            dataType={dataType}
            overrideValueFn={overrideValueFn}
            path={path}
            value={value}
          />
        ) : (
          {displayValue}
        )}

    );
  } else if (value.hasOwnProperty(meta.type)) {
    // TODO Is this type even necessary? Can we just drop it?
    children = (

        {name}
        {getMetaValueLabel(value)}

    );
  } else {
    const opener = (
      <Button className={styles.Opener} onClick={handleToggle}>
        <ButtonIcon type={open ? 'up' : 'down'} />
      </Button>
    );

    if (Array.isArray(value)) {
      children = open
        ? value.map((innerValue, index) => (
            <KeyValue
              key={index}
              depth={depth + 1}
              name={index}
              overrideValueFn={overrideValueFn}
              path={path.concat(index)}
              value={value[index]}
            />
          ))
        : [];
      children.unshift(
        <div
          key={`${depth}-root`}
          className={styles.Item}
          style={{ paddingLeft }}
        >
          {value.length > 0 && opener}
          {name}
          Array

      );
    } else {
      children = open
        ? Object.entries(value).map<Element<any>>(([name, value]) => (
            <KeyValue
              key={name}
              depth={depth + 1}
              name={name}
              overrideValueFn={overrideValueFn}
              path={path.concat(name)}
              value={value}
            />
          ))
        : [];
      children.unshift(
        <div
          key={`${depth}-root`}
          className={styles.Item}
          style={{ paddingLeft }}
        >
          {Object.entries(value).length > 0 && opener}
          {name}
          Object

      );
    }
  }

  return children;
}
<|endoftext|>


<commit_before>var ffi = require('ffi');

var myLib;
//var myLib = ffi.Library('./bin/myLib', {
//    'factorial': ['uint64', ['int']],
//    'getString': ['String',['String']]
//});
//
//if (process.argv.length < 3) {
//    console.log('default value: 5');
//}
//
////var output = myLib.factorial(parseInt(process.argv[2]) || 5);
////
////console.log('Your output: ' + output);
////
//console.log(myLib.getString("pham khac"));

module.exports = myLib || {};<commit_msg>update<commit_after>var ffi = require('ffi');

var myLib = ffi.Library('./bin/myLib', {
    'factorial': ['uint64', ['int']],
    'getString': ['String',['String']]
});
//
//if (process.argv.length < 3) {
//    console.log('default value: 5');
//}
//
////var output = myLib.factorial(parseInt(process.argv[2]) || 5);
////
////console.log('Your output: ' + output);
////
//console.log(myLib.getString("pham khac"));

module.exports = myLib || {};<|endoftext|>


<commit_before>'use strict';

var errors = require('../app/app.errors');

/**
 * The error handler for Writ, currently a very large switch statement
 * for all the different kinds of errors we expect from our express app.
 *
 * @param {Error} err - Error thrown.
 * @param {Request} req - Express request object.
 * @param {Response} res - Express response object.
 * @param {function} next - Callback for Express.
 */
function errorHandler(err, req, res, next) {

    var responseData;

    if (!req.accepts('json')) {
        res.set('Content-Type', 'text/plain')
            .status(406).send('Only JSON Content type is accepted.');

    } else if (err instanceof errors.JsonSchemaValidationError) {
        responseData = {
            status: 'INVALID_JSON_SCHEME',
            errors: {
                'body': err.errors
            }
        };
        res.status(err.status).json(responseData);

    } else if (err instanceof errors.SyntaxError) {
        responseData = {
            status: 'INVALID_JSON',
            message: err.message
        };
        res.status(400).json(responseData);

    } else if (err instanceof errors.EmailUsedError) {
        responseData = {
            status: 'EMAIL_USED',
            message: err.message
        };
        res.status(err.status).json(responseData);

    } else if (err instanceof errors.SecretNotFoundError) {
        responseData = {
            status: 'EMAIL_TOKEN_NOT_FOUND',
            message: err.message
        };
        res.status(err.status).json(responseData);

    } else if (err instanceof errors.ForbiddenError) {
        responseData = {
            status: 'FORBIDDEN',
            message: err.message
        };
        res.status(err.status).json(responseData);

    } else if (err.name === 'LoginError') {
        responseData = {
            status: 'INVALID_LOGIN',
            message: err.message
        };
        res.status(err.status).json(responseData);

    } else {
        next(err);

    }
}

module.exports = errorHandler;
<commit_msg>(areyoukiddingme)<commit_after>'use strict';

var errors = require('../app/app.errors');

/**
 * The error handler for Writ, currently a very large switch statement
 * for all the different kinds of errors we expect from our express app.
 *
 * @param {Error} err - Error thrown.
 * @param {Request} req - Express request object.
 * @param {Response} res - Express response object.
 * @param {function} next - Callback for Express.
 */
function errorHandler(err, req, res, next) {

    var responseData;

    if (!req.accepts('json')) {
        res.set('Content-Type', 'text/plain')
            .status(406).send('Only JSON Content type is accepted.');

    } else if (err instanceof errors.JsonSchemaValidationError) {
        responseData = {
            status: 'INVALID_JSON_SCHEME',
            errors: {
                'body': err.errors
            }
        };
        res.status(err.status).json(responseData);

    } else if (err instanceof errors.SyntaxError) {
        responseData = {
            status: 'INVALID_JSON',
            message: err.message
        };
        res.status(400).json(responseData);

    } else if (err instanceof errors.EmailUsedError) {
        responseData = {
            status: 'EMAIL_USED',
            message: err.message
        };
        res.status(err.status).json(responseData);

    } else if (err instanceof errors.SecretNotFoundError) {
        responseData = {
            status: 'EMAIL_TOKEN_NOT_FOUND',
            message: err.message
        };
        res.status(err.status).json(responseData);

    } else if (err instanceof errors.ForbiddenError) {
        responseData = {
            status: 'FORBIDDEN',
            message: err.message
        };
        res.status(err.status).json(responseData);

    } else {
        next(err);

    }
}

module.exports = errorHandler;
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var _ = require('lodash');

/**
 * Traverse the shema to build a populate plan object
 * that will populate every relation, sub-relation, and so on
 * reachable from the initial model and relation at least once
 * (perhaps most notable is that this provides access to most
 * related data without getting caught in loops.)
 *
 * @param  {[type]} schema          [description]
 * @param  {[type]} initialModel    [description]
 * @param  {[type]} initialRelation [description]
 * @return {[type]}                 [description]
 */
module.exports = function acyclicTraversal(schema, initialModel, initialRelation) {

	// Closure variable used to store the result plan.
	var resultPlan = {};

	// Track the edges which have already been traversed
	var alreadyTraversed = [
		// {
		//   relation: initialRelation,
		//   model: initialModel
		// }
	];

	return traverseSchemaGraph(initialModel, initialRelation);

	/**
	 * Recursive function
	 * @param  {[type]} modelIdentity  [description]
	 * @param  {[type]} nameOfRelation [description]
	 * @return {[type]}                [description]
	 */
	function traverseSchemaGraph(modelIdentity, nameOfRelation) {

		var currentModel = schema[modelIdentity];
		var currentAttributes = currentModel.attributes;

		// If this relation has already been traversed, return.
		// (i.e. `schema.attributes.modelIdentity.nameOfRelation`)
		var isRedundant = _.findWhere(alreadyTraversed, {
			alias: nameOfRelation,
			model: modelIdentity
		});
		if (isRedundant) return;

		// Push this relation onto the `alreadyTraversed` stack.
		alreadyTraversed.push({
			alias: nameOfRelation,
			model: modelIdentity
		});

		// If the `via` back-reference has already been traversed, return.
		// (because the information therein is probably redundant)
		// TODO

		var relation = currentAttributes[nameOfRelation];
		if (!relation) throw new Error('Unknown relation in schema: ' + modelIdentity + '.' + nameOfRelation);
		var identityOfRelatedModel = relation.model || relation.collection;

		// Get the current model
		var model = schema[identityOfRelatedModel];

		// Get the related model
		var relatedModel = schema[identityOfRelatedModel];

		// Lookup ALL the relations OF THE RELATED model.
		var relations =
			_(relatedModel.attributes).reduce(function buildSubsetOfAssociations(relations, attrDef, attrName) {
				if (_.isObject(attrDef) && (attrDef.model || attrDef.collection)) {
					relations.push(_.merge({
						alias: attrName,
						identity: attrDef.model || attrDef.collection,
						cardinality: attrDef.model ? 'model' : 'collection'
					}, attrDef));
					return relations;
				}
				return relations;
			}, []);

		// Return a piece of the result plan by calling `traverseSchemaGraph`
		// on each of the RELATED model's relations.
		return _.reduce(relations, function (resultPlanPart, relation) {

			// Recursive step
			resultPlanPart[relation.alias] = traverseSchemaGraph(identityOfRelatedModel, relation.alias);

			// Trim undefined result plan parts
			if (resultPlanPart[relation.alias] === undefined) {
				delete resultPlanPart[relation.alias];
			}

			return resultPlanPart;
		}, {});
	}

};<commit_msg>Made acyclic traversal smarter-- uses 'via' to eliminate unnecessary lookups in certain cases.<commit_after>/**
 * Module dependencies
 */

var _ = require('lodash');

/**
 * Traverse the shema to build a populate plan object
 * that will populate every relation, sub-relation, and so on
 * reachable from the initial model and relation at least once
 * (perhaps most notable is that this provides access to most
 * related data without getting caught in loops.)
 *
 * @param  {[type]} schema          [description]
 * @param  {[type]} initialModel    [description]
 * @param  {[type]} initialRelation [description]
 * @return {[type]}                 [description]
 */
module.exports = function acyclicTraversal(schema, initialModel, initialRelation) {

	// Track the edges which have already been traversed
	var alreadyTraversed = [
		// {
		//   relation: initialRelation,
		//   model: initialModel
		// }
	];

	return traverseSchemaGraph(initialModel, initialRelation);

	/**
	 * Recursive function
	 * @param  {[type]} modelIdentity  [description]
	 * @param  {[type]} nameOfRelation [description]
	 * @return {[type]}                [description]
	 */
	function traverseSchemaGraph(modelIdentity, nameOfRelation) {

		var currentModel = schema[modelIdentity];
		var currentAttributes = currentModel.attributes;

		var isRedundant;

		// If this relation has already been traversed, return.
		// (i.e. `schema.attributes.modelIdentity.nameOfRelation`)
		isRedundant = _.findWhere(alreadyTraversed, {
			alias: nameOfRelation,
			model: modelIdentity
		});

		if (isRedundant) return;

		// Push this relation onto the `alreadyTraversed` stack.
		alreadyTraversed.push({
			alias: nameOfRelation,
			model: modelIdentity
		});

		var relation = currentAttributes[nameOfRelation];
		if (!relation) throw new Error('Unknown relation in schema: ' + modelIdentity + '.' + nameOfRelation);
		var identityOfRelatedModel = relation.model || relation.collection;

		// Get the related model
		var relatedModel = schema[identityOfRelatedModel];

		// If this relation is a collection with a `via` back-reference,
		// push it on to the `alreadyTraversed` stack.
		// (because the information therein is probably redundant)
		// TODO: evaluate this-- it may or may not be a good idea
		// (but I think it's a nice touch)
		if (relation.via) {
			alreadyTraversed.push({
				alias: relation.via,
				model: identityOfRelatedModel
			});
		}

		// Lookup ALL the relations OF THE RELATED model.
		var relations =
			_(relatedModel.attributes).reduce(function buildSubsetOfAssociations(relations, attrDef, attrName) {
				if (_.isObject(attrDef) && (attrDef.model || attrDef.collection)) {
					relations.push(_.merge({
						alias: attrName,
						identity: attrDef.model || attrDef.collection,
						cardinality: attrDef.model ? 'model' : 'collection'
					}, attrDef));
					return relations;
				}
				return relations;
			}, []);

		// Return a piece of the result plan by calling `traverseSchemaGraph`
		// on each of the RELATED model's relations.
		return _.reduce(relations, function (resultPlanPart, relation) {

			// Recursive step
			resultPlanPart[relation.alias] = traverseSchemaGraph(identityOfRelatedModel, relation.alias);

			// Trim undefined result plan parts
			if (resultPlanPart[relation.alias] === undefined) {
				delete resultPlanPart[relation.alias];
			}

			return resultPlanPart;
		}, {});
	}

};<|endoftext|>


<commit_before>define([
  'text!./cam-widget-search.html',
  'angular',
  'jquery'
], function(
  template,
  angular,
  $
) {
  'use strict';

  var dateRegex = /(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)(?:.(\d\d\d)| )?$/;
  function getType(value) {
    if(value && typeof value === 'string' && value.match(dateRegex)) {
      return 'date';
    }
    return typeof value;
  }

  var isValid = function(search) {
    return search.type.value &&
      (!search.extended || search.name.value) &&
      search.operator.value &&
      search.value.value &&
      (getType(search.value.value) === 'date' || !search.enforceDates);
  };

  var validateOperator = function(operator) {
    if(!operator.value) {
      operator.value = operator.values[0];
      return;
    }
    var idx = operator.values.map(function(el) {
      return el.key;
    }).indexOf(operator.value.key);
    operator.value = operator.values[idx === -1 ? 0 : idx];
  };

  var parseValue = function(value) {
    if(!isNaN(value) && value.trim() !== '') {
      // value must be transformed to number
      return +value;
    }
    if(value === 'true') {
      return true;
    }
    if(value === 'false') {
      return false;
    }
    if(value === 'NULL') {
      return null;
    }
    return value;
  };

  return ['$timeout', '$location', 'search',
  function($timeout,   $location,   searchService) {

    return {
      restrict: 'A',

      scope: {
        types: '=camWidgetSearchTypes',
        translations: '=camWidgetSearchTranslations',
        operators: '=camWidgetSearchOperators',

        searches: '=?camWidgetSearchSearches',
        validSearches: '=?camWidgetSearchValidSearches'
      },

      link: function($scope, element, attrs) {

        $scope.searchTypes = $scope.types.map(function(el) {
          return el.id;
        });

        var defaultType = $scope.types.reduce(function(done, type) {
          return done || (type.default ? type : null);
        }, null);

        var getConfigByTypeKey = function(typeKey) {
          return $scope.types.reduce(function(done, type) {
            return done || (type.id.key === typeKey ? type : null);
          }, null);
        };

        var getOperators = function(config, value) {
          return config.operators || ($scope.operators[getType(parseValue(value))]);
        };

        var getSearchesFromURL = function() {
          var urlSearches = JSON.parse(($location.search() || {}).searchQuery || '[]');
          var searches = [];
          angular.forEach(urlSearches, function(search) {
            var config = getConfigByTypeKey(search.type);
            var newSearch =
                {
                  extended: config.extended,

                  type: {
                    values: $scope.searchTypes,
                    value: $scope.searchTypes.reduce(function(done, type) {
                      return done || (type.key === search.type ? type : null);
                    }, null),
                    tooltip: $scope.translations.type
                  },

                  name: {
                    value: search.name,
                    tooltip: $scope.translations.name
                  },

                  operator: {
                    tooltip: $scope.translations.operator
                  },

                  value: {
                    value: search.value,
                    tooltip: $scope.translations.value
                  },
                  allowDates: config.allowDates,
                  enforceDates: config.enforceDates
                };
            newSearch.operator.values = getOperators(config, newSearch.value.value);
            newSearch.operator.value = newSearch.operator.values.reduce(function(done, op) {
              return done || (op.key === search.operator ? op : null);
            }, null);

            newSearch.valid = isValid(newSearch);
            searches.push(newSearch);
          });
          return searches;
        };

        $scope.searches = getSearchesFromURL();
        $scope.validSearchesBuffer = $scope.searches.reduce(function(valid, search) {
          if(search.valid) {
            valid.push(search);
          }
          return valid;
        }, []);
        $scope.validSearches = angular.copy($scope.validSearchesBuffer);

        var selectNextInvalidElement = function(startIndex, startField) {
          var search = $scope.searches[startIndex];
          if(!search.valid) {
            if(search.extended && !search.name.value && startField !== 'name') {
              search.name.inEdit = true;
              return;
            } else if(startField !== 'value') {
              search.value.inEdit = true;
              return;
            }
          }
          for(var i = 1; i < $scope.searches.length; i++) {
            var idx = (i + startIndex) % $scope.searches.length;
            search = $scope.searches[idx];
            if(!search.valid) {
              if(search.extended && !search.name.value) {
                search.name.inEdit = true;
              } else {
                search.value.inEdit = true;
              }
              return;
            }
          }
        };

        $scope.createSearch = function(type) {
          if(!type && !$scope.inputQuery) {
            return;
          }

          var value = (!type ? $scope.inputQuery : '');

          type = type || defaultType;

          var operators = getOperators(type, value);

          $scope.searches.push({
            extended: type.extended,
            type: {
              values: $scope.searchTypes,
              value: type.id,
              tooltip: $scope.translations.type
            },
            name: {
              value: '',
              inEdit: type.extended,
              tooltip: $scope.translations.name
            },
            operator: {
              value: operators[0],
              values: operators,
              tooltip: $scope.translations.operator
            },
            value: {
              value: value,
              inEdit: !type.extended && !value,
              tooltip: $scope.translations.value
            },
            allowDates: type.allowDates,
            enforceDates: type.enforceDates
          });
          var search = $scope.searches[$scope.searches.length-1];
          search.valid = isValid(search);

          // To those who think, WHAT THE HECK IS THIS?!:
          //
          // Typeahead thinks, it is a good idea to focus the input field after selecting an option via mouse click
          // (see https://github.com/angular-ui/bootstrap/blob/master/src/typeahead/typeahead.js#L266)
          // We do not want this. Since they are registering their focus event per timeout AFTER we register our
          // blur event per timeout, the field is focussed in the end. How to prevent this? More timeouts x_x
          if(!value) {
            $timeout(function(){$timeout(function(){
              $scope.inputQuery = '';
              element.find('.search-container > input').blur();
            });});
          } else {
            $scope.inputQuery = '';
          }
        };

        $scope.deleteSearch = function(idx) {
          $scope.searches.splice(idx,1);
        };

        $scope.handleChange = function(idx, field, before, value, evt) {
          var config;
          var search = $scope.searches[idx];
          if(field === 'type') {
            config = getConfigByTypeKey(value.key);

            search.extended = config.extended;
            search.allowDates = config.allowDates;

            if(!search.enforceDates && config.enforceDates) {
              search.value.value = '';
            }
            search.enforceDates = config.enforceDates;
            search.operator.values = getOperators(config, search.value.value);
            validateOperator(search.operator);
          } else if(field === 'value') {
            if(idx === $scope.searches.length-1) {
              $timeout(function(){
                element.find('.search-container > input').focus();
              });
            }
            config = getConfigByTypeKey(search.type.value.key);
            if(!config.operators) {
              search.operator.values = getOperators(config, search.value.value);
              validateOperator(search.operator);
            }
          }
          search.valid = isValid(search);

          if(evt && evt.keyCode === 13) {
            selectNextInvalidElement(idx, field);
          }

        };

        $scope.onKeydown = function(evt) {
          if(evt.keyCode === 9 && !$scope.inputQuery) {
            evt.preventDefault();
            evt.stopPropagation();
            var search = $scope.searches[evt.shiftKey ? $scope.searches.length-1 : 0];
            if(search) {
              if(evt.shiftKey) {
                search.value.inEdit = true;
              } else {
                search.type.inEdit = true;
              }
            }
          } else if([38,40,13].indexOf(evt.keyCode) !== -1) {
            if(element.find(".dropdown-menu").length === 0) {
              $timeout(function(){
                $(evt.target).trigger("input");
              });
            }
          }
        };

        var extractSearches = function(searches) {
          var out = [];
          angular.forEach(searches, function(search) {
            out.push({
              type: search.type.value.key,
              operator: search.operator.value.key,
              value: search.value.value,
              name: search.name.value
            });
          });
          return out;
        };

        $scope.$watch('searches', function() {
          var searches = $scope.searches;
          // add valid searches to validSearchesBuffer
          angular.forEach(searches, function(search) {
            if(search.valid && $scope.validSearchesBuffer.indexOf(search) === -1) {
              $scope.validSearchesBuffer.push(search);
            }
          });

          // remove invalid searches from valid searches
          angular.forEach($scope.validSearchesBuffer, function(search, idx) {
            if(!search.valid || searches.indexOf(search) === -1) {
              $scope.validSearchesBuffer.splice(idx, 1);
            }
          });

          searchService.updateSilently({
            searchQuery: JSON.stringify(extractSearches($scope.validSearchesBuffer))
          });

        }, true);

        var copyValid;
        $scope.$watch('validSearchesBuffer', function() {
          $timeout.cancel(copyValid);
          copyValid = $timeout(function() {
            $scope.validSearches = angular.copy($scope.validSearchesBuffer);
          });
        }, true);

      },

      template: template
    };
  }];
});
<commit_msg>style(linting): correct some linting glitches<commit_after>define([
  'text!./cam-widget-search.html',
  'angular',
  'jquery'
], function(
  template,
  angular,
  $
) {
  'use strict';

  var dateRegex = /(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)(?:.(\d\d\d)| )?$/;
  function getType(value) {
    if(value && typeof value === 'string' && value.match(dateRegex)) {
      return 'date';
    }
    return typeof value;
  }

  var isValid = function(search) {
    return search.type.value &&
      (!search.extended || search.name.value) &&
      search.operator.value &&
      search.value.value &&
      (getType(search.value.value) === 'date' || !search.enforceDates);
  };

  var validateOperator = function(operator) {
    if(!operator.value) {
      operator.value = operator.values[0];
      return;
    }
    var idx = operator.values.map(function(el) {
      return el.key;
    }).indexOf(operator.value.key);
    operator.value = operator.values[idx === -1 ? 0 : idx];
  };

  var parseValue = function(value) {
    if(!isNaN(value) && value.trim() !== '') {
      // value must be transformed to number
      return +value;
    }
    if(value === 'true') {
      return true;
    }
    if(value === 'false') {
      return false;
    }
    if(value === 'NULL') {
      return null;
    }
    return value;
  };

  return ['$timeout', '$location', 'search',
  function($timeout,   $location,   searchService) {

    return {
      restrict: 'A',

      scope: {
        types: '=camWidgetSearchTypes',
        translations: '=camWidgetSearchTranslations',
        operators: '=camWidgetSearchOperators',

        searches: '=?camWidgetSearchSearches',
        validSearches: '=?camWidgetSearchValidSearches'
      },

      link: function($scope, element) {

        $scope.searchTypes = $scope.types.map(function(el) {
          return el.id;
        });

        var defaultType = $scope.types.reduce(function(done, type) {
          return done || (type.default ? type : null);
        }, null);

        var getConfigByTypeKey = function(typeKey) {
          return $scope.types.reduce(function(done, type) {
            return done || (type.id.key === typeKey ? type : null);
          }, null);
        };

        var getOperators = function(config, value) {
          return config.operators || ($scope.operators[getType(parseValue(value))]);
        };

        var getSearchesFromURL = function() {
          var urlSearches = JSON.parse(($location.search() || {}).searchQuery || '[]');
          var searches = [];
          angular.forEach(urlSearches, function(search) {
            var config = getConfigByTypeKey(search.type);
            var newSearch =
                {
                  extended: config.extended,

                  type: {
                    values: $scope.searchTypes,
                    value: $scope.searchTypes.reduce(function(done, type) {
                      return done || (type.key === search.type ? type : null);
                    }, null),
                    tooltip: $scope.translations.type
                  },

                  name: {
                    value: search.name,
                    tooltip: $scope.translations.name
                  },

                  operator: {
                    tooltip: $scope.translations.operator
                  },

                  value: {
                    value: search.value,
                    tooltip: $scope.translations.value
                  },
                  allowDates: config.allowDates,
                  enforceDates: config.enforceDates
                };
            newSearch.operator.values = getOperators(config, newSearch.value.value);
            newSearch.operator.value = newSearch.operator.values.reduce(function(done, op) {
              return done || (op.key === search.operator ? op : null);
            }, null);

            newSearch.valid = isValid(newSearch);
            searches.push(newSearch);
          });
          return searches;
        };

        $scope.searches = getSearchesFromURL();
        $scope.validSearchesBuffer = $scope.searches.reduce(function(valid, search) {
          if(search.valid) {
            valid.push(search);
          }
          return valid;
        }, []);
        $scope.validSearches = angular.copy($scope.validSearchesBuffer);

        var selectNextInvalidElement = function(startIndex, startField) {
          var search = $scope.searches[startIndex];
          if(!search.valid) {
            if(search.extended && !search.name.value && startField !== 'name') {
              search.name.inEdit = true;
              return;
            } else if(startField !== 'value') {
              search.value.inEdit = true;
              return;
            }
          }
          for(var i = 1; i < $scope.searches.length; i++) {
            var idx = (i + startIndex) % $scope.searches.length;
            search = $scope.searches[idx];
            if(!search.valid) {
              if(search.extended && !search.name.value) {
                search.name.inEdit = true;
              } else {
                search.value.inEdit = true;
              }
              return;
            }
          }
        };

        $scope.createSearch = function(type) {
          if(!type && !$scope.inputQuery) {
            return;
          }

          var value = (!type ? $scope.inputQuery : '');

          type = type || defaultType;

          var operators = getOperators(type, value);

          $scope.searches.push({
            extended: type.extended,
            type: {
              values: $scope.searchTypes,
              value: type.id,
              tooltip: $scope.translations.type
            },
            name: {
              value: '',
              inEdit: type.extended,
              tooltip: $scope.translations.name
            },
            operator: {
              value: operators[0],
              values: operators,
              tooltip: $scope.translations.operator
            },
            value: {
              value: value,
              inEdit: !type.extended && !value,
              tooltip: $scope.translations.value
            },
            allowDates: type.allowDates,
            enforceDates: type.enforceDates
          });
          var search = $scope.searches[$scope.searches.length-1];
          search.valid = isValid(search);

          // To those who think, WHAT THE HECK IS THIS?!:
          //
          // Typeahead thinks, it is a good idea to focus the input field after selecting an option via mouse click
          // (see https://github.com/angular-ui/bootstrap/blob/master/src/typeahead/typeahead.js#L266)
          // We do not want this. Since they are registering their focus event per timeout AFTER we register our
          // blur event per timeout, the field is focussed in the end. How to prevent this? More timeouts x_x
          if(!value) {
            $timeout(function(){$timeout(function(){
              $scope.inputQuery = '';
              element.find('.search-container > input').blur();
            });});
          } else {
            $scope.inputQuery = '';
          }
        };

        $scope.deleteSearch = function(idx) {
          $scope.searches.splice(idx,1);
        };

        $scope.handleChange = function(idx, field, before, value, evt) {
          var config;
          var search = $scope.searches[idx];
          if(field === 'type') {
            config = getConfigByTypeKey(value.key);

            search.extended = config.extended;
            search.allowDates = config.allowDates;

            if(!search.enforceDates && config.enforceDates) {
              search.value.value = '';
            }
            search.enforceDates = config.enforceDates;
            search.operator.values = getOperators(config, search.value.value);
            validateOperator(search.operator);
          } else if(field === 'value') {
            if(idx === $scope.searches.length-1) {
              $timeout(function(){
                element.find('.search-container > input').focus();
              });
            }
            config = getConfigByTypeKey(search.type.value.key);
            if(!config.operators) {
              search.operator.values = getOperators(config, search.value.value);
              validateOperator(search.operator);
            }
          }
          search.valid = isValid(search);

          if(evt && evt.keyCode === 13) {
            selectNextInvalidElement(idx, field);
          }

        };

        $scope.onKeydown = function(evt) {
          if(evt.keyCode === 9 && !$scope.inputQuery) {
            evt.preventDefault();
            evt.stopPropagation();
            var search = $scope.searches[evt.shiftKey ? $scope.searches.length-1 : 0];
            if(search) {
              if(evt.shiftKey) {
                search.value.inEdit = true;
              } else {
                search.type.inEdit = true;
              }
            }
          } else if([38,40,13].indexOf(evt.keyCode) !== -1) {
            if(element.find('.dropdown-menu').length === 0) {
              $timeout(function(){
                $(evt.target).trigger('input');
              });
            }
          }
        };

        var extractSearches = function(searches) {
          var out = [];
          angular.forEach(searches, function(search) {
            out.push({
              type: search.type.value.key,
              operator: search.operator.value.key,
              value: search.value.value,
              name: search.name.value
            });
          });
          return out;
        };

        $scope.$watch('searches', function() {
          var searches = $scope.searches;
          // add valid searches to validSearchesBuffer
          angular.forEach(searches, function(search) {
            if(search.valid && $scope.validSearchesBuffer.indexOf(search) === -1) {
              $scope.validSearchesBuffer.push(search);
            }
          });

          // remove invalid searches from valid searches
          angular.forEach($scope.validSearchesBuffer, function(search, idx) {
            if(!search.valid || searches.indexOf(search) === -1) {
              $scope.validSearchesBuffer.splice(idx, 1);
            }
          });

          searchService.updateSilently({
            searchQuery: JSON.stringify(extractSearches($scope.validSearchesBuffer))
          });

        }, true);

        var copyValid;
        $scope.$watch('validSearchesBuffer', function() {
          $timeout.cancel(copyValid);
          copyValid = $timeout(function() {
            $scope.validSearches = angular.copy($scope.validSearchesBuffer);
          });
        }, true);

      },

      template: template
    };
  }];
});
<|endoftext|>


<commit_before>// Gets data from provided url and updates DOM element.
function generate_os_data(url, element) {
    $.get(url, function (d) {
        if (d.msg == "success") {
            $(element).text(d.data);
        } else {
            $(element).text(d.msg);
        }
    }, "json");
}

// If dataTable with provided ID exists, destroy it.
function destroy_dataTable(table_id) {
    var table = $("#" + table_id);
    var ex = document.getElementById(table_id);
    if ($.fn.DataTable.fnIsDataTable(ex)) {
        table.hide().dataTable().fnClearTable();
        table.dataTable().fnDestroy();
    }
}

//DataTables
//Sort file size data.
jQuery.extend(jQuery.fn.dataTableExt.oSort, {
    "file-size-units": {
        K: 1024,
        M: Math.pow(1024, 2),
        G: Math.pow(1024, 3),
        T: Math.pow(1024, 4),
        P: Math.pow(1024, 5),
        E: Math.pow(1024, 6)
    },

    "file-size-pre": function (a) {
        var x = a.substring(0, a.length - 1);
        var x_unit = a.substring(a.length - 1, a.length);
        if (jQuery.fn.dataTableExt.oSort['file-size-units'][x_unit]) {
            return parseInt(x * jQuery.fn.dataTableExt.oSort['file-size-units'][x_unit], 10);
        }
        else {
            return parseInt(x + x_unit, 10);
        }
    },

    "file-size-asc": function (a, b) {
        return ((a < b) ? -1 : ((a > b) ? 1 : 0));
    },

    "file-size-desc": function (a, b) {
        return ((a < b) ? 1 : ((a > b) ? -1 : 0));
    }
});

//DataTables
//Sort numeric data which has a percent sign with it.
jQuery.extend(jQuery.fn.dataTableExt.oSort, {
    "percent-pre": function (a) {
        var x = (a === "-") ? 0 : a.replace(/%/, "");
        return parseFloat(x);
    },

    "percent-asc": function (a, b) {
        return ((a < b) ? -1 : ((a > b) ? 1 : 0));
    },

    "percent-desc": function (a, b) {
        return ((a < b) ? 1 : ((a > b) ? -1 : 0));
    }
});

//DataTables
//Sort IP addresses
jQuery.extend(jQuery.fn.dataTableExt.oSort, {
    "ip-address-pre": function (a) {
        // split the address into octets
        //
        var x = a.split('.');

        // pad each of the octets to three digits in length
        //
        function zeroPad(num, places) {
            var zero = places - num.toString().length + 1;
            return Array(+(zero > 0 && zero)).join("0") + num;
        }

        // build the resulting IP
        var r = '';
        for (var i = 0; i < x.length; i++)
            r = r + zeroPad(x[i], 3);

        // return the formatted IP address
        //
        return r;
    },

    "ip-address-asc": function (a, b) {
        return ((a < b) ? -1 : ((a > b) ? 1 : 0));
    },

    "ip-address-desc": function (a, b) {
        return ((a < b) ? 1 : ((a > b) ? -1 : 0));
    }
});

/*******************************
 Data Call Functions
 *******************************/

var dashboard = {};

dashboard.getRam = function () {
    $.get("./page/memory", function (data) {
        if (data.msg == "success") {
            var ram_total = data.data[0];
            var ram_used = Math.round((data.data[1] / ram_total) * 100);
            var ram_free = Math.round((data.data[2] / ram_total) * 100);

            $("#ram-total").text(ram_total);
            $("#ram-used").text(data.data[1]);
            $("#ram-free").text(data.data[2]);

            $("#ram-free-per").text(ram_free);
            $("#ram-used-per").text(ram_used);
        }
    }, "json");
}

dashboard.getDf = function () {
    $.get("./page/df", function (data) {
        var table = $("#df_dashboard");
        var ex = document.getElementById("df_dashboard");
        if ($.fn.DataTable.fnIsDataTable(ex)) {
            table.hide().dataTable().fnClearTable();
            table.dataTable().fnDestroy();
        }

        table.dataTable({
            aaData: data.data,
            aoColumns: [
                { sTitle: "Filesystem" },
                { sTitle: "BTotal", sType: "file-size" },
                { sTitle: "BUsed", sType: "file-size" },
                { sTitle: "BFree", sType: "file-size" },
                { sTitle: "BUse%", sType: "percent" },
                { sTitle: "Mounted" },
                { sTitle: "ITotal", sType: "file-size" },
                { sTitle: "IUsed", sType: "file-size" },
                { sTitle: "IFree", sType: "file-size" },
                { sTitle: "IUse%", sType: "percent" },
                { sTitle: "Vfstype" }
            ],
            bPaginate: false,
            bFilter: false,
            bAutoWidth: true,
            bInfo: false
        }).fadeIn();
    }, "json");
}

dashboard.getCpu = function () {
    $.get("./page/cpu/usage", function (data) {
        if (data.msg != "success") {
            return
        }

        var table = $("#cpu_dashboard");
        var ex = document.getElementById("cpu_dashboard");
        if ($.fn.DataTable.fnIsDataTable(ex)) {
            table.hide().dataTable().fnClearTable();
            table.dataTable().fnDestroy();
        }

        table.dataTable({
            aaData: data.data,
            aoColumns: [
                { sTitle: "idle"},
                { sTitle: "busy"},
                { sTitle: "user"},
                { sTitle: "nice"},
                { sTitle: "system"},
                { sTitle: "iowait"},
                { sTitle: "irq"},
                { sTitle: "softirq"},
                { sTitle: "steal"},
                { sTitle: "guest"}
            ],
            bPaginate: false,
            bFilter: false,
            bAutoWidth: true,
            bInfo: false
        }).fadeIn();
    }, "json");
}

dashboard.getDiskstats = function () {
    $.get("./page/diskio", function (data) {
        var table = $("#diskstats_dashboard");
        var ex = document.getElementById("diskstats_dashboard");
        if ($.fn.DataTable.fnIsDataTable(ex)) {
            table.hide().dataTable().fnClearTable();
            table.dataTable().fnDestroy();
        }

        table.dataTable({
            aaData: data.data,
            aoColumns: [
                { sTitle: "Device"},
                { sTitle: "rrqm/s"},
                { sTitle: "wrqm/s"},
                { sTitle: "r/s"},
                { sTitle: "w/s"},
                { sTitle: "rkB/s"},
                { sTitle: "wkB/s"},
                { sTitle: "avgrq-sz"},
                { sTitle: "avgqu-sz"},
                { sTitle: "await"},
                { sTitle: "svctm"},
                { sTitle: "%util"},
            ],
            bPaginate: false,
            bFilter: false,
            bAutoWidth: true,
            bInfo: false
        }).fadeIn();
    }, "json");
}

dashboard.getOs = function () {
    generate_os_data("./proc/kernel/version", "#os-info");
    generate_os_data("./proc/kernel/hostname", "#os-hostname");
    generate_os_data("./system/date", "#os-time");
    generate_os_data("./page/system/uptime", "#os-uptime");

    $.get("./version", function(d){
        $("#agent-version").text(d);
    });
}

dashboard.getLoadAverage = function () {
    $.get("./page/system/loadavg", function (d) {
        if (d.msg != "success") {
            return
        }
        $("#cpu-1min").text(d.data[0][0]);
        $("#cpu-5min").text(d.data[1][0]);
        $("#cpu-15min").text(d.data[2][0]);
        $("#cpu-1min-per").text(d.data[0][1]);
        $("#cpu-5min-per").text(d.data[1][1]);
        $("#cpu-15min-per").text(d.data[2][1]);
    }, "json");
    generate_os_data("./proc/cpu/num", "#core-number");
}

/**
 * Refreshes all widgets. Does not call itself recursively.
 */
dashboard.getAll = function () {
    for (var item in dashboard.fnMap) {
        if (dashboard.fnMap.hasOwnProperty(item) && item !== "all") {
            dashboard.fnMap[item]();
        }
    }
}

dashboard.fnMap = {
    all: dashboard.getAll,
    ram: dashboard.getRam,
    df: dashboard.getDf,
    os: dashboard.getOs,
    load: dashboard.getLoadAverage,
    cpu: dashboard.getCpu,
    diskstats: dashboard.getDiskstats,
};
<commit_msg>将public/js/dashboard.js相对路径中的./去掉，看起来舒服些^_^<commit_after>// Gets data from provided url and updates DOM element.
function generate_os_data(url, element) {
    $.get(url, function (d) {
        if (d.msg == "success") {
            $(element).text(d.data);
        } else {
            $(element).text(d.msg);
        }
    }, "json");
}

// If dataTable with provided ID exists, destroy it.
function destroy_dataTable(table_id) {
    var table = $("#" + table_id);
    var ex = document.getElementById(table_id);
    if ($.fn.DataTable.fnIsDataTable(ex)) {
        table.hide().dataTable().fnClearTable();
        table.dataTable().fnDestroy();
    }
}

//DataTables
//Sort file size data.
jQuery.extend(jQuery.fn.dataTableExt.oSort, {
    "file-size-units": {
        K: 1024,
        M: Math.pow(1024, 2),
        G: Math.pow(1024, 3),
        T: Math.pow(1024, 4),
        P: Math.pow(1024, 5),
        E: Math.pow(1024, 6)
    },

    "file-size-pre": function (a) {
        var x = a.substring(0, a.length - 1);
        var x_unit = a.substring(a.length - 1, a.length);
        if (jQuery.fn.dataTableExt.oSort['file-size-units'][x_unit]) {
            return parseInt(x * jQuery.fn.dataTableExt.oSort['file-size-units'][x_unit], 10);
        }
        else {
            return parseInt(x + x_unit, 10);
        }
    },

    "file-size-asc": function (a, b) {
        return ((a < b) ? -1 : ((a > b) ? 1 : 0));
    },

    "file-size-desc": function (a, b) {
        return ((a < b) ? 1 : ((a > b) ? -1 : 0));
    }
});

//DataTables
//Sort numeric data which has a percent sign with it.
jQuery.extend(jQuery.fn.dataTableExt.oSort, {
    "percent-pre": function (a) {
        var x = (a === "-") ? 0 : a.replace(/%/, "");
        return parseFloat(x);
    },

    "percent-asc": function (a, b) {
        return ((a < b) ? -1 : ((a > b) ? 1 : 0));
    },

    "percent-desc": function (a, b) {
        return ((a < b) ? 1 : ((a > b) ? -1 : 0));
    }
});

//DataTables
//Sort IP addresses
jQuery.extend(jQuery.fn.dataTableExt.oSort, {
    "ip-address-pre": function (a) {
        // split the address into octets
        //
        var x = a.split('.');

        // pad each of the octets to three digits in length
        //
        function zeroPad(num, places) {
            var zero = places - num.toString().length + 1;
            return Array(+(zero > 0 && zero)).join("0") + num;
        }

        // build the resulting IP
        var r = '';
        for (var i = 0; i < x.length; i++)
            r = r + zeroPad(x[i], 3);

        // return the formatted IP address
        //
        return r;
    },

    "ip-address-asc": function (a, b) {
        return ((a < b) ? -1 : ((a > b) ? 1 : 0));
    },

    "ip-address-desc": function (a, b) {
        return ((a < b) ? 1 : ((a > b) ? -1 : 0));
    }
});

/*******************************
 Data Call Functions
 *******************************/

var dashboard = {};

dashboard.getRam = function () {
    $.get("page/memory", function (data) {
        if (data.msg == "success") {
            var ram_total = data.data[0];
            var ram_used = Math.round((data.data[1] / ram_total) * 100);
            var ram_free = Math.round((data.data[2] / ram_total) * 100);

            $("#ram-total").text(ram_total);
            $("#ram-used").text(data.data[1]);
            $("#ram-free").text(data.data[2]);

            $("#ram-free-per").text(ram_free);
            $("#ram-used-per").text(ram_used);
        }
    }, "json");
}

dashboard.getDf = function () {
    $.get("page/df", function (data) {
        var table = $("#df_dashboard");
        var ex = document.getElementById("df_dashboard");
        if ($.fn.DataTable.fnIsDataTable(ex)) {
            table.hide().dataTable().fnClearTable();
            table.dataTable().fnDestroy();
        }

        table.dataTable({
            aaData: data.data,
            aoColumns: [
                { sTitle: "Filesystem" },
                { sTitle: "BTotal", sType: "file-size" },
                { sTitle: "BUsed", sType: "file-size" },
                { sTitle: "BFree", sType: "file-size" },
                { sTitle: "BUse%", sType: "percent" },
                { sTitle: "Mounted" },
                { sTitle: "ITotal", sType: "file-size" },
                { sTitle: "IUsed", sType: "file-size" },
                { sTitle: "IFree", sType: "file-size" },
                { sTitle: "IUse%", sType: "percent" },
                { sTitle: "Vfstype" }
            ],
            bPaginate: false,
            bFilter: false,
            bAutoWidth: true,
            bInfo: false
        }).fadeIn();
    }, "json");
}

dashboard.getCpu = function () {
    $.get("page/cpu/usage", function (data) {
        if (data.msg != "success") {
            return
        }

        var table = $("#cpu_dashboard");
        var ex = document.getElementById("cpu_dashboard");
        if ($.fn.DataTable.fnIsDataTable(ex)) {
            table.hide().dataTable().fnClearTable();
            table.dataTable().fnDestroy();
        }

        table.dataTable({
            aaData: data.data,
            aoColumns: [
                { sTitle: "idle"},
                { sTitle: "busy"},
                { sTitle: "user"},
                { sTitle: "nice"},
                { sTitle: "system"},
                { sTitle: "iowait"},
                { sTitle: "irq"},
                { sTitle: "softirq"},
                { sTitle: "steal"},
                { sTitle: "guest"}
            ],
            bPaginate: false,
            bFilter: false,
            bAutoWidth: true,
            bInfo: false
        }).fadeIn();
    }, "json");
}

dashboard.getDiskstats = function () {
    $.get("page/diskio", function (data) {
        var table = $("#diskstats_dashboard");
        var ex = document.getElementById("diskstats_dashboard");
        if ($.fn.DataTable.fnIsDataTable(ex)) {
            table.hide().dataTable().fnClearTable();
            table.dataTable().fnDestroy();
        }

        table.dataTable({
            aaData: data.data,
            aoColumns: [
                { sTitle: "Device"},
                { sTitle: "rrqm/s"},
                { sTitle: "wrqm/s"},
                { sTitle: "r/s"},
                { sTitle: "w/s"},
                { sTitle: "rkB/s"},
                { sTitle: "wkB/s"},
                { sTitle: "avgrq-sz"},
                { sTitle: "avgqu-sz"},
                { sTitle: "await"},
                { sTitle: "svctm"},
                { sTitle: "%util"},
            ],
            bPaginate: false,
            bFilter: false,
            bAutoWidth: true,
            bInfo: false
        }).fadeIn();
    }, "json");
}

dashboard.getOs = function () {
    generate_os_data("proc/kernel/version", "#os-info");
    generate_os_data("proc/kernel/hostname", "#os-hostname");
    generate_os_data("system/date", "#os-time");
    generate_os_data("page/system/uptime", "#os-uptime");

    $.get("version", function(d){
        $("#agent-version").text(d);
    });
}

dashboard.getLoadAverage = function () {
    $.get("page/system/loadavg", function (d) {
        if (d.msg != "success") {
            return
        }
        $("#cpu-1min").text(d.data[0][0]);
        $("#cpu-5min").text(d.data[1][0]);
        $("#cpu-15min").text(d.data[2][0]);
        $("#cpu-1min-per").text(d.data[0][1]);
        $("#cpu-5min-per").text(d.data[1][1]);
        $("#cpu-15min-per").text(d.data[2][1]);
    }, "json");
    generate_os_data("proc/cpu/num", "#core-number");
}

/**
 * Refreshes all widgets. Does not call itself recursively.
 */
dashboard.getAll = function () {
    for (var item in dashboard.fnMap) {
        if (dashboard.fnMap.hasOwnProperty(item) && item !== "all") {
            dashboard.fnMap[item]();
        }
    }
}

dashboard.fnMap = {
    all: dashboard.getAll,
    ram: dashboard.getRam,
    df: dashboard.getDf,
    os: dashboard.getOs,
    load: dashboard.getLoadAverage,
    cpu: dashboard.getCpu,
    diskstats: dashboard.getDiskstats,
};
<|endoftext|>


<commit_before>var food = ['sushi', 'tacos', 'burgers', 'curry rice', 'fries', 'ice cream', 'pasta', 'pho', ' steak'];

//*

    function renderButtons() {

        $("#buttonView").empty();

        for (var i = 0; i < food.length; i++) {
            var a = $('
')

            a.addClass('foodBtn');
            a.attr('data-name', food[i]);
			a.html('<button class="btn-lg btn-info">' + food[i] + '</button>');
            $('#buttonView').append(a);
        }
    };
//*

    function displayGif(event) {

		event.preventDefault();

        var mhmm = $(this).data('name');

        var queryURL = "http://api.giphy.com/v1/gifs/search?q=" + mhmm + "&api_key=dc6zaTOxFJmzC&limit=4";

        $.ajax({
			url: queryURL,
			method: 'GET'
		}).done(function(response){
            console.log(response);

			var results = response.data;
			console.log(results);

			$('#gif-here').empty();
			for (var r=0; r < results.length; r++){

				var imgURL = results[r].images.downsized_still.url;
				var gifDiv = $('');
				var foodImg = $('');
				gifDiv.html(foodImg);
				foodImg.addClass('image');
				foodImg.attr('src', imgURL);
				foodImg.attr('data-animatedgif', results[r].images.downsized_medium.url);
				foodImg.attr('data-stillgif', imgURL);
				foodImg.attr('data-staticimage', true);
				$('#gif-here').append(gifDiv);
				gifDiv.prepend($('
' + 'Rating: ' + results[r].rating + '
'));

			}
        });
    };

//*
	function animationOnClick() {

		if ($(this).data('staticimage') === true) {
			var animatedImage = $(this).data('animatedgif');
			$(this).attr('src', animatedImage);
			$(this).data('staticimage', false);

		} else {
			var stillImage = $(this).data('stillgif');
			$(this).attr('src', stillImage);
			$(this).data('staticimage', true);
		};

	};

    function userInputButton() {
		var foodValue = $('#foodInput').val().trim();
        food.push(foodValue);
        renderButtons();
		$('#foodInput').val(' ');

    }

    $(document).on('click', '.foodBtn', displayGif);
	renderButtons();
    $(document).on('click', '.image', animationOnClick);

	$('#searchBtn').on('click', userInputButton);

    <commit_msg>added s to http<commit_after>var food = ['sushi', 'tacos', 'burgers', 'curry rice', 'fries', 'ice cream', 'pasta', 'pho', ' steak'];

//*

    function renderButtons() {

        $("#buttonView").empty();

        for (var i = 0; i < food.length; i++) {
            var a = $('
')

            a.addClass('foodBtn');
            a.attr('data-name', food[i]);
			a.html('<button class="btn-lg btn-info">' + food[i] + '</button>');
            $('#buttonView').append(a);
        }
    };
//*

    function displayGif(event) {

		event.preventDefault();

        var mhmm = $(this).data('name');

        var queryURL = "https://api.giphy.com/v1/gifs/search?q=" + mhmm + "&api_key=dc6zaTOxFJmzC&limit=4";

        $.ajax({
			url: queryURL,
			method: 'GET'
		}).done(function(response){
            console.log(response);

			var results = response.data;
			console.log(results);

			$('#gif-here').empty();
			for (var r=0; r < results.length; r++){

				var imgURL = results[r].images.downsized_still.url;
				var gifDiv = $('');
				var foodImg = $('');
				gifDiv.html(foodImg);
				foodImg.addClass('image');
				foodImg.attr('src', imgURL);
				foodImg.attr('data-animatedgif', results[r].images.downsized_medium.url);
				foodImg.attr('data-stillgif', imgURL);
				foodImg.attr('data-staticimage', true);
				$('#gif-here').append(gifDiv);
				gifDiv.prepend($('
' + 'Rating: ' + results[r].rating + '
'));

			}
        });
    };

//*
	function animationOnClick() {

		if ($(this).data('staticimage') === true) {
			var animatedImage = $(this).data('animatedgif');
			$(this).attr('src', animatedImage);
			$(this).data('staticimage', false);

		} else {
			var stillImage = $(this).data('stillgif');
			$(this).attr('src', stillImage);
			$(this).data('staticimage', true);
		};

	};

    function userInputButton() {
		var foodValue = $('#foodInput').val().trim();
        food.push(foodValue);
        renderButtons();
		$('#foodInput').val(' ');

    }

    $(document).on('click', '.foodBtn', displayGif);
	renderButtons();
    $(document).on('click', '.image', animationOnClick);

	$('#searchBtn').on('click', userInputButton);

    <|endoftext|>


<commit_before>import mongoose from 'mongoose';
import moment from 'moment';
import { authorize, authorizedForDomain } from './auth';
import { unsetDomainIfNeeded } from './domains';
import { unsetCalendarIfNeeded } from './calendars';
import register from './register';

mongoose.Promise = global.Promise;

// /api/events

// Supporting functions for /events/resources

function eventMoments(event) {
  let result = [{
    start: moment(event.start),
    end: moment(event.end),
  }];
  if (event.times) {
    result.concat(event.times.map(time => ({
      start: moment(time.start),
      end: moment(time.end),
    })));
  }
  if (event.dates) {
    const recurrence = [];
    event.dates.forEach((date) => {
      result.forEach((time) => {
        recurrence.push({
          start: moment(date).set({
            hour: time.start.hour(),
            minute: time.start.minute(),
          }),
          end: moment(date).set({
            hour: time.end.hour(),
            minute: time.end.minute(),
          }),
        });
      });
    });
    result = result.concat(recurrence);
  }
  return result;
}

function overlapsMoments(event, moments) {
  const moments2 = eventMoments(event);
  return moments.some(moment1 => (
    moments2.some(moment2 => (
      moment1.end.isAfter(moment2.start) &&
      moment1.start.isBefore(moment2.end)
    ))
  ));
}

function overlappingEvents(event) {
  const Event = mongoose.model('Event');
  const moments = eventMoments(event);
  return Event.find({ _id: { $ne: event._id } }).exec()
  .then(events => events.filter(event2 => overlapsMoments(event2, moments)));
}

function resourceIdsWithEvents(events) {
  const resourceIdsEvents = {}; // _id => [{ _id: <event id>, name: <event name }]
  events.forEach((event2) => {
    if (event2.resourceIds) {
      event2.resourceIds.forEach((resourceId) => {
        const stringId = resourceId.toString();
        if (!resourceIdsEvents[stringId]) {
          resourceIdsEvents[stringId] = [];
        }
        resourceIdsEvents[stringId].push(
          { _id: event2._id, name: event2.name },
        );
      });
    }
  });
  return resourceIdsEvents;
}

function resourcesWithEvents(resourceIdsEvents) {
  const Resource = mongoose.model('Resource');
  return Resource.find({}).sort('name').exec()
  .then(resources => (
    // Decorate with the overlapping events used by the resources.
    resources.map((resource) => {
      // Annotated with events already using them
      const object = resource.toObject();
      object.events = resourceIdsEvents[object._id.toString()];
      return object;
    })
  ));
}

// Supporting functions for /events/unavailable-dates

function timeInHours(time) {
  const start = moment(time.start);
  const end = moment(time.end);
  return {
    start: start.hour() + (start.minute() / 60.0),
    end: end.hour() + (end.minute() / 60.0),
  };
}

function eventInHours(event) {
  let hours = [timeInHours(event)];
  if (event.times) {
    hours = hours.concat(event.times.map(timeInHours));
  }
  return hours;
}

function hoursOverlap(event2, hours) {
  const hours2 = eventInHours(event2);
  return hours.some(hour => (
    hours2.some(hour2 => (hour2.end > hour.start && hour2.start < hour.end))
  ));
}

function resourcesOverlap(event2, resourceIds) {
  return resourceIds.some(resourceId => (
    event2.resourceIds.some(resourceId2 => resourceId.equals(resourceId2))
  ));
}

function eventDates(event) {
  const dates = [event.start];
  return dates.concat(event.dates || []);
}

const unsetReferences = (data) => {
  data = unsetCalendarIfNeeded(data);
  data = unsetDomainIfNeeded(data);
  if (!data.path) {
    delete data.path;
    if (!data.$unset) {
      data.$unset = {};
    }
    data.$unset.path = '';
  }
  // remove deprecated text property
  if (!data.$unset) {
    data.$unset = {};
  }
  data.$unset.text = '';
  // remove deprecated address property
  if (!data.$unset) {
    data.$unset = {};
  }
  data.$unset.address = '';
  return data;
};

export default function (router) {
  router.post('/events/resources', (req, res) => {
    authorize(req, res)
    // Get all events that overlap this event.
    .then(() => {
      const Event = mongoose.model('Event');
      const event = new Event(req.body);
      return overlappingEvents(event);
    })
    // Collect the resourceIds they use.
    .then(resourceIdsWithEvents)
    // Get all resources and annotate with events.
    .then(resourcesWithEvents)
    .then(resources => res.status(200).json(resources))
    .catch(error => res.status(400).json(error));
  });

  router.post('/events/unavailable-dates', (req, res) => {
    authorize(req, res)
    .then(() => {
      const Event = mongoose.model('Event');
      const event = new Event(req.body);

      const hours = eventInHours(event);
      const resourceIds = event.resourceIds;

      // Find all events using the resources this event is using at the same
      // times of day.
      return Event.find({ _id: { $ne: event._id } }).exec()
      .then(events => (
        // events using a same resource
        events.filter(event2 => resourcesOverlap(event2, resourceIds))
        // events at the same time of day
        .filter(event2 => hoursOverlap(event2, hours))
        .map(eventDates)
      ));
    })
    .then((unavailableDates) => {
      let unavailableDatesMerged = [];
      unavailableDates.forEach((dates) => {
        unavailableDatesMerged = unavailableDatesMerged.concat(dates);
      });
      return unavailableDatesMerged;
    })
    .then(unavailableDates => res.status(200).json(unavailableDates))
    .catch(error => res.status(400).json(error));
  });

  register(router, {
    category: 'events',
    modelName: 'Event',
    index: {
      authorize: authorizedForDomain,
    },
    get: {
      populate: [
        { path: 'primaryEventId', select: 'name path' },
        { path: 'calendarId', select: 'name path' },
        { path: 'sections.formTemplateId',
          select: 'name',
          model: 'FormTemplate' },
        { path: 'sections.libraryId',
          select: 'name',
          model: 'Library' },
      ],
      transformOut: (doc) => {
        // convert deprecated text property to a section
        doc = doc.toObject();
        if (doc.text !== undefined) {
          if (doc.text && doc.sections.length === 0) {
            doc.sections.push({ type: 'text', text: doc.text });
          }
          delete doc.text;
        }
        // convert deprecated address property to a map
        if (doc.address !== undefined) {
          if (doc.address && doc.sections.length === 0) {
            doc.sections.push({ type: 'map', address: doc.address });
          }
          delete doc.address;
        }
        return doc;
      },
    },
    put: {
      transformIn: unsetReferences,
    },
  });
}
<commit_msg>Populate people section in events.<commit_after>import mongoose from 'mongoose';
import moment from 'moment';
import { authorize, authorizedForDomain } from './auth';
import { unsetDomainIfNeeded } from './domains';
import { unsetCalendarIfNeeded } from './calendars';
import register from './register';

mongoose.Promise = global.Promise;

// /api/events

// Supporting functions for /events/resources

function eventMoments(event) {
  let result = [{
    start: moment(event.start),
    end: moment(event.end),
  }];
  if (event.times) {
    result.concat(event.times.map(time => ({
      start: moment(time.start),
      end: moment(time.end),
    })));
  }
  if (event.dates) {
    const recurrence = [];
    event.dates.forEach((date) => {
      result.forEach((time) => {
        recurrence.push({
          start: moment(date).set({
            hour: time.start.hour(),
            minute: time.start.minute(),
          }),
          end: moment(date).set({
            hour: time.end.hour(),
            minute: time.end.minute(),
          }),
        });
      });
    });
    result = result.concat(recurrence);
  }
  return result;
}

function overlapsMoments(event, moments) {
  const moments2 = eventMoments(event);
  return moments.some(moment1 => (
    moments2.some(moment2 => (
      moment1.end.isAfter(moment2.start) &&
      moment1.start.isBefore(moment2.end)
    ))
  ));
}

function overlappingEvents(event) {
  const Event = mongoose.model('Event');
  const moments = eventMoments(event);
  return Event.find({ _id: { $ne: event._id } }).exec()
  .then(events => events.filter(event2 => overlapsMoments(event2, moments)));
}

function resourceIdsWithEvents(events) {
  const resourceIdsEvents = {}; // _id => [{ _id: <event id>, name: <event name }]
  events.forEach((event2) => {
    if (event2.resourceIds) {
      event2.resourceIds.forEach((resourceId) => {
        const stringId = resourceId.toString();
        if (!resourceIdsEvents[stringId]) {
          resourceIdsEvents[stringId] = [];
        }
        resourceIdsEvents[stringId].push(
          { _id: event2._id, name: event2.name },
        );
      });
    }
  });
  return resourceIdsEvents;
}

function resourcesWithEvents(resourceIdsEvents) {
  const Resource = mongoose.model('Resource');
  return Resource.find({}).sort('name').exec()
  .then(resources => (
    // Decorate with the overlapping events used by the resources.
    resources.map((resource) => {
      // Annotated with events already using them
      const object = resource.toObject();
      object.events = resourceIdsEvents[object._id.toString()];
      return object;
    })
  ));
}

// Supporting functions for /events/unavailable-dates

function timeInHours(time) {
  const start = moment(time.start);
  const end = moment(time.end);
  return {
    start: start.hour() + (start.minute() / 60.0),
    end: end.hour() + (end.minute() / 60.0),
  };
}

function eventInHours(event) {
  let hours = [timeInHours(event)];
  if (event.times) {
    hours = hours.concat(event.times.map(timeInHours));
  }
  return hours;
}

function hoursOverlap(event2, hours) {
  const hours2 = eventInHours(event2);
  return hours.some(hour => (
    hours2.some(hour2 => (hour2.end > hour.start && hour2.start < hour.end))
  ));
}

function resourcesOverlap(event2, resourceIds) {
  return resourceIds.some(resourceId => (
    event2.resourceIds.some(resourceId2 => resourceId.equals(resourceId2))
  ));
}

function eventDates(event) {
  const dates = [event.start];
  return dates.concat(event.dates || []);
}

const unsetReferences = (data) => {
  data = unsetCalendarIfNeeded(data);
  data = unsetDomainIfNeeded(data);
  if (!data.path) {
    delete data.path;
    if (!data.$unset) {
      data.$unset = {};
    }
    data.$unset.path = '';
  }
  // remove deprecated text property
  if (!data.$unset) {
    data.$unset = {};
  }
  data.$unset.text = '';
  // remove deprecated address property
  if (!data.$unset) {
    data.$unset = {};
  }
  data.$unset.address = '';
  return data;
};

export default function (router) {
  router.post('/events/resources', (req, res) => {
    authorize(req, res)
    // Get all events that overlap this event.
    .then(() => {
      const Event = mongoose.model('Event');
      const event = new Event(req.body);
      return overlappingEvents(event);
    })
    // Collect the resourceIds they use.
    .then(resourceIdsWithEvents)
    // Get all resources and annotate with events.
    .then(resourcesWithEvents)
    .then(resources => res.status(200).json(resources))
    .catch(error => res.status(400).json(error));
  });

  router.post('/events/unavailable-dates', (req, res) => {
    authorize(req, res)
    .then(() => {
      const Event = mongoose.model('Event');
      const event = new Event(req.body);

      const hours = eventInHours(event);
      const resourceIds = event.resourceIds;

      // Find all events using the resources this event is using at the same
      // times of day.
      return Event.find({ _id: { $ne: event._id } }).exec()
      .then(events => (
        // events using a same resource
        events.filter(event2 => resourcesOverlap(event2, resourceIds))
        // events at the same time of day
        .filter(event2 => hoursOverlap(event2, hours))
        .map(eventDates)
      ));
    })
    .then((unavailableDates) => {
      let unavailableDatesMerged = [];
      unavailableDates.forEach((dates) => {
        unavailableDatesMerged = unavailableDatesMerged.concat(dates);
      });
      return unavailableDatesMerged;
    })
    .then(unavailableDates => res.status(200).json(unavailableDates))
    .catch(error => res.status(400).json(error));
  });

  register(router, {
    category: 'events',
    modelName: 'Event',
    index: {
      authorize: authorizedForDomain,
    },
    get: {
      populate: [
        { path: 'primaryEventId', select: 'name path' },
        { path: 'calendarId', select: 'name path' },
        { path: 'sections.formTemplateId',
          select: 'name',
          model: 'FormTemplate' },
        { path: 'sections.libraryId',
          select: 'name',
          model: 'Library' },
        { path: 'sections.people.id', select: 'name image', model: 'User' },
      ],
      transformOut: (doc) => {
        // convert deprecated text property to a section
        doc = doc.toObject();
        if (doc.text !== undefined) {
          if (doc.text && doc.sections.length === 0) {
            doc.sections.push({ type: 'text', text: doc.text });
          }
          delete doc.text;
        }
        // convert deprecated address property to a map
        if (doc.address !== undefined) {
          if (doc.address && doc.sections.length === 0) {
            doc.sections.push({ type: 'map', address: doc.address });
          }
          delete doc.address;
        }
        return doc;
      },
    },
    put: {
      transformIn: unsetReferences,
    },
  });
}
<|endoftext|>


<commit_before>var request = require("request");

function XkcdPlugin(bot) {
	var self = this;
	self.name = "xkcd";
	self.help = "Xkcd plugin";
	self.depend = ["cmd", "pushbullet"];

	self.apiKey = null;
	self.chans = [];

	self.load = function(data) {
		if (data) {
			self.apiKey = data.apiKey;
			self.chans = data.chans;
		}
		bot.plugins.pushbullet.subscribe("xkcd");
	};

	self.save = function() {
		return {"apiKey": self.apiKey, "chans": self.chans};
	};

	self.xkcd = function(uri, callback) {
		request(uri + "info.0.json", function(err, res, body) {
			if (!err && res.statusCode == 200) {
				var j = JSON.parse(body);
				callback(j.title, "http://xkcd.com/" + j.num + "/");
			}
			else
				bot.out.error("xkcd", [err, body]);
		});
	};

	self.events = {
		"cmd#xkcd": function(nick, to, args) {
			if (!args[1] || /^\d+$/.test(args[1])) {
				var uri = "http://xkcd.com/";
				if (args[1])
					uri += args[1] + "/";
				self.xkcd(uri, function(title, url) {
					bot.say(to, "xkcd" + (args[1] ? " #" + args[1] : "") + ": \x02" + title + "\x02 - " + url);
				});
			}
			else if (args[1] == "random") {
				self.xkcd("http://c.xkcd.com/random/comic/", function(title, url) {
					bot.say(to, "random xkcd: \x02" + title + "\x02 - " + url);
				});
			}
			else {
				var match = args[0].match(/^(.*)\s+(\d+)\s*$/);
				var str;
				var i;
				if (match) {
					str = match[1];
					i = parseInt(match[2]);
				}
				else {
					str = args[0];
					i = 1;
				}
				str = str.trim();

				request({
						uri: "https://www.googleapis.com/customsearch/v1",
						qs: {
							key: self.apiKey,
							cx: "012652707207066138651:zudjtuwe28q",
							q: str
						}
					}, function(err, res, body) {
					if (!err && res.statusCode == 200) {
						var json = JSON.parse(body);
						if (json.items !== undefined && json.items.length !== 0) {
							if (i - 1 >= 0 && i - 1 < json.items.length) {
								var item = json.items[i - 1];
								var title = item.title.match(/^xkcd:\s+(.*)$/)[1].trim();
								bot.say(to, "xkcd '" + str + "' [" + i + "/" + json.items.length + "]: \x02" + title + "\x02 - " + item.link);
							}
							else
								bot.say(to, nick + ": '" + str + "' [" + i + "/" + json.items.length + "] invalid result index");
						}
						else
							bot.say(to, nick + ": couldn't find xkcd");
					}
				});
			}
		},

		"message": function(nick, to, text) {
			if (self.chans.indexOf(to) != -1) {
				var m = text.match(/xkcd\.com\/(\d+)/);
				if (m) {
					var uri = "http://xkcd.com/" + m[1] + "/";
					bot.out.log("xkcd", nick + " in " + to + ": " + m[0]);
					self.xkcd(uri, function(title, url) {
						bot.say(to, "xkcd" + ": \x02" + title + "\x02 - " + url);
					});
				}
			}
		},

		"pm": function(nick, text) {
			var m = text.match(/xkcd\.com\/(\d+)/);
			if (m) {
				var uri = "http://xkcd.com/" + m[1] + "/";
				bot.out.log("xkcd", nick + " in PM: " + m[0]);
				self.xkcd(uri, function(title, url) {
					bot.say(nick, "xkcd" + ": \x02" + title + "\x02 - " + url);
				});
			}
		},

		"pushbullet#subscription#xkcd": function(push) {
			var text = "new xkcd: \x02" + push.title + "\x02 - " + push.url.replace("m.", "");
			for (var i = 0; i < self.chans.length; i++) {
				bot.say(self.chans[i], text);
			}
		}
	};
}

module.exports = XkcdPlugin;
<commit_msg>xkcd: make pushbullet optional dependency<commit_after>var request = require("request");

function XkcdPlugin(bot) {
	var self = this;
	self.name = "xkcd";
	self.help = "Xkcd plugin";
	self.depend = ["cmd"];

	self.apiKey = null;
	self.chans = [];

	self.load = function(data) {
		if (data) {
			self.apiKey = data.apiKey;
			self.chans = data.chans;
		}
		if (bot.plugins.pushbullet)
			bot.plugins.pushbullet.subscribe("xkcd");
	};

	self.save = function() {
		return {"apiKey": self.apiKey, "chans": self.chans};
	};

	self.xkcd = function(uri, callback) {
		request(uri + "info.0.json", function(err, res, body) {
			if (!err && res.statusCode == 200) {
				var j = JSON.parse(body);
				callback(j.title, "http://xkcd.com/" + j.num + "/");
			}
			else
				bot.out.error("xkcd", [err, body]);
		});
	};

	self.events = {
		"cmd#xkcd": function(nick, to, args) {
			if (!args[1] || /^\d+$/.test(args[1])) {
				var uri = "http://xkcd.com/";
				if (args[1])
					uri += args[1] + "/";
				self.xkcd(uri, function(title, url) {
					bot.say(to, "xkcd" + (args[1] ? " #" + args[1] : "") + ": \x02" + title + "\x02 - " + url);
				});
			}
			else if (args[1] == "random") {
				self.xkcd("http://c.xkcd.com/random/comic/", function(title, url) {
					bot.say(to, "random xkcd: \x02" + title + "\x02 - " + url);
				});
			}
			else {
				var match = args[0].match(/^(.*)\s+(\d+)\s*$/);
				var str;
				var i;
				if (match) {
					str = match[1];
					i = parseInt(match[2]);
				}
				else {
					str = args[0];
					i = 1;
				}
				str = str.trim();

				request({
						uri: "https://www.googleapis.com/customsearch/v1",
						qs: {
							key: self.apiKey,
							cx: "012652707207066138651:zudjtuwe28q",
							q: str
						}
					}, function(err, res, body) {
					if (!err && res.statusCode == 200) {
						var json = JSON.parse(body);
						if (json.items !== undefined && json.items.length !== 0) {
							if (i - 1 >= 0 && i - 1 < json.items.length) {
								var item = json.items[i - 1];
								var title = item.title.match(/^xkcd:\s+(.*)$/)[1].trim();
								bot.say(to, "xkcd '" + str + "' [" + i + "/" + json.items.length + "]: \x02" + title + "\x02 - " + item.link);
							}
							else
								bot.say(to, nick + ": '" + str + "' [" + i + "/" + json.items.length + "] invalid result index");
						}
						else
							bot.say(to, nick + ": couldn't find xkcd");
					}
				});
			}
		},

		"message": function(nick, to, text) {
			if (self.chans.indexOf(to) != -1) {
				var m = text.match(/xkcd\.com\/(\d+)/);
				if (m) {
					var uri = "http://xkcd.com/" + m[1] + "/";
					bot.out.log("xkcd", nick + " in " + to + ": " + m[0]);
					self.xkcd(uri, function(title, url) {
						bot.say(to, "xkcd" + ": \x02" + title + "\x02 - " + url);
					});
				}
			}
		},

		"pm": function(nick, text) {
			var m = text.match(/xkcd\.com\/(\d+)/);
			if (m) {
				var uri = "http://xkcd.com/" + m[1] + "/";
				bot.out.log("xkcd", nick + " in PM: " + m[0]);
				self.xkcd(uri, function(title, url) {
					bot.say(nick, "xkcd" + ": \x02" + title + "\x02 - " + url);
				});
			}
		},

		"pushbullet#subscription#xkcd": function(push) {
			var text = "new xkcd: \x02" + push.title + "\x02 - " + push.url.replace("m.", "");
			for (var i = 0; i < self.chans.length; i++) {
				bot.say(self.chans[i], text);
			}
		}
	};
}

module.exports = XkcdPlugin;
<|endoftext|>


<commit_before>/*
 * controlCanvas is used for controlling Turtle
 * It uses the Revealing Module Pattern
 * https://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript
 *
 * For drawing and touch applications it uses CREATEJS set of libraries
 *  + EaselJS
 *  + TweenJS
 *  + SoundJS
 *  + PreloadJS
 * http://www.createjs.com/docs
*/

var controlCanvas = (function () {
    /*
	 * 																		SUBSCRIBE to controller topic
	 */
    amplify.subscribe("controller->controlCanvas", controllerMessageCallback);
    function controllerMessageCallback(message) {

    };

    /*
	 * 																		PRIVATE area
	 */
    var canvas = $('#navigation-ring-canvas');

    /*
     *  information about mouse (touch) coordinates
     */
    var coordinates = {
        x: 0,
        y: 0,
        angle: 0,
        module: 0,
        clicked: false
    };

    /*
     *  calculated speeds (in %)
     *  motor_1 - left front
     *  motor_2 - right front
     *  motor_3 - left rear
     *  motor_4 - right rear
     */
    var motorsSpeed = {
        motor_1: 0,
        motor_2: 0,
        motor_3: 0,
        motor_4: 0
    }

    /*
     *  returns touch position
     */
    function getMousePosition(canvas, event) {
        var rect = canvas.get(0).getBoundingClientRect();
        return {
            x: event.clientX - rect.left - (rect.right - rect.left) / 2,
            y: rect.bottom - event.clientY - (rect.bottom - rect.top) / 2,
        };
    }

    function getCanvasDimensions(canvas) {
        var rect = canvas.get(0).getBoundingClientRect();
        return {
            width: rect.right - rect.left,
            height: rect.bottom - rect.top
        };
    }

    function move(event) {
        if (coordinates.clicked == true) {
            updateMotors(event);
        }
    }

    function start(event) {
        coordinates.clicked = true;
        updateMotors(event);
    }

    function stop(event) {
        coordinates.clicked = false;
        stopMotors();
    }

    /*
	 * 																		EVENTS area
	 */
    canvas.mousemove(function(event) { move(event); });
    canvas[0].addEventListener("touchmove", function(event) { move(event); });

    canvas.mousedown(function(event) { start(event); });
    canvas[0].addEventListener("touchstart", function(event) { start(event); });

    canvas.mouseup(function(event) { stop(event); });
    canvas[0].addEventListener("touchend", function(event) { stop(event); });

    canvas.mouseout(function(event) {
        coordinates.clicked = false;
        stopMotors();
    });

    function updateMotors(event) {
        mousePosition = getMousePosition(canvas, event);

        var direction = -1;

        /*
        *  declare constants used to control rover
        */
        var canvasDimensions = getCanvasDimensions(canvas);
        var circleRadius = canvasDimensions.height/2;
        var emptyZoneRadius = canvasDimensions.height/10;
        var emptyZoneHeight = canvasDimensions.height/12;

        //  alternative steering method
        emptyZoneHeight = 0;

        coordinates.x = mousePosition.x;
        coordinates.y = mousePosition.y;
        coordinates.module = Math.sqrt(coordinates.x * coordinates.x + coordinates.y * coordinates.y);
        coordinates.angle = Math.asin(coordinates.y / coordinates.module) * 180 / Math.PI;

        //  calculate motors values if the appropriate zone was

        if (coordinates.module > emptyZoneRadius && coordinates.module <= circleRadius && Math.abs(coordinates.y) > emptyZoneHeight) {
            //  var a = coordinates.module / circleRadius * 100;
            //  var b = coordinates.module * (Math.sin((2 * coordinates.angle - 90) * Math.PI / 180)) / circleRadius * 100;

            //  alternative steering method
            var leftMotors;
            var rightMotors;
            //  FORWARD
            if (Math.abs(coordinates.y) > Math.abs(coordinates.x)) {
                var a = coordinates.y / circleRadius * 100;
                leftMotors = a;
                rightMotors = a;
            }
            //  TURN
            else {
                var a = -coordinates.x / circleRadius * 100;
                leftMotors = a;
                rightMotors = -a;
            }

            //  var leftMotors = (coordinates.x >= 0) ? a : b;
            //  var rightMotors = (coordinates.x >= 0) ? b : a;

            //  reverse if backward
            /*if (coordinates.y < 0) {
                leftMotors = -leftMotors;
                rightMotors = -rightMotors;
            }*/

            motorsSpeed.motor_1 = Math.round(leftMotors) * direction;
            motorsSpeed.motor_3 = Math.round(leftMotors) * direction;
            motorsSpeed.motor_2 = Math.round(rightMotors) * direction;
            motorsSpeed.motor_4 = Math.round(rightMotors) * direction;
        }
        else {
            motorsSpeed.motor_1 = 0;
            motorsSpeed.motor_2 = 0;
            motorsSpeed.motor_3 = 0;
            motorsSpeed.motor_4 = 0;
        }

        updatePowerDisplay();
    };

    function stopMotors() {
        amplify.publish("controlCanvas->port8080", "stop all motors");
        motorsSpeed.motor_1 = 0;
        motorsSpeed.motor_2 = 0;
        motorsSpeed.motor_3 = 0;
        motorsSpeed.motor_4 = 0;

        updatePowerDisplay();
    };

    function updatePowerDisplay() {
        $('#turtle-top-view-left-top-p').text(String(motorsSpeed.motor_1) + "%");
        $('#turtle-top-view-right-top-p').text(String(motorsSpeed.motor_2) + "%");
        $('#turtle-top-view-left-bottom-p').text(String(motorsSpeed.motor_3) + "%");
        $('#turtle-top-view-right-bottom-p').text(String(motorsSpeed.motor_4) + "%");
    };

    /*
	 * 																	REVEALED functions
	 */

    function isCoordinatesClickedPriv () {
        return coordinates.clicked;
    };

    function getMotorsSpeedPriv () {
        return motorsSpeed;
    };

    /*
	 * 																		PUBLIC area
	 */
    return {
        isCoordinatesClicked : isCoordinatesClickedPriv,
        getMotorsSpeed : getMotorsSpeedPriv
    };
})();<commit_msg>Touch screen works<commit_after>/*
 * controlCanvas is used for controlling Turtle
 * It uses the Revealing Module Pattern
 * https://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript
 *
 * For drawing and touch applications it uses CREATEJS set of libraries
 *  + EaselJS
 *  + TweenJS
 *  + SoundJS
 *  + PreloadJS
 * http://www.createjs.com/docs
*/

var controlCanvas = (function () {
    /*
	 * 																		SUBSCRIBE to controller topic
	 */
    amplify.subscribe("controller->controlCanvas", controllerMessageCallback);
    function controllerMessageCallback(message) {

    };

    /*
	 * 																		PRIVATE area
	 */
    var canvas = $('#navigation-ring-canvas');

    /*
     *  information about mouse (touch) coordinates
     */
    var coordinates = {
        x: 0,
        y: 0,
        angle: 0,
        module: 0,
        clicked: false
    };

    /*
     *  calculated speeds (in %)
     *  motor_1 - left front
     *  motor_2 - right front
     *  motor_3 - left rear
     *  motor_4 - right rear
     */
    var motorsSpeed = {
        motor_1: 0,
        motor_2: 0,
        motor_3: 0,
        motor_4: 0
    }

    /*
     *  returns touch position
     */
    function getMousePosition(canvas, event) {
        var rect = canvas.get(0).getBoundingClientRect();
        return {
            x: event.clientX - rect.left - (rect.right - rect.left) / 2,
            y: rect.bottom - event.clientY - (rect.bottom - rect.top) / 2,
        };
    }

    function getCanvasDimensions(canvas) {
        var rect = canvas.get(0).getBoundingClientRect();
        return {
            width: rect.right - rect.left,
            height: rect.bottom - rect.top
        };
    }

    function move(event) {
        if (coordinates.clicked == true) {
            updateMotors(event);
        }
    }

    function start(event) {
        coordinates.clicked = true;
        updateMotors(event);
    }

    function stop(event) {
        coordinates.clicked = false;
        stopMotors();
    }

    /*
	 * 																		EVENTS area
	 */
    canvas.mousemove(function(event) { move(event); });
    canvas[0].addEventListener("touchmove", function(event) {
        var touch = event.touches[0];
        var mouseEvent = new MouseEvent("mousedown", {
            clientX: touch.clientX,
            clientY: touch.clientY
        });
        canvas[0].dispatchEvent(mouseEvent);
    });

    canvas.mousedown(function(event) { start(event); });
    canvas[0].addEventListener("touchstart", function(event) {
        var touch = event.touches[0];
        var mouseEvent = new MouseEvent("mousedown", {
            clientX: touch.clientX,
            clientY: touch.clientY
        });
        canvas[0].dispatchEvent(mouseEvent);
    });

    canvas.mouseup(function(event) { stop(event); });
    canvas[0].addEventListener("touchend", function(event) { stop(event); });

    canvas.mouseout(function(event) {
        coordinates.clicked = false;
        stopMotors();
    });

    function updateMotors(event) {
        mousePosition = getMousePosition(canvas, event);
        console.log(mousePosition);

        var direction = -1;

        /*
        *  declare constants used to control rover
        */
        var canvasDimensions = getCanvasDimensions(canvas);
        var circleRadius = canvasDimensions.height/2;
        var emptyZoneRadius = canvasDimensions.height/10;
        var emptyZoneHeight = canvasDimensions.height/12;

        //  alternative steering method
        emptyZoneHeight = 0;

        coordinates.x = mousePosition.x;
        coordinates.y = mousePosition.y;
        coordinates.module = Math.sqrt(coordinates.x * coordinates.x + coordinates.y * coordinates.y);
        coordinates.angle = Math.asin(coordinates.y / coordinates.module) * 180 / Math.PI;

        //  calculate motors values if the appropriate zone was

        if (coordinates.module > emptyZoneRadius && coordinates.module <= circleRadius && Math.abs(coordinates.y) > emptyZoneHeight) {
            //  var a = coordinates.module / circleRadius * 100;
            //  var b = coordinates.module * (Math.sin((2 * coordinates.angle - 90) * Math.PI / 180)) / circleRadius * 100;

            //  alternative steering method
            var leftMotors;
            var rightMotors;
            //  FORWARD
            if (Math.abs(coordinates.y) > Math.abs(coordinates.x)) {
                var a = coordinates.y / circleRadius * 100;
                leftMotors = a;
                rightMotors = a;
            }
            //  TURN
            else {
                var a = -coordinates.x / circleRadius * 100;
                leftMotors = a;
                rightMotors = -a;
            }

            //  var leftMotors = (coordinates.x >= 0) ? a : b;
            //  var rightMotors = (coordinates.x >= 0) ? b : a;

            //  reverse if backward
            /*if (coordinates.y < 0) {
                leftMotors = -leftMotors;
                rightMotors = -rightMotors;
            }*/

            motorsSpeed.motor_1 = Math.round(leftMotors) * direction;
            motorsSpeed.motor_3 = Math.round(leftMotors) * direction;
            motorsSpeed.motor_2 = Math.round(rightMotors) * direction;
            motorsSpeed.motor_4 = Math.round(rightMotors) * direction;
        }
        else {
            motorsSpeed.motor_1 = 0;
            motorsSpeed.motor_2 = 0;
            motorsSpeed.motor_3 = 0;
            motorsSpeed.motor_4 = 0;
        }

        updatePowerDisplay();
    };

    function stopMotors() {
        amplify.publish("controlCanvas->port8080", "stop all motors");
        motorsSpeed.motor_1 = 0;
        motorsSpeed.motor_2 = 0;
        motorsSpeed.motor_3 = 0;
        motorsSpeed.motor_4 = 0;

        updatePowerDisplay();
    };

    function updatePowerDisplay() {
        $('#turtle-top-view-left-top-p').text(String(motorsSpeed.motor_1) + "%");
        $('#turtle-top-view-right-top-p').text(String(motorsSpeed.motor_2) + "%");
        $('#turtle-top-view-left-bottom-p').text(String(motorsSpeed.motor_3) + "%");
        $('#turtle-top-view-right-bottom-p').text(String(motorsSpeed.motor_4) + "%");
    };

    /*
	 * 																	REVEALED functions
	 */

    function isCoordinatesClickedPriv () {
        return coordinates.clicked;
    };

    function getMotorsSpeedPriv () {
        return motorsSpeed;
    };

    /*
	 * 																		PUBLIC area
	 */
    return {
        isCoordinatesClicked : isCoordinatesClickedPriv,
        getMotorsSpeed : getMotorsSpeedPriv
    };
})();<|endoftext|>