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

export default () => {
    return (
        <View style={styles.container}>
            <Text>
                Logout ...
            </Text>
        </View>
    );
};

const styles = {
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center'
    }
};

import React from 'react';
import { View, Text, ActivityIndicatorIOS } from 'react-native';

export default () => {
    return (
        <View style={styles.container}>
            <Text>
                Loading
            </Text>
            <ActivityIndicatorIOS
                animating={true}
                size='large'
                style={styles.activityIndicator}
            />
        </View>
    );
};

const styles = {
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center'
    },
    activityIndicator: {
        marginTop: 15
    }
};

Update the loading screen with an ActivityIndicator


'use strict';
module.exports =

angular
  .module('quill-grammar.directives.grammarCMS', [
  ])
  .directive('grammarCMSCategoriesNew', require('./categories.new.js'))
  .directive('grammarCMSCategoriesList', require('./categories.list.js'))
  .controller('GrammarCMSCtrl', require('./cms.controller.js'));

'use strict';
module.exports =

angular
  .module('quill-grammar.directives.grammarCMS', [
  ])
  .directive('grammarCmsCategoriesNew', require('./categories.new.js'))
  .directive('grammarCmsCategoriesList', require('./categories.list.js'))
  .controller('GrammarCmsCtrl', require('./cms.controller.js'));

Use strict camel case for directive names


import Ember from 'ember';
import { test } from 'qunit';
import moduleForAcceptance from '../../tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | new relic browser');

test('Loading New Relic Browser', function(assert) {
  visit('/');

  andThen(function() {
    var newRelic = window.NREUM;

    assert.expect(8);

    assert.ok(newRelic,
      'The New Relic object (NREUM) should be added to the window');

    assert.ok(typeof newRelic.noticeError === 'function',
      'New Relic Browser should be loaded');

    /* Now our errors are tracking, let's check they are
    caught by the extra Ember events like onerror */

    window.NREUM.noticeError = function(error) {

      assert.ok(true,
        'noticeError should be called by Ember.onerror');

      assert.ok(error instanceof Error,
        'noticeError should receive an error object');

      assert.ok(error.name !== 'TransitionAborted',
        'noticeError should not be called by Ember.onerror on TransitionAborted errors.');
    };

    Ember.onerror(new Error('Awh crap'));

    const transitionError = new Error('Ember Transition Aborted Test');
    transitionError.name = "TransitionAborted";
    Ember.onerror(transitionError);

    Ember.Logger.error('Whoops', 'We done messed up', {});

  });
});

test('console.error from Ember.Logger.error correctly shows messages', function(assert) {
  visit('/');

  andThen(function() {

    console.error = function(message) {
      assert.ok(
        message.toString().includes('Whoops We done messed up'),
        'Shows messages space-separated'
      );
    };

    Ember.Logger.error('Whoops', 'We done messed up');
  });
});

Add test for Ember.Logger.error messages


'use strict';

var inquirer = require('inquirer'),
  _ = require('lodash');

// callback must be in form of function(results)
module.exports = function(options, callback) {

  function required(value) {
    return !!value.trim() || 'Required';
  }

  var questions = [{
    type: 'input',
    name: 'name',
    message: 'What would you name your mean app?',
    default: options.name,
    validate: required
  }, {
    type: 'list',
    name: 'taskrunner',
    message: 'Do you prefer grunt or gulp as a taskrunner?',
    default: 'grunt',
    choices: ['grunt', 'gulp'],
    validate: required
  }, {
    type: 'checkbox',
    name: 'meanDeps',
    message: 'Which mean packages would you like to install?',
    choices: [
      {
        name: 'mean-admin',
        checked: true
      }, {
        name: 'tokens'
      }, {
        name: 'upload'
      }
    ]
  }];

  inquirer.prompt(questions, function(results) {
    _.assign(options, results);
    callback(options);
  });
};

'use strict';

var inquirer = require('inquirer'),
  _ = require('lodash');

// callback must be in form of function(results)
module.exports = function(options, callback) {

  function required(value) {
    return !!value.trim() || 'Required';
  }

  var questions = [{
    type: 'input',
    name: 'name',
    message: 'What would you name your mean app?',
    default: options.name,
    validate: required
  }, {
    type: 'list',
    name: 'taskrunner',
    message: 'Do you prefer grunt or gulp as a taskrunner?',
    default: 'grunt',
    choices: ['grunt', 'gulp'],
    validate: required
  }, {
    type: 'checkbox',
    name: 'meanDeps',
    message: 'Which mean packages would you like to install?',
    choices: [
      {
        name: 'mean-admin',
        checked: true
      }
    ]
  }];

  inquirer.prompt(questions, function(results) {
    _.assign(options, results);
    callback(options);
  });
};

Remove `tokens` and `upload` for now


$(document).ready(function () {
  $('.panel').hide();
  $('.panel').first().show();

  $('.tab a').click(function (tab) {
    var target_panel = $(tab.target).attr('href');

    $('.panel').hide();
    $(target_panel).show();

    setTimeout(function() {
      window.scrollTo(0, 0);
    }, 1);

    $(tab.target).closest('.content-tabs').find('.tab a').removeClass('red-text');
    $(tab.target).addClass('red-text');
  });

  $('.modal').modal();

  $('.share').click(function () {
    $('#share-modal').modal('open');
  });

  $('.expand').click(function () {
    $('.content-tabs').find('li.tab a').addClass('red-text');
    $('.panel').show();
  });

  $('.new-attribute-field-link').click(function (e) {
    e.preventDefault();
    $('#attribute-field-modal').modal('open');
  });

});

$(document).ready(function () {
  $('.panel').hide();
  $('.panel').first().show();

  $('.tab a').click(function (tab) {
    var target_panel = $(tab.target).attr('href');

    $('.panel').hide();
    $(target_panel).show();

    // Unset the expand button's "expanded" flag, if set
    $('.expand').removeClass('expanded');

    setTimeout(function() {
      window.scrollTo(0, 0);
    }, 1);

    $(tab.target).closest('.content-tabs').find('.tab a').removeClass('red-text');
    $(tab.target).addClass('red-text');
  });

  $('.modal').modal();

  $('.share').click(function () {
    $('#share-modal').modal('open');
  });

  $('.expand').click(function () {
    if ($(this).hasClass('expanded')) {
      $(this).removeClass('expanded');

      // Reset all selected-tab styling and activate the first one
      var all_tabs = $('.content-tabs').find('li.tab a');
      all_tabs.removeClass('red-text');
      all_tabs.first().addClass('red-text');

      // Reset all panel visibility and show the first one
      var all_panels = $('.panel');
      all_panels.hide();
      all_panels.first().show();

    } else {
      $(this).addClass('expanded');
      $('.content-tabs').find('li.tab a').addClass('red-text');
      $('.panel').show();
    }
  });

  $('.new-attribute-field-link').click(function (e) {
    e.preventDefault();
    $('#attribute-field-modal').modal('open');
  });

});

Add expand-all toggling instead of just one-way expanding


/* global google:false */
export function VenueDirective () {
  'ngInject';

  return {
    restrict: 'E',
    templateUrl: 'app/components/venue/venue.html',
    scope: {},
    controller: VenueController,
    controllerAs: 'vm',
    bindToController: true
  };
}

class VenueController {
  constructor () {
    'ngInject';

    let center = {latitude: 56.946333, longitude: 24.116870};
    this.map = {
      center: center,
      zoom: 13,
      options: {
        zoomControlOptions: {
          position: google.maps.ControlPosition.LEFT_CENTER
        },
        mapTypeControl: false,
        streetViewControl: false,
        panControl: false,
        scrollwheel: false,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        styles: [
          {
            "stylers": [{"hue": "#00aaff"}, {"saturation": -23}, {"gamma": 1.37}, {"lightness": -5}]
          }
        ]
      }
    };

    this.marker = {
      idKey: 'place',
      position: center,
      options: {
        title: 'Riga Dev Day 2016',
        icon: 'http://maps.google.com/mapfiles/ms/icons/red-dot.png',
        labelContent: 'Kino Citadele',
        labelAnchor: "46 -5",
        labelClass: 'map-label'
      }
    }
  }
}

/* global google:false */
export function VenueDirective () {
  'ngInject';

  return {
    restrict: 'E',
    templateUrl: 'app/components/venue/venue.html',
    scope: {},
    controller: VenueController,
    controllerAs: 'vm',
    bindToController: true
  };
}

class VenueController {
  constructor () {
    'ngInject';

    this.map = {
      center: {latitude: 56.946333, longitude: 24.116870},
      zoom: 16,
      options: {
        zoomControlOptions: {
          position: google.maps.ControlPosition.LEFT_CENTER
        },
        mapTypeControl: false,
        streetViewControl: false,
        panControl: false,
        scrollwheel: false,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        styles: [
          {
            "stylers": [{"hue": "#00aaff"}, {"saturation": -23}, {"gamma": 1.37}, {"lightness": -5}]
          }
        ]
      }
    };

    this.marker = {
      idKey: 'place',
      position: {latitude: 56.946333, longitude: 24.116870},
      options: {
        title: 'Riga Dev Day 2016',
        icon: 'http://maps.google.com/mapfiles/ms/icons/red-dot.png',
        labelContent: 'Kino Citadele',
        labelAnchor: "46 -5",
        labelClass: 'map-label'
      }
    }
  }
}

Fix map marker and zoom map in center


var searchApp = angular.module('searchApp', {});

searchApp.controller('SimpleController', function($scope){
  $scope.customers = [
  {name: 'Gendelman', city: 'West Bloomfield'},
  {name: 'Ryan Lesson', city: "Chicago"},
  {name: 'Corey Lesson', city: "Bloomfield Hills"}
  ];
});

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

searchApp.controller('SimpleController', function($scope){
  $scope.customers = [
  {name: 'Gendelman', city: 'West Bloomfield'},
  {name: 'Ryan Lesson', city: "Chicago"},
  {name: 'Corey Lesson', city: "Bloomfield Hills"}
  ];
});

Fix error in Angular module call


import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../actions/counter';

export default function counter(state = 0, action) {
  switch (action.type) {
  case INCREMENT_COUNTER:
    return state + 1;
  case DECREMENT_COUNTER:
    return state - 1;
  default:
    return state;
  }
}

import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../actions/counter';

export default function counter(state = 0, action = {}) {
  switch (action.type) {
  case INCREMENT_COUNTER:
    return state + 1;
  case DECREMENT_COUNTER:
    return state - 1;
  default:
    return state;
  }
}

Fix IntelliJ redux syntax error


import React, { Component } from 'react'
import {
  Text,
  View,
  StyleSheet,
  TouchableHighlight,
  Image
} from 'react-native'

export default class Interests extends Component {

  render () {
    return (
      <View style={styles.container}>
        <Image
          style={styles.logo}
          source={{uri: 'http://www.fillmurray.com/150/150'}}
        />
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#fff'
  },
  title: {
    fontSize: 20,
    textAlign: 'center',
    margin: 60,
    color: 'blue'
  }
})

import React, { Component } from 'react'
import {
  Text,
  View,
  StyleSheet,
  TouchableHighlight,
  Image
} from 'react-native'

export default class Interests extends Component {

  render () {
    return (
      <View style={styles.container}>
        <Image
          style={styles.image}
          source={{ uri: 'http://www.fillmurray.com/150/150' }}
        />
        <Text> Interests </Text>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#fff'
  },
  title: {
    fontSize: 20,
    textAlign: 'center',
    margin: 60,
    color: 'blue'
  },
  image: {
    width: 150,
    height: 150
  }
})

Add initial image to interests


import ms from 'ms';
import createDebug from 'debug';

const debug = createDebug('u-wave-hub');

const servers = new Map();

export function announce(req, res) {
  servers.set(req.ip, {
    ping: Date.now(),
    data: req.body,
  });

  debug('announce', req.ip);

  const server = servers.get(req.ip);
  res.json({
    received: server.data,
  });
}

