// ----------------------------------------------------------------
// Popover Class

class PopoverModel extends CommonModel {
  constructor({
    name = 'Popover',
    selector = null,
    help = 'popover',
    trigger = 'hover'
  } = {})
  {
    super({
      name: name
    });

    this.NAME = name;
    this.SELECTOR = selector;
    this.HELP = help;
    this.TRIGGER = trigger;
  }
}

class PopoverView extends CommonView {
  constructor(_model = new PopoverModel()) {
    super(_model);

    this.setPopover();
  }

  setPopover() {
    if (this.model.SELECTOR != null) {
      $(this.model.SELECTOR).attr('data-toggle', 'popover');
      $(this.model.SELECTOR).attr('data-content', this.model.HELP);
      $(this.model.SELECTOR).attr('data-trigger', this.model.TRIGGER);
      $(this.model.SELECTOR).popover();
    }
  }
}

// ----------------------------------------------------------------
// Controllers

class PopoverController extends CommonController {
  constructor(_obj) {
    super({
      name: 'Popover Controller'
    });

    this.model = new PopoverModel(_obj);
    this.view = new PopoverView(this.model);
  }
}

// ----------------------------------------------------------------
// Popover Class

// ----------------------------------------------------------------
// Model

class PopoverModel extends CommonModel {
  constructor(
    _setting = {},
    _initSetting = {
      NAME: 'Popover Object',
      SELECTOR: null,
      HELP: 'popover',
      TRIGGER: 'hover'
    }
  ) {
    super(_setting, _initSetting);
  }
}

// ----------------------------------------------------------------
// View

class PopoverView extends CommonView {
  constructor(
    _setting = {},
    _initSetting = {
      NAME: 'Popover View'
    }
  ) {
    super(_setting, _initSetting);
  }
}

// ----------------------------------------------------------------
// Event

class PopoverEvent extends CommonEvent {
  constructor(
    _setting = {},
    _initSetting = {
      NAME: 'Popover Event'
    }
  ) {
    super(_setting, _initSetting);
  }

  setPopover() {
    if (this.MODEL.SELECTOR != null) {
      $(this.MODEL.SELECTOR).attr('data-toggle', 'popover');
      $(this.MODEL.SELECTOR).attr('data-content', this.MODEL.HELP);
      $(this.MODEL.SELECTOR).attr('data-trigger', this.MODEL.TRIGGER);
      $(this.MODEL.SELECTOR).popover();
    }
  }
}

// ----------------------------------------------------------------
// Controller

class PopoverController extends CommonController {
  constructor(
    _setting = {},
    _initSetting = {
      NAME: 'Popover Controller',
      MODEL: new PopoverModel(),
      VIEW: new PopoverView(),
      EVENT: new PopoverEvent(),
      VIEW_OBJECT: false
    }
  ) {
    super(_setting, _initSetting);

    this.EVENT.setPopover();
  }
}

Apply Common Upgrade to Popover classes


/** @babel */

const {Disposable, CompositeDisposable} = require('atom')
const ViewURI = 'atom://deprecation-cop'
let DeprecationCopView

class DeprecationCopPackage {
  activate () {
    this.disposables = new CompositeDisposable()
    this.disposables.add(atom.workspace.addOpener((uri) => {
      if (uri === ViewURI) {
        return this.deserializeDeprecationCopView({uri})
      }
    }))
    this.disposables.add(atom.commands.add('atom-workspace', 'deprecation-cop:view', () => {
      atom.workspace.open(ViewURI)
    }))
  }

  deactivate () {
    this.disposables.dispose()
    const pane = atom.workspace.paneForURI(ViewURI)
    if (pane) {
      pane.destroyItem(pane.itemForURI(ViewURI))
    }
  }

  deserializeDeprecationCopView (state) {
    if (!DeprecationCopView) {
      DeprecationCopView = require('./deprecation-cop-view')
    }
    return new DeprecationCopView(state)
  }

  consumeStatusBar (statusBar) {
    const DeprecationCopStatusBarView = require('./deprecation-cop-status-bar-view')
    const statusBarView = new DeprecationCopStatusBarView()
    const statusBarTile = statusBar.addRightTile({item: statusBarView, priority: 150})
    this.disposables.add(new Disposable(() => { statusBarView.destroy() }))
    this.disposables.add(new Disposable(() => { statusBarTile.destroy() }))
  }
}

const instance = new DeprecationCopPackage()
export default instance

/** @babel */

import {Disposable, CompositeDisposable} from 'atom'

const ViewURI = 'atom://deprecation-cop'
let DeprecationCopView

class DeprecationCopPackage {
  activate () {
    this.disposables = new CompositeDisposable()
    this.disposables.add(atom.workspace.addOpener((uri) => {
      if (uri === ViewURI) {
        return this.deserializeDeprecationCopView({uri})
      }
    }))
    this.disposables.add(atom.commands.add('atom-workspace', 'deprecation-cop:view', () => {
      atom.workspace.open(ViewURI)
    }))
  }

  deactivate () {
    this.disposables.dispose()
    const pane = atom.workspace.paneForURI(ViewURI)
    if (pane) {
      pane.destroyItem(pane.itemForURI(ViewURI))
    }
  }

  deserializeDeprecationCopView (state) {
    if (!DeprecationCopView) {
      DeprecationCopView = require('./deprecation-cop-view')
    }
    return new DeprecationCopView(state)
  }

  consumeStatusBar (statusBar) {
    const DeprecationCopStatusBarView = require('./deprecation-cop-status-bar-view')
    const statusBarView = new DeprecationCopStatusBarView()
    const statusBarTile = statusBar.addRightTile({item: statusBarView, priority: 150})
    this.disposables.add(new Disposable(() => { statusBarView.destroy() }))
    this.disposables.add(new Disposable(() => { statusBarTile.destroy() }))
  }
}

const instance = new DeprecationCopPackage()
export default instance

Use import instead of require


import React, { Component } from 'react';
import { Text, Image, View } from 'react-native';
import styles from './styles/ActorsMoviesStyle';
import ActorImage from '../components/ActorImage';
import { StackNagivator } from 'react-navigation';

export default class ActorsMovies extends Component {
  render() {
    return (
      <Text>Movies</Text>
    )
  }
}

import React, { Component } from 'react';
import { Text, Image, View } from 'react-native';
import styles from './styles/ActorsMoviesStyle';
import ActorImage from '../components/ActorImage';
import { StackNagivator } from 'react-navigation';

export default class ActorsMovies extends Component {
  render() {
    return (
      <Text>Movies!</Text>
    )
  }
}

Test commit for account change


'use strict';

var express = require('express');
var request = require('supertest');
var logger = require('log4js').getLogger('Unit-Test');

exports['Test recevie message'] = function(test){

}

'use strict';

var express = require('express');
var request = require('supertest');
var logger = require('log4js').getLogger('Unit-Test');

