<commit_before>capture.scope = function (value) {
  var selector = /^([\@\.\%\#\*a-zA-Z0-9\[\]\+\~\=\"\'\_\-\:\&\n,\(\) ]+)/;
  if (value.substr(0, 2) === '//') {
    return 'comment inline';
  }
  if (value.substr(0, 2) === '/*') {
    return 'comment block';
  }
  if (/^\$[^:]+?:[^;]+?;/.test(value)) {
    return 'sass variable assignment';
  }
  if (/^(\*|)[a-z\- ]+:[^;]+?;/.test(value)) {
    return 'property group';
  }
  if (value.substring(0, 7) === '@extend') {
    return 'sass extend';
  }
  if (value.substring(0, 7) === '@import') {
    return 'sass import';
  }
  if (value.substring(0, 8) === '@include') {
    if (/^@include\s+[^ ]+?\s+\{/.test(value)) {
      return 'sass include block';
    }
    if (/^@include\s+[^ ]+?\(/.test(value)) {
      return 'sass include arguments';
    }
    return 'sass include';
  }
  if (value.substring(0, 6) === '@mixin') {
    return 'sass mixin';
  }
  if (value.substring(0, 9) === '@function') {
    return 'sass function';
  }
  if (value.substring(0, 7) === '@return') {
    return 'sass return';
  }
  if (value.substring(0, 3) === '@if') {
    return 'sass if';
  }
  if (value.substring(0, 4) === '@for') {
    return 'sass for';
  }
  if (value.substring(0, 5) === '@each') {
    return 'sass each';
  }
  if (/^@else[ ]+if/.test(value)) {
    return 'sass if';
  }
  if (value.substring(0, 5) === '@else') {
    return 'sass if';
  }
  if (value.substring(0, 10) === '@font-face') {
    return 'font face';
  }
  if (selector.test(value) && /^%|^[^\%^{]+?%[^\{]+?\{/.test(value)) {
    return 'sass placeholder';
  }
  if (value.substring(0, 6) === '@media') {
    return 'media query';
  }
  if (selector.test(value)) {
    return 'selector';
  }
  return false;
};
<commit_msg>Added more specificity to determining whether a property group is a property group by comparing it to an array of property group names.<commit_after>capture.scope = function (value) {
  var selector = /^([\@\.\%\#\*a-zA-Z0-9\[\]\+\~\=\"\'\_\-\:\&\n,\(\) ]+)/;
  if (value.substr(0, 2) === '//') {
    return 'comment inline';
  }
  if (value.substr(0, 2) === '/*') {
    return 'comment block';
  }
  if (/^\$[^:]+?:[^;]+?;/.test(value)) {
    return 'sass variable assignment';
  }
  if (/^(\*|)[a-z\- ]+:/.test(value) && list.properties.indexOf(value.split(':')[0].trim()) > -1) {
    return 'property group';
  }
  if (value.substring(0, 7) === '@extend') {
    return 'sass extend';
  }
  if (value.substring(0, 7) === '@import') {
    return 'sass import';
  }
  if (value.substring(0, 8) === '@include') {
    if (/^@include\s+[^ ]+?\s+\{/.test(value)) {
      return 'sass include block';
    }
    if (/^@include\s+[^ ]+?\(/.test(value)) {
      return 'sass include arguments';
    }
    return 'sass include';
  }
  if (value.substring(0, 6) === '@mixin') {
    return 'sass mixin';
  }
  if (value.substring(0, 9) === '@function') {
    return 'sass function';
  }
  if (value.substring(0, 7) === '@return') {
    return 'sass return';
  }
  if (value.substring(0, 3) === '@if') {
    return 'sass if';
  }
  if (value.substring(0, 4) === '@for') {
    return 'sass for';
  }
  if (value.substring(0, 5) === '@each') {
    return 'sass each';
  }
  if (/^@else[ ]+if/.test(value)) {
    return 'sass if';
  }
  if (value.substring(0, 5) === '@else') {
    return 'sass if';
  }
  if (value.substring(0, 10) === '@font-face') {
    return 'font face';
  }
  if (selector.test(value) && /^%|^[^\%^{]+?%[^\{]+?\{/.test(value)) {
    return 'sass placeholder';
  }
  if (value.substring(0, 6) === '@media') {
    return 'media query';
  }
  if (selector.test(value)) {
    return 'selector';
  }
  return false;
};
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow
import React, { PureComponent } from 'react';
import { MenuItem } from 'react-contextmenu';
import ContextMenu from '../shared/ContextMenu';
import explicitConnect from '../../utils/connect';
import { updatePreviewSelection } from '../../actions/profile-view';
import {
  getPreviewSelection,
  getCommittedRange,
} from '../../selectors/profile';
import { selectedThreadSelectors } from '../../selectors/per-thread';
import copy from 'copy-to-clipboard';

import type { Marker } from '../../types/profile-derived';
import type { StartEndRange } from '../../types/units';
import type {
  PreviewSelection,
  ImplementationFilter,
} from '../../types/actions';
import type { ConnectedProps } from '../../utils/connect';
import { getImplementationFilter } from '../../selectors/url-state';
import type { Thread, IndexIntoStackTable } from '../../types/profile';
import { filterCallNodePathByImplementation } from '../../profile-logic/transforms';
import {
  convertStackToCallNodePath,
  getFuncNamesAndOriginsForPath,
} from '../../profile-logic/profile-data';
import { getMarkerFullDescription } from '../../profile-logic/marker-data';

type StateProps = {|
  +previewSelection: PreviewSelection,
  +committedRange: StartEndRange,
  +selectedMarker: Marker | null,
  +thread: Thread,
  +implementationFilter: ImplementationFilter,
|};

type DispatchProps = {|
  +updatePreviewSelection: typeof updatePreviewSelection,
|};

type Props = ConnectedProps<{||}, StateProps, DispatchProps>;

class MarkerContextMenu extends PureComponent<Props> {
  setStartRange = () => {
    const {
      selectedMarker,
      updatePreviewSelection,
      previewSelection,
      committedRange,
    } = this.props;

    if (selectedMarker === null) {
      return;
    }

    const selectionEnd = previewSelection.hasSelection
      ? previewSelection.selectionEnd
      : committedRange.end;

    updatePreviewSelection({
      hasSelection: true,
      isModifying: false,
      selectionStart: selectedMarker.start,
      selectionEnd,
    });
  };

  setEndRange = () => {
    const {
      selectedMarker,
      updatePreviewSelection,
      committedRange,
      previewSelection,
    } = this.props;

    if (selectedMarker === null) {
      return;
    }

    const selectionStart = previewSelection.hasSelection
      ? previewSelection.selectionStart
      : committedRange.start;

    updatePreviewSelection({
      hasSelection: true,
      isModifying: false,
      selectionStart,
      // For markers without a duration, add an arbitrarily small bit of time at
      // the end to make sure the selected marker doesn't disappear from view.
      selectionEnd: selectedMarker.start + (selectedMarker.dur || 0.0001),
    });
  };

  setRangeByDuration = () => {
    const { selectedMarker, updatePreviewSelection } = this.props;

    if (selectedMarker === null) {
      return;
    }

    if (this._isZeroDurationMarker(selectedMarker)) {
      return;
    }

    updatePreviewSelection({
      hasSelection: true,
      isModifying: false,
      selectionStart: selectedMarker.start,
      selectionEnd: selectedMarker.start + selectedMarker.dur,
    });
  };

  _isZeroDurationMarker(marker: ?Marker): boolean {
    return !marker || !marker.dur;
  }

  _convertStackToString(stack: IndexIntoStackTable): string {
    const { thread, implementationFilter } = this.props;

    const callNodePath = filterCallNodePathByImplementation(
      thread,
      implementationFilter,
      convertStackToCallNodePath(thread, stack)
    );

    const funcNamesAndOrigins = getFuncNamesAndOriginsForPath(
      callNodePath,
      thread
    );
    return funcNamesAndOrigins
      .map(({ funcName, origin }) => `${funcName} [${origin}]`)
      .join('\n');
  }

  copyMarkerJSON = () => {
    const { selectedMarker } = this.props;

    if (selectedMarker === null) {
      return;
    }

    copy(JSON.stringify(selectedMarker, null, 2));
  };

  copyMarkerDescription = () => {
    const { selectedMarker } = this.props;

    if (selectedMarker === null) {
      return;
    }

    copy(getMarkerFullDescription(selectedMarker));
  };

  copyMarkerCause = () => {
    const { selectedMarker } = this.props;

    if (selectedMarker && selectedMarker.data && selectedMarker.data.cause) {
      const stack = this._convertStackToString(selectedMarker.data.cause.stack);
      copy(stack);
    }
  };

  render() {
    const { selectedMarker } = this.props;

    if (selectedMarker === null) {
      return null;
    }

    return (
      <ContextMenu id="MarkerContextMenu">
        <MenuItem onClick={this.setStartRange}>
          Set selection start time here
        </MenuItem>
        <MenuItem onClick={this.setEndRange}>
          Set selection end time here
        </MenuItem>
        <MenuItem
          onClick={this.setRangeByDuration}
          disabled={this._isZeroDurationMarker(selectedMarker)}
        >
          Set selection from duration
        </MenuItem>
        <MenuItem onClick={this.copyMarkerJSON}>Copy marker JSON</MenuItem>
        <MenuItem onClick={this.copyMarkerDescription}>
          Copy marker description
        </MenuItem>
        {selectedMarker.data && selectedMarker.data.cause ? (
          <MenuItem onClick={this.copyMarkerCause}>Copy marker cause</MenuItem>
        ) : null}
      </ContextMenu>
    );
  }
}

export default explicitConnect<{||}, StateProps, DispatchProps>({
  mapStateToProps: state => ({
    previewSelection: getPreviewSelection(state),
    committedRange: getCommittedRange(state),
    thread: selectedThreadSelectors.getThread(state),
    implementationFilter: getImplementationFilter(state),
    selectedMarker: selectedThreadSelectors.getSelectedMarker(state),
  }),
  mapDispatchToProps: { updatePreviewSelection },
  component: MarkerContextMenu,
});
<commit_msg>Make the context menu use the right clicked marker data instead of the selected marker data<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow
import React, { PureComponent } from 'react';
import { MenuItem } from 'react-contextmenu';
import ContextMenu from '../shared/ContextMenu';
import explicitConnect from '../../utils/connect';
import { updatePreviewSelection } from '../../actions/profile-view';
import {
  getPreviewSelection,
  getCommittedRange,
} from '../../selectors/profile';
import { selectedThreadSelectors } from '../../selectors/per-thread';
import copy from 'copy-to-clipboard';

import type { Marker } from '../../types/profile-derived';
import type { StartEndRange } from '../../types/units';
import type {
  PreviewSelection,
  ImplementationFilter,
} from '../../types/actions';
import type { ConnectedProps } from '../../utils/connect';
import { getImplementationFilter } from '../../selectors/url-state';
import type { Thread, IndexIntoStackTable } from '../../types/profile';
import { filterCallNodePathByImplementation } from '../../profile-logic/transforms';
import {
  convertStackToCallNodePath,
  getFuncNamesAndOriginsForPath,
} from '../../profile-logic/profile-data';
import { getMarkerFullDescription } from '../../profile-logic/marker-data';

type StateProps = {|
  +previewSelection: PreviewSelection,
  +committedRange: StartEndRange,
  +selectedMarker: Marker | null,
  +thread: Thread,
  +implementationFilter: ImplementationFilter,
|};

type DispatchProps = {|
  +updatePreviewSelection: typeof updatePreviewSelection,
|};

type Props = ConnectedProps<{||}, StateProps, DispatchProps>;

class MarkerContextMenu extends PureComponent<Props> {
  setStartRange = () => {
    const {
      selectedMarker,
      updatePreviewSelection,
      previewSelection,
      committedRange,
    } = this.props;

    if (selectedMarker === null) {
      return;
    }

    const selectionEnd = previewSelection.hasSelection
      ? previewSelection.selectionEnd
      : committedRange.end;

    updatePreviewSelection({
      hasSelection: true,
      isModifying: false,
      selectionStart: selectedMarker.start,
      selectionEnd,
    });
  };

  setEndRange = () => {
    const {
      selectedMarker,
      updatePreviewSelection,
      committedRange,
      previewSelection,
    } = this.props;

    if (selectedMarker === null) {
      return;
    }

    const selectionStart = previewSelection.hasSelection
      ? previewSelection.selectionStart
      : committedRange.start;

    updatePreviewSelection({
      hasSelection: true,
      isModifying: false,
      selectionStart,
      // For markers without a duration, add an arbitrarily small bit of time at
      // the end to make sure the selected marker doesn't disappear from view.
      selectionEnd: selectedMarker.start + (selectedMarker.dur || 0.0001),
    });
  };

  setRangeByDuration = () => {
    const { selectedMarker, updatePreviewSelection } = this.props;

    if (selectedMarker === null) {
      return;
    }

    if (this._isZeroDurationMarker(selectedMarker)) {
      return;
    }

    updatePreviewSelection({
      hasSelection: true,
      isModifying: false,
      selectionStart: selectedMarker.start,
      selectionEnd: selectedMarker.start + selectedMarker.dur,
    });
  };

  _isZeroDurationMarker(marker: ?Marker): boolean {
    return !marker || !marker.dur;
  }

  _convertStackToString(stack: IndexIntoStackTable): string {
    const { thread, implementationFilter } = this.props;

    const callNodePath = filterCallNodePathByImplementation(
      thread,
      implementationFilter,
      convertStackToCallNodePath(thread, stack)
    );

    const funcNamesAndOrigins = getFuncNamesAndOriginsForPath(
      callNodePath,
      thread
    );
    return funcNamesAndOrigins
      .map(({ funcName, origin }) => `${funcName} [${origin}]`)
      .join('\n');
  }

  copyMarkerJSON = () => {
    const { selectedMarker } = this.props;

    if (selectedMarker === null) {
      return;
    }

    copy(JSON.stringify(selectedMarker, null, 2));
  };

  copyMarkerDescription = () => {
    const { selectedMarker } = this.props;

    if (selectedMarker === null) {
      return;
    }

    copy(getMarkerFullDescription(selectedMarker));
  };

  copyMarkerCause = () => {
    const { selectedMarker } = this.props;

    if (selectedMarker && selectedMarker.data && selectedMarker.data.cause) {
      const stack = this._convertStackToString(selectedMarker.data.cause.stack);
      copy(stack);
    }
  };

  render() {
    const { selectedMarker } = this.props;

    if (selectedMarker === null) {
      return null;
    }

    return (
      <ContextMenu id="MarkerContextMenu">
        <MenuItem onClick={this.setStartRange}>
          Set selection start time here
        </MenuItem>
        <MenuItem onClick={this.setEndRange}>
          Set selection end time here
        </MenuItem>
        <MenuItem
          onClick={this.setRangeByDuration}
          disabled={this._isZeroDurationMarker(selectedMarker)}
        >
          Set selection from duration
        </MenuItem>
        <MenuItem onClick={this.copyMarkerJSON}>Copy marker JSON</MenuItem>
        <MenuItem onClick={this.copyMarkerDescription}>
          Copy marker description
        </MenuItem>
        {selectedMarker.data && selectedMarker.data.cause ? (
          <MenuItem onClick={this.copyMarkerCause}>Copy marker cause</MenuItem>
        ) : null}
      </ContextMenu>
    );
  }
}

export default explicitConnect<{||}, StateProps, DispatchProps>({
  mapStateToProps: state => ({
    previewSelection: getPreviewSelection(state),
    committedRange: getCommittedRange(state),
    thread: selectedThreadSelectors.getThread(state),
    implementationFilter: getImplementationFilter(state),
    selectedMarker: selectedThreadSelectors.getRightClickedMarker(state),
  }),
  mapDispatchToProps: { updatePreviewSelection },
  component: MarkerContextMenu,
});
<|endoftext|>


<commit_before>'use strict';

const Wikia = require('node-wikia');
const Command = require('../../models/Command.js');

const warframe = new Wikia('warframe');

/**
 * Displays mods from the wiki
 */
class Mod extends Command {
  /**
   * Constructs a callable command
   * @param {Genesis} bot  The bot object
   */
  constructor(bot) {
    super(bot, 'warframe.misc.mod', 'mod', 'Search the Warframe Wiki for a mod\'s image');
    this.regex = new RegExp('^mod(.+)', 'i');
    this.noResultStr = `${this.md.codeMulti}No result for search, Operator. Attempt another search query.${this.md.blockEnd}`;
  }

  /**
   * Run the command
   * @param {Message} message Message with a command to handle, reply to,
   *                          or perform an action based on parameters.
   * @returns {string} success status
   */
  async run(message) {
    const query = this.regex.exec(message.strippedContent.match(this.regex)[0])[1];
    if (!query) {
      this.messageManager.reply(message, this.noResultStr, true, false);
      return this.messageManager.statuses.FAILURE;
    }
    const searchJson = await warframe.getSearchList({ query, limit: 1 });
    const [{ id }] = searchJson.items;
    const detailsJson = await warframe.getArticleDetails({ ids: [id] });
    let thumbUrl = detailsJson.items[`${id}`].thumbnail;
    thumbUrl = thumbUrl ? thumbUrl.replace(/\/revision\/.*/, '') : 'https://i.imgur.com/11VCxbq.jpg';

    const list = await warframe.getArticlesList({ category: 'Mods', limit: 1000 });
    let sent = false;
    list.items.forEach((item) => {
      if (item.id === id && !sent) {
        sent = true;
        const embed = {
          title: detailsJson.items[id].title,
          url: detailsJson.basepath + detailsJson.items[id].url,
          color: 0xC0C0C0,
          description: `Mod result for ${query}`,
          image: {
            url: thumbUrl,
          },
        };
        this.messageManager.embed(message, embed, true, false);
      }
    });
    if (!sent) {
      this.messageManager.reply(message, this.noResultStr, true, false);
      return this.messageManager.statuses.FAILURE;
    }
    return this.messageManager.statuses.SUCCESS;
  }
}

module.exports = Mod;
<commit_msg>fix: testing new mod command organization<commit_after>'use strict';

const request = require('request-promise');

const Command = require('../../models/Command.js');
const BaseEmbed = require('../../embeds/BaseEmbed.js');
const PatchnotesEmbed = require('../../embeds/PatchnotesEmbed.js');
const { createPageCollector, apiBase, createGroupedArray } = require('../../CommonFunctions');

class ModEmbed extends BaseEmbed {
  constructor(bot, modData, query) {
    super();

    this.title = modData.name;
    this.color = 0xC0C0C0;
    this.description = `Mod result for ${query}`;
    this.url = `https://warfarme.wikia.com/wiki/${modData.name.replace(/\s/ig, '_'}`;
    this.image = {
      url: `https://cdn.warframestat.us/img/${modData.imageName}`,
    };
  }
}

/**
 * Displays mods from the wiki
 */
class Mod extends Command {
	/**
	 * Constructs a callable command
	 * @param {Genesis} bot  The bot object
	 */
	constructor(bot) {
		super(bot, 'warframe.misc.mod', 'mod', 'Search the Warframe Wiki for a mod\'s image');
		this.regex = new RegExp('^mod(.+)', 'i');
		this.noResultStr = `${this.md.codeMulti}No result for search, Operator. Attempt another search query.${this.md.blockEnd}`;
	}

	/**
	 * Run the command
	 * @param {Message} message Message with a command to handle, reply to,
	 *                          or perform an action based on parameters.
	 * @returns {string} success status
	 */
	async run(message) {
		const query = this.regex.exec(message.strippedContent.match(this.regex)[0])[1];
		if (!query) {
			this.messageManager.reply(message, this.noResultStr, true, false);
			return this.messageManager.statuses.FAILURE;
		}

    const options = {
      uri: `${apiBase}/mods/search/${query}`,
      json: true,
      rejectUnauthorized: false,
    };
    try {
      const results = await request(options);
      if (results.length > 0) {
        const pages = [];
        results.forEach((result) => {
          pages.push(new ModEmbed(this.bot, result, query));
          if (result.patchlogs && result.patchlogs.length) {
            createGroupedArray(result.patchlogs, 4).forEach((patchGroup) => {
              pages.push(new PatchnotesEmbed(this.bot, patchGroup));
            });
          }
        });

        const msg = await this.messageManager.embed(message, pages[0], true, false);
        await createPageCollector(msg, pages, message.author);
        return this.messageManager.statuses.SUCCESS;
      }
      this.messageManager.reply(message, this.noResultStr, true, false);
      return this.messageManager.statuses.FAILURE;
    } catch (e) {
      this.logger.error(e);
      this.messageManager.reply(message, this.noResultStr, true, false);
      return this.messageManager.statuses.FAILURE;
    }
	}
}

module.exports = Mod;
<|endoftext|>


<commit_before>/**
 * Split into declaration and initialization for better startup performance.
 */
var User = require('../models/User');
var _ = require('lodash');
var async = require('async');
var querystring = require('querystring');
var refresh = require('passport-oauth2-refresh');

var secrets = require('../config/secrets');
var google = require('googleapis');
var {downloadGoogleSpreadsheet} = require('../libs/downloadingFile');
import {genSchema} from '../libs/genSchema';

/**
* GET /api
* List of API examples.
*/
exports.getApi = function(req, res) {
 res.render('api/index', {
   title: 'API Examples'
 });
};

/**
 * GET /api/files
 */
exports.getGoogleFiles = function(req, res, next) {
  var token = _.find(req.user.tokens, { kind: 'google' });
  var retries = 2;
  var OAuth2 = google.auth.OAuth2;

  function makeRequest() {
    retries--;
    if(!retries) {
      // Couldn't refresh the access token.
      return res.status(401).end();
    }
    var oauth2Client = new OAuth2(
      secrets.google.clientID,
      secrets.google.clientSecret,
      secrets.google.callbackURL
    );
    oauth2Client.setCredentials({
      access_token: token.accessToken,
      refresh_token: token.refreshToken,
    });

    var drive = google.drive({ version: 'v2', auth: oauth2Client });

    drive.files.list({
      q: 'mimeType = \'application/vnd.google-apps.spreadsheet\''
    }, function(err, result) {
      if (err) {
        if (err.code === 401) {
          refresh.requestNewAccessToken('google', token.refreshToken, function(err, accessToken) {
            console.log(err)
            console.log(accessToken)
            if(err || !accessToken) { return res.status(401).end(); }
            token.accessToken = accessToken;
            // Save the new accessToken for future use
            User.findById(req.user, function(err, user) {
              user.tokens = user.tokens.map(t => {
                if (t.kind === 'google') {
                  return { kind: 'google', accessToken, refreshToken: t.refreshToken }
                }
                return t;
              });
              user.save(function() {
                // Retry the request.
                makeRequest();
              });
            });
          });
          return;
        }
        return next(err);
      }
      User.findById(req.user.id, function(err, user) {
        if (err) {
          return next(err);
        }
        user.googleFiles = result.items.map(f => {
          if (f.exportLinks) {
            f.exportLinks = {
              officedocument: f.exportLinks['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
            }
          }
          // var file resource = {
          //   'id': 'someRandomId',
          //   'type':
          // }
          // var watchReq = drive.files.watch({'fileId': f.id}, function(channel) {console.log('watch result:', channel);});
          // watchReq.execute();
          return f;
        });
        user.save((err) => {
          if (err) {
            return next(err);
          }
          res.render('api/files', {
            files: result.items,
          });
        });
      });
    });
  }
  makeRequest();
};

exports.getSyncedFiles = function(req, res, next) {
  User.findById(req.user.id, function(err, user) {
    if (err) {
      return next(err);
    }
    return res.render('api/synced',
      {apiFiles : user.apiFiles}
    )
  });
};

exports.unsyncFile = function(req, res, next) {
  User.findById(req.user.id, function(err, user) {
    if (err) {
      return next(err);
    }
    user.apiFiles = user.apiFiles.filter(
      f => f.id != req.params.id
    )
    user.save();
    return res.render('api/synced',
      {apiFiles : user.apiFiles}
    )
  });
};

/**
 * GET /api/file
 */
exports.getGoogleFile = function(req, res, next) {
  var fileId = req.params.file;
  var file = req.user.googleFiles.find(f => f.id === fileId);
  if (!file) { return next(new Error('no file with this id')); }
  var token = _.find(req.user.tokens, { kind: 'google' });

  var alreadyHave = req.user.apiFiles.find(f => f.id === file.id);
  if (!alreadyHave || new Date(alreadyHave.modifiedDate) !== new Date(file.modifiedDate)) {
    downloadGoogleSpreadsheet(token, file, () => {
      genSchema();
      console.log('done')
    });
    User.findById(req.user.id, function(err, user) {
      if (err) {
        return next(err);
      }
      if (alreadyHave) {
        user.apiFiles = user.apiFiles.map(f => f.id === file.id ? file : f);
      } else {
        user.apiFiles.push(file);
      }
      user.save(() => {
        res.render('api/file', {
          file,
        });
      })
    })
    return;
  }

var watchReq = google.drive.files.watch({
  'fileId': file.id,
})
var watchResp = request.exec()

  res.render('api/file', {
    file,
  });

};
<commit_msg>trying file watch<commit_after>/**
 * Split into declaration and initialization for better startup performance.
 */
var User = require('../models/User');
var _ = require('lodash');
var async = require('async');
var querystring = require('querystring');
var refresh = require('passport-oauth2-refresh');

var secrets = require('../config/secrets');
var google = require('googleapis');
var {downloadGoogleSpreadsheet} = require('../libs/downloadingFile');
import {genSchema} from '../libs/genSchema';

/**
* GET /api
* List of API examples.
*/
exports.getApi = function(req, res) {
 res.render('api/index', {
   title: 'API Examples'
 });
};

/**
 * GET /api/files
 */
exports.getGoogleFiles = function(req, res, next) {
  var token = _.find(req.user.tokens, { kind: 'google' });
  var retries = 2;
  var OAuth2 = google.auth.OAuth2;

  function makeRequest() {
    retries--;
    if(!retries) {
      // Couldn't refresh the access token.
      return res.status(401).end();
    }
    var oauth2Client = new OAuth2(
      secrets.google.clientID,
      secrets.google.clientSecret,
      secrets.google.callbackURL
    );
    oauth2Client.setCredentials({
      access_token: token.accessToken,
      refresh_token: token.refreshToken,
    });

    var drive = google.drive({ version: 'v2', auth: oauth2Client });

    drive.files.list({
      q: 'mimeType = \'application/vnd.google-apps.spreadsheet\''
    }, function(err, result) {
      if (err) {
        if (err.code === 401) {
          refresh.requestNewAccessToken('google', token.refreshToken, function(err, accessToken) {
            console.log(err)
            console.log(accessToken)
            if(err || !accessToken) { return res.status(401).end(); }
            token.accessToken = accessToken;
            // Save the new accessToken for future use
            User.findById(req.user, function(err, user) {
              user.tokens = user.tokens.map(t => {
                if (t.kind === 'google') {
                  return { kind: 'google', accessToken, refreshToken: t.refreshToken }
                }
                return t;
              });
              user.save(function() {
                // Retry the request.
                makeRequest();
              });
            });
          });
          return;
        }
        return next(err);
      }
      User.findById(req.user.id, function(err, user) {
        if (err) {
          return next(err);
        }
        user.googleFiles = result.items.map(f => {
          if (f.exportLinks) {
            f.exportLinks = {
              officedocument: f.exportLinks['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
            }
          }
          var watchReq = drive.files.watch({'fileId': f.id}, function(channel) {console.log('watch result:', channel);});

          return f;
        });
        user.save((err) => {
          if (err) {
            return next(err);
          }
          res.render('api/files', {
            files: result.items,
          });
        });
      });
    });
  }
  makeRequest();
};

exports.getSyncedFiles = function(req, res, next) {
  User.findById(req.user.id, function(err, user) {
    if (err) {
      return next(err);
    }
    return res.render('api/synced',
      {apiFiles : user.apiFiles}
    )
  });
};

exports.unsyncFile = function(req, res, next) {
  User.findById(req.user.id, function(err, user) {
    if (err) {
      return next(err);
    }
    user.apiFiles = user.apiFiles.filter(
      f => f.id != req.params.id
    )
    user.save();
    return res.render('api/synced',
      {apiFiles : user.apiFiles}
    )
  });
};

/**
 * GET /api/file
 */
exports.getGoogleFile = function(req, res, next) {
  var fileId = req.params.file;
  var file = req.user.googleFiles.find(f => f.id === fileId);
  if (!file) { return next(new Error('no file with this id')); }
  var token = _.find(req.user.tokens, { kind: 'google' });

  var alreadyHave = req.user.apiFiles.find(f => f.id === file.id);
  if (!alreadyHave || new Date(alreadyHave.modifiedDate) !== new Date(file.modifiedDate)) {
    downloadGoogleSpreadsheet(token, file, () => {
      genSchema();
      console.log('done')
    });
    User.findById(req.user.id, function(err, user) {
      if (err) {
        return next(err);
      }
      if (alreadyHave) {
        user.apiFiles = user.apiFiles.map(f => f.id === file.id ? file : f);
      } else {
        user.apiFiles.push(file);
      }
      user.save(() => {
        res.render('api/file', {
          file,
        });
      })
    })
    return;
  }

var watchReq = google.drive.files.watch({
  'fileId': file.id,
})
var watchResp = request.exec()

  res.render('api/file', {
    file,
  });

};
<|endoftext|>


<commit_before>const fs = require("fs");
const path = require("path");
const webpack = require("webpack");
const process = require("process");
const express = require("express");
const proxy = require("http-proxy-middleware");
const WebpackIsomorphicToolsPlugin = require("webpack-isomorphic-tools/plugin");
const webpackSharedConfig = require("../config/webpack-shared-config");
const detectEnvironmentVariables = require("../lib/detectEnvironmentVariables");
const getWebpackAdditions = require("../lib/getWebpackAdditions").default;
const buildWebpackEntries = require("../lib/buildWebpackEntries").default;
const { additionalLoaders, additionalPreLoaders, vendor, plugins } = getWebpackAdditions();
import { getLogger } from "../lib/server/logger";
const logger = getLogger();

let assetPath = require(path.join(process.cwd(), "src", "config", "application")).default.assetPath;
if (assetPath.substr(-1) !== "/") {
  assetPath = assetPath + "/";
}

const PORT = 8888;
const OUTPUT_PATH = path.join(process.cwd(), "build");
const OUTPUT_FILE = "app.bundle.js";
const PUBLIC_PATH = assetPath;

const webpackIsomorphicToolsPlugin = new WebpackIsomorphicToolsPlugin(require("../config/webpack-isomorphic-tools-config"))
  .development(process.env.NODE_ENV !== "production");

process.env.NODE_PATH = path.join(__dirname, "../..");
const isProduction = process.env.NODE_ENV === "production";

let environmentPlugins = [];

if (isProduction) {
  environmentPlugins = environmentPlugins.concat([
    webpackIsomorphicToolsPlugin,
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]);
}
else {
  environmentPlugins = environmentPlugins.concat([
    webpackIsomorphicToolsPlugin,
    new webpack.HotModuleReplacementPlugin(),
  ]);
}

// The config/application.js file is consumed on both the server side and the
// client side. However, we want developers to have access to environment
// constiables in there so they can override defaults with an environment
// constiable. For that reason we are going to perform static analysis on that
// file to determine all of the environment constiables that are used in that
// file and make sure that webpack makes those available in the application.
const configEnvVariables = detectEnvironmentVariables(path.join(process.cwd(), "src", "config", "application.js"));
configEnvVariables.push("NODE_ENV");
const exposedEnvironmentVariables = {};
configEnvVariables.forEach((v) => {
  exposedEnvironmentVariables[v] = JSON.stringify(process.env[v]);
});

const compiler = webpack({
  context: process.cwd(),
  devtool: isProduction ? null : "cheap-module-eval-source-map",
  entry: {
    ...buildWebpackEntries(isProduction),
    vendor: vendor
  },
  module: {
    loaders: [
    ].concat(webpackSharedConfig.loaders, additionalLoaders),
    preLoaders: [
    // only place client specific preLoaders here
    ].concat(webpackSharedConfig.preLoaders, additionalPreLoaders),
  },
  node: {
    fs: "empty"
  },
  output: {
    path: OUTPUT_PATH,
    filename: `[name]-${OUTPUT_FILE}`,
    chunkFilename: `[name]-chunk-${OUTPUT_FILE}`,
    publicPath: PUBLIC_PATH
  },
  plugins: [
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.NoErrorsPlugin(),
    new webpack.DefinePlugin({
      "process.env": exposedEnvironmentVariables
    }),
    new webpack.IgnorePlugin(/\.server(\.js)?$/),
    new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.bundle.js"),
    new webpack.optimize.CommonsChunkPlugin("commons", "commons.bundle.js"),
    new webpack.optimize.AggressiveMergingPlugin()
  ].concat(environmentPlugins, webpackSharedConfig.plugins, plugins),
  resolve: {
    ...webpackSharedConfig.resolve
  }
});

module.exports = function (buildOnly) {
  if (!buildOnly && !isProduction) {
    const app = express();
    app.use(require("webpack-dev-middleware")(compiler, {
      noInfo: true,
      publicPath: PUBLIC_PATH
    }));
    app.use(require("webpack-hot-middleware")(compiler));

    // Proxy http requests from server to client in development mode
    app.use(proxy({
      changeOrigin: false,
      target: "http://localhost:8880",
      logLevel: logger.level,
      logProvider: () => {
        return logger;
      },
      onError: (err, req, res) => {
        // When the client is restarting, show our polling message
        res.status(200).sendFile("poll.html", {root: path.join(__dirname, "../lib")});
      }
    }));

    app.listen(PORT, "localhost", function (error) {
      if (error) {
        logger.error(error);
        return;
      }

      logger.info(`Server running on http://localhost:${PORT}`);
    });
  }
  else {
    logger.info("Bundling assets…");
    compiler.run((error, stats) => {
      fs.writeFileSync("webpack-bundle-stats.json", JSON.stringify(stats.toJson()));
      const errors = stats.toJson().errors;
      if (errors.length) {
        errors.forEach((e) => {
          logger.error(e);
        });
        return;
      }

      logger.info("Assets have been prepared for production.");
      logger.info("Assets can be served from the \"/assets\" route but it is recommended that you serve the generated \"build\" folder from a Content Delivery Network");
    });
  }
};

<commit_msg>improve server only file support<commit_after>const fs = require("fs");
const path = require("path");
const webpack = require("webpack");
const process = require("process");
const express = require("express");
const proxy = require("http-proxy-middleware");
const WebpackIsomorphicToolsPlugin = require("webpack-isomorphic-tools/plugin");
const webpackSharedConfig = require("../config/webpack-shared-config");
const detectEnvironmentVariables = require("../lib/detectEnvironmentVariables");
const getWebpackAdditions = require("../lib/getWebpackAdditions").default;
const buildWebpackEntries = require("../lib/buildWebpackEntries").default;
const { additionalLoaders, additionalPreLoaders, vendor, plugins } = getWebpackAdditions();
import { getLogger } from "../lib/server/logger";
const logger = getLogger();

let assetPath = require(path.join(process.cwd(), "src", "config", "application")).default.assetPath;
if (assetPath.substr(-1) !== "/") {
  assetPath = assetPath + "/";
}

const PORT = 8888;
const OUTPUT_PATH = path.join(process.cwd(), "build");
const OUTPUT_FILE = "app.bundle.js";
const PUBLIC_PATH = assetPath;

const webpackIsomorphicToolsPlugin = new WebpackIsomorphicToolsPlugin(require("../config/webpack-isomorphic-tools-config"))
  .development(process.env.NODE_ENV !== "production");

process.env.NODE_PATH = path.join(__dirname, "../..");
const isProduction = process.env.NODE_ENV === "production";

let environmentPlugins = [];

if (isProduction) {
  environmentPlugins = environmentPlugins.concat([
    webpackIsomorphicToolsPlugin,
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]);
}
else {
  environmentPlugins = environmentPlugins.concat([
    webpackIsomorphicToolsPlugin,
    new webpack.HotModuleReplacementPlugin(),
  ]);
}

// The config/application.js file is consumed on both the server side and the
// client side. However, we want developers to have access to environment
// constiables in there so they can override defaults with an environment
// constiable. For that reason we are going to perform static analysis on that
// file to determine all of the environment constiables that are used in that
// file and make sure that webpack makes those available in the application.
const configEnvVariables = detectEnvironmentVariables(path.join(process.cwd(), "src", "config", "application.js"));
configEnvVariables.push("NODE_ENV");
const exposedEnvironmentVariables = {};
configEnvVariables.forEach((v) => {
  exposedEnvironmentVariables[v] = JSON.stringify(process.env[v]);
});

const compiler = webpack({
  context: process.cwd(),
  devtool: isProduction ? null : "cheap-module-eval-source-map",
  entry: {
    ...buildWebpackEntries(isProduction),
    vendor: vendor
  },
  module: {
    loaders: [
    ].concat(webpackSharedConfig.loaders, additionalLoaders),
    preLoaders: [
    // only place client specific preLoaders here
    ].concat(webpackSharedConfig.preLoaders, additionalPreLoaders),
  },
  node: {
    fs: "empty"
  },
  output: {
    path: OUTPUT_PATH,
    filename: `[name]-${OUTPUT_FILE}`,
    chunkFilename: `[name]-chunk-${OUTPUT_FILE}`,
    publicPath: PUBLIC_PATH
  },
  plugins: [
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.NoErrorsPlugin(),
    new webpack.DefinePlugin({
      "process.env": exposedEnvironmentVariables
    }),

    // Make it so *.server.js files return empty function in client
    new webpack.NormalModuleReplacementPlugin(/\.server(\.js)?$/, () => {}),

    new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.bundle.js"),
    new webpack.optimize.CommonsChunkPlugin("commons", "commons.bundle.js"),
    new webpack.optimize.AggressiveMergingPlugin()
  ].concat(environmentPlugins, webpackSharedConfig.plugins, plugins),
  resolve: {
    ...webpackSharedConfig.resolve
  }
});

module.exports = function (buildOnly) {
  if (!buildOnly && !isProduction) {
    const app = express();
    app.use(require("webpack-dev-middleware")(compiler, {
      noInfo: true,
      publicPath: PUBLIC_PATH
    }));
    app.use(require("webpack-hot-middleware")(compiler));

    // Proxy http requests from server to client in development mode
    app.use(proxy({
      changeOrigin: false,
      target: "http://localhost:8880",
      logLevel: logger.level,
      logProvider: () => {
        return logger;
      },
      onError: (err, req, res) => {
        // When the client is restarting, show our polling message
        res.status(200).sendFile("poll.html", {root: path.join(__dirname, "../lib")});
      }
    }));

    app.listen(PORT, "localhost", function (error) {
      if (error) {
        logger.error(error);
        return;
      }

      logger.info(`Server running on http://localhost:${PORT}`);
    });
  }
  else {
    logger.info("Bundling assets…");
    compiler.run((error, stats) => {
      fs.writeFileSync("webpack-bundle-stats.json", JSON.stringify(stats.toJson()));
      const errors = stats.toJson().errors;
      if (errors.length) {
        errors.forEach((e) => {
          logger.error(e);
        });
        return;
      }

      logger.info("Assets have been prepared for production.");
      logger.info("Assets can be served from the \"/assets\" route but it is recommended that you serve the generated \"build\" folder from a Content Delivery Network");
    });
  }
};

<|endoftext|>


<commit_before>import template from '../templates/button.html';
import { severity } from '../meta';

function unCapitalizeFirstLetter(string) {
    return string.charAt(0).toLowerCase() + string.slice(1);
}

export default Marionette.View.extend({
    template: Handlebars.compile(template),

    templateContext() {
        return {
            isMobile: this.options.mode === 'Mobile',
            showName: (this.options.showName || !this.model.get('iconClass')) && this.model.get('name')
        };
    },

    attributes() {
        return {
            tabindex: 0,
            title: this.model.get('description') || ''
        };
    },

    className() {
        const severityLevel = this.model.get('severity');
        const severityItem = severity[severityLevel] || severity.None;
        const type = this.model.get('type');
        const typeClass = typeof type === 'string' ? unCapitalizeFirstLetter(type) : 'withoutType';

        return `${severityItem.class} ${this.model.get('class') || ''} toolbar-btn_${typeClass}`;
    }
});
<commit_msg>ButtonView: Fallback to name for title was added.<commit_after>import template from '../templates/button.html';
import { severity } from '../meta';

function unCapitalizeFirstLetter(string) {
    return string.charAt(0).toLowerCase() + string.slice(1);
}

export default Marionette.View.extend({
    template: Handlebars.compile(template),

    templateContext() {
        return {
            isMobile: this.options.mode === 'Mobile',
            showName: (this.options.showName || !this.model.get('iconClass')) && this.model.get('name')
        };
    },

    attributes() {
        return {
            tabindex: 0,
            title: this.model.get('description') || this.model.get('name') || ''
        };
    },

    className() {
        const severityLevel = this.model.get('severity');
        const severityItem = severity[severityLevel] || severity.None;
        const type = this.model.get('type');
        const typeClass = typeof type === 'string' ? unCapitalizeFirstLetter(type) : 'withoutType';

        return `${severityItem.class} ${this.model.get('class') || ''} toolbar-btn_${typeClass}`;
    }
});
<|endoftext|>


<commit_before>/**
 * dirPagination - AngularJS module for paginating (almost) anything.
 *
 *
 * Credits
 * =======
 *
 * Daniel Tabuenca: https://groups.google.com/d/msg/angular/an9QpzqIYiM/r8v-3W1X5vcJ
 * for the idea on how to dynamically invoke the ng-repeat directive.
 *
 * I borrowed a couple of lines and a few attribute names from the AngularUI Bootstrap project:
 * https://github.com/angular-ui/bootstrap/blob/master/src/pagination/pagination.js
 *
 * Copyright 2014 Michael Bromley <michael@michaelbromley.co.uk>
 */

(function() {

    /**
     * Config
     */
    var moduleName = 'angularUtils.directives.dirPagination';
    var templatePath = 'directives/pagination/dirPagination.tpl.html';

    /**
     * Module
     */
    var module;
    try {
        module = angular.module(moduleName);
    } catch(err) {
        // named module does not exist, so create one
        module = angular.module(moduleName, []);
    }

    module.directive('dirPaginate', ['$compile', '$parse', '$timeout', 'paginationService', function($compile, $parse, $timeout, paginationService) {
        return  {
            terminal: true,
            compile: function(element, attrs){
                attrs.$set('ngRepeat', attrs.dirPaginate); // Add ng-repeat to the dom element
                element.removeAttr(attrs.$attr.dirPaginate); // Remove the dir-paginate attribute to prevent infinite recursion of compilation

                var expression = attrs.dirPaginate;
                // regex taken directly from https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js#L211
                var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);

                var filterPattern = /\|\s*itemsPerPage:[^|]*/;
                if (match[2].match(filterPattern) === null) {
                    throw 'pagination directive: the \'itemsPerPage\' filter must be set.';
                }
                var itemsPerPageFilterRemoved = match[2].replace(filterPattern, '');
                var collectionGetter = $parse(itemsPerPageFilterRemoved);

                return function(scope, element, attrs){
                    var paginationId;
                    var compiled =  $compile(element); // we manually compile the element again, as we have now swapped dir-paginate for an ng-repeat

                    paginationId = attrs.paginationId || '__default';
                    paginationService.registerInstance(paginationId);

                    var currentPageGetter;
                    if (attrs.currentPage) {
                        currentPageGetter = $parse(attrs.currentPage);
                    } else {
                        // if the current-page attribute was not set, we'll make our own
                        var defaultCurrentPage = paginationId + '__currentPage';
                        scope[defaultCurrentPage] = 1;
                        currentPageGetter = $parse(defaultCurrentPage);
                    }
                    paginationService.setCurrentPageParser(paginationId, currentPageGetter, scope);

                    if (typeof attrs.totalItems !== 'undefined') {
                        paginationService.setAsyncModeTrue(paginationId);
                        scope.$watch(function() {
                            return $parse(attrs.totalItems)(scope);
                        }, function (result) {
                            if (0 < result) {
                                paginationService.setCollectionLength(paginationId, result);
                            }
                        });
                    } else {
                        scope.$watchCollection(function() {
                            return collectionGetter(scope);
                        }, function(collection) {
                            if (collection) {
                                paginationService.setCollectionLength(paginationId, collection.length);
                            }
                        });
                    }

                    // Delegate to the link function returned by the new compilation of the ng-repeat
                    compiled(scope);
                };
            }
        };
    }]);

    module.directive('dirPaginationControls', ['paginationService', function(paginationService) {
        var numberRegex = /^\d+$/;
        /**
         * Generate an array of page numbers (or the '...' string) which is used in an ng-repeat to generate the
         * links used in pagination
         *
         * @param currentPage
         * @param rowsPerPage
         * @param paginationRange
         * @param collectionLength
         * @returns {Array}
         */
        function generatePagesArray(currentPage, collectionLength, rowsPerPage, paginationRange) {
            var pages = [];
            var totalPages = Math.ceil(collectionLength / rowsPerPage);
            var halfWay = Math.ceil(paginationRange / 2);
            var position;

            if (currentPage <= halfWay) {
                position = 'start';
            } else if (totalPages - halfWay < currentPage) {
                position = 'end';
            } else {
                position = 'middle';
            }

            var ellipsesNeeded = paginationRange < totalPages;
            var i = 1;
            while (i <= totalPages && i <= paginationRange) {
                var pageNumber = calculatePageNumber(i, currentPage, paginationRange, totalPages);

                var openingEllipsesNeeded = (i === 2 && (position === 'middle' || position === 'end'));
                var closingEllipsesNeeded = (i === paginationRange - 1 && (position === 'middle' || position === 'start'));
                if (ellipsesNeeded && (openingEllipsesNeeded || closingEllipsesNeeded)) {
                    pages.push('...');
                } else {
                    pages.push(pageNumber);
                }
                i ++;
            }
            return pages;
        }

        /**
         * Given the position in the sequence of pagination links [i], figure out what page number corresponds to that position.
         *
         * @param i
         * @param currentPage
         * @param paginationRange
         * @param totalPages
         * @returns {*}
         */
        function calculatePageNumber(i, currentPage, paginationRange, totalPages) {
            var halfWay = Math.ceil(paginationRange/2);
            if (i === paginationRange) {
                return totalPages;
            } else if (i === 1) {
                return i;
            } else if (paginationRange < totalPages) {
                if (totalPages - halfWay < currentPage) {
                    return totalPages - paginationRange + i;
                } else if (halfWay < currentPage) {
                    return currentPage - halfWay + i;
                } else {
                    return i;
                }
            } else {
                return i;
            }
        }

        return {
            restrict: 'AE',
            templateUrl: function(elem, attrs) {
                return attrs.templateUrl || templatePath;
            },
            scope: {
                maxSize: '=?',
                onPageChange: '&?'
            },
            link: function(scope, element, attrs) {
                var paginationId;
                paginationId = attrs.paginationId || '__default';
                if (!scope.maxSize) { scope.maxSize = 9; }
                scope.directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$parent.$eval(attrs.directionLinks) : true;
                scope.boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$parent.$eval(attrs.boundaryLinks) : false;

                if (!paginationService.isRegistered(paginationId)) {
                    var idMessage = (paginationId !== '__default') ? ' (id: ' + paginationId + ') ' : ' ';
                    throw 'pagination directive: the pagination controls' + idMessage + 'cannot be used without the corresponding pagination directive.';
                }

                var paginationRange = Math.max(scope.maxSize, 5);
                scope.pages = [];
                scope.pagination = {
                    last: 1,
                    current: 1
                };

                scope.$watch(function() {
                    return (paginationService.getCollectionLength(paginationId) + 1) * paginationService.getItemsPerPage(paginationId);
                }, function(length) {
                    if (0 < length) {
                        generatePagination();
                    }
                });

                scope.$watch(function() {
                    return paginationService.getCurrentPage(paginationId);
                }, function(currentPage) {
                    goToPage(currentPage);
                });

                scope.setCurrent = function(num) {
                    if (isValidPageNumber(num)) {
                        paginationService.setCurrentPage(paginationId, num);
                    }
                };

                function goToPage(num) {
                    if (isValidPageNumber(num)) {
                        scope.pages = generatePagesArray(num, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange);
                        scope.pagination.current = num;

                        // if a callback has been set, then call it with the page number as an argument
                        if (scope.onPageChange) {
                            scope.onPageChange({ newPageNumber : num });
                        }
                    }
                }

                function generatePagination() {
                    scope.pages = generatePagesArray(1, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange);
                    scope.pagination.current = parseInt(paginationService.getCurrentPage(paginationId));
                    scope.pagination.last = scope.pages[scope.pages.length - 1];
                    if (scope.pagination.last < scope.pagination.current) {
                        scope.setCurrent(scope.pagination.last);
                    }
                }

                function isValidPageNumber(num) {
                    return (numberRegex.test(num) && (0 < num && num <= scope.pagination.last));
                }
            }
        };
    }]);

    module.filter('itemsPerPage', ['paginationService', function(paginationService) {
        return function(collection, itemsPerPage, paginationId) {
            if (typeof (paginationId) === 'undefined') {
                paginationId = '__default';
            }
            if (!paginationService.isRegistered(paginationId)) {
                throw 'pagination directive: the itemsPerPage id argument (id: ' + paginationId + ') does not match a registered pagination-id.';
            }
            var end;
            var start;
            if (collection instanceof Array) {
                itemsPerPage = parseInt(itemsPerPage) || 9999999999;
                if (paginationService.isAsyncMode(paginationId)) {
                    start = 0;
                } else {
                    start = (paginationService.getCurrentPage(paginationId) - 1) * itemsPerPage;
                }
                end = start + itemsPerPage;
                paginationService.setItemsPerPage(paginationId, itemsPerPage);

                return collection.slice(start, end);
            } else {
                return collection;
            }
        };
    }]);

    module.service('paginationService', function() {
        var instances = {};
        var lastRegisteredInstance;
        this.paginationDirectiveInitialized = false;

        this.registerInstance = function(instanceId) {
            if (typeof instances[instanceId] === 'undefined') {
                instances[instanceId] = {
                    asyncMode: false
                };
                lastRegisteredInstance = instanceId;
            }
        };

        this.isRegistered = function(instanceId) {
            return (typeof instances[instanceId] !== 'undefined');
        };

        this.getLastInstanceId = function() {
            return lastRegisteredInstance;
        };

        this.setCurrentPageParser = function(instanceId, val, scope) {
            instances[instanceId].currentPageParser = val;
            instances[instanceId].context = scope;
        };
        this.setCurrentPage = function(instanceId, val) {
            instances[instanceId].currentPageParser.assign(instances[instanceId].context, val);
        };
        this.getCurrentPage = function(instanceId) {
            return instances[instanceId].currentPageParser(instances[instanceId].context);
        };

        this.setItemsPerPage = function(instanceId, val) {
            instances[instanceId].itemsPerPage = val;
        };
        this.getItemsPerPage = function(instanceId) {
            return instances[instanceId].itemsPerPage;
        };

        this.setCollectionLength = function(instanceId, val) {
            instances[instanceId].collectionLength = val;
        };
        this.getCollectionLength = function(instanceId) {
            return instances[instanceId].collectionLength;
        };

        this.setAsyncModeTrue = function(instanceId) {
            instances[instanceId].asyncMode = true;
        };

        this.isAsyncMode = function(instanceId) {
            return instances[instanceId].asyncMode;
        };
    });
})();
<commit_msg>Fix issue 46<commit_after>/**
 * dirPagination - AngularJS module for paginating (almost) anything.
 *
 *
 * Credits
 * =======
 *
 * Daniel Tabuenca: https://groups.google.com/d/msg/angular/an9QpzqIYiM/r8v-3W1X5vcJ
 * for the idea on how to dynamically invoke the ng-repeat directive.
 *
 * I borrowed a couple of lines and a few attribute names from the AngularUI Bootstrap project:
 * https://github.com/angular-ui/bootstrap/blob/master/src/pagination/pagination.js
 *
 * Copyright 2014 Michael Bromley <michael@michaelbromley.co.uk>
 */

(function() {

    /**
     * Config
     */
    var moduleName = 'angularUtils.directives.dirPagination';
    var templatePath = 'directives/pagination/dirPagination.tpl.html';

    /**
     * Module
     */
    var module;
    try {
        module = angular.module(moduleName);
    } catch(err) {
        // named module does not exist, so create one
        module = angular.module(moduleName, []);
    }

    module.directive('dirPaginate', ['$compile', '$parse', '$timeout', 'paginationService', function($compile, $parse, $timeout, paginationService) {
        return  {
            terminal: true,
            compile: function(element, attrs){
                attrs.$set('ngRepeat', attrs.dirPaginate); // Add ng-repeat to the dom element
                element.removeAttr(attrs.$attr.dirPaginate); // Remove the dir-paginate attribute to prevent infinite recursion of compilation

                var expression = attrs.dirPaginate;
                // regex taken directly from https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js#L211
                var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);

                var filterPattern = /\|\s*itemsPerPage:[^|]*/;
                if (match[2].match(filterPattern) === null) {
                    throw 'pagination directive: the \'itemsPerPage\' filter must be set.';
                }
                var itemsPerPageFilterRemoved = match[2].replace(filterPattern, '');
                var collectionGetter = $parse(itemsPerPageFilterRemoved);

                return function(scope, element, attrs){
                    var paginationId;
                    var compiled =  $compile(element); // we manually compile the element again, as we have now swapped dir-paginate for an ng-repeat

                    paginationId = attrs.paginationId || '__default';
                    paginationService.registerInstance(paginationId);

                    var currentPageGetter;
                    if (attrs.currentPage) {
                        currentPageGetter = $parse(attrs.currentPage);
                    } else {
                        // if the current-page attribute was not set, we'll make our own
                        var defaultCurrentPage = paginationId + '__currentPage';
                        scope[defaultCurrentPage] = 1;
                        currentPageGetter = $parse(defaultCurrentPage);
                    }
                    paginationService.setCurrentPageParser(paginationId, currentPageGetter, scope);

                    if (typeof attrs.totalItems !== 'undefined') {
                        paginationService.setAsyncModeTrue(paginationId);
                        scope.$watch(function() {
                            return $parse(attrs.totalItems)(scope);
                        }, function (result) {
                            if (0 <= result) {
                                paginationService.setCollectionLength(paginationId, result);
                            }
                        });
                    } else {
                        scope.$watchCollection(function() {
                            return collectionGetter(scope);
                        }, function(collection) {
                            if (collection) {
                                paginationService.setCollectionLength(paginationId, collection.length);
                            }
                        });
                    }

                    // Delegate to the link function returned by the new compilation of the ng-repeat
                    compiled(scope);
                };
            }
        };
    }]);

    module.directive('dirPaginationControls', ['paginationService', function(paginationService) {
        var numberRegex = /^\d+$/;
        /**
         * Generate an array of page numbers (or the '...' string) which is used in an ng-repeat to generate the
         * links used in pagination
         *
         * @param currentPage
         * @param rowsPerPage
         * @param paginationRange
         * @param collectionLength
         * @returns {Array}
         */
        function generatePagesArray(currentPage, collectionLength, rowsPerPage, paginationRange) {
            var pages = [];
            var totalPages = Math.ceil(collectionLength / rowsPerPage);
            var halfWay = Math.ceil(paginationRange / 2);
            var position;

            if (currentPage <= halfWay) {
                position = 'start';
            } else if (totalPages - halfWay < currentPage) {
                position = 'end';
            } else {
                position = 'middle';
            }

            var ellipsesNeeded = paginationRange < totalPages;
            var i = 1;
            while (i <= totalPages && i <= paginationRange) {
                var pageNumber = calculatePageNumber(i, currentPage, paginationRange, totalPages);

                var openingEllipsesNeeded = (i === 2 && (position === 'middle' || position === 'end'));
                var closingEllipsesNeeded = (i === paginationRange - 1 && (position === 'middle' || position === 'start'));
                if (ellipsesNeeded && (openingEllipsesNeeded || closingEllipsesNeeded)) {
                    pages.push('...');
                } else {
                    pages.push(pageNumber);
                }
                i ++;
            }
            return pages;
        }

        /**
         * Given the position in the sequence of pagination links [i], figure out what page number corresponds to that position.
         *
         * @param i
         * @param currentPage
         * @param paginationRange
         * @param totalPages
         * @returns {*}
         */
        function calculatePageNumber(i, currentPage, paginationRange, totalPages) {
            var halfWay = Math.ceil(paginationRange/2);
            if (i === paginationRange) {
                return totalPages;
            } else if (i === 1) {
                return i;
            } else if (paginationRange < totalPages) {
                if (totalPages - halfWay < currentPage) {
                    return totalPages - paginationRange + i;
                } else if (halfWay < currentPage) {
                    return currentPage - halfWay + i;
                } else {
                    return i;
                }
            } else {
                return i;
            }
        }

        return {
            restrict: 'AE',
            templateUrl: function(elem, attrs) {
                return attrs.templateUrl || templatePath;
            },
            scope: {
                maxSize: '=?',
                onPageChange: '&?'
            },
            link: function(scope, element, attrs) {
                var paginationId;
                paginationId = attrs.paginationId || '__default';
                if (!scope.maxSize) { scope.maxSize = 9; }
                scope.directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$parent.$eval(attrs.directionLinks) : true;
                scope.boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$parent.$eval(attrs.boundaryLinks) : false;

                if (!paginationService.isRegistered(paginationId)) {
                    var idMessage = (paginationId !== '__default') ? ' (id: ' + paginationId + ') ' : ' ';
                    throw 'pagination directive: the pagination controls' + idMessage + 'cannot be used without the corresponding pagination directive.';
                }

                var paginationRange = Math.max(scope.maxSize, 5);
                scope.pages = [];
                scope.pagination = {
                    last: 1,
                    current: 1
                };

                scope.$watch(function() {
                    return (paginationService.getCollectionLength(paginationId) + 1) * paginationService.getItemsPerPage(paginationId);
                }, function(length) {
                    if (0 < length) {
                        generatePagination();
                    }
                });

                scope.$watch(function() {
                    return paginationService.getCurrentPage(paginationId);
                }, function(currentPage) {
                    goToPage(currentPage);
                });

                scope.setCurrent = function(num) {
                    if (isValidPageNumber(num)) {
                        paginationService.setCurrentPage(paginationId, num);
                    }
                };

                function goToPage(num) {
                    if (isValidPageNumber(num)) {
                        scope.pages = generatePagesArray(num, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange);
                        scope.pagination.current = num;

                        // if a callback has been set, then call it with the page number as an argument
                        if (scope.onPageChange) {
                            scope.onPageChange({ newPageNumber : num });
                        }
                    }
                }

                function generatePagination() {
                    scope.pages = generatePagesArray(1, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange);
                    scope.pagination.current = parseInt(paginationService.getCurrentPage(paginationId));
                    scope.pagination.last = scope.pages[scope.pages.length - 1];
                    if (scope.pagination.last < scope.pagination.current) {
                        scope.setCurrent(scope.pagination.last);
                    }
                }

                function isValidPageNumber(num) {
                    return (numberRegex.test(num) && (0 < num && num <= scope.pagination.last));
                }
            }
        };
    }]);

    module.filter('itemsPerPage', ['paginationService', function(paginationService) {
        return function(collection, itemsPerPage, paginationId) {
            if (typeof (paginationId) === 'undefined') {
                paginationId = '__default';
            }
            if (!paginationService.isRegistered(paginationId)) {
                throw 'pagination directive: the itemsPerPage id argument (id: ' + paginationId + ') does not match a registered pagination-id.';
            }
            var end;
            var start;
            if (collection instanceof Array) {
                itemsPerPage = parseInt(itemsPerPage) || 9999999999;
                if (paginationService.isAsyncMode(paginationId)) {
                    start = 0;
                } else {
                    start = (paginationService.getCurrentPage(paginationId) - 1) * itemsPerPage;
                }
                end = start + itemsPerPage;
                paginationService.setItemsPerPage(paginationId, itemsPerPage);

                return collection.slice(start, end);
            } else {
                return collection;
            }
        };
    }]);

    module.service('paginationService', function() {
        var instances = {};
        var lastRegisteredInstance;
        this.paginationDirectiveInitialized = false;

        this.registerInstance = function(instanceId) {
            if (typeof instances[instanceId] === 'undefined') {
                instances[instanceId] = {
                    asyncMode: false
                };
                lastRegisteredInstance = instanceId;
            }
        };

        this.isRegistered = function(instanceId) {
            return (typeof instances[instanceId] !== 'undefined');
        };

        this.getLastInstanceId = function() {
            return lastRegisteredInstance;
        };

        this.setCurrentPageParser = function(instanceId, val, scope) {
            instances[instanceId].currentPageParser = val;
            instances[instanceId].context = scope;
        };
        this.setCurrentPage = function(instanceId, val) {
            instances[instanceId].currentPageParser.assign(instances[instanceId].context, val);
        };
        this.getCurrentPage = function(instanceId) {
            return instances[instanceId].currentPageParser(instances[instanceId].context);
        };

        this.setItemsPerPage = function(instanceId, val) {
            instances[instanceId].itemsPerPage = val;
        };
        this.getItemsPerPage = function(instanceId) {
            return instances[instanceId].itemsPerPage;
        };

        this.setCollectionLength = function(instanceId, val) {
            instances[instanceId].collectionLength = val;
        };
        this.getCollectionLength = function(instanceId) {
            return instances[instanceId].collectionLength;
        };

        this.setAsyncModeTrue = function(instanceId) {
            instances[instanceId].asyncMode = true;
        };

        this.isAsyncMode = function(instanceId) {
            return instances[instanceId].asyncMode;
        };
    });
})();
<|endoftext|>


<commit_before>#!/usr/bin/env node

child_process = require('child_process');

var log = function() {
	var args = Array.prototype.map.call(arguments, function(value) {
		if (typeof value === 'string') {
			return value;
		} else {
			return JSON.stringify(value, null, '\t')
		}
	});
	process.stdout.write(args.join('') + '\n');
}

module.exports = function(context) {
	var fs = context.requireCordovaModule('fs');
	var path = context.requireCordovaModule('path');
	var deferral = context.requireCordovaModule('q').defer();
	var async = context.requireCordovaModule(path.join('request', 'node_modules', 'form-data', 'node_modules', 'async'));
	var XmlHelpers = context.requireCordovaModule("cordova-lib/src/util/xml-helpers");
	var et = context.requireCordovaModule('elementtree');

	var byConfigXml = function(next) {
		var configFile = path.join(context.opts.projectRoot, 'config.xml');
		var xml = XmlHelpers.parseElementtreeSync(configFile);

		async.parallel(
				[
				function(next) {
					var target;
					xml.findall('preference').forEach(function(e) {
						if (e.get('name') === 'deployment-target') target = e.get('value');
					});
					if (!target) target = "8.0";

					var podfile = path.join(context.opts.projectRoot, 'platforms', 'ios', 'Podfile');
					fs.writeFile(podfile, "platform :ios,'" + target + "'\n\n", next);
				},
				function(next) {
					var platform = (function(tag, name) {
						var list = xml.findall(tag);
						var ios;
						list.forEach(function(e) {
							if (e.get('name') === name) ios = e;
						});
						if (!ios) {
							ios = et.Element(tag, {name: name});
							xml.getroot().append(ios);
						}
						return ios;
					})('platform', 'ios');

					var addHook = function(name, ext) {
						var script_path = path.join(path.dirname(context.scriptLocation), 'global', [name, ext].join('.'));
						var child = et.Element('hook', {type: name, src: path.relative(context.opts.projectRoot, script_path)});
						platform.append(child);
					}
					addHook('after_prepare', 'rb');

					fs.writeFile(configFile, xml.write({indent: 4}), 'utf-8', next);
				}
				 ], next);
	}

	var main = function() {
		async.parallel(
				[
				byConfigXml
				],
				function(err, result) {
					if (err) {
						log(err);
						deferral.reject(err);
					} else {
						deferral.resolve(result);
					}
				});
	}
	main();
	return deferral.promise;
};
<commit_msg>after_plugin_install.js はもう要らない<commit_after><|endoftext|>


<commit_before>/*
 *
 * Description:
 * This file holds the controller logic.  It manages the connection to the Atmega328.
 *
 */
var path = require('path'), spawn = require('child_process').spawn, CONFIG = require('./config'), StatusReader = require('./StatusReader'), ArduinoPhysics = require('./ArduinoPhysics'), logger = require('./logger').create(CONFIG), EventEmitter = require('events').EventEmitter, Hardware = require('../' + CONFIG.Hardware);
var setup_serial = function () {
  var location = path.join(__dirname, '..', './linux');
  logger.log('Starting the script from ' + location + ' to setup UART1...');
  var setuart_process = spawn('sudo', [path.join(location, 'setuart.sh')]);
  setuart_process.on('error', function (err) {
    logger.log('Error while starting the UART1 setup scipt!\nThe error was: ' + err);
  });
};
var statusdata = {};
var settingsCollection = {
    smoothingIncriment: 0,
    deadZone_min: 0,
    deadZone_max: 0
  };
var rovsys = { capabilities: 0 };
var OpenROVController = function (eventLoop) {
  var serial;
  var globalEventLoop = eventLoop;
  var reader = new StatusReader();
  var physics = new ArduinoPhysics();
  var hardware = new Hardware();
  var controller = new EventEmitter();
  setInterval(function () {
    controller.emit('status', statusdata);
  }, 1000);
  hardware.on('serial-recieved', function (data) {
    globalEventLoop.emit('serial-recieved', data);
  });
  hardware.on('status', function (status) {
    for (var i in status) {
      statusdata[i] = status[i];
    }
    if ('ver' in status) {
      controller.ArduinoFirmwareVersion = status.ver;
    }
    if ('TSET' in status) {
      console.log(status.settings);
      var setparts = status.settings.split(',');
      settingsCollection.smoothingIncriment = setparts[0];
      settingsCollection.deadZone_min = setparts[1];
      settingsCollection.deadZone_max = setparts[2];
      controller.emit('Arduino-settings-reported', settingsCollection);
    }
    if ('CAPA' in status) {
      var s = rovsys;
      console.log('RovSys: ' + status.CAPA);
      s.capabilities = parseInt(status.CAPA);
      controller.Capabilities = s.capabilities;
      controller.emit('rovsys', s);
    }
    if ('cmd' in status) {
      if (status.com != 'ping(0)'){
        console.log('cmd: ' + status.cmd);
        controller.emit('command', status.cmd);
      }
    }
    if ('log' in status) {
      console.log('log: ' + status.log);
    }
    if ('boot' in status){
      this.Capabilities = 0;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
    }
  });
  setup_serial();
  hardware.connect();
  controller.ArduinoFirmwareVersion = 0;
  controller.Capabilities = 0;

  controller.requestCapabilities = function () {
    console.log('Sending rcap to arduino');
    var command = 'rcap();';
    hardware.write(command);
  };
  controller.requestSettings = function () {
    var command = 'reportSetting();';
    hardware.write(command);
    command = 'rmtrmod();';
    hardware.write(command);
  };
  controller.updateSetting = function () {

    var command = 'updateSetting(' + CONFIG.preferences.get('smoothingIncriment') + ',' + CONFIG.preferences.get('deadzone_neg') + ',' + CONFIG.preferences.get('deadzone_pos') + ',' + CONFIG.preferences.get('water_type') + ';';
    hardware.write(command);
    //This is the multiplier used to make the motor act linear fashion.
    //for example: the props generate twice the thrust in the positive direction
    //than the negative direction.  To make it linear we have to multiply the
    //negative direction * 2.
    var port = CONFIG.preferences.get('thrust_modifier_port');
    var vertical = CONFIG.preferences.get('thrust_modifier_vertical');
    var starbord = CONFIG.preferences.get('thrust_modifier_starbord');
    var nport = CONFIG.preferences.get('thrust_modifier_nport');
    var nvertical = CONFIG.preferences.get('thrust_modifier_nvertical');
    var nstarbord = CONFIG.preferences.get('thrust_modifier_nstarbord');
    if (CONFIG.preferences.get('reverse_port_thruster')) {
      port = port * -1;
      nport = nport * -1;
    }
    if (CONFIG.preferences.get('reverse_lift_thruster')) {
      vertical = vertical * -1;
      nvertical = nvertical * -1;
    }
    if (CONFIG.preferences.get('reverse_starbord_thruster')) {
      starbord = starbord * -1;
      nstarbord = nstarbord * -1;
    }
    //API to Arduino to pass a percent in 2 decimal accuracy requires multipling by 100 before sending.
    command = 'mtrmod(' + port * 100 + ',' + vertical * 100 + ',' + starbord * 100 + ',' + nport * 100 + ',' + nvertical * 100 + ',' + nstarbord * 100 + ');';
    hardware.write(command);
  };
  controller.notSafeToControl = function () {
    //Arduino is OK to accept commands. After the Capabilities was added, all future updates require
    //being backward safe compatible (meaning you cannot send a command that does something unexpected but
    //instead it should do nothing).
    if (this.Capabilities !== 0)
      return false;
    //This feature added after the swap to ms on the Arduino
    console.log('Waiting for the capability response from Arduino before sending command.');
    console.log('Arduno Version: ' + this.ArduinoFirmwareVersion);
    console.log('Capability bitmap: ' + this.Capabilities);
    return true;
  };
  controller.send = function (cmd) {
    if (this.notSafeToControl())
      return;

    var command = cmd + ';';
    console.log('Sending command to arduino: ' + command);

    hardware.write(command);
  };
  controller.sendMotorTest = function (port, starbord, vertical) {
    if (this.notSafeToControl())
      return;
    var command = 'go(' + physics.mapRawMotor(port) + ',' + physics.mapRawMotor(vertical) + ',' + physics.mapRawMotor(starbord) + ',1);';
    //the 1 bypasses motor smoothing
    hardware.write(command);
  };
  controller.sendCommand = function (throttle, yaw, vertical) {
    if (this.notSafeToControl())
      return;
    var motorCommands = physics.mapMotors(throttle, yaw, vertical);
    var command = 'go(' + motorCommands.port + ',' + motorCommands.vertical + ',' + motorCommands.starbord + ');';
    hardware.write(command);
  };
  controller.stop = function (value) {
    if (this.notSafeToControl())
      return;
    var command = 'stop();';
    hardware.write(command);
  };
  controller.start = function (value) {
    if (this.notSafeToControl())
      return;
    var command = 'start();';
    hardware.write(command);
  };
  globalEventLoop.on('register-ArdunoFirmwareVersion', function (val) {
    controller.ArduinoFirmwareVersion = val;
  });
  globalEventLoop.on('register-ArduinoCapabilities', function (val) {
    controller.Capabilities = val;
  });
  globalEventLoop.on('SerialMonitor_toggle_rawSerial', function () {
    hardware.toggleRawSerialData();
  });
  globalEventLoop.on('serial-stop', function () {
    logger.log('Closing serial connection for firmware upload');
    hardware.close();
  });
  globalEventLoop.on('serial-start', function () {
    hardware.connect();
    controller.updateSetting();
    logger.log('Opened serial connection after firmware upload');
  });

  controller.updateSetting();
  //Every few seconds we check to see if capabilities or settings changes on the arduino.
  //This handles the cases where we have garbled communication or a firmware update of the arduino.
  controller.requestSettings();
  controller.requestCapabilities();

  setInterval(function () {
    if (!controller.notSafeToControl()) return;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
  }, 10000);

  return controller;
};
module.exports = OpenROVController;
<commit_msg>Cleanup<commit_after>/*
 *
 * Description:
 * This file holds the controller logic.  It manages the connection to the Atmega328.
 *
 */
var path = require('path'), spawn = require('child_process').spawn, CONFIG = require('./config'), StatusReader = require('./StatusReader'), ArduinoPhysics = require('./ArduinoPhysics'), logger = require('./logger').create(CONFIG), EventEmitter = require('events').EventEmitter, Hardware = require('../' + CONFIG.Hardware);
var setup_serial = function () {
  var location = path.join(__dirname, '..', './linux');
  logger.log('Starting the script from ' + location + ' to setup UART1...');
  var setuart_process = spawn('sudo', [path.join(location, 'setuart.sh')]);
  setuart_process.on('error', function (err) {
    logger.log('Error while starting the UART1 setup scipt!\nThe error was: ' + err);
  });
};
var statusdata = {};
var settingsCollection = {
    smoothingIncriment: 0,
    deadZone_min: 0,
    deadZone_max: 0
  };

var rovsys = { capabilities: 0 };

var OpenROVController = function (eventLoop) {
  var controller = this;
  var serial;
  var globalEventLoop = eventLoop;
  this.physics = new ArduinoPhysics();
  this.hardware = new Hardware();

  setInterval(function () {
    controller.emit('status', statusdata);
  }, 1000);

  this.hardware.on('serial-recieved', function (data) {
    globalEventLoop.emit('serial-recieved', data);
  });

  this.hardware.on('status', function (status) {
    for (var i in status) {
      statusdata[i] = status[i];
    }
    if ('ver' in status) {
      controller.ArduinoFirmwareVersion = status.ver;
    }
    if ('TSET' in status) {
      console.log(status.settings);
      var setparts = status.settings.split(',');
      settingsCollection.smoothingIncriment = setparts[0];
      settingsCollection.deadZone_min = setparts[1];
      settingsCollection.deadZone_max = setparts[2];
      controller.emit('Arduino-settings-reported', settingsCollection);
    }
    if ('CAPA' in status) {
      var s = rovsys;
      console.log('RovSys: ' + status.CAPA);
      s.capabilities = parseInt(status.CAPA);
      controller.Capabilities = s.capabilities;
      controller.emit('rovsys', s);
    }
    if ('cmd' in status) {
      if (status.com != 'ping(0)'){
        console.log('cmd: ' + status.cmd);
        controller.emit('command', status.cmd);
      }
    }
    if ('log' in status) {
      console.log('log: ' + status.log);
    }
    if ('boot' in status){
      this.Capabilities = 0;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
    }
  });
  setup_serial();
  this.hardware.connect();
  controller.ArduinoFirmwareVersion = 0;
  controller.Capabilities = 0;

  controller.notSafeToControl = function () {
    //Arduino is OK to accept commands. After the Capabilities was added, all future updates require
    //being backward safe compatible (meaning you cannot send a command that does something unexpected but
    //instead it should do nothing).
    if (controller.Capabilities !== 0)
      return false;
    //This feature added after the swap to ms on the Arduino
    console.log('Waiting for the capability response from Arduino before sending command.');
    console.log('Arduno Version: ' + controller.ArduinoFirmwareVersion);
    console.log('Capability bitmap: ' + controller.Capabilities);
    return true;
  };

  globalEventLoop.on('register-ArdunoFirmwareVersion', function (val) {
    controller.ArduinoFirmwareVersion = val;
  });
  globalEventLoop.on('register-ArduinoCapabilities', function (val) {
    controller.Capabilities = val;
  });

  globalEventLoop.on('SerialMonitor_toggle_rawSerial', function () {
    controller.hardware.toggleRawSerialData();
  });

  globalEventLoop.on('serial-stop', function () {
    logger.log('Closing serial connection for firmware upload');
    controller.hardware.close();
  });

  globalEventLoop.on('serial-start', function () {
    controller.hardware.connect();
    controller.updateSetting();
    logger.log('Opened serial connection after firmware upload');
  });

  controller.updateSetting();
  //Every few seconds we check to see if capabilities or settings changes on the arduino.
  //This handles the cases where we have garbled communication or a firmware update of the arduino.
  controller.requestSettings();
  controller.requestCapabilities();

  setInterval(function () {
    if (!controller.notSafeToControl()) return;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
  }, 10000);

  return controller;
};
OpenROVController.prototype = new EventEmitter();
OpenROVController.prototype.constructor = OpenROVController;

OpenROVController.prototype.send = function (cmd) {
  var controller = this;
  if (controller.notSafeToControl())
    return;

  var command = cmd + ';';
  console.log('Sending command to arduino: ' + command);

  controller.hardware.write(command);
};

OpenROVController.prototype.requestCapabilities = function () {
  console.log('Sending rcap to arduino');
  var command = 'rcap();';
  this.hardware.write(command);
};

OpenROVController.prototype.requestSettings = function () {
  var command = 'reportSetting();';
  this.hardware.write(command);
  command = 'rmtrmod();';
  this.hardware.write(command);
};

OpenROVController.prototype.updateSetting = function () {

  var command = 'updateSetting(' + CONFIG.preferences.get('smoothingIncriment') + ',' + CONFIG.preferences.get('deadzone_neg') + ',' + CONFIG.preferences.get('deadzone_pos') + ',' + CONFIG.preferences.get('water_type') + ';';
  this.hardware.write(command);
  //This is the multiplier used to make the motor act linear fashion.
  //for example: the props generate twice the thrust in the positive direction
  //than the negative direction.  To make it linear we have to multiply the
  //negative direction * 2.
  var port = CONFIG.preferences.get('thrust_modifier_port');
  var vertical = CONFIG.preferences.get('thrust_modifier_vertical');
  var starbord = CONFIG.preferences.get('thrust_modifier_starbord');
  var nport = CONFIG.preferences.get('thrust_modifier_nport');
  var nvertical = CONFIG.preferences.get('thrust_modifier_nvertical');
  var nstarbord = CONFIG.preferences.get('thrust_modifier_nstarbord');
  if (CONFIG.preferences.get('reverse_port_thruster')) {
    port = port * -1;
    nport = nport * -1;
  }
  if (CONFIG.preferences.get('reverse_lift_thruster')) {
    vertical = vertical * -1;
    nvertical = nvertical * -1;
  }
  if (CONFIG.preferences.get('reverse_starbord_thruster')) {
    starbord = starbord * -1;
    nstarbord = nstarbord * -1;
  }
  //API to Arduino to pass a percent in 2 decimal accuracy requires multipling by 100 before sending.
  command = 'mtrmod(' + port * 100 + ',' + vertical * 100 + ',' + starbord * 100 + ',' + nport * 100 + ',' + nvertical * 100 + ',' + nstarbord * 100 + ');';
  this.hardware.write(command);
};

OpenROVController.prototype.sendMotorTest = function (port, starbord, vertical) {
  var command = 'go(' + this.physics.mapRawMotor(port) + ',' +
    this.physics.mapRawMotor(vertical) + ',' +
    this.physics.mapRawMotor(starbord) + ',1)';
  //the 1 bypasses motor smoothing
  this.send(command);
};

OpenROVController.prototype.sendCommand = function (throttle, yaw, vertical) {
  var motorCommands = this.physics.mapMotors(throttle, yaw, vertical);
  var command = 'go(' + motorCommands.port + ','
    + motorCommands.vertical + ','
    + motorCommands.starbord + ')';
  this.send(command);
};

OpenROVController.prototype.stop = function (value) {
  var command = 'stop()';
  this.send(command);
};

OpenROVController.prototype.start = function (value) {
  var command = 'start()';
  this.send(command);
};

module.exports = OpenROVController;
<|endoftext|>