export function list(req, res) {
  const response = [];

  servers.forEach((value) => {
    response.push(value.data);
  });

  res.json({
    servers: response,
  });
}

export function prune() {
  debug('prune');
  servers.forEach((server, ip) => {
    if (server.ping + ms('5 minutes') < Date.now()) {
      debug('prune', ip);
      servers.delete(ip);
    }
  });
}

import ms from 'ms';
import createDebug from 'debug';

const debug = createDebug('u-wave-hub');

const servers = new Map();

export function announce(req, res) {
  const data = req.body

  servers.set(data.url, {
    ping: Date.now(),
    data,
  });

  debug('announce', data.url);

  const server = servers.get(data.url);
  res.json({
    received: server.data,
  });
}

export function list(req, res) {
  const response = [];

  servers.forEach((value) => {
    response.push(value.data);
  });

  res.json({
    servers: response,
  });
}

export function prune() {
  debug('prune');
  servers.forEach((server, url) => {
    if (server.ping + ms('5 minutes') < Date.now()) {
      debug('prune', url);
      servers.delete(url);
    }
  });
}

Use server URL as storage key.


import React from 'react';
import CircularProgress from '@material-ui/core/CircularProgress';

const ServerListContainer = React.lazy(() => Promise.all([
  import('@u-wave/react-server-list/dist/u-wave-react-server-list.css'),
  import('@u-wave/react-server-list'),
]).then(([, js]) => ({ default: js.Container })));

function ServerList(props) {
  const loading = (

      <CircularProgress />

  );

  return (
    <React.Suspense fallback={loading}>

        <ServerListContainer {...props} />

    </React.Suspense>
  );
}

export default ServerList;

import React from 'react';
import CircularProgress from '@material-ui/core/CircularProgress';

const ServerListContainer = React.lazy(() => Promise.all([
  import('@u-wave/react-server-list/dist/dist/u-wave-react-server-list.css'),
  import('@u-wave/react-server-list'),
]).then(([, js]) => ({ default: js.Container })));

function ServerList(props) {
  const loading = (

      <CircularProgress />

  );

  return (
    <React.Suspense fallback={loading}>

        <ServerListContainer {...props} />

    </React.Suspense>
  );
}

export default ServerList;

Work around bug in @u-wave/react-server-list build system


/*global WebWorker:false */
(function () {
    'use strict';

    var worker = null,
        $output = null;

    $output = $('#worker-output');

    /**
    worker = new Worker('/js/example-worker.js');

    worker.addEventListener('message', function (event) {
        $output.text(event.data);
        return;
    })

    //worker.postMessage();
    /**/

    worker = new WebWorker('/js/example-worker.js');

    worker.on('message', function (event) {
        $output.text(event.data);
        return;
    });

    worker.load().on(WebWorker.Event.WORKER_LOADED, function () {
        console.log('has loaded');
        worker.start();
        return;
    });

    return;
})();

/*global WebWorker:false */
(function () {
    'use strict';

    var worker = null,
        $output = null;

    $output = $('#worker-output');

    /**
    worker = new Worker('/js/example-worker.js');

    worker.addEventListener('message', function (event) {
        $output.text(event.data);
        return;
    })

    //worker.postMessage();
    /**/

    worker = new WebWorker('/js/example-worker.js');
    window.worker = worker;

    worker.on('message', function (event) {
        $output.text(event.data);
        return;
    });

    worker.on(WebWorker.Event.WORKER_LOADING, function () {
        console.log('worker loading');
        return;
    });

    worker.on(WebWorker.Event.WORKER_LOADED, function () {
        console.log('has loaded');
        worker.start();
        return;
    });

    worker.on(WebWorker.Event.WORKER_STARTING, function () {
        console.log('worker starting');
        return;
    });

    worker.on(WebWorker.Event.WORKER_STARTED, function () {
        console.log('worker started');
        return;
    });

    worker.load();

    return;
})();

Add event listeners for better tracking of worker.


import { module, test } from 'qunit';
import Ember from 'ember';
import isHTMLSafe from 'ember-string-ishtmlsafe-polyfill';

module('Unit | isHTMLSafe');

test('Imported isHTMLSafe() function properly detects safe strings', function(assert) {
  let plainStr = 'Hello World',
      htmlSafeStr = Ember.String.htmlSafe(plainStr);

  assert.notOk(isHTMLSafe(plainStr), 'Plain string is not html safe string');
  assert.ok(isHTMLSafe(htmlSafeStr), 'Html safe string matches');

  assert.notOk(isHTMLSafe([]), 'Array is not html safe string');
  assert.notOk(isHTMLSafe({}), 'Object is not html safe string');
  assert.notOk(isHTMLSafe(10), 'Number is not html safe string');
  assert.notOk(isHTMLSafe(null), 'Null is not html safe string');
});

test('"Native" Ember.String.isHTMLSafe() function properly detects safe strings', function(assert) {
  let plainStr = 'Hello World',
      htmlSafeStr = Ember.String.htmlSafe(plainStr);

  assert.notOk(Ember.String.isHTMLSafe(plainStr), 'Plain string is not html safe string');
  assert.ok(Ember.String.isHTMLSafe(htmlSafeStr), 'Html safe string matches');

  assert.notOk(Ember.String.isHTMLSafe([]), 'Array is not html safe string');
  assert.notOk(Ember.String.isHTMLSafe({}), 'Object is not html safe string');
  assert.notOk(Ember.String.isHTMLSafe(10), 'Number is not html safe string');
  assert.notOk(Ember.String.isHTMLSafe(null), 'Null is not html safe string');
});

import { module, test } from 'qunit';
import Ember from 'ember';

module('Unit | isHTMLSafe');

test('"Native" Ember.String.isHTMLSafe() function properly detects safe strings', function(assert) {
  let plainStr = 'Hello World',
      htmlSafeStr = Ember.String.htmlSafe(plainStr);

  assert.notOk(Ember.String.isHTMLSafe(plainStr), 'Plain string is not html safe string');
  assert.ok(Ember.String.isHTMLSafe(htmlSafeStr), 'Html safe string matches');

  assert.notOk(Ember.String.isHTMLSafe([]), 'Array is not html safe string');
  assert.notOk(Ember.String.isHTMLSafe({}), 'Object is not html safe string');
  assert.notOk(Ember.String.isHTMLSafe(10), 'Number is not html safe string');
  assert.notOk(Ember.String.isHTMLSafe(null), 'Null is not html safe string');
});

Remove obsolete unit test for imported isHTMLSafe() function


// var _ = require('underscore');

module.exports = function(robot){

	robot.respond(/last beer/i, function(res){
		var response = 'My last eber was from ' + robot.brain.get('lastBeerFrom');
		if (robot.auth.isAdmin(res.message.user))
			res.reply(response + '.  I\'ve had ' + robot.brain.get('totalBeersHad'));
		else
			res.reply(response);
	});

	robot.respond(/tell me my userid/i, function(res){
		if (robot.auth.isAdmin(res.message.user))
			res.reply('Your user ID is ' + res.message.user.id);
	});

	robot.respond(/userid of (.*)/i, function(res){
		if (!robot.auth.isAdmin(res.message.user))
			return;

		var users = {};
		var apiUrl = robot.brain.get('slack-api-url') + 'users.list';
		var userName = res.match[1];
		if (userName[0] === '@')
			userName = userName.substring(1);

		robot.http(apiUrl).get(function(err, response, body){
			res.send(JSON.stringify(body));
		});

		//res.reply(userName + '\'s user ID is ' + );
	});
}

// var _ = require('underscore');

module.exports = function(robot){

	robot.respond(/last beer/i, function(res){
		var response = 'My last eber was from ' + robot.brain.get('lastBeerFrom');
		if (robot.auth.isAdmin(res.message.user))
			res.reply(response + '.  I\'ve had ' + robot.brain.get('totalBeersHad'));
		else
			res.reply(response);
	});

	robot.respond(/tell me my userid/i, function(res){
		if (robot.auth.isAdmin(res.message.user))
			res.reply('Your user ID is ' + res.message.user.id);
	});

	robot.respond(/userid of (.*)/i, function(res){
		if (!robot.auth.isAdmin(res.message.user))
			return;

		var users = {};
		var apiUrl = robot.brain.get('slack-api-url') + 'users.list';
		var userName = res.match[1];
		if (userName[0] === '@')
			userName = userName.substring(1);

		robot.http(apiUrl).get(function(err, response, body){
			res.send(JSON.stringify(body));
		});

		//res.reply(userName + '\'s user ID is ' + );
	});

	robot.respond(/give me my user object/i, function(res){
		if (robot.auth.isAdmin(res.message.user)){
			res.send(JSON.stringify(res.message.user));
		}
	});
}

Add ability to get user object


document.getElementById("ayuda").setAttribute("aria-current", "page");

var aside = document.getElementById("complementario");

var form = document.createElement("FORM");
var p = document.createElement("P");
var label = document.createElement("LABEL");
label.setAttribute("for", "repo");
t = document.createTextNode("cuenta/repositorio de GitHub");
label.appendChild(t);
var input = document.createElement("INPUT");
input.setAttribute("type", "text");
input.setAttribute("id", "repo");
input.setAttribute("name", "repo");
label.appendChild(input);
var submit = document.createElement("BUTTON");
submit.setAttribute("id", "submit");
submit.setAttribute("type", "button");
var t = document.createTextNode("Consultar descargas de última versión");
submit.appendChild(t);
p.appendChild(label);
form.appendChild(p);
form.appendChild(submit);

$(document).ready(function () {
	$("#submit").click(function () {
		$.getJSON("https://api.github.com/repos/releases/latest", function(json) {
			var name = json.name;
		});
	});
});

document.getElementById("ayuda").setAttribute("aria-current", "page");

var aside = document.getElementById("complementario");

var form = document.createElement("FORM");
var p = document.createElement("P");
var label = document.createElement("LABEL");
label.setAttribute("for", "repo");
t = document.createTextNode("cuenta/repositorio de GitHub");
label.appendChild(t);
var input = document.createElement("INPUT");
input.setAttribute("type", "text");
input.setAttribute("id", "repo");
input.setAttribute("name", "repo");
label.appendChild(input);
var submit = document.createElement("INPUT");
submit.setAttribute("id", "submit");
submit.setAttribute("type", "button");
var t = document.createTextNode("Consultar descargas de última versión");
submit.appendChild(t);
p.appendChild(label);
form.appendChild(p);
form.appendChild(submit);

$(document).ready(function () {
	$("#submit").click(function () {
		$.getJSON("https://api.github.com/repos/releases/latest", function(json) {
			var name = json.name;
		});
	});
});

Create input for submit button


'use strict'

const schema = require('../../app/schema')

exports.shortlink = (body) => {
  return new Promise((resolve, reject) => {
    if (schema.validate(body)) {
      resolve()
    } else {
      reject()
    }
  })
}

exports.error = (body) => {
  return new Promise((resolve, reject) => {
    if (body.message.substr(0, 5) !== 'Error') {
      reject()
    }
    if (body.code.toString()[0] !== 4) {
      reject()
    }
    if (body.errors && !Array.isArray(body.errors)) {
      reject()
    }
    resolve()
  })
}

'use strict'

const schema = require('../../app/schema')

exports.shortlink = (body) => {
  return new Promise((resolve, reject) => {
    if (schema.validate(body)) {
      resolve()
    } else {
      reject()
    }
  })
}

exports.error = (body) => {
  return new Promise((resolve, reject) => {
    if (body.message.substr(0, 5) !== 'Error') {
      reject()
    }
    if (body.code.toString()[0] !== '4') {
      reject()
    }
    if (body.errors && !Array.isArray(body.errors)) {
      reject()
    }
    resolve()
  })
}

Fix mismatch due to strictequal