exports['Test send message success'] = function(test){

	var sendObject = {
		message:{
			receiver:'@tester';
			text:'Hello World!';
	}

	time:new Date().getTime();

}

Add Test send message success test case


/* @flow */
'use strict';

import Relay from 'react-relay';
import React from 'react';
import { View, Text, Dimensions } from 'react-native';

import removeMarkdown from 'remove-markdown';

import Headline from '../text/headline';
import SerifText from '../text/serif';

const sideMargin = Dimensions.get('window').width > 700 ? 50 : 0;

class Biography extends React.Component {
  static propTypes = {
    artist: React.PropTypes.shape({
      bio: React.PropTypes.string,
    }),
  };

  render() {
    const artist = this.props.artist;
    if (!artist.blurb && !artist.bio) { return null; }

    return (
      <View style={{marginLeft: sideMargin, marginRight: sideMargin}}>
        <Headline style={{ marginBottom: 20 }}>Biography</Headline>
        { this.blurb(artist) }
        <SerifText style={{ marginBottom: 40 }}>{artist.bio}</SerifText>
      </View>
    );
  }

  blurb(artist) {
    return artist.blurb ? <SerifText style={{ marginBottom: 20, lineHeight: 25 }} numberOfLines={0}>{removeMarkdown(artist.blurb)}</SerifText> : null;
  }
}

export default Relay.createContainer(Biography, {
  fragments: {
    artist: () => Relay.QL`
      fragment on Artist {
        bio
        blurb
      }
    `,
  }
});

/* @flow */
'use strict';

import Relay from 'react-relay';
import React from 'react';
import { View, Text, Dimensions } from 'react-native';

import removeMarkdown from 'remove-markdown';

import Headline from '../text/headline';
import SerifText from '../text/serif';

const sideMargin = Dimensions.get('window').width > 700 ? 50 : 0;

class Biography extends React.Component {
  static propTypes = {
    artist: React.PropTypes.shape({
      bio: React.PropTypes.string,
    }),
  };

  render() {
    const artist = this.props.artist;
    if (!artist.blurb && !artist.bio) { return null; }

    return (
      <View style={{marginLeft: sideMargin, marginRight: sideMargin}}>
        <Headline style={{ marginBottom: 20 }}>Biography</Headline>
        { this.blurb(artist) }
        <SerifText style={{ marginBottom: 40 }} numberOfLines={0}>{this.bioText()}</SerifText>
      </View>
    );
  }

  blurb(artist) {
    return artist.blurb ? <SerifText style={{ marginBottom: 20, lineHeight: 25 }} numberOfLines={0}>{removeMarkdown(artist.blurb)}</SerifText> : null;
  }

  bioText() {
    const bio = this.props.artist.bio;
    return bio.replace("born", "b.");
  }
}

export default Relay.createContainer(Biography, {
  fragments: {
    artist: () => Relay.QL`
      fragment on Artist {
        bio
        blurb
      }
    `,
  }
});

Fix truncation + Replace born with abbreviation


/**
 * app.js
 *
 * Use `app.js` to run your app in environments where `sails lift` is not available.
 * To start the server, run: `node app.js`.
 *
 * The same command-line arguments as sails lift are also supported,
 * e.g.: `node app.js --silent --port=80 --prod`
 */

// Ensure a "sails" can be located:
var sails;
try {
	sails = require('sails');
}
catch (e) {
	console.error('To run an app using `node app.js`, you usually need to have a version of `sails` installed in the same directory as your app.');
	console.error('You might run `npm install sails` to install sails in this directory.');
	console.error('');
	console.error('Alternatively, if you have sails installed globally (i.e. you did `npm install -g sails`), you can use `sails lift`.');
	console.error('When you run `sails lift`, your app will still use a local `./node_modules/sails` dependency if it exists,');
	console.error('but if it doesn\'t, the app will run with the global sails instead!');
	return;
}

// Start server
sails.lift(require('optimist').argv);

/**
 * app.js
 *
 * Use `app.js` to run your app in environments where `sails lift` is not available.
 * To start the server, run: `node app.js`.
 *
 * The same command-line arguments as sails lift are also supported,
 * e.g.: `node app.js --silent --port=80 --prod`
 */

// Ensure a "sails" can be located:
var sails;
try {
	sails = require('sails');
}
catch (e) {
	console.error('To run an app using `node app.js`, you usually need to have a version of `sails` installed in the same directory as your app.');
	console.error('To do that, run `npm install sails`');
	console.error('');
	console.error('Alternatively, if you have sails installed globally (i.e. you did `npm install -g sails`), you can use `sails lift`.');
	console.error('When you run `sails lift`, your app will still use a local `./node_modules/sails` dependency if it exists,');
	console.error('but if it doesn\'t, the app will run with the global sails instead!');
	return;
}

// Start server
sails.lift(require('optimist').argv);

Make sentence make more sense


(function() {
  function chaingun(obj) {
    function _chained_(v) {
      function _chain_() { return curr; }

      var curr = v;
      if (typeof obj == 'function') curr = obj.apply(this, arguments);

      return extend(_chain_, obj, function(fn) {
        if (typeof fn != 'function') return;

        return function() {
          Array.prototype.unshift.call(arguments, curr);
          curr = fn.apply(this, arguments);
          return this;
        };
      });
    }

    return extend(_chained_, obj);
  }

  function extend(target, source, fn) {
    var result;
    fn = fn || identity;

    for (var k in source) {
      if (!source.hasOwnProperty(k)) return;
      result = fn.call(this, source[k]);
      if (typeof result != 'undefined') target[k] = result;
    }

    return target;
  }

  function identity(v) { return v; }

  if (typeof module != 'undefined')
    module.exports = chaingun;
  else if (typeof define == 'function' && define.amd)
    define(function() { return chaingun; });
  else
    this.chaingun = chaingun;
})();

(function() {
  function chaingun(obj) {
    function _chained_(v) {
      function _chain_() { return curr; }

      var curr = v;
      if (typeof obj == 'function') curr = obj.apply(this, arguments);

      return extend(_chain_, obj, function(fn) {
        if (typeof fn != 'function') return;

        return function() {
          Array.prototype.unshift.call(arguments, curr);
          curr = fn.apply(this, arguments);
          return this;
        };
      });
    }

    return extend(_chained_, obj);
  }

  function extend(target, source, fn) {
    var result;
    fn = fn || identity;

    for (var k in source) {
      if (!source.hasOwnProperty(k)) return;
      result = fn.call(this, source[k]);
      if (typeof result != 'undefined') target[k] = result;
    }

    return target;
  }

  function identity(v) { return v; }

  if (typeof module != 'undefined')
    module.exports = chaingun;
  else if (typeof define == 'function' && define.amd)
    define(function() { return chaingun; });
  else
    this.chaingun = chaingun;
}).call(this);

Maintain the current context `this` context when giving the module its own scope


'use strict';

var helpers = require('../helpers');

module.exports = {
  'name': 'placeholder-in-extend',
  'defaults': {},
  'detect': function (ast, parser) {
    var result = [];

    ast.traverseByType('atkeyword', function (keyword, i, parent) {
      keyword.forEach(function (item) {
        if (item.content === 'extend') {

          parent.forEach('simpleSelector', function (selector) {
            var placeholder = false;

            selector.content.forEach(function (selectorPiece) {
              if (selectorPiece.type === 'placeholder') {
                placeholder = true;
              }
            });

            if (!placeholder) {
              result = helpers.addUnique(result, {
                'ruleId': parser.rule.name,
                'line': selector.start.line,
                'column': selector.start.column,
                'message': '@extend must be used with a %placeholder',
                'severity': parser.severity
              });
            }
          });
        }
      });
    });

    return result;
  }
};

'use strict';

var helpers = require('../helpers');

module.exports = {
  'name': 'placeholder-in-extend',
  'defaults': {},
  'detect': function (ast, parser) {
    var result = [];

    ast.traverseByType('atkeyword', function (keyword, i, parent) {
      keyword.forEach(function (item) {
        if (item.content === 'extend') {

          parent.forEach('selector', function (selector) {
            var placeholder = false;

            selector.content.forEach(function (selectorPiece) {
              if (selectorPiece.type === 'placeholder') {
                placeholder = true;
              }
            });

            if (!placeholder) {
              result = helpers.addUnique(result, {
                'ruleId': parser.rule.name,
                'line': selector.start.line,
                'column': selector.start.column,
                'message': '@extend must be used with a %placeholder',
                'severity': parser.severity
              });
            }
          });
        }
      });
    });

    return result;
  }
};

Replace deprecated node type simpleSelector with selector


import React from 'react';
import icon from './icon.png';
import translate from './translate';
import detectLanguage from './detectLanguage';
import toLanguageCode from './toLanguageCode';
import Preview from './Preview';
import { id, order, REGEXP } from './constants.js';

const translatePlugin = (term, callback) => {
  const match = term.match(REGEXP);
  if (match) {
    // Show translation in results list
    // TODO: check why using const here throws undefined variable text in production build
    var text = match[1];
    const targetLang = toLanguageCode(match[2]);

    detectLanguage(text).then(sourceLang =>
      translate(text, `${sourceLang}-${targetLang}`)
    ).then(({lang, text}) => {
      const translation = text[0];
      const [sourceLang, targetLang] = lang.split('-')[0];
      const options = {
        text,
        sourceLang,
        targetLang,
        translation
      }
      callback({
        id,
        icon,
        title: `${translation}`,
        getPreview: () => <Preview {...options} />
      });
    });
    return;
  }

  // Fallback result with lower priority for every request
  callback({
    id,
    icon,
    // Low priority for fallback result
    order: 3,
    title: `Translate ${term}`,
    getPreview: () => <Preview text={term} />
  });
};

export default {
  fn: translatePlugin,
};

import React from 'react';
import icon from './icon.png';
import translate from './translate';
import detectLanguage from './detectLanguage';
import toLanguageCode from './toLanguageCode';
import Preview from './Preview';
import { id, order, REGEXP } from './constants.js';

const translatePlugin = (term, callback) => {
  const match = term.match(REGEXP);
  if (match) {
    // Show translation in results list
    // TODO: check why using const here throws undefined variable text in production build
    var text = match[1];
    const targetLang = toLanguageCode(match[2]);

    detectLanguage(text).then(sourceLang =>
      translate(text, `${sourceLang}-${targetLang}`)
    ).then(({lang, text}) => {
      const translation = text[0];
      const [sourceLang, targetLang] = lang.split('-');
      const options = {
        text,
        sourceLang,
        targetLang,
        translation
      }
      callback({
        id,
        icon,
        title: `${translation}`,
        getPreview: () => <Preview {...options} />
      });
    });
    return;
  }

  // Fallback result with lower priority for every request
  callback({
    id,
    icon,
    // Low priority for fallback result
    order: 3,
    title: `Translate ${term}`,
    getPreview: () => <Preview text={term} />
  });
};

export default {
  fn: translatePlugin,
};

FIx translation preview for detected language


/**
 * @class Denkmal_Component_HeaderBar
 * @extends Denkmal_Component_Abstract
 */
var Denkmal_Component_HeaderBar = Denkmal_Component_Abstract.extend({

  /** @type String */
  _class: 'Denkmal_Component_HeaderBar',

  /** @type Boolean */
  narrow: null,

  events: {
    'click .menu.dates .active .navButton': function() {
      if (!this.narrow) {
        return;
      }
      this.toggleMenu(true);
    },

    'click .menu-expand .menu.dates .navButton': function() {
      if (!this.narrow) {
        return;
      }
      this.toggleMenu(false);
    }
  },

  ready: function() {
    var self = this;
    var handlers = {
      match: function() {
        self.narrow = true;
      },
      unmatch: function() {
        self.narrow = false;
        self.toggleMenu(false);
      }

    };

    enquire.register('(max-width: 580px)', handlers);

    this.on('destruct', function() {
      enquire.unregister('(max-width: 580px)', handlers);
    });
  },

  /**
   *
   * @param {Boolean} state
   */
  toggleMenu: function(state) {
    this.$('.bar').toggleClass('menu-expand', state);
  }

});

/**
 * @class Denkmal_Component_HeaderBar
 * @extends Denkmal_Component_Abstract
 */
var Denkmal_Component_HeaderBar = Denkmal_Component_Abstract.extend({

  /** @type String */
  _class: 'Denkmal_Component_HeaderBar',

  /** @type Boolean */
  narrow: null,

  events: {
    'click .menu.dates .active .navButton': function() {
      if (this.narrow) {
        this.toggleMenu(true);
      }
    },

    'click .menu-expand .menu.dates .navButton': function() {
      if (this.narrow) {
        this.toggleMenu(false);
      }
    }
  },

  ready: function() {
    var self = this;
    var handlers = {
      match: function() {
        self.narrow = true;
      },
      unmatch: function() {
        self.narrow = false;
        self.toggleMenu(false);
      }

    };

    enquire.register('(max-width: 580px)', handlers);

    this.on('destruct', function() {
      enquire.unregister('(max-width: 580px)', handlers);
    });
  },

  /**
   *
   * @param {Boolean} state
   */
  toggleMenu: function(state) {
    if (state) {
      this.$('.bar').toggleModal(function(state) {
        $(this).toggleClass('menu-expand', state);
      });
    } else {
      this.$('.bar').toggleModalClose();
    }
  }

});

Use toggleModal for headerbar navigation


import queryString from 'query-string';
import parseUrl from 'parse-url';

import { baseInterceptor } from './baseInterceptor';
import { Response as KakapoResponse } from '../Response';
import { nativeFetch } from '../helpers/nativeServices';

export const name = 'fetch';
export const reference = nativeFetch;

const fakeResponse = (response = {}, headers = {}) => {
  const responseStr = JSON.stringify(response);
  return new window.Response(responseStr, { headers });
};

export const fakeService = config =>
  baseInterceptor(config, (helpers, url, options = {}) => {
    const body = options.body || '';
    const method = options.method || 'GET';
    const headers = options.headers || {};

    const handler = helpers.getHandler(url, method);
    const params = helpers.getParams(url, method);

    if (!handler) {
      return reference(url, options);
    }

    const query = queryString.parse(parseUrl(url).search);
    const response = handler({ params, query, body, headers });

    if (!(response instanceof KakapoResponse)) {
      return new Promise((resolve) => setTimeout(
        () => resolve(fakeResponse(response)),
        config.requestDelay
      ));
    }

    const result = fakeResponse(response.body, response.headers);
    return new Promise((resolve, reject) => setTimeout(
      () => {
        if (response.error) { return reject(result); }
        return resolve(result);
      },
      config.requestDelay
    ));
  });

import queryString from 'query-string';
import parseUrl from 'parse-url';

import { baseInterceptor } from './baseInterceptor';
import { Response as KakapoResponse } from '../Response';
import { nativeFetch } from '../helpers/nativeServices';

export const name = 'fetch';
export const reference = nativeFetch;

const fakeResponse = (response = {}, headers = {}) => {
  const responseStr = JSON.stringify(response);
  return new window.Response(responseStr, { headers });
};

export const fakeService = config =>
  baseInterceptor(config, (helpers, url, options = {}) => {
    url = url instanceof Request ? url.url : url;

    const body = options.body || '';
    const method = options.method || 'GET';
    const headers = options.headers || {};

    const handler = helpers.getHandler(url, method);
    const params = helpers.getParams(url, method);

    if (!handler) {
      return reference(url, options);
    }

    const query = queryString.parse(parseUrl(url).search);
    const response = handler({ params, query, body, headers });

    if (!(response instanceof KakapoResponse)) {
      return new Promise((resolve) => setTimeout(
        () => resolve(fakeResponse(response)),
        config.requestDelay
      ));
    }

    const result = fakeResponse(response.body, response.headers);
    return new Promise((resolve, reject) => setTimeout(
      () => {
        if (response.error) { return reject(result); }
        return resolve(result);
      },
      config.requestDelay
    ));
  });

Support Request url in fetch interceptor


import React from 'react';

export default ({ modules, serverID }) => (

Summary not implemented yet

);

import React from 'react';

import { NAME, PAGES, FEATURES } from '../data/columnNames';

export default ({ modules, serverID }) => (
  (!modules || !serverID) ? (

  ) : (

Captiva Capture License ID: {serverID}

          {row(
            'Server Type',
            isEnterprise(modules) ? 'Enterprise' : 'Standard'
          )}
          {row(
            'Page Volume',
            pageVolume(modules)
          )}

  )
);

function row(title, value) {
  return (

      {title}:
      {value}

  )
}

function isEnterprise(modules) {
  const serverModule = modules.find(module => module[NAME].includes('SERVER'));

  const hasFeatures = /[CDEFSW]/.test(serverModule[FEATURES]);
  const hasModules = modules.some(module => (
    ['DPMANAGER', 'WSINPUT', 'WSOUTPUT', 'ECOPY'].some(name => (
      module[NAME].includes(name)
    ))
  ));

  return hasFeatures || hasModules;
}

function pageVolume(modules) {
  return modules.filter(
    module => module[NAME].includes('ANNUAL')
  ).map(
    module => module[PAGES]
  ).reduce((a, b) => (
    parseInt(a) + parseInt(b)
  ), 0);
}

Add summary with first two rows implemented


/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var files = [
  'stdlib',
  'io',
  'writer',
  'socket',
  'hash',
  'base64',
  'encodings',
  'utf8',
  'parse',
  'event',
  'JSONUtil',
  'XMLUtil',
  'context',
  'FOAM',
  'TemplateUtil',
  'AbstractPrototype',
  'ModelProto',
  'mm1Model',
  'mm2Property',
  'mm3Types',
  'mm4Method',
  'mm5Misc',
  'mm6Protobuf',
  'mlang',
  'QueryParser',
  'search',
  'async',
  'visitor',
  'dao',
  'ClientDAO',
  'diff',
  'SplitDAO',
  'index',
  'experimental/protobufparser',
  'experimental/protobuf',
  'models',
  'oauth'
];

/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var files = [
  'stdlib',
  'io',
  'writer',
  'socket',
  'hash',
  'base64',
  'encodings',
  'utf8',
  'parse',
  'event',
  'JSONUtil',
  'XMLUtil',
  'context',
  'FOAM',
  'JSONParser',
  'TemplateUtil',
  'AbstractPrototype',
  'ModelProto',
  'mm1Model',
  'mm2Property',
  'mm3Types',
  'mm4Method',
  'mm5Misc',
  'mm6Protobuf',
  'mlang',
  'QueryParser',
  'search',
  'async',
  'visitor',
  'dao',
  'ClientDAO',
  'diff',
  'SplitDAO',
  'index',
  'experimental/protobufparser',
  'experimental/protobuf',
  'models',
  'oauth'
];

Add JSONParser.js to ViewlessModels - working in node again


Template.latestActivitiesByType.created = function () {
  // Create 'instance' variable for use througout template logic
  var instance = this;

  // Subscribe to all activity types
  instance.subscribe('allActivityTypes');

  // Create variable to hold activity type selection
  instance.activityTypeSelection = new ReactiveVar();

  // Create latest resident activity placeholder
  instance.latestResidentsActivityByType = new ReactiveVar();
};

Template.latestActivitiesByType.helpers({
  'activityTypeOptions': function () {
    // Get all activity types
    activityTypes = ActivityTypes.find().fetch();

    return activityTypes;
  }
});

Template.latestActivitiesByType.events({
  'change #activity-type-select': function (event, template) {
    // Create instance variable for consistency
    var instance = Template.instance();

    var selectedActivityType = event.target.value;

    instance.activityTypeSelection.set(selectedActivityType);
  }
});

Template.latestActivitiesByType.created = function () {
  // Create 'instance' variable for use througout template logic
  var instance = this;

  // Subscribe to all activity types
  instance.subscribe('allActivityTypes');

  // Create variable to hold activity type selection
  instance.activityTypeSelection = new ReactiveVar();

  // Create latest resident activity placeholder
  instance.latestResidentsActivityByType = new ReactiveVar();

  instance.autorun(function () {
    // Get activity type selection
    var activityTypeSelection = instance.activityTypeSelection.get();

    if (activityTypeSelection) {
      // Get latest resident activities for selected activity type
      Meteor.call(
        'getResidentsLatestActivityByType',
        activityTypeSelection,
        function (error, latestActivity) {
          if (error) {
            console.log(error);
          } else {
            // Update the reactive variable with latest resident activity
            instance.latestResidentsActivityByType.set(latestActivity);
          }
        });
    };
  });
};

Template.latestActivitiesByType.helpers({
  'activityTypeOptions': function () {
    // Get all activity types
    activityTypes = ActivityTypes.find().fetch();

    return activityTypes;
  }
});

Template.latestActivitiesByType.events({
  'change #activity-type-select': function (event, template) {
    // Create instance variable for consistency
    var instance = Template.instance();

    var selectedActivityType = event.target.value;

    instance.activityTypeSelection.set(selectedActivityType);
  }
});

Add autorun to update resident activities


redactParagraph = Redact.addModule(
  'paragraph',
  (
    typeof Template != 'undefined'
      ? Template.redactParagraph
      : ''
  ),
  {
    label: 'Paragraph',
    icon: '/redactParagraph.svg',
    defaults: {
      _html: 'Lorem Ipsum'
    }
  }
)

if(Meteor.isClient) {
  Template.redactParagraph.events({
    'keydown .redactParagraph': function (e) {
      if(
        e.keyCode == 8
        && (
          e.currentTarget.innerHTML.length < 1
          || e.currentTarget.innerHTML === '<br>'
        )
      ) {
        redactParagraph.removeElement(
          Template.currentData().collection
          Template.parentData(1)._id,
          '_draft',
          Template.currentData()._id
        )
      }
    }
  })
}

redactParagraph = Redact.addModule(
  'paragraph',
  (
    typeof Template != 'undefined'
      ? Template.redactParagraph
      : ''
  ),
  {
    label: 'Paragraph',
    icon: '/redactParagraph.svg',
    defaults: {
      _html: 'Lorem Ipsum'
    }
  }
)

if(Meteor.isClient) {
  Template.redactParagraph.events({
    'keydown .redactParagraph': function (e) {
      if(
        e.keyCode == 8
        && (
          e.currentTarget.innerHTML.length < 1
          || e.currentTarget.innerHTML === '<br>'
        )
      ) {
        redactParagraph.removeElement(
          Template.currentData().collection,
          Template.parentData(1)._id,
          '_draft',
          Template.currentData()._id
        )
      }
    }
  })
}

Fix a small syntax error


var sqlite3 = require('sqlite3').verbose();
var config = require('./data/config.js');
var db = new sqlite3.Database(config.getDatabasePath());

db.run("\
	CREATE TABLE IF NOT EXISTS devices (\
		id VARCHAR(20) PRIMARY KEY NOT NULL\
	);\
");

db.run("\
	CREATE TABLE IF NOT EXISTS updates (\
		id INTEGER PRIMARY KEY AUTOINCREMENT,\
		timestamp DATETIME NOT NULL,\
		md5sum CHARACTER(32),\
		filename VARCHAR(255) NOT NULL,\
		channel VARCHAR(10) NOT NULL,\
		changelog TEXT,\
		api_level INTEGER NOT NULL,\
		subdirectory VARCHAR(255) NULL,\
		device VARCHAR(20) NOT NULL,\
		active BOOLEAN DEFAULT FALSE NOT NULL,\
		FOREIGN KEY(device) REFERENCES devices(id),\
		CONSTRAINT unique_file_per_device UNIQUE(device, filename, subdirectory)\
	);\
");

db.run("\
	CREATE TABLE IF NOT EXISTS statistics (\
		update_id INTEGER NOT NULL,\
		timestamp DATETIME DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,\
		FOREIGN KEY(update_id) REFERENCES updates(id)\
	);\
");

module.exports.getInstance = function() { return db; }

var sqlite3 = require('sqlite3').verbose();
var config = require('./data/config.js');
var db = new sqlite3.Database(config.getDatabasePath());

db.run("\
	CREATE TABLE IF NOT EXISTS updates (\
		id INTEGER PRIMARY KEY AUTOINCREMENT,\
		timestamp DATETIME NOT NULL,\
		md5sum CHARACTER(32),\
		filename VARCHAR(255) NOT NULL,\
		channel VARCHAR(10) NOT NULL,\
		changelog TEXT,\
		api_level INTEGER NOT NULL,\
		subdirectory VARCHAR(255) NULL,\
		device VARCHAR(20) NOT NULL,\
		active BOOLEAN DEFAULT FALSE NOT NULL,\
		CONSTRAINT unique_file_per_device UNIQUE(device, filename, subdirectory)\
	);\
");

db.run("\
	CREATE TABLE IF NOT EXISTS statistics (\
		update_id INTEGER NOT NULL,\
		timestamp DATETIME DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,\
		FOREIGN KEY(update_id) REFERENCES updates(id)\
	);\
");

module.exports.getInstance = function() { return db; }

Remove the devices table for the moment. This is not normalized, but works for the moment :-).


const vertPlotLine = (epoch, color, text) => ({
    id: text,
    value: epoch * 1000,
    color,
    width: 2,
    label: {
        text,
        style: {
            color,
        }
    }
});

export default (contract) => [
    vertPlotLine(contract.date_expiry, 'navy', 'Time of Expiry'),
    vertPlotLine(contract.date_settlement, 'navy', 'Settlement Time'),
    vertPlotLine(contract.date_start, 'navy', 'Start Time'),
    vertPlotLine(contract.entry_tick_time, 'navy', 'Entry Spot'),
    vertPlotLine(contract.expiry_time, 'navy', 'Expiry Time'),
];

const vertPlotLine = (epoch, color, text, textAlign) => ({
    id: text,
    value: epoch * 1000,
    color,
    width: 2,
    label: {
        text,
        textAlign,
        style: {
            color,
        }
    }
});

export default (contract) => [
    vertPlotLine(contract.purchase_time, 'navy', 'Purchase Time', 'left'),
    vertPlotLine(contract.date_start, 'navy', 'Start Time', 'left'),
    vertPlotLine(contract.entry_tick_time, 'navy', 'Entry Spot', 'right'),
    vertPlotLine(contract.date_expiry, 'navy', 'Time of Expiry', 'left'),
    vertPlotLine(contract.date_settlement, 'navy', 'Settlement Time', 'left'),
    vertPlotLine(contract.expiry_time, 'navy', 'End Time', 'right'),
    vertPlotLine(contract.exit_tick_time, 'navy', 'Exit Spot', 'left'),
    vertPlotLine(contract.sell_spot_time, 'navy', 'Sell Time', 'right'),

];

Add plot lines for more time points and fix overlapping text for some that fall on the same time


module.exports = {
    'port': 8889,
    'providers': ['directory', 's3'],
    'files': __dirname + '/files',
    'mapfile_dir': __dirname + '/files/.cache',
    'data_dir': __dirname + '/files/.cache',
    'export_dir': __dirname + '/files/output',
    // TODO: request-specific overrides
    'header_defaults': {
        'Expires': new Date(Date.now() +
            1000 // second
            * 60 // minute
            * 60 // hour
            * 24 // day
            * 365 // year
            )
    }
}

module.exports = {
    'port': 8889,
    'providers': ['directory', 's3'],
    'files': __dirname + '/files',
    'mapfile_dir': __dirname + '/files/.cache',
    'data_dir': __dirname + '/files/.cache',
    'export_dir': __dirname + '/files/export',
    // TODO: request-specific overrides
    'header_defaults': {
        'Expires': new Date(Date.now() +
            1000 // second
            * 60 // minute
            * 60 // hour
            * 24 // day
            * 365 // year
            )
    }
}

Move export output directory from files/output to files/export.


import Controller from '@ember/controller';
import { computed, get } from '@ember/object';
import { inject as service } from '@ember/service';