$(document).ready(function() {
    $('#clearSearch').on('click', function() {
        event.preventDefault();

        $('#idForm, #descriptionForm')
            .trigger('reset')
            .find('input').each(clearValueAttributeIfNotHidden);
    });
});

function clearValueAttributeIfNotHidden() {
    if ($(this).attr('type') !== 'hidden') {
        $(this).attr('value', '');
    }
}

$(document).ready(function() {
    $('#clearSearch').on('click', function() {
        event.preventDefault();

        $('#idForm, #descriptionForm')
            .trigger('reset')
            .find('input').each(clearValueAttributeIfNotHidden);

        $('#clearSearch').blur();
    });
});

function clearValueAttributeIfNotHidden() {
    if ($(this).attr('type') !== 'hidden') {
        $(this).attr('value', '');
    }
}

Remove focus after clear search


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

function supportsInterfaceIndexLocalOnly() {
  try {
    var sr = new dns_sd.DNSServiceRef()
      , flags  = 0
      , iface  = dns_sd.kDNSServiceInterfaceIndexLocalOnly
      , name   = null
      , type   = '_http._tcp'
      , domain = null
      , host   = null
      , port   = 4321
      , txtRec = null
      , cb     = null
      , ctx    = null
      ;
    dns_sd.DNSServiceRegister( sr, flags, iface, name, type, domain,
          host, port, txtRec, cb, ctx);
  } catch (ex) {
    if (ex.errorCode === dns_sd.kDNSServiceErr_Unsupported) {
      if (sr && sr.initialized) {
        dns_sd.DNSServiceRefDeallocate(sr);
      }
      return false;
    }
    console.warn('Unexpected result while probing for avahi:', ex);
  }
  dns_sd.DNSServiceRefDeallocate(sr);
  return true;
}

module.exports = ! supportsInterfaceIndexLocalOnly();

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

function supportsInterfaceIndexLocalOnly() {
  try {
    var sr = new dns_sd.DNSServiceRef()
      , flags  = 0
      , iface  = dns_sd.kDNSServiceInterfaceIndexLocalOnly
      , name   = null
      , type   = '_http._tcp'
      , domain = null
      , host   = null
      , port   = 4321
      , txtRec = null
      , cb     = null
      , ctx    = null
      ;
    dns_sd.DNSServiceRegister( sr, flags, iface, name, type, domain,
          host, port, txtRec, cb, ctx);
  } catch (ex) {
    if (ex.errorCode === dns_sd.kDNSServiceErr_Unsupported) {
      if (sr && sr.initialized) {
        dns_sd.DNSServiceRefDeallocate(sr);
      }
      return false;
    }
    console.warn('Unexpected result while probing for avahi:', ex);
  }
  if (sr && sr.initialized) {
    dns_sd.DNSServiceRefDeallocate(sr);
  }
  return true;
}

module.exports = ! supportsInterfaceIndexLocalOnly();

Fix exception from require('mdns') if Avahi detection fails with an unexpected error


import PropTypes from 'prop-types';
import React from 'react';

import { AREA_UNITS } from '../../constants/units';

const AreaUnits = ({ value, unit, className, ...rest }) => {
  switch (unit) {
    case AREA_UNITS.METERS_SQUARED: return (

        { value }
        m2

    );
    case AREA_UNITS.SQUARE_FOOT:
    default: return (

        { value } sq ft

    );
  }
};

AreaUnits.propTypes = {
  value: PropTypes.oneOfType([
    PropTypes.number,
    PropTypes.string,
  ]).isRequired,
  unit: PropTypes.string.isRequired,
  className: PropTypes.string,
};

AreaUnits.defaultProps = {
  unit: AREA_UNITS.SQUARE_FOOT,
};

export default AreaUnits;

import PropTypes from 'prop-types';
import React from 'react';

import { AREA_UNITS } from '../../constants/units';

const AreaUnits = ({ value, unit, className, ...rest }) => {
  switch (unit) {
    case AREA_UNITS.METERS_SQUARED: return (
      <span
        { ...rest }
        className={ className }
      >
        { value }
        m²
      </span>
    );
    case AREA_UNITS.SQUARE_FOOT:
    default: return (
      <span
        { ...rest }
        className={ className }
      >
        { value } sq ft
      </span>
    );
  }
};

AreaUnits.propTypes = {
  value: PropTypes.oneOfType([
    PropTypes.number,
    PropTypes.string,
  ]).isRequired,
  unit: PropTypes.string.isRequired,
  className: PropTypes.string,
};

AreaUnits.defaultProps = {
  unit: AREA_UNITS.SQUARE_FOOT,
};

export default AreaUnits;

Use proper symbol for square meters


/**
 * ModuleRuntime.js (Parse) -- Provides the standard / default configuration that is the same as Backbone 1.2.3
 */

'use strict';

import Backbone         from 'backbone-es6/src/Backbone.js';
import ParseCollection  from './ParseCollection.js';
import TyphonEvents     from 'typhonjs-core-backbone-events/src/TyphonEvents.js';
import History          from 'backbone-es6/src/History.js';
import Model            from './ParseModel.js';
import Router           from 'backbone-es6/src/Router.js';
import View             from 'backbone-es6/src/View.js';

import parseSync        from './parseSync.js';

import parseExtend      from './parseExtend.js';
import typhonExtend     from 'typhonjs-core-backbone-common/src/typhonExtend.js';

const options =
{
   // Current version of the library. Keep in sync with Backbone version supported.
   VERSION: '1.2.3'
};

const backbone = new Backbone(ParseCollection, TyphonEvents, History, Model, Router, View, parseSync, options);

parseExtend(backbone);
typhonExtend(backbone);

export default backbone;

/**
 * ModuleRuntime.js (Parse) -- Provides the standard / default configuration that is the same as Backbone 1.2.3
 */

'use strict';

import Backbone         from 'backbone-es6/src/Backbone.js';
import ParseCollection  from './ParseCollection.js';
import TyphonEvents     from 'typhonjs-core-backbone-events/src/TyphonEvents.js';
import History          from 'backbone-es6/src/History.js';
import Model            from './ParseModel.js';
import Router           from 'backbone-es6/src/Router.js';
import View             from 'backbone-es6/src/View.js';

import parseSync        from './parseSync.js';

import parseExtend      from './parseExtend.js';
import typhonExtend     from 'typhonjs-core-backbone-common/src/typhonExtend.js';

const options =
{
   // Current version of the library. Keep in sync with Backbone version supported.
   VERSION: '1.3.3'
};

const backbone = new Backbone(ParseCollection, TyphonEvents, History, Model, Router, View, parseSync, options);

parseExtend(backbone);
typhonExtend(backbone);

export default backbone;

Update for Backbone 1.3.3 parity.


import { postData, deleteData } from '../utils/APIUtils';
import { API_URLS } from '../constants/Constants';

export function sendSubscription(data, url = API_URLS.NOTIFICATIONS_SUBSCRIBE) {
    return postData(url, data);
}

export function deleteSubscription(data, url = API_URLS.NOTIFICATIONS_UNSUBSCRIBE) {
    return deleteData(url, data);
}

import { postData, deleteData } from '../utils/APIUtils';
import { API_URLS } from '../constants/Constants';

export function sendSubscription(data, url = API_URLS.NOTIFICATIONS_SUBSCRIBE) {
    return postData(url, data);
}

export function deleteSubscription(data, url = API_URLS.NOTIFICATIONS_UNSUBSCRIBE) {
    return postData(url, data);
}

Use post method instead of delete for unsubscribing


var express = require('express');
var router = express.Router();

router.get('/summary', function(req, res, next) {
  res.json({
  	'totals': {},
  	'activities': []
  });
});

module.exports = router;

var express = require('express');
var router = express.Router();

var Fitbit = require('../model/fitbit');
var Strava = require('../model/strava');
var _ = require('underscore');

router.get('/activity', function(req, res, next) {
	if (!req.query.date) return next(new Error('date param is required'));
	var dateObj = new Date(req.query.date);

	Fitbit.findOne({dateTime: dateObj}, function(err, data) {
		if (err) return next(err);
		res.json({
			'date': req.query.date,
			'summary': _.pick(data, globalConfig.fitbit.exposed),
			'workouts': []
		});
	});

});

module.exports = router;

Return Fitbit data at activity endpoint


if('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js', {scope: './'}).then(function(registration) {
    // Registration was successful 😊
    console.log('ServiceWorker registration successful with scope: ',
      registration.scope);
  }).catch(function(err) {
    // registration failed :(
    console.log('ServiceWorker registration failed: ', err);
  });
}

if('serviceWorker' in navigator) {
  navigator.serviceWorker.register('./sw.js').then(function(registration) {
    // Registration was successful 😊
    console.log('ServiceWorker registration successful with scope: ',
      registration.scope);
  }).catch(function(err) {
    // registration failed :(
    console.log('ServiceWorker registration failed: ', err);
  });
}

Fix import path of sw.js


'use strict';
angular.module('arethusa.core').directive('nextToken', [
  'state',
  function (state) {
    return {
      restrict: 'E',
      link: function (scope, element, attrs) {
        element.bind('click', function (e) {
          scope.$apply(state.selectNextToken());
        });
      }
    };
  }
]);

'use strict';

angular.module('arethusa.core').directive('nextToken', [
  'state',
  function (state) {
    return {
      restrict: 'AE',
      link: function (scope, element, attrs) {
        element.bind('click', function (e) {
          scope.$apply(state.selectNextToken());
        });
      }
    };
  }
]);

Allow nextToken directive as attribute


'use strict';

var fs = require('vow-fs');
var linter = require('./linter');

var LessHint = function () {

};

LessHint.prototype.checkDirectory = function (path) {
    return fs.listDir(path).then(function (files) {
        return files.forEach(function (file) {
            var fullPath = path + '/' + file;

            return fs.stat(fullPath).then(function (stats) {
                if (stats.isDirectory()) {
                    return this.checkDirectory(fullPath);
                }

                if (file.substr(0, 1) === '.') {
                    return;
                }

                return this.checkFile(fullPath);
            }, this);
        }, this);
    }, this);
};

LessHint.prototype.checkFile = function (path) {
    return fs.read(path, 'utf8').then(function (data) {
        return this.checkString(data, path);
    }, this);
};

LessHint.prototype.checkPath = function (path) {
    return fs.stat(path).then(function (stats) {
        if (stats.isDirectory()) {
            return this.checkDirectory(path);
        }

        return this.checkFile(path);
    }, this);
};

LessHint.prototype.checkString = function (input, path) {
    return linter.lint(input, path, this.config);
};

LessHint.prototype.configure = function (config) {
    this.config = config;
};

module.exports = LessHint;

'use strict';

var fs = require('vow-fs');
var linter = require('./linter');
var Vow = require('Vow');

var LessHint = function () {

};

LessHint.prototype.checkDirectory = function (path) {
    return fs.listDir(path).then(function (files) {
        return Vow.all(files.map(function(file) {
            var fullPath = path + '/' + file;

            return fs.stat(fullPath).then(function (stats) {
                if (stats.isDirectory()) {
                    return this.checkDirectory(fullPath);
                }

                if (file.substr(0, 1) === '.') {
                    return;
                }

                return this.checkFile(fullPath);
            }, this);
        }, this)).then(function(errors) {
            return [].concat.apply([], errors);
        });
    }, this);
};

LessHint.prototype.checkFile = function (path) {
    return fs.read(path, 'utf8').then(function (data) {
        return this.checkString(data, path);
    }, this);
};

LessHint.prototype.checkPath = function (path) {
    return fs.stat(path).then(function (stats) {
        if (stats.isDirectory()) {
            return this.checkDirectory(path);
        }

        return this.checkFile(path);
    }, this);
};

LessHint.prototype.checkString = function (input, path) {
    return linter.lint(input, path, this.config);
};

LessHint.prototype.configure = function (config) {
    this.config = config;
};

module.exports = LessHint;

Fix issue where multiple directories and files weren't linted


const { CLIEngine } = require('eslint');