export default Controller.extend({
  router: service(),

  clusterTemplateRevisionId: null,

  actions: {
    save() {
      if (this.clusterTemplateRevisionId) {
        this.router.transitionTo('global-admin.clusters.new.launch', this.model.provider, { queryParams: { clusterTemplateRevision: this.clusterTemplateRevisionId } });
      } else {
        this.router.transitionTo('global-admin.clusters.new.launch', this.model.provider, { queryParams: { clusterTemplateRevision: null } });
      }
    },
    cancel() {
      this.router.transitionTo('global-admin.clusters.new')
    }
  },

  allTemplates: computed('model.clusterTemplates.[]', 'model.clusterTemplateRevisions.[]', function() {
    const remapped = [];
    let { clusterTemplates, clusterTemplateRevisions } = this.model;

    clusterTemplates         = clusterTemplates.filterBy('enabled');
    clusterTemplateRevisions = clusterTemplateRevisions.filterBy('enabled');

    clusterTemplateRevisions.forEach((rev) => {
      let match = clusterTemplates.findBy('id', get(rev, 'clusterTemplateId'));

      remapped.pushObject({
        clusterTemplateId:           get(match, 'id'),
        clusterTemplateName:         get(match, 'displayName'),
        clusterTemplateRevisionId:   get(rev, 'id'),
        clusterTemplateRevisionName: get(rev, 'name'),
      });
    });

    return remapped;
  }),

});

import Controller from '@ember/controller';
import { computed, get } from '@ember/object';
import { inject as service } from '@ember/service';

export default Controller.extend({
  router: service(),

  clusterTemplateRevisionId: null,

  actions: {
    save() {
      if (this.clusterTemplateRevisionId) {
        this.router.transitionTo('global-admin.clusters.new.launch', this.model.provider, { queryParams: { clusterTemplateRevision: this.clusterTemplateRevisionId } });
      } else {
        this.router.transitionTo('global-admin.clusters.new.launch', this.model.provider, { queryParams: { clusterTemplateRevision: null } });
      }
    },
    cancel() {
      this.router.transitionTo('global-admin.clusters.new')
    }
  },

  allTemplates: computed('model.clusterTemplates.[]', 'model.clusterTemplateRevisions.[]', function() {
    const remapped = [];
    let { clusterTemplates, clusterTemplateRevisions } = this.model;

    clusterTemplateRevisions = clusterTemplateRevisions.filterBy('enabled');

    clusterTemplateRevisions.forEach((rev) => {
      let match = clusterTemplates.findBy('id', get(rev, 'clusterTemplateId'));

      if (match) {
        remapped.pushObject({
          clusterTemplateId:           get(match, 'id'),
          clusterTemplateName:         get(match, 'displayName'),
          clusterTemplateRevisionId:   get(rev, 'id'),
          clusterTemplateRevisionName: get(rev, 'name'),
        });
      }
    });

    return remapped;
  }),

});

Remove enabled filter on clusterTemplates that caused js error


/* This file is part of Indico.
 * Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

var ndServices = angular.module('ndServices', []);

ndServices.provider('url', function() {
    var baseUrl = Indico.Urls.Base;
    var modulePath = '';
    var debug = $('body').data('debug') ? '?' + +Date.now() : '';

    return {
        setModulePath: function(path) {
            if (path.substr(-1) == '/') {
                path = path.substr(0, path.length - 1);
            }

            modulePath = path;
        },

        $get: function() {
            return {
                tpl: function(path) {
                    return baseUrl + modulePath + '/tpls/' + path + debug;
                }
            };
        }
    };
});

/* This file is part of Indico.
 * Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

var ndServices = angular.module('ndServices', []);

ndServices.provider('url', function() {
    var baseUrl = Indico.Urls.Base;
    var modulePath = '';
    // XXX: don't remove the () around `+Date.now()`
    // the minifier converts this to `'?'++Date.now()` which is a syntax error
    var debug = $('body').data('debug') ? '?' + (+Date.now()) : '';

    return {
        setModulePath: function(path) {
            if (path.substr(-1) == '/') {
                path = path.substr(0, path.length - 1);
            }

            modulePath = path;
        },

        $get: function() {
            return {
                tpl: function(path) {
                    return baseUrl + modulePath + '/tpls/' + path + debug;
                }
            };
        }
    };
});

Fix error with minified JS


import Resolver from 'resolver';
import routerMap from 'bibliaolvaso/router';

var App = Ember.Application.create({
  LOG_ACTIVE_GENERATION: true,
  LOG_VIEW_LOOKUPS: true,
  LOG_TRANSITIONS: true,
  modulePrefix: 'bibliaolvaso',
  Resolver: Resolver
});

App.Router.map(routerMap);

App.Router.reopen({
  location: 'history'
});

App.ApplicationAdapter = DS.FixtureAdapter.extend();

export default App;

import Resolver from 'resolver';
import routerMap from 'bibliaolvaso/router';

var App = Ember.Application.create({
  //LOG_STACKTRACE_ON_DEPRECATION: true,
  //LOG_BINDINGS:                  true,
  LOG_TRANSITIONS:               true,
  //LOG_TRANSITIONS_INTERNAL:      false,
  LOG_VIEW_LOOKUPS:              true,
  LOG_ACTIVE_GENERATION:         true
  modulePrefix:                  'bibliaolvaso',
  Resolver:                      Resolver
});

App.Router.map(routerMap);

App.Router.reopen({
  location: 'history'
});

App.ApplicationAdapter = DS.FixtureAdapter.extend();

export default App;

Include all available log flags, comment out unused ones


"use strict";

var store = require_core("server/store");
var config = require_core("server/config");
var connect = require('connect');

module.exports = {
  setup_packager: function() {
    // sets up the packager endpoint for react
    require_app("server/react").install();
  },
  setup_app: function() {
    console.log("Main setup stuff, something, something");
    if (config.slog) {
      require_app("controllers/slog/server").install();
    }
  },
  setup_cache: function(app) {
    // setup static helpers
    var oneDay = 1000 * 60 * 60 * 24;
    var oneYear = oneDay * 365;
    app.use(connect.static('react/', { maxAge: oneYear }));
  }
};

"use strict";

var store = require_core("server/store");
var config = require_core("server/config");
var connect = require('connect');

module.exports = {
  setup_packager: function() {
    // sets up the packager endpoint for react
    require_app("server/react").install();
  },
  setup_app: function() {
    console.log("Main setup stuff, something, something");
    if (config.slog) {
      require_app("controllers/slog/server").install();
    }
  },
  setup_request: function(req, res) {
    console.log("Handling Request to", req.path, req.query);
  },
  setup_cache: function(app) {
    // setup static helpers
    var oneDay = 1000 * 60 * 60 * 24;
    var oneYear = oneDay * 365;
    app.use(connect.static('react/', { maxAge: oneYear }));
  }
};

Add simple logger for request handler (useful with slog)


function isDomSelector(str) {
  if (typeof str !== 'string') {
    return false;
  }

  try {
    document.querySelector(str);
    return true;
  } catch (error) {
    return false;
  }
}

module.exports = isDomSelector;

function isDomSelector(str) {
  if (typeof str !== 'string') {
    return false;
  }

  try {
    if (!document) {
      throw new Error('avoriaz must be run in a browser environment like PhantomJS, jsdom or chrome');
    }
  } catch (error) {
    throw new Error('avoriaz must be run in a browser environment like PhantomJS, jsdom or chrome');
  }

  try {
    document.querySelector(str);
    return true;
  } catch (error) {
    return false;
  }
}

module.exports = isDomSelector;

Throw error - avoriaz must be run in a browser - if document does not exist


(function(d) {
	"use strict";
	var hs = d.getElementById("DocumentationText").querySelectorAll("H1, H2, H3"), h;

	for (var i = 0; i < hs.length; i++) {
		h = hs[i];
		if (h.id != null && h.id.length > 0) {
			h.insertAdjacentHTML('beforeend', '¶')
		}
	}

})(document);

Fix for in-page anchor links


/** @typedef {import('./index').EventBridgeCloudWatchAlarmsEvent} EventBridgeCloudWatchAlarmsEvent */

const urls = require('./urls');

module.exports = {
  /**
   * @param {EventBridgeCloudWatchAlarmsEvent} event
   * @param {AWS.CloudWatch.DescribeAlarmsOutput} desc
   * @param {AWS.CloudWatch.DescribeAlarmHistoryOutput} history
   * @returns {String[]}
   */
  detailLines(event, desc, history) {
    if (
      event.detail?.previousState?.reasonData &&
      event.detail?.state?.reasonData
    ) {
      const stateData = JSON.parse(event.detail.state.reasonData);
      const previousData = JSON.parse(event.detail.previousState.reasonData);

      if (stateData?.startDate && previousData?.startDate) {
        const okTime = Date.parse(stateData.startDate);
        const alarmTime = Date.parse(previousData.startDate);
        const dif = okTime - alarmTime;
        const difSec = dif / 1000;

        let duration = difSec;
        let durationUnit = 'seconds';

        if (difSec >= 3600) {
          duration = Math.round(difSec / 3600);
          durationUnit = 'hours';
        } else if (difSec >= 60) {
          duration = Math.round(difSec / 60);
          durationUnit = 'minutes';
        }

        const url = urls.metricsConsole(event, desc, history);

        return [`*Alarm duration:* <${url}|${duration} ${durationUnit}>`];
      }
    }

    return [];
  },
};

/** @typedef {import('./index').EventBridgeCloudWatchAlarmsEvent} EventBridgeCloudWatchAlarmsEvent */

const urls = require('./urls');

module.exports = {
  /**
   * @param {EventBridgeCloudWatchAlarmsEvent} event
   * @param {AWS.CloudWatch.DescribeAlarmsOutput} desc
   * @param {AWS.CloudWatch.DescribeAlarmHistoryOutput} history
   * @returns {String[]}
   */
  detailLines(event, desc, history) {
    if (
      event.detail?.previousState?.reasonData &&
      event.detail?.state?.reasonData
    ) {
      const stateData = JSON.parse(event.detail.state.reasonData);
      const previousData = JSON.parse(event.detail.previousState.reasonData);

      if (stateData?.startDate && previousData?.startDate) {
        const okTime = Date.parse(stateData.startDate);
        const alarmTime = Date.parse(previousData.startDate);
        const dif = okTime - alarmTime;
        const difSec = dif / 1000;

        let duration = difSec;
        let durationUnit = 'seconds';

        if (difSec >= 3600) {
          duration = Math.round(difSec / 3600);
          durationUnit = 'hours';
        } else if (difSec >= 60) {
          duration = Math.round(difSec / 60);
          durationUnit = 'minutes';
        }

        const url = urls.metricsConsole(event, desc, history);

        return [
          `*Alarm duration:* ${duration} ${durationUnit} | View in: <${url}|CloudWatch Metrics>`,
        ];
      }
    }

    return [];
  },
};

Clean up OK alarm links


module.exports = function(grunt){

	grunt.initConfig({
		uglify: {
			options: {
				mangle: true,
				compress: true,
				sourceMap: "dist/application.map",
				banner: "/* Anastasios Zouzias 2015*/\n"
			},
			target: {
				src: "dest/application.js",
				dest: "dist/application.min.js"
			}
		},
		jshint: {
			options : {
				eqeqeq : true, /* Only ===, not ==*/
				curly: true,  /* Use curly everywhere*/
				undef: true
			},
			target: {
				src : "src/*.js"
			}
		},
		concat: {
			options: {
				seperator: ";"
			},
			target: {
				src: ["src/application.js", "src/util.js"],
				dest: "dest/application.js"
			}
		}
	});

	grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-concat');

	/* Run tasks : jshint, concat and uglify*/
	grunt.registerTask("default", ["jshint", "concat", "uglify"]);

}