const cli = new CLIEngine({});

module.exports = {
  '*.js': (files) =>
    'eslint --cache --fix --max-warnings=0 ' +
    files.filter((file) => !cli.isPathIgnored(file)).join(' '),
  'lib/**/*.js': function libFlow(files) {
    return 'yarn workspace lib flow --quiet';
  },
  'web/**/*.js': function webFlow(files) {
    return 'yarn workspace web flow --quiet';
  },
  'native/**/*.js': function nativeFlow(files) {
    return 'yarn workspace native flow --quiet';
  },
  'server/**/*.js': function serverFlow(files) {
    return 'yarn workspace server flow --quiet';
  },
};

const { CLIEngine } = require('eslint');

const cli = new CLIEngine({});

module.exports = {
  '*.js': (files) =>
    'eslint --cache --fix --max-warnings=0 ' +
    files.filter((file) => !cli.isPathIgnored(file)).join(' '),
  'lib/**/*.js': function libFlow(files) {
    return 'yarn workspace lib flow --quiet';
  },
  '{web,lib}/**/*.js': function webFlow(files) {
    return 'yarn workspace web flow --quiet';
  },
  '{native,lib}/**/*.js': function nativeFlow(files) {
    return 'yarn workspace native flow --quiet';
  },
  '{server,web,lib}/**/*.js': function serverFlow(files) {
    return 'yarn workspace server flow --quiet';
  },
};

Make sure lint-staged checks all dependent projects


var users = require('./controllers/usersController.js');
var recipes = require('./controllers/recipesController.js');
var branches = require('./controllers/branchesController.js');
var versions = require('./controllers/versionsController.js');

module.exports = function(app, express) {
  // /*** Sign up / Sign in / Logout ***/
  // app.post('/user/signup', users.signup);
  // app.post('/user/login', users.login);
  // app.get('/user/logout', users.logout);

  // /*** Users ***/
  app.get('/:username/profile', users.getProfile); //gets recipes
  // app.put('/:username/profile', users.updateProfile);

  // /*** Recipes ***/
  app.post('/:username/create-recipe', recipes.createRecipe);
  app.get('/:username/:recipe', recipes.getRecipe);
  app.delete('/:username/:recipe', recipes.deleteRecipe);

  // /*** Branches ***/
  app.post('/:username/:recipe/:branch', branches.createBranch);
  app.get('/:username/:recipe/:branch', branches.getBranch);
  app.delete('/:username/:recipe/:branch', branches.deleteBranch);

  /*** Versions ***/
  app.post('/:username/:recipe/:branch/:version', versions.createVersion);
  app.get('/:username/:recipe/:branch/:version', versions.getVersion);
  app.delete('/:username/:recipe/:branch/:version', versions.deleteVersion);
};

var users = require('./controllers/usersController.js');
var recipes = require('./controllers/recipesController.js');
var branches = require('./controllers/branchesController.js');
var versions = require('./controllers/versionsController.js');

module.exports = function(app, express) {
  // /*** Sign up / Sign in / Logout ***/
  // app.post('/user/signup', users.signup);
  // app.post('/user/login', users.login);
  // app.get('/user/logout', users.logout);

  // /*** Users ***/
  app.get('/:username/profile', users.getProfile); //gets recipes
  // app.put('/:username/profile', users.updateProfile);

  // /*** Recipes ***/
  app.post('/:username/create-recipe', recipes.createRecipe);
  app.get('/:username/:recipe', recipes.getRecipe);
  app.delete('/:username/:recipe', recipes.deleteRecipe);

  // /*** Branches ***/
  app.post('/:username/:recipe/:branch', branches.createBranch);
  app.get('/:username/:recipe/:branch', branches.getBranch);
  app.delete('/:username/:recipe/:branch', branches.deleteBranch);

  /*** Versions ***/
  app.post('/:username/:recipe/:branch/create-version', versions.createVersion);
  app.get('/:username/:recipe/:branch/:version', versions.getVersion);
  app.delete('/:username/:recipe/:branch/:version', versions.deleteVersion);
};

Fix route for create version


/* jshint node: true */

module.exports = {
  normalizeEntityName: function() {},

  afterInstall: function() {
  	this.addBowerPackageToProject('typeahead.js');
  	return this.addBowerPackageToProject('bootstrap-tagsinput');
  }
};

/* jshint node: true */
import RSVP from "rsvp"

module.exports = {
  normalizeEntityName: function() {},

  afterInstall: function() {
  	return RSVP.all([
      this.addBowerPackageToProject('typeahead.js'),
      this.addBowerPackageToProject('bootstrap-tagsinput')
    ]);
  }
};

Change way to import bower


'use strict';

const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
const urls = require('./lib/prember-urls');

module.exports = function(defaults) {
  var includePolyfill = process.env.EMBER_ENV === 'production' || process.env.CI;

  var babelOptions = {};
  if (includePolyfill) {
    babelOptions.includePolyfill = true;
  } else {
    babelOptions.blacklist = ['regenerator'];
  }

  var app = new EmberAddon(defaults, {
    minifyJS: {
      enabled: false
    },

    snippetPaths: ['tests/dummy/snippets'],
    snippetSearchPaths: ['app', 'tests/dummy/app', 'addon'],

    emberCliFontAwesome: {
      useScss: true
    },

    babel: babelOptions,

    prember: {
      urls,
      // GitHub Pages uses this filename to serve 404s
      emptyFile: '404.html'
    }
  });

  /*
    This build file specifes the options for the dummy test app of this
    addon, located in `/tests/dummy`
    This build file does *not* influence how the addon or the app using it
    behave. You most likely want to be modifying `./index.js` or app's build file
  */

  app.import('vendor/dummy-deps/rx.js');

  return app.toTree();
};

'use strict';

const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
const urls = require('./lib/prember-urls');

module.exports = function(defaults) {
  var includePolyfill = process.env.EMBER_ENV === 'production' || process.env.CI;

  var babelOptions = {};
  if (includePolyfill) {
    babelOptions.includePolyfill = true;
  } else {
    babelOptions.exclude = ['@babel/plugin-transform-regenerator'];
  }

  var app = new EmberAddon(defaults, {
    minifyJS: {
      enabled: false
    },

    snippetPaths: ['tests/dummy/snippets'],
    snippetSearchPaths: ['app', 'tests/dummy/app', 'addon'],

    emberCliFontAwesome: {
      useScss: true
    },

    babel: babelOptions,

    prember: {
      urls,
      // GitHub Pages uses this filename to serve 404s
      emptyFile: '404.html'
    }
  });

  /*
    This build file specifes the options for the dummy test app of this
    addon, located in `/tests/dummy`
    This build file does *not* influence how the addon or the app using it
    behave. You most likely want to be modifying `./index.js` or app's build file
  */

  app.import('vendor/dummy-deps/rx.js');

  return app.toTree();
};

Fix babel config for babel 7


var Watcher = require('./watcher')
  , Deployer = require('./deployer')
  , Generator = require('./generator')
  , Config = require('./config')
  , events = require('events')
  , path = require('path')
  , when = require('when')
  , fs = require('fs')

  , resolve = path.resolve
  , lstat = fs.lstatSync
  , exists = fs.existsSync;

var Peak = function (path, options) {
  this.path = resolve(path);
  this.config = new Config(this);
  this.options = this.config.load(options);
  this.emitter = new events.EventEmitter;
}

Peak.prototype = {

  generate: function () {
    var generator = new Generator(this);
    return generator.start();
  },

  watch: function () {
    var watcher = new Watcher(this);
    return when.try(this.validate_path.bind(this))
      .then(watcher.start.bind(watcher));
  },

  deploy: function (options) {
    var deployer = new Deployer(this);
    return when.try(this.validate_path.bind(this))
      .then(deployer.start.bind(deployer));
  },

  validate_path: function () {
    if (!exists(this.path)) throw new Error('Path doesn\'t exist.');

    this.lstat = lstat(this.path);
    if (!this.lstat.isDirectory()) throw new Error('Path is not a directory.');
  }

}

module.exports = Peak;

var Watcher = require('./watcher')
  , Deployer = require('./deployer')
  , Generator = require('./generator')
  , Config = require('./config')
  , Compiler = require('./compiler')
  , events = require('events')
  , path = require('path')
  , when = require('when')
  , fs = require('fs')

  , resolve = path.resolve
  , lstat = fs.lstatSync
  , exists = fs.existsSync;

var Peak = function (path, options) {
  this.path = resolve(path);
  this.config = new Config(this);
  this.options = this.config.load(options);
  this.emitter = new events.EventEmitter;
}

Peak.prototype = {

  generate: function () {
    var generator = new Generator(this);
    return generator.start();
  },

  watch: function () {
    var watcher = new Watcher(this);
    return when.try(this.validate_path.bind(this))
      .then(watcher.start.bind(watcher));
  },

  deploy: function (options) {
    var deployer = new Deployer(this);
    return when.try(this.validate_path.bind(this))
      .then(deployer.start.bind(deployer));
  },

  validate_path: function () {
    if (!exists(this.path)) throw new Error('Path doesn\'t exist.');

    this.lstat = lstat(this.path);
    if (!this.lstat.isDirectory()) throw new Error('Path is not a directory.');
  }

}

Peak.Compiler = Compiler;
module.exports = Peak;

Add compiler to Peak object.


gulp.task('build', function() {
  return browserify('public/javascripts/main.jsx')
    .transform(babelify, { presets: ['react'] })
    .bundle()
    .pipe(source('bundle.js'))
    .pipe(gulp.dest('public/javascripts'));
});

gulp.task('build', function() {
  return browserify({ entries: 'public/javascripts/main.jsx', extensions: ['.jsx'], debug: true })
    .transform(babelify, { presets: ['react'] })
    .bundle()
    .pipe(source('bundle.js'))
    .pipe(gulp.dest('public/javascripts'));
});

Use jsx extension option in browserify gulp task


const parse = (obj) => Object.keys(obj).reduce((prev, curr) => {
  const value = obj[curr];

  if (value === 'true') return Object.assign({}, prev, { [curr]: true });
  if (value === 'false') return Object.assign({}, prev, { [curr]: false });
  return value !== null && typeof value === 'object' ?
    Object.assign({}, prev, { [curr]: parse(value) }) : Object.assign({}, prev, { [curr]: true });
}, {});

module.exports = parse;

const parse = (obj) => Object.keys(obj).reduce((prev, curr) => {
  const value = obj[curr];

  if (value === 'true') return Object.assign({}, prev, { [curr]: true });
  if (value === 'false') return Object.assign({}, prev, { [curr]: false });
  return value !== null && typeof value === 'object' ?
    Object.assign({}, prev, { [curr]: parse(value) }) : Object.assign({}, prev, { [curr]: value });
}, {});

module.exports = parse;

Change ternary return to value from true if value is not an object


'use strict';

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

let payload = {};

payload.build = function() {
  return (req, res, next) => {
      // req.body.album = album;
      // req.body.api_key = config.api_key;
      // req.body.artist = artist;
      // req.body.format = 'json';
      // req.body.method = method;
      // req.body.sk = config.sk;
      // req.body.timestamp = Math.floor(new Date() / 1000);
      // req.body.track = track;
      next();
  };
};

payload.squish = function() {
  return (req, res, next) => {
    let raw = '';
    for (var key in req.body) {
      if (req.body.hasOwnProperty(key) && key != 'format' && key != 'secret') {
        raw += key + req.body[key];
      };
    };
    raw += req.body.secret;
    req.body.api_sig = raw;
    next();
  };
};

module.exports = payload;

'use strict';

require('../../../env');

let payload = {};

payload.build = function() {
  return (req, res, next) => {
      // req.body.album = album;
      req.body.api_key = process.env.API_KEY;
      req.body.artist = req.query.artist;
      req.body.format = 'json';
      req.body.method = 'track.scrobble';
      req.body.sk = process.env.SK;
      req.body.timestamp = Math.floor(new Date() / 1000);
      req.body.track = req.query.title;
      next();
  };
};