module.exports = function(grunt){

	grunt.initConfig({
		uglify: { /* Minifies JS code */
			options: {
				mangle: true,
				compress: true,
				sourceMap: 'dist/application.map',
				banner: '/* Anastasios Zouzias 2015*/\n'
			},
			target: {
				src: 'dest/application.js',
				dest: 'dist/application.min.js'
			}
		},
		jshint: { /* Checks Javascript for error */
			options : {
				eqeqeq : true, /* Only ===, not ==*/
				curly: true,  /* Use curly everywhere*/
				undef: true
			},
			target: {
				src : 'src/*.js'
			}
		},
		concat: { /* Concats the following files to dest/application.js */
			options: {
				seperator: ';'
			},
			target: {
				src: ['src/application.js', 'src/util.js'],
				dest: 'dest/application.js'
			}
		},
		clean: { /* Clean dest and dist directories*/
			target: ['dist', 'dest']
		}
	});

	grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-concat');
	grunt.loadNpmTasks('grunt-contrib-clean');

	/* Run tasks : jshint, concat and uglify*/
	grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
	grunt.registerTask('rebuild', ['clean', 'default']);

}

Add clean task and comments


import React, { PropTypes } from 'react';
import { Field, FieldArray } from 'redux-form';

import ComputationFieldBasic from '../computation-field-basic';
import ComputationFieldCovariates from '../computation-field-covariates';

/**
 * Consortium computation fields.
 *
 * @param {Object} props
 * @param {Object[]} props.computationInputs Collection of field description objects
 * @param {Object} props.fields Collection of Redux Form fields
 * @returns {React.Component}
 */
export default function ConsortiumComputationFields({
  computationInputs,
  fields,
}) {
  return (

      {fields.map((name, index) => {
        const field = computationInputs[index];
        const component = field.type === 'covariates' ?
          <FieldArray
            component={ComputationFieldCovariates}
            name={name}
            {...field}
          /> :
          <Field
            component={ComputationFieldBasic}
            name={name}
            {...field}
          />;

        return
{component}
;
      })}

  );
}

ConsortiumComputationFields.propTypes = {
  computationInputs: PropTypes.arrayOf(PropTypes.object).isRequired,
  fields: PropTypes.shape({
    map: PropTypes.func.isRequired,
  }).isRequired,
};

import React, { PropTypes } from 'react';
import { Field, FieldArray } from 'redux-form';
import { round } from 'lodash';

import ComputationFieldBasic from '../computation-field-basic';
import ComputationFieldCovariates from '../computation-field-covariates';

/**
 * Normalize numeric input.
 *
 * {@link http://redux-form.com/6.6.0/examples/normalizing/}
 *
 * @param {number} value
 * @returns {number} Normalized value
 */
const normalizer = value => round(value, 3);

/**
 * Consortium computation fields.
 *
 * @param {Object} props
 * @param {Object[]} props.computationInputs Collection of field description objects
 * @param {Object} props.fields Collection of Redux Form fields
 * @returns {React.Component}
 */
export default function ConsortiumComputationFields({
  computationInputs,
  fields,
}) {
  return (

      {fields.map((name, index) => {
        const fieldProps = Object.assign({ name }, computationInputs[index]);
        let component;

        if (fieldProps.type === 'covariates') {
          component = (
            <FieldArray
              component={ComputationFieldCovariates}
              {...fieldProps}
            />
          );
        } else {
          if (fieldProps.type === 'number') {
            fieldProps.normalize = normalizer;
          }

          component = (
            <Field
              component={ComputationFieldBasic}
              {...fieldProps}
            />
          );
        }

        return
{component}
;
      })}

  );
}

ConsortiumComputationFields.propTypes = {
  computationInputs: PropTypes.arrayOf(PropTypes.object).isRequired,
  fields: PropTypes.shape({
    map: PropTypes.func.isRequired,
  }).isRequired,
};

Add rounding to numeric computation input fields.


import { h } from 'preact' /** @jsx h */
import { connect } from 'preact-redux'
import ButtonPrimary from '../components/ButtonPrimary'
import * as MenuActions from '../../menu/redux/action-creators'

const Home = ({ setMenuActive }) => (

      <button className="menu" onClick={() => setMenuActive(true)}>

      </button>

        Vamos usar a memória como ferramenta para mudança. Homenageando
        aqueles que estão #VivosEmNós, podemos transformar saudade
        em mobilização e, juntos, lutar por mais respeito à vida.

      <ButtonPrimary text="crie sua homenagem" href="/homenagem" />

)

const mapDispatchToProps = {
  setMenuActive: MenuActions.setActive
}

export default connect(undefined, mapDispatchToProps)(Home)

import { h } from 'preact' /** @jsx h */
import { connect } from 'preact-redux'
import ButtonPrimary from '../components/ButtonPrimary'
import * as MenuActions from '../../menu/redux/action-creators'
import { Header, MyLayout } from '../tags/layout'

const Home = ({ setMenuActive }) => (

      <button className="menu" onClick={() => setMenuActive(true)}>

      </button>

        Vamos usar a memória como ferramenta para mudança. Homenageando
        aqueles que estão #VivosEmNós, podemos transformar saudade
        em mobilização e, juntos, lutar por mais respeito à vida.

      <ButtonPrimary text="crie sua homenagem" href="/homenagem" />

)

const HomePage = ({ setMenuActive }) => {
  return (
      <MyLayout>
      <Home setMenuActive={ setMenuActive } />
      </MyLayout>
  )
}

const mapDispatchToProps = {
  setMenuActive: MenuActions.setActive
}

export default connect(undefined, mapDispatchToProps)(HomePage)

Set HomePage to use preact layout


import * as path from "path";
import _ from "lodash";
import rimraf from "rimraf";

import prettyConsole from "./libs/pretty_console";
import build from "./build";
import dev from "./dev";

require("es6-promise").polyfill();

exports.develop = execute(develop);
exports.start = execute(develop); // convenience alias
exports.build = execute(build);

function execute(target) {
  return ({ antwar, webpack, environment }) =>
    target({
      environment,
      antwar: _.merge(
        defaultConfiguration(),
        _.isFunction(antwar) ? antwar(environment) : antwar
      ),
      webpack: webpack(environment),
    });
}

function defaultConfiguration() {
  return {
    port: 3000,
    output: "build",
    console: prettyConsole,
  };
}

function develop(configurations) {
  const cwd = process.cwd();
  const buildDir = path.join(cwd, "./.antwar");

  return new Promise(function(resolve, reject) {
    rimraf(buildDir, function(err) {
      if (err) {
        return reject(err);
      }

      return build
        .devIndex(configurations)
        .then(dev.server.bind(null, configurations))
        .then(resolve)
        .catch(reject);
    });
  });
}

import * as path from "path";
import _ from "lodash";
import rimraf from "rimraf";

import prettyConsole from "./libs/pretty_console";
import build from "./build";
import dev from "./dev";

require("es6-promise").polyfill();

exports.develop = execute(develop);
exports.start = exports.develop; // convenience alias
exports.build = execute(build);

function execute(target) {
  return ({ antwar, webpack, environment }) =>
    target({
      environment,
      antwar: _.merge(
        defaultConfiguration(),
        _.isFunction(antwar) ? antwar(environment) : antwar
      ),
      webpack: webpack(environment),
    });
}

function defaultConfiguration() {
  return {
    port: 3000,
    output: "build",
    console: prettyConsole,
  };
}

function develop(configurations) {
  const cwd = process.cwd();
  const buildDir = path.join(cwd, "./.antwar");

  return new Promise(function(resolve, reject) {
    rimraf(buildDir, function(err) {
      if (err) {
        return reject(err);
      }

      return build
        .devIndex(configurations)
        .then(dev.server.bind(null, configurations))
        .then(resolve)
        .catch(reject);
    });
  });
}

Write alias in a better way


import Cookies from 'js-cookie'
import * as types from '../mutation-types'

const { locale, locales } = window.config

// state
export const state = {
  locale: Cookies.get('locale') || locale,
  locales: locales
}

// getters
export const getters = {
  locale: state => state.locale,
  locales: state => state.locales
}

// mutations
export const mutations = {
  [types.SET_LOCALE] (state, { locale }) {
    state.locale = locale
  }
}

// actions
export const actions = {
  setLocale ({ commit }, { locale }) {
    commit(types.SET_LOCALE, { locale })

    Cookies.set('locale', locale, { expires: 365 })
  }
}

import Cookies from 'js-cookie'
import * as types from '../mutation-types'

const { locale, locales } = window.config

function validateCookieLocale () {
  const cookieLocale = Cookies.get('locale') || locale
  if (locales.hasOwnProperty(cookieLocale)) {
    return cookieLocale
  } else {
    Cookies.set('locale', locale, { expires: 365 })
    return locale
  }
}

// state
export const state = {
  locale: validateCookieLocale(),
  locales: locales
}

// getters
export const getters = {
  locale: state => state.locale,
  locales: state => state.locales
}

// mutations
export const mutations = {
  [types.SET_LOCALE] (state, { locale }) {
    state.locale = locale
  }
}

// actions
export const actions = {
  setLocale ({ commit }, { locale }) {
    commit(types.SET_LOCALE, { locale })

    Cookies.set('locale', locale, { expires: 365 })
  }
}

Validate cookie contains known locale when initialising the store


'use strict';

var glob = require('glob'),
    _ = require('underscore'),
    ParallelExec = require('./lib/ParallelExec'),
    BehatTask = require('./lib/BehatTask'),
    defaults = {
        src: './**/*.feature',
        bin: './bin/behat',
        cwd: './',
        config: './behat.yml',
        flags: '',
        maxProcesses: 10000,
        baseDir: './',
        debug: false,
        numRetries: 0,
        timeout: 600000,
        env: {}
    };

/**
 * Grunt task for executing behat feature files in parallel
 *
 * @param {Grunt} grunt
 */
function GruntTask (grunt) {

    grunt.registerMultiTask('behat', 'Parallel behat', function () {
        var done = this.async(),
            options = this.options(defaults),
            executor = new ParallelExec(options.maxProcesses, {cwd: options.cwd, timeout: options.timeout, env: options.env}),
            behat;

        options.files = this.filesSrc;
        options.done = done;
        options.executor = executor;
        options.log = grunt.log;
        options.fail = grunt.fail;

        behat = new BehatTask(options);
        behat.run();
    });

}

module.exports = GruntTask;

'use strict';

var glob = require('glob'),
    _ = require('underscore'),
    ParallelExec = require('./lib/ParallelExec'),
    BehatTask = require('./lib/BehatTask'),
    defaults = {
        src: './**/*.feature',
        bin: './bin/behat',
        cwd: './',
        config: './behat.yml',
        flags: '',
        maxProcesses: 10000,
        baseDir: './',
        debug: false,
        numRetries: 0,
        timeout: 600000,
        env: null
    };

/**
 * Grunt task for executing behat feature files in parallel
 *
 * @param {Grunt} grunt
 */
function GruntTask (grunt) {

    grunt.registerMultiTask('behat', 'Parallel behat', function () {
        var done = this.async(),
            options = this.options(defaults),
            executor = new ParallelExec(options.maxProcesses, {cwd: options.cwd, timeout: options.timeout, env: options.env}),
            behat;

        options.files = this.filesSrc;
        options.done = done;
        options.executor = executor;
        options.log = grunt.log;
        options.fail = grunt.fail;

        behat = new BehatTask(options);
        behat.run();
    });

}

module.exports = GruntTask;

Change default for env execOption to null


module.exports = {
    preset: 'ts-jest',
    testEnvironment: 'node',
};

module.exports = {
    preset: 'ts-jest',
    testEnvironment: 'node',
    collectCoverageFrom: ['*.ts'],
    coverageThreshold: {
        global: {
            branches: 100,
            functions: 100,
            lines: 100,
            statements: 100,
        },
    },
};

Add coverage requirements to @proton/util