payload.squish = function() {
  return (req, res, next) => {
    let raw = '';
    for (var key in req.body) {
      if (req.body.hasOwnProperty(key) && key != 'format' && key != 'secret') {
        raw += key + req.body[key];
      };
    };
    if (req.body.secret) {
      raw += req.body.secret;
    } else {
      raw += process.env.SECRET;
    }
    req.body.api_sig = raw;
    next();
  };
};

module.exports = payload;

Check to see if req.body has secret, otherwise read from env


import React from 'react';
import { css } from 'glamor';
import Globals from '../utils/Globals';

import Logo from './Logo';
import Infos from './Infos';
import Title from './Title';
import Ingresso from './Ingresso';
import VideoPlayer from './VideoPlayer';

const styles = {
  container: css({
    background: Globals.colors.transparent,
    color: Globals.colors.primary,
    width: '100%',
    minWidth: '100%',
    display: 'flex',
    alignItems: 'center',
    flexDirection: 'column',
    justifyContent: 'space-between',
    height: '100vh',
  }),
};

const Header = () =>
  <div {...styles.container}>
    <VideoPlayer />
    <Title />
    <Logo />
    <Ingresso />
    <Infos />
  </div>;

export default Header;

import React from 'react';
import { css } from 'glamor';
import Globals from '../utils/Globals';

import Logo from './Logo';
import Infos from './Infos';
import Title from './Title';
import Ingresso from './Ingresso';
import VideoPlayer from './VideoPlayer';

const styles = {
  container: css({
    background: Globals.colors.transparent,
    color: Globals.colors.primary,
    width: '100%',
    minWidth: '100%',
    display: 'flex',
    alignItems: 'center',
    flexDirection: 'column',
    justifyContent: 'space-between',
  }),
};

const Header = () =>
  <div {...styles.container}>
    <VideoPlayer />
    <Title />
    <Logo />
    <Ingresso />
    <Infos />
  </div>;

export default Header;

Revert "Added vh to fit the total height of the window size."


'use strict';

const request = require('request');
const chalk = require('chalk');

const outputFormatter = require('./output-formatter');

const url = process.argv[2];

const startTime = Date.now();

request(url, (error, response, body) => {
  console.log(outputFormatter.formatStatusLine(response));
  console.log('');
  console.log(outputFormatter.formatHeaders(response.rawHeaders));
  console.log('');
  console.log(body);

  const endTime = Date.now();
  console.log(`Completed in ${(endTime - startTime) / 1000} sec.`);

  //console.log(response);
});

'use strict';

const request = require('request');
const chalk = require('chalk');

const pkg = require('../package.json');
const outputFormatter = require('./output-formatter');

const url = process.argv[2];

const startTime = Date.now();

const options = {
  url,
  headers: {
    'User-Agent': `http-tool/${pkg.version}`
  }
};

request(options, (error, response, body) => {
  console.log(outputFormatter.formatStatusLine(response));
  console.log('');
  console.log(outputFormatter.formatHeaders(response.rawHeaders));
  console.log('');
  console.log(body);

  const endTime = Date.now();
  console.log(`Completed in ${(endTime - startTime) / 1000} sec.`);

  //console.log(response);
});

Add http-tool user agent header


import express from 'express';
import log, {INFO} from "./log";
import {getOpengraphData, removeOpengraphData} from "./opengraph";

const HTTP_TIMEOUT = Number(process.env.HTTP_TIMEOUT) || 10000;

log(INFO, "Using a HTTP timeout of " + HTTP_TIMEOUT + " milliseconds");

function respondWithData(res, data) {
	res.status(data.status).json(data.json).end();
}

const app = express();
app.get('/opengraph', async (req, res) => {
	const data = await getOpengraphData(req.query.url);
	respondWithData(res, data);
});
app.delete('/opengraph', async (req, res) => {
	const data = await removeOpengraphData(req.query.url);
	respondWithData(res, data);
});
app.get('/_health', (req, res) => res.end('Jolly good here'));
app.listen(7070, () => log(INFO, 'Server is listening'));

import express from 'express';
import log, {INFO, ERR} from "./log";
import {getOpengraphData, removeOpengraphData} from "./opengraph";

const HTTP_TIMEOUT = Number(process.env.HTTP_TIMEOUT) || 10000;

process.on('uncaughtException', function (err) {
	log(ERR, `uncaughtException: ${err}`);
	process.exit(1);
});
process.on('unhandledRejection', function (err) {
	log(ERR, `unhandledRejection: ${err}`);
	process.exit(1);
});

log(INFO, "Using a HTTP timeout of " + HTTP_TIMEOUT + " milliseconds");

function respondWithData(res, data) {
	res.status(data.status).json(data.json).end();
}

const app = express();
app.get('/opengraph', async (req, res) => {
	const data = await getOpengraphData(req.query.url);
	respondWithData(res, data);
});
app.delete('/opengraph', async (req, res) => {
	const data = await removeOpengraphData(req.query.url);
	respondWithData(res, data);
});
app.get('/_health', (req, res) => res.end('Jolly good here'));
app.listen(7070, () => log(INFO, 'Server is listening'));

Add logging in case of process termination


// @flow
/* eslint-disable no-console */
import _ from 'lodash'
import stdin from 'get-stdin'
import Promise from 'bluebird'

import { parseOptions } from './cli'
import { checkFiles, checkString } from './checks'
import { formatOutput } from './formatters'
import { hasError } from './utils'
import { getDiffInformation } from './utils/git'
import { setErrorToWarning } from './utils/checkstyle'
import setup from './setup'

function handleResult(result, options) {
  const output = options.warning ? _.map(result, setErrorToWarning) : result
  console.log(formatOutput(options.format, output))
  process.exit(hasError(output) ? 1 : 0)
}

export default async function main(): Promise<> {
  const options = parseOptions()

  if (options.command === 'generate-config') {
    return setup(options)
  }

  const diff = await getDiffInformation(options)

  if (options.command === 'list-files') {
    return console.log(_.keys(diff).join(' '))
  }

  if (!options.command) {
    let result
    if (_.isEmpty(options.files)) {
      const input = await stdin()
      result = await checkString(diff, input, options)
    } else {
      result = await checkFiles(diff, options.files, options)
    }
    return handleResult(result, options)
  }

  throw new Error(`Unknown command '${options.command}'`)
}

if (!module.parent) {
  exports.default()
}

// @flow
/* eslint-disable no-console */
import _ from 'lodash'
import stdin from 'get-stdin'
import Promise from 'bluebird'

import { parseOptions } from './cli'
import { checkFiles, checkString } from './checks'
import { formatOutput } from './formatters'
import { hasError } from './utils'
import { getDiffInformation } from './utils/git'
import { setErrorToWarning } from './utils/checkstyle'
import setup from './setup'

function handleResult(result, options) {
  const output = options.warning ? _.map(result, setErrorToWarning) : result
  console.log(formatOutput(options.format, output))
  process.exit(hasError(output) ? 1 : 0)
}

export default async function main(): Promise<> {
  const options = parseOptions()

  if (options.command === 'generate-config') {
    return setup(options)
  }

  const diff = await getDiffInformation(options)

  if (options.command === 'list-files') {
    return console.log(_.keys(diff).join(' '))
  }

  if (!options.command) {
    let result
    if (_.isEmpty(options.files)) {
      const input = await stdin()

      if (input === '') {
        throw new Error('stdin was empty')
      }

      result = await checkString(diff, input, options)
    } else {
      result = await checkFiles(diff, options.files, options)
    }
    return handleResult(result, options)
  }

  throw new Error(`Unknown command '${options.command}'`)
}

if (!module.parent) {
  exports.default()
}

Add guard against empty stdin


var autocomplete = {
  // options for the EasyAutocomplete API
  setUp: function(input) {
    $input = $(input);

    options = {
      adjustWidth: false,
      data: autocompleteDict[$input.attr('name')],
      getValue: 'name',
      template: {
        type: 'custom',
        method: function(value, item) {
          return value +
            ' ' +
            item.count +
            '';
        }
      },
      list: {
        match: {
          enabled: true,
          method: function(element, phrase) {
            if (element.indexOf(phrase) === 0) {
              return true;
            } else {
              return false;
            }
          }
        },
        maxNumberOfElements: 20,
        sort: { enabled: true },
        onChooseEvent: function() {
          $input.closest('form').submit();
        },
      },
      placeholder: $input.attr('title')
    };

    $input.easyAutocomplete(options);
  },
  init: function() {
    self = this;
    $('input.autocomplete').each(function() {
      self.setUp(this);
    });
  }
};

$(document).ready(function() {
  autocomplete.init();
});

var autocomplete = {
  // options for the EasyAutocomplete API
  setUp: function(input) {
    $input = $(input);

    options = {
      adjustWidth: false,
      data: autocompleteDict[$input.attr('name')],
      getValue: 'name',
      template: {
        type: 'custom',
        method: function(value, item) {
          return value +
            ' ' +
            item.count +
            '';
        }
      },
      list: {
        match: {
          enabled: true,
          method: function(element, phrase) {
            if (element.indexOf(phrase) === 0) {
              return true;
            } else {
              return false;
            }
          }
        },
        maxNumberOfElements: 10,
        sort: { enabled: true },
        onChooseEvent: function() {
          $input.closest('form').submit();
        },
      },
      placeholder: $input.attr('title')
    };

    $input.easyAutocomplete(options);
  },
  init: function() {
    self = this;
    $('input.autocomplete').each(function() {
      self.setUp(this);
    });
  }
};

$(document).ready(function() {
  autocomplete.init();
});

Set the autocomplete list size to 10 elements maximum.


import React from 'react';
import {browserHistory, Router, Route, IndexRoute} from 'react-router';
import Layout from './containers/Layout';
import NotFound from './components/NotFound';
import {About, Home} from './components/Page';
import {Login, Profile} from './containers/User';
import Trends from './containers/Trends';
import {authRequired, authNoRequired, authLogout} from './helpers/routes';

const routes = store => {
  return (
    <Router history={browserHistory}>
      <Route path="/" component={Layout}>
        <IndexRoute component={Home} />
        <Route path="about" component={About} />
        <Route path="trends" component={Trends} />

        <Route onEnter={authNoRequired(store)}>
          <Route path="login" component={Login} />
        </Route>

        <Route onEnter={authRequired(store)}>
          <Route path="profile" component={Profile} />
          <Route path="logout" onEnter={authLogout(store)} />
        </Route>

        <Route path="*" name="not-found" component={NotFound} />
      </Route>
    </Router>
  );
};

export default routes;

import React from 'react';
import {browserHistory, Router, Route, IndexRoute} from 'react-router';
import Layout from './containers/Layout';
import NotFound from './components/NotFound';
import {About, Home} from './components/Page';
import {Login, Profile} from './containers/User';
import Trends from './containers/Trends';
import {fetchTrends} from './actions/Github';
import {
  authRequired,
  authNoRequired,
  authLogout
} from './helpers/routes';

const routes = store => {
  /**
   * Dispatch fetch trends action
   */
  function loadTrends() {
    store.dispatch(fetchTrends());
  }

  return (
    <Router history={browserHistory}>
      <Route path="/" component={Layout}>
        <IndexRoute component={Home} />
        <Route path="about" component={About} />
        <Route path="trends" component={Trends} onEnter={loadTrends} />

        <Route onEnter={authNoRequired(store)}>
          <Route path="login" component={Login} />
        </Route>

        <Route onEnter={authRequired(store)}>
          <Route path="profile" component={Profile} />
          <Route path="logout" onEnter={authLogout(store)} />
        </Route>

        <Route path="*" name="not-found" component={NotFound} />
      </Route>
    </Router>
  );
};

export default routes;

Load trend on enter to route