export default {
  '/users/doc/test-user': {
    id: 'test-user',
    name: 'test user',
    email: 'secret@secret.com',
  },
  '/users/doc/current-user': {
    id: 'current-user',
    name: 'current user',
    email: 'hi@me.com',
  },
  '/articles/doc/some-doc': {
    articleReplies: [
      { status: 'NORMAL', appId: 'WEBSITE', userId: 'current-user' },
      { status: 'NORMAL', appId: 'WEBSITE', userId: 'current-user' },
    ],
  },
  '/articles/doc/another-doc': {
    articleReplies: [
      { status: 'NORMAL', appId: 'WEBSITE', userId: 'current-user' },
    ],
  },
  '/articles/doc/not-this-doc': {
    articleReplies: [
      { status: 'DELETED', appId: 'WEBSITE', userId: 'current-user' },
    ],
  },
};

export default {
  '/users/doc/test-user': {
    id: 'test-user',
    name: 'test user',
    email: 'secret@secret.com',
  },
  '/users/doc/current-user': {
    id: 'current-user',
    name: 'current user',
    email: 'hi@me.com',
  },
  '/articles/doc/some-doc': {
    articleReplies: [
      // replies to the same doc only count as 1 for repliedArticleCount
      { status: 'NORMAL', appId: 'WEBSITE', userId: 'current-user' },
      { status: 'NORMAL', appId: 'WEBSITE', userId: 'current-user' },
    ],
  },
  '/articles/doc/another-doc': {
    articleReplies: [
      { status: 'NORMAL', appId: 'WEBSITE', userId: 'current-user' },
    ],
  },
  '/articles/doc/not-this-doc': {
    articleReplies: [
      { status: 'DELETED', appId: 'WEBSITE', userId: 'current-user' },
    ],
  },
};

Add comment to clarify fixture for repliedArticleCount


let defaultSnippet = `
from player_map import playerPositions
print playerPositions()`;

export default class Controller {
    constructor($log, $rootScope, connection, $mdToast) {
        var ctrl = this;
        this.$log = $log;
        this.$rootScope = $rootScope;
        this.connection = connection;
        this.$mdToast = $mdToast;
        this.codeSnippet = defaultSnippet;

        function aceLoaded(_editor) {
            _editor.commands.addCommand({
                name: "Execute",
                bindKey: {
                    mac: "Command-Shift-Up",
                    win: "Alt-Shift-Up"
                },
                exec: function () {
                    ctrl.run(ctrl.snippet);
                }
            });
        }

        function aceChanged() {
            //console.debug("ace was changed");
        }

        this.aceConfig = {
            useWrapMode: true,
            mode: "python",
            onLoad: aceLoaded,
            onChange: aceChanged
        };
    }

    run() {
        // Make sure we are still connected
        if (!this.connection.isConnected) {
            let msg = "Lost the connection";
            $mdToast.show($mdToast.simple().content(msg));
        }
        this.connection.send(this.codeSnippet);
    }
}

let defaultSnippet = `
from player_map import playerPositions
print playerPositions()`;

export default class Controller {
    constructor($log, $rootScope, connection, $mdToast) {
        this.$log = $log;
        this.$rootScope = $rootScope;
        this.connection = connection;
        this.$mdToast = $mdToast;
        this.codeSnippet = defaultSnippet;

        var aceLoaded = (_editor) => {
            _editor.commands.addCommand({
                name: "Execute",
                bindKey: {
                    mac: "Command-Shift-Up",
                    win: "Alt-Shift-Up"
                },
                exec: function () {
                    this.run(this.snippet);
                }
            });
        };

        function aceChanged() {
            //console.debug("ace was changed");
        }

        this.aceConfig = {
            useWrapMode: true,
            mode: "python",
            onLoad: aceLoaded,
            onChange: aceChanged
        };
    }

    run() {
        // Make sure we are still connected
        if (!this.connection.isConnected) {
            let msg = "Lost the connection";
            $mdToast.show($mdToast.simple().content(msg));
        }
        this.connection.send(this.codeSnippet);
    }
}

Use an arrow function to get rid of ctrl = this


module.exports = function(grunt) {
    // Do grunt-related things in here.
    grunt.initConfig({
        // Project configuration
        pkg: grunt.file.readJSON('package.json'),

        jshint: {
            files: ['gruntfile.js'],
        },

        concat: {
            css: {
                src: ['node_modules/normalize.css/normalize.css', 'src/css/style.css'],
                dest: 'dist/style.css'
            }
        },

        cssmin: {
            target: {
                files: [{
                    expand: true,
                    cwd: 'dist',
                    src: '*.css',
                    dest: 'dist',
                    ext: '.min.css'
                }]
            }
        },

        processhtml: {
            dist: {
                files: {
                    'dist/index.html': ['src/index.html']
                }
            }
        }
    });

    // Load the plugins that provides the tasks:
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-processhtml');

    // Default tasks:
    grunt.registerTask('default', ['jshint', 'concat', 'cssmin', 'processhtml']);

};

module.exports = function(grunt) {
    // Do grunt-related things in here.
    grunt.initConfig({
        // Project configuration
        pkg: grunt.file.readJSON('package.json'),

        jshint: {
            files: ['gruntfile.js'],
        },

        concat: {
            css: {
                src: ['node_modules/normalize.css/normalize.css', 'src/css/style.css'],
                dest: 'dist/css/style.css'
            }
        },

        cssmin: {
            target: {
                files: [{
                    expand: true,
                    cwd: 'dist/css',
                    src: '*.css',
                    dest: 'dist/css',
                    ext: '.min.css'
                }]
            }
        },

        processhtml: {
            dist: {
                files: {
                    'dist/index.html': ['src/index.html']
                }
            }
        }
    });

    // Load the plugins that provides the tasks:
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-processhtml');

    // Default tasks:
    grunt.registerTask('default', ['jshint', 'concat', 'cssmin', 'processhtml']);

};

Change 'dest' address for built css files


'use strict';

angular.module('nin')
  .controller('BottomCtrl', function ($scope, $interval, socket) {

    var linesContainer = null;

    $scope.onBottomScroll = function(event) {
      linesContainer = event.target;
      $scope.bottomScrollOffset = event.target.scrollLeft;
    };

    $scope.musicLayerClick = function($event) {
      $scope.demo.jumpToFrame($event.offsetX);
    };

    $scope.layerLabelClick = function(layer) {
      $scope.$parent.$parent.inspectedLayer = $scope.inspectedLayer == layer
                                            ? null
                                            : layer;
    };

    $scope.dragResizeLayer = function(event, ui, layer) {
      console.log(event, ui, layer);
      socket.sendEvent('set', {
        id: layer.position,
        field: 'startFrame',
        value: ui.position.left
      });
      socket.sendEvent('set', {
        id: layer.position,
        field: 'endFrame',
        value: ui.position.left + ui.size.width
      });
    };

    $interval(function(){
      $scope.hideMarker = false;
      if(!linesContainer) {
        return;
      }
      if(linesContainer.scrollLeft > $scope.currentFrame ||
        $scope.currentFrame >= linesContainer.scrollLeft + $(linesContainer).width()) {
        $scope.hideMarker = true;
      } else {
        $scope.hideMarker = false;
      }
    }, 1000 / 60);
  });

'use strict';

angular.module('nin')
  .controller('BottomCtrl', function ($scope, $interval, socket) {

    var linesContainer = null;

    $scope.onBottomScroll = function(event) {
      linesContainer = event.target;
      $scope.bottomScrollOffset = event.target.scrollLeft;
    };

    $scope.musicLayerClick = function($event) {
      $scope.demo.jumpToFrame($event.offsetX);
    };

    $scope.layerLabelClick = function(layer) {
      $scope.$parent.$parent.inspectedLayer = $scope.inspectedLayer == layer
                                            ? null
                                            : layer;
    };

    $scope.dragResizeLayer = function(event, ui, layer) {
      if (ui.position.left != layer.startFrame) {
        socket.sendEvent('set', {
          id: layer.position,
          field: 'startFrame',
          value: ui.position.left
        });
      } else {
        socket.sendEvent('set', {
          id: layer.position,
          field: 'endFrame',
          value: ui.position.left + ui.size.width
        });
      }
    };

    $interval(function(){
      $scope.hideMarker = false;
      if(!linesContainer) {
        return;
      }
      if(linesContainer.scrollLeft > $scope.currentFrame ||
        $scope.currentFrame >= linesContainer.scrollLeft + $(linesContainer).width()) {
        $scope.hideMarker = true;
      } else {
        $scope.hideMarker = false;
      }
    }, 1000 / 60);
  });

Fix bug when modifying the startFrame of a layer


import { dbAdapter } from '../../../models'
import { reportError } from '../../../support/exceptions'
import { serializePostsCollection } from '../../../serializers/v2/post';

export default class TimelinesController {
  app = null;

  constructor(app) {
    this.app = app;
  }

  bestOf = async (req, res) => {
    try {
      const currentUserId = req.user ? req.user.id : null;

      const foundPosts = await dbAdapter.bestPosts(req.user);
      const postsObjects = dbAdapter.initRawPosts(foundPosts, { currentUser: currentUserId });
      const postsCollectionJson = await serializePostsCollection(postsObjects);

      res.jsonp(postsCollectionJson);
    } catch (e) {
      reportError(res)(e);
    }
  };
}

import { dbAdapter } from '../../../models'
import { reportError } from '../../../support/exceptions'
import { serializePostsCollection } from '../../../serializers/v2/post';

export default class TimelinesController {
  app = null;

  constructor(app) {
    this.app = app;
  }

  bestOf = async (req, res) => {
    try {
      const DEFAULT_LIMIT = 30;

      const currentUserId = req.user ? req.user.id : null;
      const offset = parseInt(req.query.offset, 10) || 0;
      const limit =  parseInt(req.query.limit, 10) || DEFAULT_LIMIT;

      const foundPosts = await dbAdapter.bestPosts(req.user, offset, limit);
      const postsObjects = dbAdapter.initRawPosts(foundPosts, { currentUser: currentUserId });
      const postsCollectionJson = await serializePostsCollection(postsObjects);

      res.jsonp(postsCollectionJson);
    } catch (e) {
      reportError(res)(e);
    }
  };
}

Apply offset/limit to Best Of


import { NativeModules, Platform } from 'react-native'

const { RNBranch } = NativeModules

export default async function createBranchUniversalObject(identifier, options = {}) {
  if (typeof identifier !== 'string') throw new Error('react-native-branch: identifier must be a string')

  const branchUniversalObject = {
    contentIndexingMode: 'private',
    canonicalIdentifier: identifier,
    ...options
  }

  let { ident } = await RNBranch.createUniversalObject(branchUniversalObject)

  return {
    showShareSheet(shareOptions = {}, linkProperties = {}, controlParams = {}) {
      shareOptions = {
        title: options.title || '',
        text: options.contentDescription || '',
        ...shareOptions,
      }

      linkProperties = {
        feature: 'share',
        channel: 'RNApp',
        ...linkProperties,
      }

      return RNBranch.showShareSheet(ident, shareOptions, linkProperties, controlParams)
    },
    registerView() {
      return RNBranch.registerView(ident)
    },
    generateShortUrl(linkProperties = {}, controlParams = {}) {
      return RNBranch.generateShortUrl(ident, linkProperties, controlParams)
    },
    listOnSpotlight() {
      if (Platform.OS !== 'ios') return Promise.resolve()
      return RNBranch.listOnSpotlight(ident)
    },
    release() {
      RNBranch.releaseUniversalObject(ident)
    }
  }
}

import { NativeModules, Platform } from 'react-native'

const { RNBranch } = NativeModules