;(function(window) {
  'use strict';

  var angular = window.angular;
  var ImageLoader = window.ImageLoader;
  var ismobile = window.navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i);

  angular
    .module('tuchong-daily')
    .service('imageLoader', [
      '$ionicLoading',
      '$timeout',
      imageLoader
    ]);

  function imageLoader($ionicLoading, $timeout) {
    this.load = load;

    function load(uri, callback) {
      $ionicLoading.show();

      var img = new BlobImage(ismobile ? uri : proxy(uri));
      img.element.onload = success;
      img.element.onerror = fail;

      function success() {
        $ionicLoading.hide();
        callback(img.blobURL);
        img = null;
      }

      function fail() {
        $ionicLoading.show({
          template: '图片加载失败，请稍后再试试...'
        });
        img = null;
      }

      function proxy(realuri) {
        return realuri.replace(
          'http://photos.tuchong.com',
          'http://localhost:8100/photos'
        );
      }
    }
  }
})(this);

;(function(window) {
  'use strict';

  var angular = window.angular;
  var ImageLoader = window.ImageLoader;
  var ismobile = window.navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i);

  angular
    .module('tuchong-daily')
    .service('imageLoader', [
      '$ionicLoading',
      '$timeout',
      imageLoader
    ]);

  function imageLoader($ionicLoading, $timeout) {
    this.load = load;

    function load(uri, callback) {
      $ionicLoading.show();

      var img = new BlobImage(ismobile ? uri : proxy(uri));
      img.element.onload = success;
      img.element.onerror = fail;

      function success() {
        $ionicLoading.hide();
        callback(img.blobURL);
        img = null;
      }

      function fail() {
        $ionicLoading.show({
          template: '图片加载失败，请稍后再试试...'
        });
        img = null;

        $timeout($ionicLoading.hide, 1000);
      }

      function proxy(realuri) {
        return realuri.replace(
          'http://photos.tuchong.com',
          'http://localhost:8100/photos'
        );
      }
    }
  }
})(this);

Remove loading directive after request fails


import functionalText from "functional-text";

window.addEventListener("DOMContentLoaded", function () {
    let inputNode = document.querySelector("#input");
    let outputHtmlNode = document.querySelector("#output-html");

    let str = window.location.hash.length > 0 ?
        window.location.hash.substr(1) :
        `Sample Text for parsing`.trim();

    inputNode.value = str;
    inputNode.style.height = '200px';
    inputNode.style.width = '100%';

    let savedLog = console.log.bind(console);
    console.log = function (...args) {
        print(...args);
        savedLog(...args);
    };

    function print(...args) {
        outputHtmlNode.innerHTML += `<div>${args.join(" ")}</div>`;
    }

    function runParser() {
        outputHtmlNode.innerHTML = "";

        try {
            let parsedHtml = functionalText(inputNode.value);
            outputHtmlNode.style.borderColor = "black";
            print(parsedHtml.replace(/</g, "<").replace(/>/g, ">"));
        } catch (error) {
            outputHtmlNode.style.borderColor = "red";
            print(error);
        }

        window.location.hash = `#${window.escape(inputNode.value)}`;
    }

    inputNode.addEventListener("input", runParser);
    runParser();
});

import functionalText from "functional-text";

window.addEventListener("DOMContentLoaded", function () {
    let inputNode = document.querySelector("#input");
    let outputHtmlNode = document.querySelector("#output-html");

    let str = window.location.hash.length > 0 ?
        decodeURI(window.location.hash.substr(1)) :
        `Sample Text for parsing`.trim();

    inputNode.value = str;
    inputNode.style.height = '200px';
    inputNode.style.width = '100%';

    let savedLog = console.log.bind(console);
    console.log = function (...args) {
        print(...args);
        savedLog(...args);
    };

    function print(...args) {
        outputHtmlNode.innerHTML += `<div>${args.join(" ")}</div>`;
    }

    function runParser() {
        outputHtmlNode.innerHTML = "";

        try {
            let parsedHtml = functionalText(inputNode.value);
            outputHtmlNode.style.borderColor = "black";
            print(parsedHtml.replace(/</g, "<").replace(/>/g, ">"));
        } catch (error) {
            outputHtmlNode.style.borderColor = "red";
            print(error);
        }

        window.location.hash = `#${encodeURI(inputNode.value)}`;
    }

    inputNode.addEventListener("input", runParser);
    runParser();
});

Move to using methods that are not deprecated and unescape the hash when using it as default value.


var program = require('commander'),
    apiController = require('./apis/apiController')
    colors = require('colors'),
    ran = false;

var testCb = function(result, apiCall) {
  console.log('Test results for ' + apiCall.bold);
  if(result === true) {
    process.exit(0);
  } else {
    for(var i = 0; i < result.length; i++) {
      var info = result[i];
      switch(info.severity) {
        case 'info':
          console.log('Info:'.underline.green);
          break;
        case 'warning':
          console.log('Warning:'.underline.yellow);
          break;
        case 'breaking':
          process.exitCode = 1;
          console.log('Breaking API change:'.underline.red);
          break;
        default:
          console.log('Unkown severity'.underline.red);
      }
      console.log(info.type + ': (' + info.path + ')');
      console.log('old type: ' + info.oldType);
      console.log('new type: ' + info.newType)
      if(program.verbose) {
        console.log('old data: ', info.oldData);
        console.log('new data: ', info.newData);
      }
    }
  }
}

program.arguments('[apiPath]')
  .option('-v, --verbose', 'show api dump')
  .action(function(apiPath, options) {
    ran = true;
    if(apiPath) {
      apiController.testApi(apiPath, testCb);
    }
  })
  .parse(process.argv);

if(!ran) {
   apiController.testAll(testCb);
 }

var program = require('commander'),
    apiController = require('./apis/apiController')
    colors = require('colors'),
    ran = false;

var testCb = function(result, apiCall) {
  console.log('Test results for ' + apiCall.bold);
  if(result !== true) {
    for(var i = 0; i < result.length; i++) {
      var info = result[i];
      switch(info.severity) {
        case 'info':
          console.log('Info:'.underline.green);
          break;
        case 'warning':
          console.log('Warning:'.underline.yellow);
          break;
        case 'breaking':
          process.exitCode = 1;
          console.log('Breaking API change:'.underline.red);
          break;
        default:
          console.log('Unkown severity'.underline.red);
      }
      console.log(info.type + ': (' + info.path + ')');
      console.log('old type: ' + info.oldType);
      console.log('new type: ' + info.newType)
      if(program.verbose) {
        console.log('old data: ', info.oldData);
        console.log('new data: ', info.newData);
      }
    }
  }
}

program.arguments('[apiPath]')
  .option('-v, --verbose', 'show api dump')
  .action(function(apiPath, options) {
    ran = true;
    if(apiPath) {
      apiController.testApi(apiPath, testCb);
    }
  })
  .parse(process.argv);

if(!ran) {
   apiController.testAll(testCb);
 }

Fix test valid even though it was not


import colors from 'colors/safe';

const IS_ERROR_RE = /^error/;

export default function logEvents(cache, options = {}) {
  cache.onAny(function (...args) {
    const out = IS_ERROR_RE.test(this.event) ? 'stderr' : 'stdout';
    const timestamp = (new Date()).toISOString();
    const log = [colors.grey(timestamp)];

    if (options.namespace) log.push(options.namespace);
    log.push(colors.cyan(this.event), args);

    process[out].write(log.join(' ') + '\n');
  });
}

import colors from 'colors/safe';
import _forEach from 'lodash/collection/forEach';

const IS_ERROR_RE = /^error/;

export default function logEvents(cache, options = {}) {
  if (options.events) {
    const events = options.events;
    _forEach(events, function (event) {
      cache.on(event, function (...args) {
        const out = IS_ERROR_RE.test(this.event) ? 'stderr' : 'stdout';
        const timestamp = (new Date()).toISOString();
        const log = [colors.grey(timestamp)];

        if (options.namespace) log.push(options.namespace);
        log.push(colors.cyan(this.event), args);

        process[out].write(log.join(' ') + '\n');
      });
    });
  } else {
    cache.onAny(function (...args) {
      const out = IS_ERROR_RE.test(this.event) ? 'stderr' : 'stdout';
      const timestamp = (new Date()).toISOString();
      const log = [colors.grey(timestamp)];

      if (options.namespace) log.push(options.namespace);
      log.push(colors.cyan(this.event), args);

      process[out].write(log.join(' ') + '\n');
    });
  }
}

Add ability to pass in options.events to specify what cache events to log


module.exports = (task, campaignInfo) => {

  // Ref https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SES.html#sendEmail-property

  const email = {
    Source: `"${campaignInfo.fromName}" <${task.email}>`, // From email
    Destination: { // To email
      ToAddresses: [`<${task.email}>`] // Set name as follows https://docs.aws.amazon.com/ses/latest/DeveloperGuide/email-format.html
    },
    Message: {
      Body: {},
      Subject: { // Subject
        Data: campaignInfo.emailSubject
      }
    }
  };

  if (campaignInfo.type === 'Plaintext') { // Send as plaintext if plaintext, else send as HTML (no other format concerns us)
    Object.assign(email.Message.Body, { Text: { Data: campaignInfo.emailBody } });
  } else {
    Object.assign(email.Message.Body, { Html: { Data: campaignInfo.emailBody } });
  }

  return email;
};

module.exports = (task, campaignInfo) => {

  // Ref https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SES.html#sendEmail-property

  const email = {
    Source: `"${campaignInfo.fromName}" <${campaignInfo.fromEmail}>`, // From email
    Destination: { // To email
      ToAddresses: [`<${task.email}>`] // Set name as follows https://docs.aws.amazon.com/ses/latest/DeveloperGuide/email-format.html
    },
    Message: {
      Body: {},
      Subject: { // Subject
        Data: campaignInfo.emailSubject
      }
    }
  };

  if (campaignInfo.type === 'Plaintext') { // Send as plaintext if plaintext, else send as HTML (no other format concerns us)
    Object.assign(email.Message.Body, { Text: { Data: campaignInfo.emailBody } });
  } else {
    Object.assign(email.Message.Body, { Html: { Data: campaignInfo.emailBody } });
  }

  return email;
};

Fix 'from' address SES verification bug


import React from 'react';
import PropTypes from 'prop-types';

import styles from './Text.module.css';

/**
 * Render some text using the default typography scale.
 *
 * @param {Object} props
 * @param {string} props.scaleCategory -
 *   One of the styles `'h1'`, `'h1-medium'`, `'h2'`, `'h3'`, `'body'`, `'caption'`.
 * @param {string} [props.inline] - Render a span instread of a div.
 * @param {string} props.children - Nodes to render with specified typography.
 */
export function Text({inline, scaleCategory, children}) {
  return React.createElement(inline ? 'span' : 'div',
                             {className: styles[scaleCategory]},
                             children);
}

Text.propTypes = {
  children: PropTypes.node.isRequired,
  inline: PropTypes.bool,
  scaleCategory: PropTypes.oneOf(['h1', 'h1-medium', 'h2', 'body', 'caption']),
}

import React from 'react';
import PropTypes from 'prop-types';

import styles from './Text.module.css';

/**
 * Render some text using the default typography scale.
 *
 * @param {Object} props
 * @param {string} props.scaleCategory -
 *   One of the styles `'heading-lg'`, `'heading-md'`, `'heading-sm'`,
 *   `'heading-xs'`, `'body'`, `'caption'`.
 * @param {string} [props.inline] - Render a span instread of a div.
 * @param {string} props.children - Nodes to render with specified typography.
 */
export function Text({inline, scaleCategory, children}) {
  return React.createElement(inline ? 'span' : 'div',
                             {className: styles[scaleCategory]},
                             children);
}

Text.propTypes = {
  children: PropTypes.node.isRequired,
  inline: PropTypes.bool,
  scaleCategory: PropTypes.oneOf([
    'heading-lg', 'heading-md', 'heading-sm', 'heading-xs', 'body', 'caption'
  ]),
}

Fix scaleCategory prop types and docs


'use strict';

// TODO: Make everything handle signed int64 properly...

/**
 * A class for wrapping a 64-bit integer in Javascript to avoid loss
 * of precision issues at high values.
 *
 * @constructor
 * @param {number} lo
 * @param {number} hi
 */
function Int64(lo, hi) {
  if (lo === undefined && hi === undefined) {
    lo = 0;
    hi = 0;
  }
  this.lo = lo;
  this.hi = hi;
}

Int64.prototype.isBitSet = function(bit) {
  if (bit < 32) {
    return this.lo & (1 << bit);
  } else {
    return this.hi & (1 << (bit-32));
  }
};

Int64.prototype.toString = function(radix) {
  if (radix === 10 || radix === undefined) {
    return '?int64_tostring_badradix?';
  } else if (radix === 16) {
    var str = this.lo.toString(16);
    while (str.length < 8) {
      str = '0' + str;
    }
    return this.hi.toString(16) + str;
  } else {
    return '?int64_tostring_badradix?';
  }
};

Int64.prototype.toNumber = function() {
  return this.hi << 32 | this.lo;
};

'use strict';

// TODO: Make everything handle signed int64 properly...

/**
 * A class for wrapping a 64-bit integer in Javascript to avoid loss
 * of precision issues at high values.
 *
 * @constructor
 * @param {number} [lo]
 * @param {number} [hi]
 */
function Int64(lo, hi) {
  if (lo === undefined && hi === undefined) {
    lo = 0;
    hi = 0;
  }
  this.lo = lo;
  this.hi = hi;
}

Int64.prototype.isBitSet = function(bit) {
  if (bit < 32) {
    return this.lo & (1 << bit);
  } else {
    return this.hi & (1 << (bit-32));
  }
};

Int64.prototype.toString = function(radix) {
  if (radix === 10 || radix === undefined) {
    return '?int64_tostring_badradix?';
  } else if (radix === 16) {
    var str = this.lo.toString(16);
    while (str.length < 8) {
      str = '0' + str;
    }
    return this.hi.toString(16) + str;
  } else {
    return '?int64_tostring_badradix?';
  }
};

Int64.prototype.toNumber = function() {
  return this.hi << 32 | this.lo;
};

Fix Int64 constructor to be documented as having optional params.


var Documentation = require('./model/Documentation');
var Component = require('../ui/Component');
var DocumentationReader = require('./DocumentationReader');
var $$ = Component.$$;
var $ = require('../util/jquery');
var _ = require('../util/helpers');
var importDocumentation = require('./model/importDocumentation');

var _loadDocument = function(cb) {
  _.request('GET', './documentation.json', null, function(err, rawDoc) {
    if (err) { console.error(err); cb(err); }
    var doc = importDocumentation(rawDoc);
    window.doc = doc;
    // console.log('LE DOC', doc);
    cb(null, doc);
  });
};

$(function() {
  var doc = new Documentation();
  window.doc = doc;
  _loadDocument(function(err, doc) {
    Component.mount($$(DocumentationReader, {
      doc: doc
    }), $('body'));
  });
});

var Documentation = require('./model/Documentation');
var Component = require('../ui/Component');
var DocumentationReader = require('./DocumentationReader');
var $ = require('../util/jquery');
var _ = require('../util/helpers');
var importDocumentation = require('./model/importDocumentation');

var _loadDocument = function(cb) {
  _.request('GET', './documentation.json', null, function(err, rawDoc) {
    if (err) { console.error(err); cb(err); }
    var doc = importDocumentation(rawDoc);
    window.doc = doc;
    // console.log('LE DOC', doc);
    cb(null, doc);
  });
};

$(function() {
  var doc = new Documentation();
  window.doc = doc;
  _loadDocument(function(err, doc) {
    Component.mount(DocumentationReader, {
      doc: doc
    }, $('body'));
  });
});

Use new Component.mount API for documentation.


import Em from 'ember';
import Column from './column';
var ArrayProxy = Em.ArrayProxy;
var Sortable = Em.SortableMixin;

var ControllerArray = ArrayProxy.extend({
	itemController: Em.ObjectController,
	mapController: function (obj) {
		return this.itemController.create({
			content: obj
		});
	},
	arrangedContent: function () {
		return this.get('content').map(this.mapController, this);
	}.property('content'),
	contentArrayDidChange: function (arr, i, removedCount, addedCount) {
		var addedObjects = arr.slice(i, i + addedCount);
		addedObjects = addedObjects.map(this.mapController, this);
		this.get('arrangedContent').replace(i, removedCount, addedObjects);
	}
});

var Columns = ArrayProxy.extend(Sortable, {
	content: function (key, value) {
		return ControllerArray.create({
			itemController: Column,
			content: value
		});
	}.property()
});

export default Columns;

import Em from 'ember';
import Column from './column';
var ArrayProxy = Em.ArrayProxy;
var Sortable = Em.SortableMixin;

var ControllerArray = ArrayProxy.extend({
	itemController: Em.ObjectController,
	lookupItemController: function (object) {
		return this.get('itemController');
	},
	mapController: function (obj) {
		var controllerClass = this.lookupItemController(obj);
		if (controllerClass) {
			return controllerClass.create({
				target: this,
				parentController: this,
				content: obj
			});
		}
	},
	arrangedContent: function () {
		return this.get('content').map(this.mapController, this);
	}.property('content'),
	contentArrayDidChange: function (arr, i, removedCount, addedCount) {
		var addedObjects = arr.slice(i, i + addedCount);
		addedObjects = addedObjects.map(this.mapController, this);
		this.get('arrangedContent').replace(i, removedCount, addedObjects);
	}
});

var Columns = ArrayProxy.extend(Sortable, {
	content: function (key, value) {
		return ControllerArray.create({
			itemController: Column,
			content: value
		});
	}.property()
});

export default Columns;

Implement lookupItemController() function in controller array


if (!window.console || !window.console.log) {
  window.console = {
    log: function() {}
  };
}

/**
 * Very simple reporter for jasmine
 */
var SimpleReporter = function() {

  this.reportRunnerStarting = function(runner) {
    var count = runner.specs().length;
    console.log('start runner', count);
    window.parent.socket.emit('result', 'Running ' + count + ' specs...');
  };

  this.reportRunnerResults = function(runner) {
    console.log('complete');
    window.parent.socket.emit('result', 'COMPLETE');
  };

  this.reportSuiteResults = function(suite) {
    console.log('suite');
  };

  this.reportSpecStarting = function(spec) {
    console.log('start spec: ' + spec.suite.description + ' ' + spec.description + '...');
  };

  this.reportSpecResults = function(spec) {
    var result = spec.results_.failedCount === 0 ? 'PASSED' : 'FAILED';
    window.parent.socket.emit('result', spec.suite.description + ': ' + spec.description + ' -- ' + result);
    console.log('spec result', spec);
  };

  this.log = function() {
    console.log('LOG', arguments);
  };
};

window.addEventListener('DOMContentLoaded', function() {
  var jasmineEnv = jasmine.getEnv();
  jasmineEnv.addReporter(new SimpleReporter());
  jasmineEnv.execute();
});

//      jasmineEnv.updateInterval = 1000;
//      jasmineEnv.specFilter = function(spec) {
//        return trivialReporter.specFilter(spec);
//      };

Add fake console to get it running on iPhone


import babel from 'rollup-plugin-babel';

export default {
    entry: 'index.js',
    moduleName: 'fc_datajoin',
    format: 'umd',
    plugins: [ babel() ],
    dest: 'build/d3fc-data-join.js',
    globals: {
        'd3': 'd3'
    }
};

import babel from 'rollup-plugin-babel';

export default {
    entry: 'index.js',
    moduleName: 'fc_data_join',
    format: 'umd',
    plugins: [ babel() ],
    dest: 'build/d3fc-data-join.js',
    globals: {
        'd3': 'd3'
    }
};

Make global module name consistent with d3


angular.module('geojsonApp',[])
  .controller('MainCtrl', ['$http', function($http) {

    var self = this;

    self.items = [];
    self.queryItems = [];
    self.item = {};
    self.query = {};
    self.currentTab = 'home';

    var resetItemModel = function() {
      self.item={};
      self.item.location={};
      self.item.location.coordinates=[];
    };

    resetItemModel();

    var fetchItems = function() {
      return $http.get('/api/item')
      .then(
        function(response){
          self.items = response.data;
        },
        function(errResponse) {
          console.error('Error while fetching items');
        }
      );
    };

    fetchItems();

    self.add = function() {
      self.item.location.type = "Point";
      $http.post('/api/item', self.item)
        .then(fetchItems)
        .then( function(response) {
          resetItemModel();
          self.currentTab = 'items';
        });
    };

    self.inquire = function() {
      console.log(self.query);
      $http.post('/api/query', self.query)
        .then( function(response) {
          self.queryItems = response.data;
          self.currentTab = 'query';
        });
    };

    self.delete = function(id) {
      $http.delete('/api/item/' + id);
      fetchItems();
      self.currentTab = 'items';
    };

  }]);

angular.module('geojsonApp',[])
  .controller('MainCtrl', ['$http', function($http) {

    var self = this;

    self.items = [];
    self.queryItems = [];
    self.item = {};
    self.query = {};
    self.currentTab = 'home';

    var resetItemModel = function() {
      self.item={};
      self.item.location={};
      self.item.location.coordinates=[];
    };

    resetItemModel();

    var fetchItems = function() {
      return $http.get('/api/item')
      .then(
        function(response){
          self.items = response.data;
        },
        function(errResponse) {
          console.error('Error while fetching items');
        }
      );
    };

    fetchItems();

    self.add = function() {
      self.item.location.type = "Point";
      $http.post('/api/item', self.item)
        .then(fetchItems)
        .then( function(response) {
          resetItemModel();
          self.currentTab = 'items';
        });
    };

    self.inquire = function() {
      console.log(self.query);
      $http.post('/api/query', self.query)
        .then( function(response) {
          self.queryItems = response.data;
          self.currentTab = 'query';
        });
    };

    self.delete = function(id) {
      $http.delete('/api/item/' + id)
        .then(fetchItems)
        .then(
          function(response) {
            self.currentTab = 'items';
          },
          function(error) {
            console.log("Error deleting item");
          });
    };

  }]);

Use promises and log an error


describe('The CamlTag should build a valid XML String', function() {
	var CamlTag;
	beforeEach(module('ngSharepoint'));
	beforeEach(inject(function(_CamlTag_) {
		CamlTag = _CamlTag_;
	}));
	it('builds a valid XML Tag', function() {
		expect(new CamlTag('Test').build()).toEqual('<Test></Test>');
	});
});

describe('The CamlTag should build a valid XML String', function() {
	var CamlTag;
	beforeEach(module('ngSharepoint'));
	beforeEach(inject(function(_CamlTag_) {
		CamlTag = _CamlTag_;
	}));
	it('builds a valid XML Tag', function() {
		expect(new CamlTag('Test').build()).toEqual('<Test/>');
	});
});

Update test to respect self closing tags


var config = {
  /*
  * Maps flash message keys to css classes
  */
  flashes: {
    defaultClass: 'alert',
    classes: {
      success: 'alert alert-success',
      alert: 'alert',
      error: 'alert alert-danger',
      info: 'alert alert-info'
    }
  }
  /*
  metrics: {
    port: 4001
  }
  */
};

module.exports = config;

var config = {
  /*
  * Maps flash message keys to css classes
  */
  flashes: {
    defaultClass: 'alert',
    classes: {
      success: 'alert alert-success',
      alert: 'alert',
      error: 'alert alert-error',
      info: 'alert alert-info'
    }
  }
  /*
  metrics: {
    port: 4001
  }
  */
};

module.exports = config;

Use alert-error in place of alert-danger


$(function(){
    setup_search_box();
    $(window).resize(setup_search_box);
});