export default async function createBranchUniversalObject(identifier, options = {}) {
  if (typeof identifier !== 'string') throw new Error('react-native-branch: identifier must be a string')

  const branchUniversalObject = {
    contentIndexingMode: 'private',
    canonicalIdentifier: identifier,
    ...options
  }

  const { ident } = await RNBranch.createUniversalObject(branchUniversalObject)

  return {
    showShareSheet(shareOptions = {}, linkProperties = {}, controlParams = {}) {
      shareOptions = {
        title: options.title || '',
        text: options.contentDescription || '',
        ...shareOptions,
      }

      linkProperties = {
        feature: 'share',
        channel: 'RNApp',
        ...linkProperties,
      }

      return RNBranch.showShareSheet(ident, shareOptions, linkProperties, controlParams)
    },
    registerView() {
      return RNBranch.registerView(ident)
    },
    generateShortUrl(linkProperties = {}, controlParams = {}) {
      return RNBranch.generateShortUrl(ident, linkProperties, controlParams)
    },
    listOnSpotlight() {
      if (Platform.OS !== 'ios') return Promise.resolve()
      return RNBranch.listOnSpotlight(ident)
    },
    release() {
      RNBranch.releaseUniversalObject(ident)
    }
  }
}

Make { ident } const instead of let for closure


import React, { Component } from "react";
import { injectGlobal } from "styled-components";

import Api from "./api";
import StoryList from "./containers/StoryList";

// eslint-disable-next-line no-unused-expressions
injectGlobal`
@font-face {
  font-family: 'Verdana, Geneva, sans-serif'
}
body {
  margin: 0;
}
`;

class App extends Component {
  state = {
    newStories: []
  };

  fetchNewStories(storyIds) {
    let actions = storyIds.slice(0, 30).map(this.fetchSingleStory);
    let results = Promise.all(actions);
    results.then(data =>
      this.setState(
        Object.assign({}, this.state, {
          newStories: data
        })
      )
    );
  }

  fetchSingleStory(id, index) {
    const rank = index + 1;
    return new Promise(resolve => {
      Api.fetch(`/item/${id}`, {
        context: this,
        then(data) {
          let item = data;
          // add the rank since it does not exist yet
          item.rank = rank;
          resolve(item);
        }
      });
    });
  }

  componentDidMount() {
    Api.fetch(`/newstories`, {
      context: this,
      asArray: true,
      then(storyIds) {
        this.fetchNewStories(storyIds);
      }
    });
  }

  render() {
    return <StoryList items={this.state.newStories} />;
  }
}

export default App;

import React, { Component } from "react";
import { injectGlobal } from "styled-components";

import Api from "./api";
import StoryList from "./containers/StoryList";

// eslint-disable-next-line no-unused-expressions
injectGlobal`
@font-face {
  font-family: 'Verdana, Geneva, sans-serif'
}
body {
  margin: 0;
}
`;

class App extends Component {
  state = {
    newStories: []
  };

  fetchNewStories(storyIds) {
    let actions = storyIds.slice(0, 30).map(this.fetchSingleStory);
    let results = Promise.all(actions);
    results.then(data =>
      this.setState(
        Object.assign({}, this.state, {
          newStories: data
        })
      )
    );
  }

  fetchSingleStory(id, index) {
    const rank = index + 1;
    return new Promise(resolve => {
      Api.fetch(`/item/${id}`, {
        then(data) {
          let item = data;
          // add the rank since it does not exist yet
          item.rank = rank;
          resolve(item);
        }
      });
    });
  }

  componentDidMount() {
    Api.fetch(`/newstories`, {
      context: this,
      then(storyIds) {
        this.fetchNewStories(storyIds);
      }
    });
  }

  render() {
    return <StoryList items={this.state.newStories} />;
  }
}

export default App;

Remove optional options from api call


const sass = require('gulp-sass');
const gulpif = require('gulp-if');
const autoprefixer = require('gulp-autoprefixer');
const preprocess = require('gulp-preprocess');
const sourcemaps = require('gulp-sourcemaps');
const config = require('../../../config/config');
const paths = require('../../paths');

const isProduction = config.env === 'production';

// add extra sass paths
const SASS_PATHS = [
  `${paths.nodeModules}`,
];

module.exports = (gulp) => {
  return gulp.src(`${paths.sourceStyles}/**/*.scss`)
    .pipe(gulpif(!isProduction, sourcemaps.init()))
    .pipe(sass({
      includePaths: SASS_PATHS,
      outputStyle: isProduction ? 'compressed' : 'expanded',
    }).on('error', sass.logError))
    .pipe(autoprefixer({
      browsers: ['> 0%', 'IE 8'],
    }))
    .pipe(preprocess({
      context: {
        FONT_CDN_PATH: config.fontCdn,
      },
    }))
    .pipe(gulpif(!isProduction, sourcemaps.write('.')))
    .pipe(gulp.dest(`${paths.outputStyles}`));
};

const sass = require('gulp-sass');
const gulpif = require('gulp-if');
const autoprefixer = require('gulp-autoprefixer');
const preprocess = require('gulp-preprocess');
const sourcemaps = require('gulp-sourcemaps');
const config = require('../../../config/config');
const paths = require('../../paths');

const isProduction = config.env === 'production';

// add extra sass paths
const SASS_PATHS = [
  `${paths.nodeModules}`,
];

function handleError(error) {
  sass.logError.call(this, error);
  process.exit(1);
}

module.exports = (gulp) => {
  return gulp.src(`${paths.sourceStyles}/**/*.scss`)
    .pipe(gulpif(!isProduction, sourcemaps.init()))
    .pipe(sass({
      includePaths: SASS_PATHS,
      outputStyle: isProduction ? 'compressed' : 'expanded',
    }).on('error', handleError))
    .pipe(autoprefixer({
      browsers: ['> 0%', 'IE 8'],
    }))
    .pipe(preprocess({
      context: {
        FONT_CDN_PATH: config.fontCdn,
      },
    }))
    .pipe(gulpif(!isProduction, sourcemaps.write('.')))
    .pipe(gulp.dest(`${paths.outputStyles}`));
};

Break build on Sass error


let acceptableDomainsFromEnv = process.env.ACCEPTABLE_DOMAINS;

if (acceptableDomainsFromEnv) {
  acceptableDomainsFromEnv = acceptableDomainsFromEnv.split(',').filter(
    domain => !!domain // Remove any empty items from the list.
  );
}

module.exports = (req, res, next, {
  /**
   * @param acceptableDomains
   *
   * List of fully qualified accceptable domain names.
   * Should be for example 'safaricom.co.ke', not just 'safaricom' or 'co.ke'
   *
   * IMPORTANT!!
   * If you use this middleware and add other acceptableDomains, make sure to
   * add 'safaricom.co.ke' in your list as well. It's added here as a default
   * and will be overridden if other values are passed.
   * It's HIGHLY recommended that you don't edit the code to add domains
   * into the list, rather, add them into your environment as a comma
   * separated list in an env variable named ACCEPTABLE_DOMAINS.
   *
   * Not going to validate that you didn't override 'safaricom.co.ke', I trust
   * that you're a developer and you what you're doing. ¯\_(ツ)_/¯
   */
  acceptableDomains = ['safaricom.co.ke']
} = {}) => {
  let domains = acceptableDomains;

  if (acceptableDomainsFromEnv) {
    domains = domains.concat(acceptableDomainsFromEnv);
  }
  if (req.body.email) { // Only try to validate if we have an email.
    for (const domain of domains) {
      if (new RegExp(`${domain}$`, 'i').test(req.body.email)) {
        return next();
      }
    }

    return res.status(400).send({
      email: 'This email is invalid.'
    });
  }

  return next();
};

let acceptableDomainsFromEnv = process.env.ACCEPTABLE_DOMAINS;

if (acceptableDomainsFromEnv) {
  acceptableDomainsFromEnv = acceptableDomainsFromEnv.split(',').filter(
    domain => !!domain // Remove any empty items from the list.
  );
}

module.exports = (req, res, next, {
  /**
   * @param acceptableDomains
   *
   * List of fully qualified accceptable domain names.
   */
  acceptableDomains = []
} = {}) => {
  let domains = acceptableDomains;

  if (acceptableDomainsFromEnv) {
    domains = domains.concat(acceptableDomainsFromEnv);
  }
  if (req.body.email) { // Only try to validate if we have an email.
    for (const domain of domains) {
      if (new RegExp(`${domain}$`, 'i').test(req.body.email)) {
        return next();
      }
    }

    return res.status(400).send({
      email: 'This email is invalid.'
    });
  }

  return next();
};

Remove default acceptable email domain.


module.exports = {
  // Chrome
  chrome_canary_osx: {
    browserName: 'chrome',
    platform: 'OS X 10.11',
    version: 'dev',
    base: 'SauceLabs',
  },

  chrome_latest_osx: {
    browserName: 'chrome',
    platform: 'OS X 10.11',
    version: 'latest',
    base: 'SauceLabs',
  },

  // Firefox
  firefox_latest_osx: {
    browserName: 'firefox',
    platform: 'OS X 10.11',
    version: 'latest',
    base: 'SauceLabs',
  },

  safari_latest: {
    browserName: 'safari',
    platform: 'OS X 10.11',
    version: 'latest',
    base: 'SauceLabs',
  },

  // IE
  internet_explorer_11: {
    browserName: 'internet explorer',
    platform: 'Windows 10',
    version: '11',
    base: 'SauceLabs',
  },

  // Edge
  microsoftedge_latest: {
    browserName: 'microsoftedge',
    platform: 'Windows 10',
    version: 'latest',
    base: 'SauceLabs',
  },
};

module.exports = {
  // Chrome
  chrome_canary_osx: {
    browserName: 'chrome',
    platform: 'OS X 10.11',
    version: 'dev',
    base: 'SauceLabs',
  },

  chrome_latest_osx: {
    browserName: 'chrome',
    platform: 'OS X 10.11',
    version: 'latest',
    base: 'SauceLabs',
  },

  // Firefox
  firefox_latest_osx: {
    browserName: 'firefox',
    platform: 'OS X 10.11',
    version: 'latest',
    base: 'SauceLabs',
  },

  safari_latest: {
    browserName: 'safari',
    platform: 'OS X 10.11',
    version: 'latest',
    base: 'SauceLabs',
  },

  // IE
  // internet_explorer_11: {
  //   browserName: 'internet explorer',
  //   platform: 'Windows 10',
  //   version: '11',
  //   base: 'SauceLabs',
  // },
  //
  // https://github.com/jonathanweiss/sk-progress-circle/issues/6

  // Edge
  microsoftedge_latest: {
    browserName: 'microsoftedge',
    platform: 'Windows 10',
    version: 'latest',
    base: 'SauceLabs',
  },
};

Remove IE11 from SauceLabs tests until compatibility is restored


import React from "react";
import { RoutingApp } from "./modules/RoutingApp";
import store from "./store";
import { Provider } from "react-redux";
import { STUY_SPEC_API_URL } from "./constants";