function setup_search_box() {
    var sel = $('#search'), head = $('#logo').parent();
    if ( ! sel.length ) { return; }

    if ( head.offset().top + head.innerHeight() <= sel.offset().top ) {
        sel.addClass('two-row');
    }
    else {
        sel.removeClass('two-row');
    }

    $('#query').focus();
}

$(function(){
    setup_search_box();
    $(window).resize(setup_search_box);
});

function setup_search_box() {
    var sel = $('#search'), head = $('#logo').parent();
    if ( ! sel.length ) { return; }

    /* Setup handling of narrow screens */
    if ( head.offset().top + head.innerHeight() <= sel.offset().top ) {
        sel.addClass('two-row');
    }
    else {
        sel.removeClass('two-row');
    }

    $('#query').focus();
}

Clarify what the code is for


import Promise from 'bluebird';

/**
 * Returns a Promise resolved with a Horseman instance.
 *
 * @param {Server} server - A Server instance.
 * @param {string} url - An optional authentication domain.
 *
 * @return {Promise}.
 */
export default function horsemanFactory(server, domain) {

  let horseman;

  if (server.plugins.kibi_access_control) {
    return server.plugins.kibi_access_control.getSentinlHorseman(domain);
  } else {
    try {
      const Horseman = require('node-horseman');
      return Promise.resolve(new Horseman({ 'ignoreSSLErrors': true }));
    } catch (error) {
      return Promise.reject(error);
    }
  }
}

import Promise from 'bluebird';

/**
 * Returns a Promise resolved with a Horseman instance.
 *
 * @param {Server} server - A Server instance.
 * @param {string} url - An optional authentication domain.
 *
 * @return {Promise}.
 */
export default function horsemanFactory(server, domain) {

  let horseman;

  if (server.plugins.kibi_access_control) {
    return server.plugins.kibi_access_control.getSentinlHorseman(domain);
  } else {
    try {
      const Horseman = require('node-horseman');
      const options = {
        'ignoreSSLErrors': true,
        'phantomPath': `${__dirname}/../../node_modules/phantomjs/bin/phantomjs`
      };
      return Promise.resolve(new Horseman(options));
    } catch (error) {
      return Promise.reject(error);
    }
  }
}

Add path to phantomjs binary.


'use strict'

class API {
  static createQueryFromRequest (request) {
    delete request.rats
    delete request.CMDRs

    let limit = parseInt(request.limit) || 25
    delete request.limit

    let offset = (parseInt(request.page) - 1) * limit || parseInt(request.offset) || 0
    delete request.offset
    delete request.page

    let order = request.order || 'createdAt'
    delete request.order

    let direction = request.direction || 'ASC'
    delete request.direction

    if (request.firstLimpet) {
      request.firstLimpetId = request.firstLimpet
      delete request.firstLimpet
    }

    if (request.data) {
      let dataQuery = request.data
      delete request.data

      request.data = {
        $contains: JSON.parse(dataQuery)
      }
    }

    let query = {
      where: request,
      order: [
        [order, direction]
      ],
      limit: limit,
      offset: offset,
    }

    return query
  }

  static version (version) {
    return function (req, res, next) {
      req.apiVersion = version
      next()
    }
  }
}

module.exports = API

'use strict'

class API {
  static createQueryFromRequest (req) {
    let request = Object.assign({}, req)
    delete request.rats
    delete request.CMDRs

    let limit = parseInt(request.limit) || 25
    delete request.limit

    let offset = (parseInt(request.page) - 1) * limit || parseInt(request.offset) || 0
    delete request.offset
    delete request.page

    let order = request.order || 'createdAt'
    delete request.order

    let direction = request.direction || 'ASC'
    delete request.direction

    if (request.firstLimpet) {
      request.firstLimpetId = request.firstLimpet
      delete request.firstLimpet
    }

    if (request.data) {
      let dataQuery = request.data
      delete request.data

      request.data = {
        $contains: JSON.parse(dataQuery)
      }
    }

    let query = {
      where: request,
      order: [
        [order, direction]
      ],
      limit: limit,
      offset: offset,
    }

    return query
  }

  static version (version) {
    return function (req, res, next) {
      req.apiVersion = version
      next()
    }
  }
}

module.exports = API

Make request argument in createQueryFromRequest optional


const electron = require('electron')
const app = require('electron').app
const dialog = electron.dialog
const Channel = require('./channel')
const path = require('path')

module.exports.showAbout = function () {
  dialog.showMessageBox({
    title: 'Brave',
    message: `Brave: ${app.getVersion()}
Electron: ${process.versions['atom-shell']}
libchromiumcontent: ${process.versions['chrome']}
V8: ${process.versions.v8}
Node.js: ${process.versions.node}
Update channel: ${Channel.channel()}`,
    icon: path.join(__dirname, '..', 'app', 'img', 'braveAbout.png'),
    buttons: ['Ok']
  })
}

const electron = require('electron')
const app = require('electron').app
const dialog = electron.dialog
const Channel = require('./channel')
const path = require('path')

module.exports.showAbout = function () {
  dialog.showMessageBox({
    title: 'Brave',
    message: `Brave: ${app.getVersion()}
Electron: ${process.versions['atom-shell']}
libchromiumcontent: ${process.versions['chrome']}
V8: ${process.versions.v8}
Node.js: ${process.versions.node}
Update channel: ${Channel.channel()}

This software uses libraries from the FFmpeg project under the LGPLv2.1`,
    icon: path.join(__dirname, '..', 'app', 'img', 'braveAbout.png'),
    buttons: ['Ok']
  })
}

Add LGPL FFmpeg to about


//autocomplete for organism search
 $("#search_organism").autocomplete({
    position: {
       my: "right top", at: "right bottom"
    },
    source: function (request, response) {
        var $search = request.term;
        $.ajax({
            url: WebRoot.concat("/ajax/listing/Organisms"),
            data: {term:  request.term, limit: 500, search: $search},
            dataType: "json",
            success: function (data) {
                response(data);
            }
        });
    },
    minLength: 3
});

$("#search_organism").data("ui-autocomplete")._renderItem = function (ul, item) {
    var li = $("
")
            .append("" + item.scientific_name + "" + item.rank + "")
            .appendTo(ul);
    return li;
};

$("#btn_search_organism").click(function(){
    $searchTerm = $("#search_organism").val();
    $.ajax({
        url: WebRoot.concat("/ajax/listing/Organisms"),
        data: {limit: 500, search: $searchTerm},
        dataType: "json",
        success: function (data) {
            console.log(data);
        }
    });
});

Remove non-used click function for organism search button


"use strict";
var Codesearch = function() {
  return {
    socket: null,
    delegate: null,
    connect: function(delegate) {
      if (Codesearch.socket !== null)
        return;
      console.log("Connecting...");
      Codesearch.remote = null;
      Codesearch.delegate = delegate;
      var socket = io.connect("http://" + document.location.host.replace(/:\d+$/, '') + ":8910");
      socket.on('connect', function () {
                  Codesearch.socket = socket;
                  if (Codesearch.delegate.on_connect)
                    Codesearch.delegate.on_connect();
                });
      socket.on('regex_error', Codesearch.delegate.error);
      socket.on('match', Codesearch.delegate.match);
      socket.on('search_done', Codesearch.delegate.search_done);
    },
    new_search: function(re, file, id) {
      if (Codesearch.socket !== null)
        Codesearch.socket.emit('new_search', re, file, id);
    }
  };
}();

"use strict";
var Codesearch = function() {
  return {
    socket: null,
    delegate: null,
    connect: function(delegate) {
      if (Codesearch.socket !== null)
        return;
      Codesearch.remote = null;
      Codesearch.delegate = delegate;
      var socket = io.connect("http://" + document.location.host.replace(/:\d+$/, '') + ":8910");
      socket.on('connect', function () {
                  Codesearch.socket = socket;
                  if (Codesearch.delegate.on_connect)
                    Codesearch.delegate.on_connect();
                });
      socket.on('regex_error', Codesearch.delegate.error);
      socket.on('match', Codesearch.delegate.match);
      socket.on('search_done', Codesearch.delegate.search_done);
    },
    new_search: function(re, file, id) {
      if (Codesearch.socket !== null)
        Codesearch.socket.emit('new_search', re, file, id);
    }
  };
}();

Stop using console.log on the web.


import React, { Component } from 'react';

class AccountPage extends Component {
    constructor () {
        super();
    }

    render () {
        const {
            account
        } = this.props;
        return (

{account.name}

Last worked: {account.lastCredit}

Last purchase: {account.lastMeal}

                    Barter Credits: ${(account.currentCredit / 100).toFixed(2)}

                    <button class="btn btn-info col-sm-offset-1"
                            onClick={() => this.props.switchView('buymealpage', account)}>
                        Buy Meal
                    </button>
                    <button class="btn btn-success col-sm-offset-1"
                            onClick={() => this.props.switchView('addcreditpage', account)}>
                        Add Credit
                    </button>

 this.props.switchView('searchpage')}>
                    <button class="btn btn-lg btn-danger col-sm-offset-5 center-block">Back to Search</button>

         );
    }
}

export default AccountPage;

import React, { Component } from 'react';

class AccountPage extends Component {
    constructor () {
        super();
    }

    render () {
        const {
            account
        } = this.props;
        return (

{account.name}

Last worked: {account.lastCredit}

Last purchase: {account.lastMeal}

                    Barter Credits: ${(account.currentCredit / 100).toFixed(2)}

                    <button class="btn btn-info col-sm-offset-1"
                            onClick={() => this.props.switchView('buycardpage', account)}>
                        Buy Card
                    </button>
                    <button class="btn btn-info col-sm-offset-1"
                            onClick={() => this.props.switchView('buymealpage', account)}>
                        Buy Meal
                    </button>
                    <button class="btn btn-success col-sm-offset-1"
                            onClick={() => this.props.switchView('addcreditpage', account)}>
                        Add Credit
                    </button>

 this.props.switchView('searchpage')}>
                    <button class="btn btn-lg btn-danger col-sm-offset-5 center-block">Back to Search</button>

         );
    }
}

export default AccountPage;

Add buy card button to account page


/**
 * View for viewing downloaded videos.
 */
export default class DownloadedList {
  /**
   * Default constructor for setting the values
   *
   * @param {HTMLElement} element - The HTML element to bind/adopt
   * @param {Array<Object>} [mediaItems=null] - The array containing media items
   */
  constructor(element, mediaItems = null) {
    this.element = element;
    this.mediaItems = mediaItems;
  }

  /**
   * Render page.
   *
   * The cards should show the program name, episode number and
   * episode length.
   */
  render() {
    let html = `

      `;
      this.mediaItems.forEach((episode) => {
        html += `

            ${episode.getTitle()}`;
        if (episode.getDuration() !== ' ') {
          html += `<span class="lDur">Kesto ${episode.getDuration()}min</span>`;
        }
         html += `

              delete_forever
              play_circle_filled

        `;
        });
      html += `

    `;
    this.element.innerHTML = html;
  }
}

/**
 * View for viewing downloaded videos.
 */
export default class DownloadedList {
  /**
   * Default constructor for setting the values
   *
   * @param {HTMLElement} element - The HTML element to bind/adopt
   * @param {Array<Object>} [mediaItems=null] - The array containing media items
   */
  constructor(element, mediaItems = null) {
    this.element = element;
    this.mediaItems = mediaItems;
  }

  /**
   * Render page.
   *
   * The cards should show the program name, episode number and
   * episode length.
   */
  render() {
    let html = `

      `;
      this.mediaItems.forEach((episode) => {
        html += `

            ${episode.getTitle()}`;
        if (episode.getDuration() !== ' ') {
          html += `<span class="lDur">Kesto ${episode.getDuration()} min</span>`;
        }
         html += `

              delete_forever
              play_circle_filled

        `;
        });
      html += `

    `;
    this.element.innerHTML = html;
  }
}

Format duration in downloaded list