import { ApolloProvider } from "react-apollo";
import { ApolloClient } from "apollo-client";
import { HttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";

import { objectFilter } from "./utils";
import './index.scss';

const apolloClient = new ApolloClient({
  link: new HttpLink({ uri: `${STUY_SPEC_API_URL}/graphql` }),
  cache: new InMemoryCache(),
  connectToDevTools: true
});

Object.filter = objectFilter;

function App () {
  return(
    <Provider store={store}>
      <ApolloProvider client={apolloClient}>
        <RoutingApp />
      </ApolloProvider>
    </Provider>
  )
}

export default App;

import React, { useEffect } from "react";
import { RoutingApp } from "./modules/RoutingApp";
import store from "./store";
import { Provider } from "react-redux";
import { STUY_SPEC_API_URL } from "./constants";

import { ApolloProvider } from "react-apollo";
import { ApolloClient } from "apollo-client";
import { HttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";

import { objectFilter } from "./utils";
import useDarkMode from "use-dark-mode";
import "./index.scss";

const apolloClient = new ApolloClient({
  link: new HttpLink({ uri: `${STUY_SPEC_API_URL}/graphql` }),
  cache: new InMemoryCache(),
  connectToDevTools: true,
});

Object.filter = objectFilter;

function App() {
  const darkMode = useDarkMode(false);

  useEffect(() => {
    if (localStorage.getItem("darkMode") == null) {
      darkMode.disable();
    }
  });
  return (
    <Provider store={store}>
      <ApolloProvider client={apolloClient}>
        <RoutingApp />
      </ApolloProvider>
    </Provider>
  );
}

export default App;

Set default to be light mode


import { keccak256 as _keccak256, toHexString } from "lib/data/decode/utils";

export function prefixName(prefix, fn) {
  Object.defineProperty(fn, 'name', {
    value: `${prefix}.${fn.name}`,
    configurable: true
  });

  return fn;
}

/**
 * @return 0x-prefix string of keccak256 hash
 */
export function keccak256(...args) {
  return toHexString(_keccak256(...args));
}

Add convenience helper for keccak hash


import React from 'react';

const SearchBar = () => {
	return <input />;
}

export default SearchBar;

import React from 'react';

class SearchBar extends React.Component {
	render() {
		return <input />;
	}
}

export default SearchBar;

Replace the constant with a class, add render method returning the same jsx input.


import express from 'express'
import {logger, http_logger} from './utils/logger'
import {cookie_parser, session} from './utils/session'
import body_parser from 'body-parser'
import passport from 'passport'
import express_validator from 'express-validator'
import {authentication_router} from './routers/authentication_router'
import {group_router} from './routers/group_router'
import {counter_router} from './routers/counter_router'
import {error_handler} from './utils/errors'
import {init_authentication} from './utils/authentication'
import {init_mongodb} from './utils/mongodb'

init_mongodb(() => {
  const app = express()
  app.use(http_logger)
  app.use(cookie_parser)
  app.use(body_parser.urlencoded({
    extended: true,
  }))
  app.use(body_parser.json())
  app.use(session)
  app.use(passport.initialize())
  app.use(passport.session())
  app.use(express_validator())
  app.use(authentication_router)
  app.use(group_router)
  app.use(counter_router)
  app.use(error_handler)

  init_authentication()

  const port = process.env.VK_GROUP_STATS_SERVER_PORT || 3000
  app.listen(port, () => {
    logger.info(`app listening on port ${port}`)
  })
})

import express from 'express'
import {logger, http_logger} from './utils/logger'
import {cookie_parser, session} from './utils/session'
import body_parser from 'body-parser'
import passport from 'passport'
import express_validator from 'express-validator'
import {authentication_router} from './routers/authentication_router'
import {group_router} from './routers/group_router'
import {counter_router} from './routers/counter_router'
import {error_handler} from './utils/errors'
import {init_authentication} from './utils/authentication'
import {init_mongodb} from './utils/mongodb'

init_mongodb(() => {
  const app = express()
  app.use(http_logger)
  app.use(cookie_parser)
  app.use(body_parser.urlencoded({
    extended: true,
  }))
  app.use(body_parser.json())
  app.use(session)
  app.use(passport.initialize())
  app.use(passport.session())
  app.use(express_validator())
  app.use(authentication_router)

  const base_api_endpoint = '/api/v1'
  app.use(base_api_endpoint, group_router)
  app.use(base_api_endpoint, counter_router)
  app.use(error_handler)

  init_authentication()

  const port = process.env.VK_GROUP_STATS_SERVER_PORT || 3000
  app.listen(port, () => {
    logger.info(`app listening on port ${port}`)
  })
})

Set a base API endpoint


import http from '../http';

export default class collections {

    static getAll() {
        return http.get(`/zebedee/collections`)
            .then(response => {
                return response;
            })
    }

}

import http from '../http';

export default class collections {

    static getAll() {
        return http.get(`/zebedee/collections`)
            .then(response => {
                return response;
            })
    }

    static addAPIDataset(collectionID, instanceID) {
        // return http.put(`/zebedee/collections/${collectionID}/dataset/${instanceID}`, body , true)
        //     .then(response => {
        //         return response;
        //     })

        // mocked ok response from Zebedee
        return new Promise(resolve => {
            setTimeout(() => { resolve(); }, 2000);
        })

    }

    static removeAPIDataset(collectionID, instanceID) {
        // return http.delete(`/zebedee/collections/${collectionID}/dataset/${instanceID}`, true)
        //     .then(response => {
        //         return response;
        //     })

        // mocked ok response from Zebedee
        return new Promise(resolve => {
            setTimeout(() => { resolve(); }, 1000);
        })

    }

}

Add add and remove methods - currently returns promise after set time until api is ready


/*
 This file is a part of libertysoil.org website
 Copyright (C) 2015  Loki Education (Social Enterprise)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
export function defaultSelector(state) {
  let data = state.toJS();

  data.is_logged_in = !!data.current_user.id;

  if (data.is_logged_in) {
    let current_user_id = data.current_user.id;

    data.current_user_tags = data.current_user.tags;

    data.current_user = data.users[current_user_id];
    data.current_user.likes = data.likes[current_user_id] || [];
    data.current_user.favourites = data.favourites[current_user_id] || [];

    data.i_am_following = data.following[current_user_id];
  } else {
    data.current_user = null;
  }

  return data;
}

/*
 This file is a part of libertysoil.org website
 Copyright (C) 2015  Loki Education (Social Enterprise)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
export function defaultSelector(state) {
  let data = state.toJS();

  data.is_logged_in = !!data.current_user.id;

  if (data.is_logged_in) {
    let current_user_id = data.current_user.id;

    data.current_user_tags = data.current_user.tags;

    data.current_user = Object.assign(data.current_user, data.users[current_user_id]);
    data.current_user.likes = data.likes[current_user_id] || [];
    data.current_user.favourites = data.favourites[current_user_id] || [];

    data.i_am_following = data.following[current_user_id];
  } else {
    data.current_user = null;
  }

  return data;
}

Change selector to take current_user from state


// GitHub Gist: <%= name %>
// <%= _.repeat('=', name.length + 13) %>
//
// > (c) <%= new Date().getFullYear() %> Chao Huang <chao@realguess.net>

'use strict';

// Dependencies
// ============
//
// Define module dependencies.
var request = require('request');
var _       = require('underscore');

// Functions
// =========
//
// Define internal functions.

// My Func
// -------
function myFunc() {
}

// Exports
// =======
//
// Define module exports.

// Foo
// ---
exports.foo = function foo() {
  return 'Foo';
};

Add source code documentation format


'use strict';

/* eslint-disable no-process-exit */

const util = require('util');
const Cli = require('./Cli');
const CliError = require('./CliError');
const cli = new Cli(process.argv.slice(1), process.stdin, process.stdout, process.stderr);

cli.on('error', (err) => {
	process.stderr.write(err.message + '\n');
	process.exit(1);
});

cli.on('warning', (err) => {
	process.stderr.write(err.message + '\n');
});

try {
	cli.run();

} catch (err) {
	if (err instanceof CliError) {
		process.stderr.write(err.message);
		process.exit(err.code);
	} else {
		process.stderr.write(util.inspect(err));
		process.exit(254);
	}
}

'use strict';

/* eslint-disable no-process-exit */

const util = require('util');
const Cli = require('./Cli');
const CliError = require('./CliError');
const cli = new Cli(process.argv.slice(1), process.stdin, process.stdout, process.stderr);

cli.on('error', (err) => {
	const message = err.message || err.stack;

	process.stderr.write(message + '\n');
	process.exit(1);
});

cli.on('warning', (err) => {
	process.stderr.write(err.message + '\n');
});

try {
	cli.run();

} catch (err) {
	if (err instanceof CliError) {
		process.stderr.write(err.message);
		process.exit(err.code);
	} else {
		process.stderr.write(util.inspect(err));
		process.exit(254);
	}
}

Print trace for errors without message


// @flow

const { JSDOM } = require('jsdom');
const Node = require('jsdom/lib/jsdom/living/node-document-position');

// We can use jsdom-global at some point if maintaining that list turns out to be a burden.
const whiteList = ['HTMLElement', 'Performance'];
const blackList = ['sessionStorage', 'localStorage'];

function createDOM() {
  const dom = new JSDOM('', { pretendToBeVisual: true });
  global.window = dom.window;
  global.Node = Node;
  global.document = dom.window.document;
  // Not yet supported: https://github.com/jsdom/jsdom/issues/317
  global.document.createRange = () => ({
    setStart: () => {},
    setEnd: () => {},
    commonAncestorContainer: {
      nodeName: 'BODY',
      ownerDocument: document,
    },
  });
  global.navigator = {
    userAgent: 'node.js',
  };

  Object.keys(dom.window)
    .filter(key => !blackList.includes(key))
    .concat(whiteList)
    .forEach(key => {
      if (typeof global[key] === 'undefined') {
        global[key] = dom.window[key];
      }
    });
}

module.exports = createDOM;

// @flow

const { JSDOM } = require('jsdom');
const Node = require('jsdom/lib/jsdom/living/node-document-position');

// We can use jsdom-global at some point if maintaining these lists is a burden.
const whitelist = ['HTMLElement', 'Performance'];
const blacklist = ['sessionStorage', 'localStorage'];

function createDOM() {
  const dom = new JSDOM('', { pretendToBeVisual: true });
  global.window = dom.window;
  global.Node = Node;
  global.document = dom.window.document;
  // Not yet supported: https://github.com/jsdom/jsdom/issues/317
  global.document.createRange = () => ({
    setStart: () => {},
    setEnd: () => {},
    commonAncestorContainer: {
      nodeName: 'BODY',
      ownerDocument: document,
    },
  });
  global.navigator = {
    userAgent: 'node.js',
  };

  Object.keys(dom.window)
    .filter(key => !blacklist.includes(key))
    .concat(whitelist)
    .forEach(key => {
      if (typeof global[key] === 'undefined') {
        global[key] = dom.window[key];
      }
    });
}

module.exports = createDOM;

Fix typo in whitelist and blacklist


#!/usr/bin/env node

var yargs = require('yargs');

yargs
  .command(
    'init',
    'Initialize standalone CRA server',
    () => {},
    argv => {
      require('./cli/init');
    }
  )
  .command(
    'start',
    'Start CRA server',
    () => {},
    argv => {
      require('./cli/start');
    }
  )
  .command(
    'build',
    'Build CRA server',
    () => {},
    argv => {
      require('./cli/build');
    }
  )
  .command(
    'clean',
    'Clean build result',
    () => {},
    argv => {
      require('./cli/clean');
    }
  )
  .demandCommand(1, 'Please choose your command')
  .epilog('CRA Universal CLI')
  .help()
  .strict().argv;

#!/usr/bin/env node

require('babel-register')({
  presets: ['env'],
  plugins: ['transform-object-rest-spread']
});

var yargs = require('yargs');

yargs
  .command(
    'init',
    'Initialize standalone CRA server',
    () => {},
    argv => {
      require('./cli/init');
    }
  )
  .command(
    'start',
    'Start CRA server',
    () => {},
    argv => {
      require('./cli/start');
    }
  )
  .command(
    'build',
    'Build CRA server',
    () => {},
    argv => {
      require('./cli/build');
    }
  )
  .command(
    'clean',
    'Clean build result',
    () => {},
    argv => {
      require('./cli/clean');
    }
  )
  .demandCommand(1, 'Please choose your command')
  .epilog('CRA Universal CLI')
  .help()
  .strict().argv;

Add babel register for node compat