import React from 'react';
import Helmet from 'react-helmet';
import styles from './styles';

function calculateViewportFromWindow() {
  if (window.innerWidth >= 544) return 'sm';
  if (window.innerWidth >= 768) return 'md';
  if (window.innerWidth >= 992) return 'lg';
  if (window.innerWidth >= 1200) return 'xl';
  return'xs';
}

function renderAugmentedChildren(props) {
  return React.Children.map(props.children, (child) => {
    if (!child) return null;
    return React.cloneElement(child, { viewport: props.viewport });
  });
}

const LandingCanvas = (props) => {

  const s = styles(props);

  let {
    viewport
  } = props;

  viewport = viewport || calculateViewportFromWindow();

  return (
    <div style={ s.wrapper }>
      <Helmet
        link={[
          { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Lato' },
          { rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css' }
        ]}
      />
      { renderAugmentedChildren(props) }
    </div>
  );
}

export default LandingCanvas;

import React from 'react';
import Helmet from 'react-helmet';
import styles from './styles';

function calculateViewportFromWindow() {
  if (typeof window !== 'undefined') {
    if (window.innerWidth >= 544) return 'sm';
    if (window.innerWidth >= 768) return 'md';
    if (window.innerWidth >= 992) return 'lg';
    if (window.innerWidth >= 1200) return 'xl';
    return'xs';
  } else {
    return null;
  }
}

function renderAugmentedChildren(props) {
  return React.Children.map(props.children, (child) => {
    if (!child) return null;
    return React.cloneElement(child, { viewport: props.viewport });
  });
}

const LandingCanvas = (props) => {

  const s = styles(props);

  let {
    viewport
  } = props;

  viewport = viewport || calculateViewportFromWindow();

  return (
    <div style={ s.wrapper }>
      <Helmet
        link={[
          { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Lato' },
          { rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css' }
        ]}
      />
      { renderAugmentedChildren(props) }
    </div>
  );
}

export default LandingCanvas;

Disable viewport calculation in case of server side render


const SET_PHOTOS = 'SET_PHOTOS'

const initialState = {
  photos: [],
  photosDetail: []
}

const photos = (state = initialState, action = {}) => {

  switch (action.type) {
    case SET_PHOTOS:
      return {...state, photos: action.payload.ids, photosDetail:action.payload.photoList}
    default:
      return state
  }
}

export default photos

const SET_PHOTOS = 'SET_PHOTOS'

const initialState = {
  photos: [],
  photosDetail: []
}

const photos = (state = initialState, action = {}) => {

  switch (action.type) {
    case SET_PHOTOS:

      let index = state.photosDetail.filter((el) => {
        return action.payload.photoList.findIndex( (node) => el.node.id == node.node.id)
      });
      return {...state, photos: Array.from(new Set([...state.photos,  ...action.payload.ids])), photosDetail:[...state.photosDetail, ...action.payload.photoList]}

    default:
      return state
  }
}

export default photos

Add conditions to remove duplicates.


if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('./service-worker.js', {scope: './'})
    .catch(function(error) {
      alert('Error registering service worker:'+error);
    });
} else {
  alert('service worker not supported');
}

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('./service-worker.js', {scope: './'})
    .catch(function(error) {
      console.error('Error registering service worker:'+error);
    });
} else {
  console.log('service worker not supported');
}

Use console.error and console.log instead of alert


const socketio = require('socket.io')
const data = require('../data/tasks')
let counter = 0
exports.listen = function (server) {
  io = socketio.listen(server)
  io.sockets.on('connection', function (socket) {
    console.log('Connection created')
    createTask(socket)
    displayAllTask(socket)
  })

  const createTask = (socket) => {
    socket.on('createTask', (data) => {
      console.log('DB call-->', data.title, data.description, data.assignedTo, data.dueDate)
      //++counter
      let counter = ++data.seq
      console.log('Counter = ', counter)
      data['tasks'][counter] = {
        title: data.title,
        desc: data.description,
        status: 'new',
        assgnBy: 'current',
        assgnTo: data.assignedTo,
        createdOn: new Date().toISOString(),
        dueDate: data.dueDate
      }
      io.emit('updateTaskList', data)
    })
  }

  const displayAllTask = (socket) => {
    socket.on('populateAllTask', (data) => {
      socket.emit('displayAllTask', data)
    })
  }

}

const socketio = require('socket.io')
const data = require('../data/tasks')
exports.listen = function (server) {
  io = socketio.listen(server)
  io.sockets.on('connection', function (socket) {
    console.log('Connection created')
    createTask(socket)
    displayAllTask(socket)
  })

  const createTask = (socket) => {
    socket.on('createTask', (task) => {
      let counter = ++(data.seq)
      data['tasks'][counter] = {
        title: task.title,
        desc: task.description,
        status: 'new',
        assgnBy: 'current',
        assgnTo: task.assignedTo,
        createdOn: new Date().toISOString(),
        dueDate: task.dueDate
      }
      io.emit('updateTaskList', {task: task, status: 'new'})
    })
  }

  const displayAllTask = (socket) => {
    socket.on('populateAllTask', (data) => {
      socket.emit('displayAllTask', data)
    })
  }

}

Add createTask on and emit event with mock data


/*
 * Copyright (c) 2014-2020 Bjoern Kimminich.
 * SPDX-License-Identifier: MIT
 */

const models = require('../models/index')
const insecurity = require('../lib/insecurity')
const utils = require('../lib/utils')
const cache = require('../data/datacache')
const challenges = cache.challenges

module.exports = function updateUserProfile () {
  return (req, res, next) => {
    const loggedInUser = insecurity.authenticatedUsers.get(req.cookies.token)

    if (loggedInUser) {
      models.User.findByPk(loggedInUser.data.id).then(user => {
        utils.solveIf(challenges.csrfChallenge, () => {
          return ((req.headers.origin && req.headers.origin.includes('://htmledit.squarefree.com')) ||
            (req.headers.referrer && req.headers.referrer.includes('://htmledit.squarefree.com'))) &&
            req.body.username !== user.username
        })
        return user.update({ username: req.body.username })
      }).catch(error => {
        next(error)
      })
    } else {
      next(new Error('Blocked illegal activity by ' + req.connection.remoteAddress))
    }
    res.location(process.env.BASE_PATH + '/profile')
    res.redirect(process.env.BASE_PATH + '/profile')
  }
}

/*
 * Copyright (c) 2014-2020 Bjoern Kimminich.
 * SPDX-License-Identifier: MIT
 */

const models = require('../models/index')
const insecurity = require('../lib/insecurity')
const utils = require('../lib/utils')
const cache = require('../data/datacache')
const challenges = cache.challenges

module.exports = function updateUserProfile () {
  return (req, res, next) => {
    const loggedInUser = insecurity.authenticatedUsers.get(req.cookies.token)

    if (loggedInUser) {
      models.User.findByPk(loggedInUser.data.id).then(user => {
        utils.solveIf(challenges.csrfChallenge, () => {
          return ((req.headers.origin && req.headers.origin.includes('://htmledit.squarefree.com')) ||
            (req.headers.referer && req.headers.referer.includes('://htmledit.squarefree.com'))) &&
            req.body.username !== user.username
        })
        return user.update({ username: req.body.username })
      }).catch(error => {
        next(error)
      })
    } else {
      next(new Error('Blocked illegal activity by ' + req.connection.remoteAddress))
    }
    res.location(process.env.BASE_PATH + '/profile')
    res.redirect(process.env.BASE_PATH + '/profile')
  }
}

Fix spelling of HTTP referer header


var fs = require('fs');
var run = require('./runner');

var defaults = {
    opensslPath : '/usr/bin/openssl',
    padding : 'pkcs'
};

function verifyOptions (options) {
    if (!fs.existsSync(options.opensslPath)) {
        throw new Error(options.opensslPath + ': No such file or directory');
    }

    if (options.padding !== 'pkcs' && options.padding !== 'raw') {
        throw new Error('Unsupported padding: ' + options.padding);
    }
}

function operation (data, key, callback, options) {
    var options = options || {};

    for (var attr in defaults) {
        if (!options[attr]) options[attr] = defaults[attr];
    }

    options.operation = operation.caller.name;

    try {
        verifyOptions(options);
        run(options, data, key, callback);
    } catch (err) {
        return callback(err);
    }
}

exports.encrypt = function encrypt (data, key, callback, options) { operation(data, key, callback, options); };
exports.decrypt = function decrypt (data, key, callback, options) { operation(data, key, callback, options); };
exports.sign = function sign (data, key, callback, options) { operation(data, key, callback, options); };
exports.verify = function verify (data, key, callback, options) { operation(data, key, callback, options); };

var fs = require('fs');
var run = require('./runner');

var defaults = {
    opensslPath : '/usr/bin/openssl',
    padding : 'pkcs'
};

function verifyOptions (options) {
    if (fs.existsSync !== undefined && !fs.existsSync(options.opensslPath)) {
        throw new Error(options.opensslPath + ': No such file or directory');
    }

    if (options.padding !== 'pkcs' && options.padding !== 'raw') {
        throw new Error('Unsupported padding: ' + options.padding);
    }
}

function operation (data, key, callback, options) {
    var options = options || {};

    for (var attr in defaults) {
        if (!options[attr]) options[attr] = defaults[attr];
    }

    options.operation = operation.caller.name;

    try {
        verifyOptions(options);
        run(options, data, key, callback);
    } catch (err) {
        return callback(err);
    }
}

exports.encrypt = function encrypt (data, key, callback, options) { operation(data, key, callback, options); };
exports.decrypt = function decrypt (data, key, callback, options) { operation(data, key, callback, options); };
exports.sign = function sign (data, key, callback, options) { operation(data, key, callback, options); };
exports.verify = function verify (data, key, callback, options) { operation(data, key, callback, options); };

Handle Meteor's stripping out methods from the fs core API.


import resolve from 'rollup-plugin-node-resolve';
import eslint from 'rollup-plugin-eslint';
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import replace from 'rollup-plugin-replace';
import pkg from './package.json';

export default [
    {
        input: 'src/index.js',
        external: ['react', 'react-dom'],
        output: [
            { file: pkg.main, format: 'umd', name: 'reactAccessibleAccordion' },
            { file: pkg['jsnext:main'], format: 'es' },
        ],
        name: 'reactAccessibleAccordion',
        plugins: [
            resolve({
                jsnext: true,
                main: true,
                browser: true,
            }),
            eslint(),
            babel(),
            commonjs(),
            replace({
                exclude: 'node_modules/**',
                ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
            }),
        ],
    },
];

import resolve from 'rollup-plugin-node-resolve';
import eslint from 'rollup-plugin-eslint';
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import replace from 'rollup-plugin-replace';
import pkg from './package.json';

export default [
    {
        input: 'src/index.js',
        external: ['react', 'react-dom'],
        output: [
            { file: pkg.main, format: 'umd', name: 'reactAccessibleAccordion' },
            { file: pkg['jsnext:main'], format: 'es' },
        ],
        name: 'reactAccessibleAccordion',
        plugins: [
            replace({
                'process.env.NODE_ENV': JSON.stringify('production'),
            }),
            resolve({
                jsnext: true,
                main: true,
                browser: true,
            }),
            eslint(),
            babel(),
            commonjs(),
        ],
    },
];

Fix 'rollup-plugin-replace' order and variable name


product
.config(function ($routeProvider) {
    $routeProvider
        .when('/', {
            templateUrl: 'components/chooseLanguage/chooseLanguage.tpl.html'
            ,controller: 'ChooseLanguageCtrl'
            ,resolve: {
                LanguageService: 'LanguageService',
                languages: function(LanguageService){
                    // This line is updated to return the promise
                    //return LanguageService.query().$promise;
                }
            }
        })
        .otherwise({
                redirectTo: '/whatever'
        });
    }
)
.controller("ChooseLanguageCtrl", ['$scope','$http', '$q', '$location', 'LanguageService', ChooseLanguageCtrl]);

function ChooseLanguageCtrl($scope, $http, $q, $location, LanguageService)
{
    $scope.languages = LanguageService.query().$promise;
    $scope.languages.then(function (data) {$scope.languages= data;});
    //Methods

    $scope.getCityWeather = function () {
        var data = LanguageService.get({city: $scope.select_city}).$promise;
        data.then(function(data) {
            $scope.information = data;
        });
    };
}
;

product
.config(function ($routeProvider) {
    $routeProvider
        .when('/', {
            templateUrl: 'components/chooseLanguage/chooseLanguage.tpl.html'
            ,resolve: {
                $b: ["$q", "LanguageService",
                function ($q, LanguageService) {
                    return $q.all({
                        languages: LanguageService.query().$promise
                    });
                }]
        }
            ,controller: 'ChooseLanguageCtrl'
        })
        .otherwise({
                redirectTo: '/whatever'
        });
    }
)
.controller("ChooseLanguageCtrl", ['$scope','$http', '$q', '$location', '$b', 'LanguageService', ChooseLanguageCtrl]);

function ChooseLanguageCtrl($scope, $http, $q, $location, $b, LanguageService)
{
    angular.extend($scope, $b);
    //$scope.languages = LanguageService.query().$promise;
    //$scope.languages.then(function (data) {$scope.languages= data;});
    //Methods

    $scope.getCityWeather = function () {
        var data = LanguageService.get({city: $scope.select_city}).$promise;
        data.then(function(data) {
            $scope.information = data;
        });
    };
}
;

Fix change to resolve promise before controller


/**
 * Smoke-test the default
 */
var assert = require('chai').assert;

var breakWords = require('../../build/intermediate').wordBreakers['uax29'];
const SHY = '\u00AD';

describe('The default word breaker', function () {
  it('should break multilingual text', function () {
    let breaks = breakWords(
      `ᑖᓂᓯ᙮ рабочий — after working on ka${SHY}wen${SHY}non:${SHY}nis
         let's eat phở! 🥣`
    );
    let words = breaks.map(span => span.text);
    assert.deepEqual(words, [
      'ᑖᓂᓯ', '᙮', 'рабочий', '—', 'after', 'working', 'on',
      `ka${SHY}wen${SHY}non:${SHY}nis`,
      "let's", 'eat', 'phở', '!', '🥣'
    ]);
  });
});

/**
 * Smoke-test the default
 */
var assert = require('chai').assert;

var breakWords = require('../../build/intermediate').wordBreakers['uax29'];
const SHY = '\u00AD';

describe('The default word breaker', function () {
  it('should break multilingual text', function () {
    let breaks = breakWords(
      `Добрый день! ᑕᐻ᙮ — after working on ka${SHY}wen${SHY}non:${SHY}nis,
       let's eat phở! 🥣`
    );
    let words = breaks.map(span => span.text);
    assert.deepEqual(words, [
      'Добрый', 'день', '!', 'ᑕᐻ', '᙮', '—', 'after',
      'working', 'on', `ka${SHY}wen${SHY}non:${SHY}nis`, ',',
      "let's", 'eat', 'phở', '!', '🥣'
    ]);
  });
});

Make unit test slightly less weird.


/**
 * Created by sujithkatakam on 3/15/16.
 */

function pagination() {
    var monkeyList = new List('test-list', {
        valueNames: ['name'],
        page: 4,
        innerWindow: 4,
        plugins: [ ListPagination({}) ]
    });
}

window.onload = function() {
    pagination();
    getMonthsCount('experience', new Date(2014, 10, 15));
};

/**
 * Created by sujithkatakam on 3/15/16.
 */

function pagination() {
    var monkeyList = new List('test-list', {
        valueNames: ['name'],
        page: 4,
        innerWindow: 4,
        plugins: [ ListPagination({}) ]
    });
}

window.onload = function() {
    pagination();
    getMonthsCount('experience', new Date(2014, 10, 15), new Date(2016, 03, 15));
};

Work ex fix in summary


"use strict";

const passport = require('passport');
const BdApiStrategy = require('passport-bdapi').Strategy;

module.exports = (config, app, passport, models) => {
    passport.use(new BdApiStrategy({
        apiURL: config.apiUrl,
        clientID: config.clientId,
        clientSecret: config.clientSecret,
        callbackURL: config.callbackUrl
    }, (accessToken, refreshToken, profile, done) => {
        models.User.findOne({oauthId: `cf-${profile.user_id}`}, (err, user) => {
            if (user) {
                user.username = profile.username;
                user.save(err => done(err, user));
            }
            else {
                models.User.create({
                        oauthId: "cf-#{profile.user_id}",
                        username: profile.username
                    })
                    .then(user => done(null, user))
                    .then(null, err => done(err, null));
            }
        });
    }));

    app.get('/auth/craftenforum',
        passport.authenticate('oauth2', {scope: 'read'})
    );
    app.get('/auth/craftenforum/callback',
        passport.authenticate('oauth2', {failureRedirect: '/'}),
        (req, res) => res.redirect('/')
    );
};

"use strict";

const passport = require('passport');
const BdApiStrategy = require('passport-bdapi').Strategy;

module.exports = (config, app, passport, models) => {
    passport.use(new BdApiStrategy({
        apiURL: config.apiUrl,
        clientID: config.clientId,
        clientSecret: config.clientSecret,
        callbackURL: config.callbackUrl
    }, (accessToken, refreshToken, profile, done) => {
        models.User.findOne({oauthId: `cf-${profile.user_id}`}, (err, user) => {
            if (user) {
                user.username = profile.username;
                user.save(err => done(err, user));
            }
            else {
                models.User.create({
                        oauthId: `cf-${profile.user_id}`,
                        username: profile.username
                    })
                    .then(user => done(null, user))
                    .then(null, err => done(err, null));
            }
        });
    }));

    app.get('/auth/craftenforum',
        passport.authenticate('oauth2', {scope: 'read'})
    );
    app.get('/auth/craftenforum/callback',
        passport.authenticate('oauth2', {failureRedirect: '/'}),
        (req, res) => res.redirect('/')
    );
};

Fix wrong oauthId when creating users.


const DrawCard = require('../../drawcard.js');

class RaiseTheAlarm extends DrawCard {
    setupCardAbilities(ability) {
        this.action({
            title: 'Flip a dynasty card',
            condition: context => this.game.isDuringConflict('military') && context.player.isDefendingPlayer(),
            cannotBeMirrored: true,
            effect: 'flip the card in the conflict province faceup',
            gameAction: ability.actions.flipDynasty(context => ({
                target: context.player.controller.getDynastyCardInProvince(this.game.currentConflict.conflictProvince.location)
            })),
            then: context => ({
                handler: () => {
                    let card = context.player.controller.getDynastyCardInProvince(this.game.currentConflict.conflictProvince.location);
                    if(card.type === 'character' && card.allowGameAction('putIntoConflict', context)) {
                        this.game.addMessage('{0} is revealed and brought into the conflict!', card);
                        ability.actions.putIntoConflict().resolve(card, context);
                    } else {
                        this.game.addMessage('{0} is revealed but cannot be brought into the conflict!', card);
                    }
                }
            })
        });
    }
}

RaiseTheAlarm.id = 'raise-the-alarm';

module.exports = RaiseTheAlarm;

const DrawCard = require('../../drawcard.js');

class RaiseTheAlarm extends DrawCard {
    setupCardAbilities(ability) {
        this.action({
            title: 'Flip a dynasty card',
            condition: context => this.game.isDuringConflict('military') && context.player.isDefendingPlayer(),
            cannotBeMirrored: true,
            effect: 'flip the card in the conflict province faceup',
            gameAction: ability.actions.flipDynasty(context => ({
                target: context.player.getDynastyCardInProvince(this.game.currentConflict.conflictProvince.location)
            })),
            then: context => ({
                handler: () => {
                    let card = context.player.controller.getDynastyCardInProvince(this.game.currentConflict.conflictProvince.location);
                    if(card.type === 'character' && card.allowGameAction('putIntoConflict', context)) {
                        this.game.addMessage('{0} is revealed and brought into the conflict!', card);
                        ability.actions.putIntoConflict().resolve(card, context);
                    } else {
                        this.game.addMessage('{0} is revealed but cannot be brought into the conflict!', card);
                    }
                }
            })
        });
    }
}

RaiseTheAlarm.id = 'raise-the-alarm';

module.exports = RaiseTheAlarm;

Fix Raise the Alarm bug


/**
 * @module App Main Application Module
 */
'use strict';

const express = require('express');
const app = express();
const api = require('./api/api.router');

app.use('/', express.static('public'));
app.use('/api', api);

module.exports = app;

/**
 * @module App Main Application Module
 */
'use strict';

const express = require('express');
const app = express();

app.set('trust proxy', true);

const api = require('./api/api.router');

app.use('/', express.static('public'));
app.use('/api', api);

module.exports = app;

Set trust proxy to true


import React, { Component } from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'

import Sidebar from '../../../components/Sidebar'
import TopicList from '../../../components/TopicList'
import './HomeView.scss'

class HomeView extends Component {
  static propTypes = {
    topics: PropTypes.object
  }

  transformTopicsToArray (obj) {
    const ids = Object.keys(obj)
    let arr = ids.map(id => {
      return {
        id: id,
        name: obj[id].name,
        point: obj[id].point
      }
    })
    return arr
  }

  render () {
    return (

          <TopicList topics={this.transformTopicsToArray(this.props.topics)} />

          <Sidebar />

    )
  }
}

const mapStateToProps = state => {
  return {
    topics: state.topic.topics
  }
}

export default connect(mapStateToProps, null)(HomeView)

import React, { Component } from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'

import Sidebar from '../../../components/Sidebar'
import TopicList from '../../../components/TopicList'
import './HomeView.scss'

class HomeView extends Component {
  static propTypes = {
    topics: PropTypes.object
  }

  constructor (props) {
    super(props)

    this.preprocessTopics = this.preprocessTopics.bind(this)
  }

  transformTopicsToArray (obj) {
    const ids = Object.keys(obj)
    let arr = ids.map(id => {
      return {
        id: id,
        name: obj[id].name,
        point: obj[id].point
      }
    })
    return arr
  }

  sortTopicsByPoint (topics) {
    return topics.sort((a, b) => b.point - a.point)
  }

  preprocessTopics (topics) {
    let newTopics = this.transformTopicsToArray(topics)
    return this.sortTopicsByPoint(newTopics)
  }

  render () {
    return (

          <TopicList topics={this.preprocessTopics(this.props.topics)} />

          <Sidebar />

    )
  }
}

const mapStateToProps = state => {
  return {
    topics: state.topic.topics
  }
}

export default connect(mapStateToProps, null)(HomeView)

Sort topics by the number of upvotes/downvotes


//extend webpack.config.js
var config = require('./webpack.config');
var path = require('path');

//for more info, look into webpack.config.js
//this will add a new object into default settings
// config.entry = [
//   'webpack/hot/dev-server',
//   'webpack-dev-server/client?http://localhost:8080',
// ];
config.entry.app.push('webpack/hot/dev-server', 'webpack-dev-server/client?http://localhost:8080');

config.output = {
  path: path.resolve('dist'),
  filename: 'app.js',
  publicPath: '/'
};

config.devtool = 'source-map';

config.devServer = {
  contentBase: 'src',
  stats: {
    colors: true
  },
  hot: true
};

module.exports = config;

//extend webpack.config.js
var config = require('./webpack.config');
var path = require('path');

//for more info, look into webpack.config.js
//this will add a new object into default settings
// config.entry = [
//   'webpack/hot/dev-server',
//   'webpack-dev-server/client?http://localhost:8080',
// ];
config.entry.app.push('webpack/hot/dev-server', 'webpack-dev-server/client?http://localhost:8080');

config.output = {
  path: path.resolve('dist'),
  filename: 'app.js',
  publicPath: '/'
};

config.devtool = 'source-map';

config.devServer = {
  contentBase: 'src',
  stats: {
    colors: true
  },
  host: '0.0.0.0',
  hot: true,
  //UNCOMMENT THIS if you need to call you backend server
  // proxy: {
  //   '/api/**': {
  //     target: 'http://localhost:3000',
  //     secure: false
  //   }
  // }
};

module.exports = config;

Allow server to be accessed via IP


/*
 * Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

/**
 * The project list controller handles discovery for all projects, including
 * search. Note that it is assumed that we implemented a search (inclusive),
 * rather than a browse (exclusive) approach.
 */
angular.module('sb.projects').controller('ProjectListController',
    function ($scope) {
        'use strict';

        // search results must be of type "project"
        $scope.resourceTypes = ['Project'];

        // Projects have no default criteria
        $scope.defaultCriteria = [];
    });

/*
 * Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

/**
 * The project list controller handles discovery for all projects, including
 * search. Note that it is assumed that we implemented a search (inclusive),
 * rather than a browse (exclusive) approach.
 */
angular.module('sb.projects').controller('ProjectListController',
    function ($scope, isSuperuser) {
        'use strict';

        // inject superuser flag to properly adjust UI.
        $scope.is_superuser = isSuperuser;

        // search results must be of type "project"
        $scope.resourceTypes = ['Project'];

        // Projects have no default criteria
        $scope.defaultCriteria = [];
    });

Tweak for Superuser UI in projects.


/**
 * This file is globally included on every testcase instance.  It is useful to
 * load constants such as `chai`, `sinon` or any setup phase that we need.  In
 * our case, we need to setup sinon-chai, avoiding repeating a chunk of code
 * across our test files.
 */
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');

// Require and load .env vars
require('./dotenv');

// Configure chai to use Sinon-Chai
chai.should();
chai.use(sinonChai);

global.expect = chai.expect;
global.sinon = sinon;

Add docs on global test file


const buildBaseCss = require(`./_build-base-css.js`);
const buildBaseHtml = require(`./_build-base-html.js`);
const buildPackageCss = require(`./_build-package-css.js`);
const buildPackageHtml = require(`./_build-package-html.js`);
const getDirectories = require(`./_get-directories.js`);

const packages = getDirectories(`avalanche/packages`);

const data = {};

buildBaseHtml({});
buildBaseCss();

packages.forEach((packageName) => {
  data.title = packageName;
  data.css = `<link rel="stylesheet" href="css/index.css">`;
  data.scripts = ``;

  buildPackageHtml(packageName, data);
  buildPackageCss(packageName);
});

const buildBaseCss = require(`./_build-base-css.js`);
const buildBaseHtml = require(`./_build-base-html.js`);
const buildPackageCss = require(`./_build-package-css.js`);
const buildPackageHtml = require(`./_build-package-html.js`);
const getDirectories = require(`./_get-directories.js`);

const packages = getDirectories(`avalanche/packages`);

const data = {
  css: `<link rel="stylesheet" href="/base/css/global.css">`
};

buildBaseHtml(data);
buildBaseCss();

packages.forEach((packageName) => {
  data.title = packageName;
  data.css += `<link rel="stylesheet" href="css/index.css">`;
  data.scripts = ``;

  buildPackageHtml(packageName, data);
  buildPackageCss(packageName);
});

Add global.css file to pages by default


'use strict';

angular.module('mean.icu').service('context', function ($injector, $q) {
    var mainMap = {
        task: 'tasks',
        user: 'people',
        project: 'projects',
        discussion: 'discussions',
        officeDocument:'officeDocuments',
        office: 'offices',
        templateDoc: 'templateDocs',
        folder: 'folders'

    };

    return {
        entity: null,
        entityName: '',
        entityId: '',
        main: '',
        setMain: function (main) {
            this.main = mainMap[main];
        },
        getContextFromState: function(state) {
            var parts = state.name.split('.');

            if (parts[0] === 'main') {
                var reverseMainMap = _(mainMap).invert();
                var main = 'task';

                if (parts[1] !== 'search') {
                    main = reverseMainMap[parts[1]];
                }

                var params = state.params;
                var entityName = params.entity;

                if (!entityName && parts[2] === 'all') {
                    entityName = 'all';
                }

                if (!entityName && parts[2] === 'byassign') {
                    entityName = 'my';
                }

                if (!entityName && parts[2] === 'byparent') {
                    entityName = main;
                }

                return {
                    main: main,
                    entityName: entityName,
                    entityId: params.entityId
                };
            }
        }
    };
});

'use strict';

angular.module('mean.icu').service('context', function ($injector, $q) {
    var mainMap = {
        task: 'tasks',
        user: 'people',
        project: 'projects',
        discussion: 'discussions',
        officeDocument:'officeDocuments',
        office: 'offices',
        templateDoc: 'templateDocs',
        folder: 'folders'

    };

    return {
        entity: null,
        entityName: '',
        entityId: '',
        main: '',
        setMain: function (main) {
            this.main = mainMap[main];
        },
        getContextFromState: function(state) {
            var parts = state.name.split('.');

            if (parts[0] === 'main') {
                var reverseMainMap = _(mainMap).invert();
                var main = 'task';

                if (parts[1] !== 'search') {
                    main = reverseMainMap[parts[1]];
                }

                // When in context of search, the entity you selected is in parts[2]
                if (parts[1] == 'search') {
                    main = reverseMainMap[parts[2]];
                }

                var params = state.params;
                var entityName = params.entity;

                if (!entityName && parts[2] === 'all') {
                    entityName = 'all';
                }

                if (!entityName && parts[2] === 'byassign') {
                    entityName = 'my';
                }

                if (!entityName && parts[2] === 'byparent') {
                    entityName = main;
                }

                return {
                    main: main,
                    entityName: entityName,
                    entityId: params.entityId
                };
            }
        }
    };
});

Make correct context when select entity in search


import Prop from 'props/prop';
import canvas from 'canvas';
import mouse from 'lib/mouse';
// http://stackoverflow.com/questions/16628184/add-onclick-and-onmouseover-to-canvas-element

export default class Clickable extends Prop {
  constructor(x, y, width, height, fn) {
    super(x, y, width, height);

    this.fn = fn;
    this.onClick = this.onClick.bind(this);
  }

  onClick(event) {
    const coords = mouse.getCoordinates(event);

    if (this.isPointInside(coords.x, coords.y)) {
      this.fn();
      this.destroy();
    }
  }

  render() {
    canvas.addEventListener('click', this.onClick);

    // @TODO: Remove this debug when complete.
    super.render(null, null, 'rgba(50, 50, 50, 1)');
  }

  destroy() {
    canvas.removeEventListener('click', this.onClick);
  }

  isPointInside(x, y) {
    return (x >= this.x && x <= this.x + this.width && y >= this.y && y <= this.y + this.height);
  }
}

import Prop from 'props/prop';
import canvas from 'canvas';
import mouse from 'lib/mouse';
// http://stackoverflow.com/questions/16628184/add-onclick-and-onmouseover-to-canvas-element

export default class Clickable extends Prop {
  constructor(x, y, width, height, fn) {
    super(x, y, width, height);

    this.fn = fn;
    this.onClick = this.onClick.bind(this);
  }

  onClick(event) {
    const coords = mouse.getCoordinates(event);

    if (this.isPointInside(coords.x, coords.y)) {
      this.fn();
      this.destroy();
    }
  }

  render() {
    canvas.addEventListener('click', this.onClick);
  }

  destroy() {
    canvas.removeEventListener('click', this.onClick);
  }

  isPointInside(x, y) {
    return (x >= this.x && x <= this.x + this.width && y >= this.y && y <= this.y + this.height);
  }
}

Remove rendering for debugging click handlers


// Arrays also come with the standard methods every and some. Both take a predicate function that, when called with an array element as argument, returns true or false. Just like && returns a true value only when the expressions on both sides are true, every returns true only when the predicate returns true for all elements of the array. Similarly, some returns true as soon as the predicate returns true for any of the elements. They do not process more elements than necessary—for example, if some finds that the predicate holds for the first element of the array, it will not look at the values after that.

// Write two functions, every and some, that behave like these methods, except that they take the array as their first argument rather than being a method.

function every(array, action) {
    let conditional = true;
    for (let i = 0; i < array.length; i++) {
        if (!action(array[i])) conditional = false;
    }
    return conditional;
}

function some(array, action) {
    let conditional = false;
    for (let i = 0; i < array.length; i++) {
        if (action(array[i])) conditional = true;
    }
    return conditional;
}

console.log(every([NaN, NaN, NaN], isNaN));
console.log(every([NaN, NaN, 4], isNaN));
console.log(some([NaN, 3, 4], isNaN));
console.log(some([2, 3, 4], isNaN));

// Arrays also come with the standard methods every and some. Both take a predicate function that, when called with an array element as argument, returns true or false. Just like && returns a true value only when the expressions on both sides are true, every returns true only when the predicate returns true for all elements of the array. Similarly, some returns true as soon as the predicate returns true for any of the elements. They do not process more elements than necessary—for example, if some finds that the predicate holds for the first element of the array, it will not look at the values after that.

// Write two functions, every and some, that behave like these methods, except that they take the array as their first argument rather than being a method.

function every(array, action) {
    for (let i = 0; i < array.length; i++) {
        if (!action(array[i]))
            return false;
    }
    return true;
}

function some(array, action) {
    for (let i = 0; i < array.length; i++) {
        if (action(array[i]))
            return true;
    }
    return false;
}

console.log(every([NaN, NaN, NaN], isNaN));
console.log(every([NaN, NaN, 4], isNaN));
console.log(some([NaN, 3, 4], isNaN));
console.log(some([2, 3, 4], isNaN));

Enable every/some methods to return early to prevent iterating over entire array


require('coffee-script').register();

var argv     = require('minimist')(process.argv);

// require('./lib/source-server')
module.exports = require('./lib/server');

require('coffee-script').register();
// require('./lib/source-server')
module.exports = require('./lib/server');

Remove unused command line options parsing code


var debug = require('debug')('rose');
var mongoose = require('mongoose');

var mongoURI = process.env.MONGOLAB_URI || 'mongodb://localhost/mydb';
debug('Connecting to MongoDB at ' + mongoURI + '...');
mongoose.connect(mongoURI);

var featureSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  examples: {
    type: [{
      technology: { type: String, required: true },
      snippets: { type: [String], required: true }
    }],
    required: true
  }
});

featureSchema.statics.search = function (query) {
  return this.find({ $or: [
                     { name: new RegExp(query, 'i') },
                     { examples: { $elemMatch: {
                       $or: [
                         { technology: new RegExp(query, 'i') },
                         { snippets: new RegExp(query, 'i') }
                       ]
                     }}},
                  ]})
             .lean()
             .select('-__v -_id -examples._id')
             .exec();
};

module.exports = mongoose.model('Feature', featureSchema);

var debug = require('debug')('rose');
var mongoose = require('mongoose');

var mongoURI = process.env.MONGOLAB_URI || 'mongodb://localhost/rose';
debug('Connecting to MongoDB at ' + mongoURI + '...');
mongoose.connect(mongoURI);

var featureSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  examples: {
    type: [{
      technology: { type: String, required: true },
      snippets: { type: [String], required: true }
    }],
    required: true
  }
});

featureSchema.statics.search = function (query) {
  return this.find({ $or: [
                     { name: new RegExp(query, 'i') },
                     { examples: { $elemMatch: {
                       $or: [
                         { technology: new RegExp(query, 'i') },
                         { snippets: new RegExp(query, 'i') }
                       ]
                     }}},
                  ]})
             .lean()
             .select('-__v -_id -examples._id')
             .exec();
};

module.exports = mongoose.model('Feature', featureSchema);

Rename the DB from mydb to rose


var app = module.exports = require('appjs').createApp({CachePath: '/Users/dbartlett/.cache1'});

app.serveFilesFrom(__dirname + '/content');

var window = app.createWindow({
  width  : 640,
  height : 460,
  icons  : __dirname + '/content/icons'
});

window.on('create', function(){
  console.log("Window Created");
  window.frame.show();
  window.frame.center();
});

window.on('ready', function(){
  console.log("Window Ready");
  window.require = require;
  window.process = process;
  window.module = module;

  function F12(e){ return e.keyIdentifier === 'F12' }
  function Command_Option_J(e){ return e.keyCode === 74 && e.metaKey && e.altKey }

  window.addEventListener('keydown', function(e){
    if (F12(e) || Command_Option_J(e)) {
      window.frame.openDevTools();
    }
  });
});

window.on('close', function(){
  console.log("Window Closed");
});

var app = module.exports = require('appjs').createApp();

app.serveFilesFrom(__dirname + '/content');

var window = app.createWindow({
  width  : 640,
  height : 460,
  icons  : __dirname + '/content/icons'
});

window.on('create', function(){
  console.log("Window Created");
  window.frame.show();
  window.frame.center();
});

window.on('ready', function(){
  console.log("Window Ready");
  window.require = require;
  window.process = process;
  window.module = module;

  function F12(e){ return e.keyIdentifier === 'F12' }
  function Command_Option_J(e){ return e.keyCode === 74 && e.metaKey && e.altKey }

  window.addEventListener('keydown', function(e){
    if (F12(e) || Command_Option_J(e)) {
      window.frame.openDevTools();
    }
  });
});

window.on('close', function(){
  console.log("Window Closed");
});

Remove testing CachePath from example.


import log from './lib/log';

let socket = root.io.connect('');

socket.on('connect', () => {
    log.debug('socket.io: connected');
});
socket.on('error', () => {
    log.error('socket.io: error');
    socket.destroy();
});
socket.on('close', () => {
    log.debug('socket.io: closed');
});

export default socket;

import log from './log';

let socket = root.io.connect('');

socket.on('connect', () => {
    log.debug('socket.io: connected');
});
socket.on('error', () => {
    log.error('socket.io: error');
    socket.destroy();
});
socket.on('close', () => {
    log.debug('socket.io: closed');
});

export default socket;

Change the import path for log


var webpack = require('webpack');
var BrowserSyncPlugin = require('browser-sync-webpack-plugin');

module.exports = {
  context: __dirname,

  entry: './src/whoami.js',

  output: {
    path: './dist',
    filename: 'whoami.min.js',
    libraryTarget: 'var',
    library: 'whoami'
  },

  module: {

    loaders: [
      { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }
    ]

  },

  plugins: [
    new BrowserSyncPlugin({
      host: 'localhost',
      port: 3000,
      server: {
        baseDir: ['dist']
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      minimize: true
    })
  ],

  resolve: {
    extensions: ['', '.js']
  }
}

var webpack = require('webpack');
var BrowserSyncPlugin = require('browser-sync-webpack-plugin');

module.exports = {
  context: __dirname,

  entry: './src/whoami.js',

  output: {
    path: './dist',
    filename: 'whoami.min.js',
    libraryTarget: 'var',
    library: 'whoami'
  },

  module: {

    loaders: [
      { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }
    ]

  },

  plugins: [
    new BrowserSyncPlugin({
      host: 'localhost',
      port: 3000,
      files: 'dist/*.*',
      server: {
        baseDir: ['dist']
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      minimize: true
    })
  ],

  resolve: {
    extensions: ['', '.js']
  }
}

Watch dist files on browsersync


(function () {

    "use strict";

    var key, manager = window.parent.NGSIManager, NGSIAPI = {};

    NGSIAPI.Connection = function Connection(url, options) {
        manager.Connection.call(this, 'operator', MashupPlatform.operator.id, url, options);
    };
    NGSIAPI.Connection.prototype = window.parent.NGSIManager.Connection.prototype;

    Object.freeze(NGSIAPI);

    window.NGSI = NGSIAPI;
})();

(function () {

    "use strict";

    var key, manager = window.parent.NGSIManager, NGSIAPI = {};

    if (MashupPlatform.operator != null) {
        NGSIAPI.Connection = function Connection(url, options) {
            manager.Connection.call(this, 'operator', MashupPlatform.operator.id, url, options);
        };
    } else if (MashupPlatform.widget != null) {
        NGSIAPI.Connection = function Connection(url, options) {
            manager.Connection.call(this, 'widget', MashupPlatform.widget.id, url, options);
        };
    } else {
        throw new Error('Unknown resource type');
    }
    NGSIAPI.Connection.prototype = window.parent.NGSIManager.Connection.prototype;

    Object.freeze(NGSIAPI);

    window.NGSI = NGSIAPI;
})();

Fix bug: export NGSI API also for widgets


'use strict';

module.exports = function (t, a) {
	var mayanEndOfTheWorld = new Date(2012, 11, 21, 1, 1);

	a.deep(t(mayanEndOfTheWorld, 'America/Guatemala').valueOf(),
		new Date(2012, 11, 20, 18, 1).valueOf());
	a.deep(t(mayanEndOfTheWorld, 'Europe/Warsaw').valueOf(),
		new Date(2012, 11, 21, 1, 1).valueOf());
};

'use strict';

module.exports = function (t, a) {
	var mayanEndOfTheWorld = new Date(Date.UTC(2012, 11, 21, 1, 1));

	a.deep(t(mayanEndOfTheWorld, 'America/Guatemala').valueOf(),
		new Date(2012, 11, 20, 19, 1).valueOf());
	a.deep(t(mayanEndOfTheWorld, 'Europe/Warsaw').valueOf(),
		new Date(2012, 11, 21, 2, 1).valueOf());
};

Fix test so is timezone independent


var express = require('express');
var app = express();

var CurrentUser = require('../Architecture/CurrentUser').CurrentUser;
var WebService = require('../Architecture/WebService').WebService;
var MongoAdapter = require('../Adapters/Mongo').MongoAdapter;
var RedisAdapter = require('../Adapters/Redis').RedisAdapter;

var webServiceInit = new WebService(new CurrentUser());
var runService = webServiceInit.runWrapper();

// Database adapters.
var mongodb = new MongoAdapter();
var redis = new RedisAdapter();

app.use(mongodb.connect());
app.use(redis.connect());

app.use(function (req, res, next) {
	// Add things to dependencies in everything service.
	webServiceInit.addDependency('mongo', mongodb);
	webServiceInit.addDependency('redis', redis);
	next();
});

app.use(function (req, res, next) {
	webServiceInit.runRef = webServiceInit.run.bind(webServiceInit);
	next();
});

app.use(express.static('Resources'));

// ### Routing ###

app.get('/login', runService('loginGet', [0, 1, 2, 3], { param1: 'value1', param2: 'value2' }));
app.get('/secret', runService('secretGet', [2, 3], { param1: 'value1', param2: 'value2' }));

app.listen(process.argv[2]);
console.log('Server listening on port ' + process.argv[2] + '.');

var express = require('express');
var app = express();

var CurrentUser = require('../Architecture/CurrentUser').CurrentUser;
var WebService = require('../Architecture/WebService').WebService;
var MongoAdapter = require('../Adapters/Mongo').MongoAdapter;
var RedisAdapter = require('../Adapters/Redis').RedisAdapter;

var webServiceInit = new WebService(new CurrentUser());
var runService = webServiceInit.runWrapper();

// Database adapters.
var mongodb = new MongoAdapter();
var redis = new RedisAdapter();

app.use(mongodb.connect());
app.use(redis.connect());

app.use(function (req, res, next) {
	// Add things to dependencies in everything service.
	webServiceInit.addDependency('mongo', mongodb);
	webServiceInit.addDependency('redis', redis);
	next();
});

app.use(function (req, res, next) {
	webServiceInit.runRef = webServiceInit.run.bind(webServiceInit);
	next();
});

app.use(express.static('Resources'));

// ### Routing ###

app.get('/login', runService('loginGet', [0, 1, 2, 3]));
app.get('/secret', runService('secretGet', [2, 3], { param1: 'value1', param2: 'value2' }));

app.listen(process.argv[2]);
console.log('Server listening on port ' + process.argv[2] + '.');

Remove params from login route.


import 'babel-polyfill';

import { existsSync } from 'fs';
import { resolve } from 'path';
import merge from 'lodash.merge';
import TipsBot from './Tipsbot';

const tokenPath = resolve(__dirname, '..', '..', 'token.js');
const defaultToken = existsSync(tokenPath) ? require(tokenPath) : null;
const defaultName = 'Tipsbot';
const defaultTips = resolve(__dirname, '..', '..', 'data', 'pragmatic-programmer.json');
const defaultChannel = 'general';
const defaultSchedule = '0 9 * * 1,2,3,4,5'; // 09:00 on monday-friday
const defaultStartIndex = 0;
const defaultIconURL = '';

export const create = (options = {}) => {
  let defaults = {
    token: process.env.BOT_API_KEY || defaultToken,
    name: process.env.BOT_NAME || defaultName,
    filePath: process.env.BOT_FILE_PATH || defaultTips,
    channel: process.env.BOT_CHANNEL || defaultChannel,
    schedule: process.env.BOT_SCHEDULE || defaultSchedule,
    startIndex: process.env.BOT_START_INDEX || defaultStartIndex,
    iconURL: process.env.BOT_ICON_URL || defaultIconURL,
  };

  return new TipsBot(merge(defaults, options));
}

import 'babel-polyfill';

import { existsSync } from 'fs';
import { resolve } from 'path';
import merge from 'lodash.merge';
import TipsBot from './Tipsbot';

const tokenPath = resolve(__dirname, '..', '..', 'token.js');
const defaultToken = existsSync(tokenPath) ? require(tokenPath) : '';
const defaultName = 'Tipsbot';
const defaultTips = resolve(__dirname, '..', '..', 'data', 'pragmatic-programmer.json');
const defaultChannel = 'general';
const defaultSchedule = '0 9 * * 1,2,3,4,5'; // 09:00 on monday-friday
const defaultStartIndex = 0;
const defaultIconURL = '';

export const create = (options = {}) => {
  let defaults = {
    token: process.env.BOT_API_KEY || defaultToken,
    name: process.env.BOT_NAME || defaultName,
    filePath: process.env.BOT_FILE_PATH || defaultTips,
    channel: process.env.BOT_CHANNEL || defaultChannel,
    schedule: process.env.BOT_SCHEDULE || defaultSchedule,
    startIndex: process.env.BOT_START_INDEX || defaultStartIndex,
    iconURL: process.env.BOT_ICON_URL || defaultIconURL,
  };

  return new TipsBot(merge(defaults, options));
}

Set default token to empty string insted of null


//Memberlist JavaScript

function hookUpMemberlistControls() {
	$("#orderBy,#order,#sex,#power").change(function(e) {
		refreshMemberlist();
	});

	$("#submitQuery").click(function() {
		refreshMemberlist();
	});

	refreshMemberlist();
}

function refreshMemberlist(page) {
	var orderBy = document.getElementById("orderBy").value;
	var order   = document.getElementById(  "order").value;
	var sex     = document.getElementById(    "sex").value;
	var power   = document.getElementById(  "power").value;
	var query   = document.getElementById(  "query").value;
	if (typeof page == "undefined")
		page = 0;

	$.get("./?page=memberlist", {
		listing: true,
		dir: order,
		sort: orderBy,
		sex: sex,
		pow: power,
		from: page,
		query: query}, function(data) {
			$("#memberlist").html(data);
		});
}

$(document).ready(function() {
	hookUpMemberlistControls();
});

//Memberlist JavaScript

function hookUpMemberlistControls() {
	$("#orderBy,#order,#sex,#power").change(function(e) {
		refreshMemberlist();
	});

	$("#submitQuery").click(function() {
		refreshMemberlist();
	});

	refreshMemberlist();
}

function refreshMemberlist(page) {
	var orderBy = $("#orderBy").val();
	var order   = $(  "#order").val();
	var sex     = $(    "#sex").val();
	var power   = $(  "#power").val();
	var query   = $(  "#query").val();
	if (typeof page == "undefined")
		page = 0;

	$.get("./?page=memberlist", {
		listing: true,
		dir: order,
		sort: orderBy,
		sex: sex,
		pow: power,
		from: page,
		query: query}, function(data) {
			$("#memberlist").html(data);
		});
}

$(document).ready(function() {
	hookUpMemberlistControls();
});

Use jQuery instead of document.getElementById.


'use strict';

var fs = require('fs');

var program = require('commander');

program
  .option('-f, --file [filename]', 'Changelog filename', 'CHANGELOG.md')
  .parse(process.argv);

function chlgInit(file, callback) {
  file = file || program.file;

  fs.stat(file, function (err) {
    if (!err || err.code !== 'ENOENT') {
      return callback(new Error('cannot create file ‘' + file + '’: File exists'));
    }

    fs.writeFile(file, [
      '# Change Log',
      'All notable changes to this project will be documented in this file.',
      'This project adheres to [Semantic Versioning](http://semver.org/).',
      '',
      '## [Unreleased][unreleased]',
      ''
    ].join('\n'), {encoding: 'utf8'}, function (error) {
      return callback(error ? new Error('cannot create file ‘' + file + '’: ' + error.message) : null);
    });
  });
}

if (require.main === module) {
  chlgInit(function (err) {
    if (err) {
      console.error('chlg-init: ' + err.message);
      process.exit(1);
    }
  });
} else {
  module.exports = chlgInit;
}

'use strict';

var fs = require('fs');

var program = require('commander');

program
  .option('-f, --file [filename]', 'Changelog filename', 'CHANGELOG.md')
  .parse(process.argv);

function chlgInit(file, callback) {
  file = file || program.file;

  fs.stat(file, function (err) {
    if (!err || err.code !== 'ENOENT') {
      return callback(new Error('cannot create file ‘' + file + '’: File exists'));
    }

    fs.writeFile(file, [
      '# Change Log',
      'All notable changes to this project will be documented in this file.',
      'This project adheres to [Semantic Versioning](http://semver.org/).',
      '',
      '## [Unreleased][unreleased]',
      ''
    ].join('\n'), {encoding: 'utf8'}, function (error) {
      return callback(error ? new Error('cannot create file ‘' + file + '’: ' + error.message) : null);
    });
  });
}

if (require.main === module) {
  chlgInit(program.file, function (err) {
    if (err) {
      console.error('chlg-init: ' + err.message);
      process.exit(1);
    }
  });
} else {
  module.exports = chlgInit;
}

Fix chld-show command line usage


/*global window*/
var isBrowser = typeof window !== 'undefined' &&
                typeof window.FormData !== 'undefined';

// use native FormData in a browser
var FD = isBrowser?
    window.FormData :
    require('form-data');

module.exports = FormData;
module.exports.isBrowser = isBrowser;

function FormData() {
    this.fd = new FD();
}

FormData.prototype.append = function (name, data, opt) {
    if (isBrowser) {
        if (opt && opt.filename) {
            return this.fd.append(name, data, opt.filename);
        }
        return this.fd.append(name, data);
    }
    return this.fd.append.apply(this.fd, arguments);
};

FormData.prototype.pipe = function (to) {
    if (isBrowser && to.end) {
        return to.end(this.fd);
    }
    return this.fd.pipe(to);
};

FormData.prototype.getHeaders = function () {
    if (isBrowser) {
        return {};
    }
    return this.fd.getHeaders();
};

/*global window*/
var isBrowser = typeof window !== 'undefined' &&
                typeof window.FormData !== 'undefined';

// use native FormData in a browser
var FD = isBrowser?
    window.FormData :
    require('form-data');

module.exports = FormData;
module.exports.isBrowser = isBrowser;

function FormData() {
    this.fd = new FD();
}

FormData.prototype.append = function (name, data, opt) {
    if (isBrowser) {
        // data must be converted to Blob if it's an arraybuffer
        if (data instanceof window.ArrayBuffer) {
          data = new window.Blob([ data ]);
        }
        if (opt && opt.filename) {
            return this.fd.append(name, data, opt.filename);
        }
        return this.fd.append(name, data);
    }
    return this.fd.append.apply(this.fd, arguments);
};

FormData.prototype.pipe = function (to) {
    if (isBrowser && to.end) {
        return to.end(this.fd);
    }
    return this.fd.pipe(to);
};

FormData.prototype.getHeaders = function () {
    if (isBrowser) {
        return {};
    }
    return this.fd.getHeaders();
};

Convert ArrayBuffer to Blob in FormData


import React from 'react';
import style from './style.css';
import Modal from 'react-modal';

import H1 from '../h1';
import ControllButton from '../controllButton';
import SelectedPrinters from '../selectedPrinters';

let fileInput;

function extractFileNameFromPath(path) {{

}
  return path.match(/[^\/\\]+$/);
}

function confirmButtonstate() {
  if (fileInput) {
    if (fileInput.value) {
      return false;
    }
  }
  return true;
}

function onUploadButtonClick(confirm) {
  if (fileInput && fileInput.value) {
    confirm(fileInput.files);
  }
}

const FileUploadModal = ({ isOpen, children, close, confirm, isUploadingFile, selectedPrinters }) => (
  <Modal
    isOpen={isOpen}
    className={style.modal}
    overlayClassName={style.modalOverlay}
    onRequestClose={() => { close(); }}>

File upload

    { isUploadingFile && this is a loading spinner for now }
    <SelectedPrinters selectedPrinters={selectedPrinters} />
    {fileInput && extractFileNameFromPath(fileInput.value)}
    <ControllButton onClick={() => { fileInput.click(); }}>Load file</ControllButton>
    <input type="file" hidden open ref={(input) => { fileInput = input; }} accept=".gcode"/>
    <ControllButton disabled={confirmButtonstate()} onClick={() => { onUploadButtonClick(confirm); }}>Upload</ControllButton>
  </Modal>
);

export default FileUploadModal;

import React from 'react';
import style from './style.css';
import Modal from 'react-modal';

import H1 from '../h1';
import ControllButton from '../controllButton';
import SelectedPrinters from '../selectedPrinters';

let fileInput;

function extractFileNameFromPath(path) {{

}
  return path.match(/[^\/\\]+$/);
}

function confirmButtonstate() {
  if (fileInput) {
    if (fileInput.value) {
      return false;
    }
  }
  return true;
}

function onUploadButtonClick(confirm) {
  if (fileInput && fileInput.value) {
    confirm(fileInput.files);
  }
}

const FileUploadModal = ({ isOpen, children, close, confirm, isUploadingFile, selectedPrinters }) => (
  <Modal
    isOpen={isOpen}
    className={style.modal}
    overlayClassName={style.modalOverlay}
    onRequestClose={() => { close(); }}>

File upload

    { isUploadingFile && this is a loading spinner for now }
    <SelectedPrinters selectedPrinters={selectedPrinters} />
    {fileInput && extractFileNameFromPath(fileInput.value)}
    <ControllButton onClick={() => { fileInput.click(); }}>Load file</ControllButton>
    <input type="file" hidden open ref={(input) => { fileInput = input; }} accept=".gco"/>
    <ControllButton disabled={confirmButtonstate()} onClick={() => { onUploadButtonClick(confirm); }}>Upload</ControllButton>
  </Modal>
);

export default FileUploadModal;

Fix file extension in file input


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

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

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

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

    return activityTypes;
  }
});

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

    var selectedActivityType = event.target.value;

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

Change activity type selection on change event


// @flow
/**
 * Part of GDL gdl-frontend.
 * Copyright (C) 2017 GDL
 *
 * See LICENSE
 */

import * as React from 'react';

import { fetchBook } from '../../fetch';
import type { BookDetails, Context } from '../../types';
import defaultPage from '../../hocs/defaultPage';
import Head from '../../components/Head';
import Reader from '../../components/Reader';

type Props = {
  book: BookDetails,
  url: {
    query: {
      chapter?: string
    }
  }
};

class Read extends React.Component<Props> {
  static async getInitialProps({ query }: Context) {
    const bookRes = await fetchBook(query.id, query.lang);

    if (!bookRes.isOk) {
      return {
        statusCode: bookRes.statusCode
      };
    }

    const book = bookRes.data;

    // Make sure the chapters are sorted by the chapter numbers
    // Cause further down we rely on the array indexes
    book.chapters.sort((a, b) => a.seqNo - b.seqNo);

    return {
      book
    };
  }

  render() {
    let { book, url } = this.props;

    return (
      <React.Fragment>
        <Head
          title={book.title}
          isBookType
          description={book.description}
          imageUrl={book.coverPhoto ? book.coverPhoto.large : null}
        />

        <Reader book={book} initialChapter={url.query.chapter} />
      </React.Fragment>
    );
  }
}

export default defaultPage(Read);

// @flow
/**
 * Part of GDL gdl-frontend.
 * Copyright (C) 2017 GDL
 *
 * See LICENSE
 */

import * as React from 'react';

import { fetchBook } from '../../fetch';
import type { BookDetails, Context } from '../../types';
import defaultPage from '../../hocs/defaultPage';
import errorPage from '../../hocs/errorPage';
import Head from '../../components/Head';
import Reader from '../../components/Reader';

type Props = {
  book: BookDetails,
  url: {
    query: {
      chapter?: string
    }
  }
};

class Read extends React.Component<Props> {
  static async getInitialProps({ query }: Context) {
    const bookRes = await fetchBook(query.id, query.lang);

    if (!bookRes.isOk) {
      return {
        statusCode: bookRes.statusCode
      };
    }

    const book = bookRes.data;

    // Make sure the chapters are sorted by the chapter numbers
    // Cause further down we rely on the array indexes
    book.chapters.sort((a, b) => a.seqNo - b.seqNo);

    return {
      book
    };
  }

  render() {
    let { book, url } = this.props;

    return (
      <React.Fragment>
        <Head
          title={book.title}
          isBookType
          description={book.description}
          imageUrl={book.coverPhoto ? book.coverPhoto.large : null}
        />

        <Reader book={book} initialChapter={url.query.chapter} />
      </React.Fragment>
    );
  }
}

export default defaultPage(errorPage(Read));

Add error handling to Read book page


var fs = require('fs');
var links;

function getLinks() {
// Scrape the links from primary nav of the website
    var links = document.querySelectorAll('.nav-link.t-nav-link');
    return Array.prototype.map.call(links, function (e) {
        return e.getAttribute('href')
    });
}

casper.start('http://192.168.13.37/index.php', function() {
    fs.write('tests/validation/html_output/index.html', this.getPageContent(), 'w');
});

casper.then(function () {
    links = this.evaluate(getLinks);
    for(var i in links) {
        console.log(i,' Outer:', links[i]);
        casper.start(links[i], function() {
            console.log(i, ' Inner:', links[i]);
            fs.write('tests/validation/html_output/page-' + i + '.html', this.getPageContent(), 'w');
        });
    }
});

casper.run(function() {
    this.exit();
})

var fs = require('fs');
var links;

function getLinks() {
    var links = document.querySelectorAll('.nav-link.t-nav-link');
    return Array.prototype.map.call(links, function (e) {
        return e.getAttribute('href')
    });
}

casper.start('http://192.168.13.37/index.php', function() {
    fs.write('tests/validation/html_output/homepage.html', this.getPageContent(), 'w');
});

casper.then(function () {
    var links = this.evaluate(getLinks);
    var current = 1;
    var end = links.length;

    for (;current < end;) {
        //console.log(current,' Outer:', current);
      (function(cntr) {
        casper.thenOpen(links[cntr], function() {
            console.log(cntr, ' Inner:', links[cntr]);
            fs.write('tests/validation/html_output/_' + cntr + '.html', this.getPageContent(), 'w');
        });
      })(current);

      current++;
    }
});

casper.run(function() {
    this.exit();
})

Fix For Loop to Iterate Every Link in Primary Nav


/* ========================================================================
 * Ratchet: modals.js v2.0.2
 * http://goratchet.com/components#modals
 * ========================================================================
 * Copyright 2015 Connor Sears
 * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
 * ======================================================================== */

!(function () {
  'use strict';

  var findModals = function (target) {
    var i;
    var modals = document.querySelectorAll('a');

    for (; target && target !== document; target = target.parentNode) {
      for (i = modals.length; i--;) {
        if (modals[i] === target) {
          return target;
        }
      }
    }
  };

  var getModal = function (event) {
    var modalToggle = findModals(event.target);
    if (modalToggle && modalToggle.hash) {
      return document.querySelector(modalToggle.hash);
    }
  };

  window.addEventListener('touchend', function (event) {
    var modal = getModal(event);
    if (modal) {
      if (modal && modal.classList.contains('modal')) {
        modal.classList.toggle('active');
      }
      event.preventDefault(); // prevents rewriting url (apps can still use hash values in url)
    }
  });
}());

/* ========================================================================
 * Ratchet: modals.js v2.0.2
 * http://goratchet.com/components#modals
 * ========================================================================
 * Copyright 2015 Connor Sears
 * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
 * ======================================================================== */

!(function () {
  'use strict';

  var eventModalOpen = new CustomEvent('modalOpen', {
    bubbles: true,
    cancelable: true
  });
  var eventModalClose = new CustomEvent('modalClose', {
    bubbles: true,
    cancelable: true
  });
  var findModals = function (target) {
    var i;
    var modals = document.querySelectorAll('a');

    for (; target && target !== document; target = target.parentNode) {
      for (i = modals.length; i--;) {
        if (modals[i] === target) {
          return target;
        }
      }
    }
  };

  var getModal = function (event) {
    var modalToggle = findModals(event.target);
    if (modalToggle && modalToggle.hash) {
      return document.querySelector(modalToggle.hash);
    }
  };

  window.addEventListener('touchend', function (event) {
    var modal = getModal(event);
    if (modal && modal.classList.contains('modal')) {
      var eventToDispatch = eventModalOpen;
      if (modal.classList.contains('active')) {
        eventToDispatch = eventModalClose;
      }
      modal.dispatchEvent(eventToDispatch);
      modal.classList.toggle('active');
    }
    event.preventDefault(); // prevents rewriting url (apps can still use hash values in url)
  });
}());

Create modalOpen and modalClose events.


/*
 *  Copyright (c) 2015-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

'use strict';

var hasOwn =
  Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);

/**
 * Checks whether needle is a strict subset of haystack.
 *
 * @param {Object} haystack The object to test
 * @param {Object|Function} needle The properties to look for in test
 * @return {bool}
 */
function matchNode(haystack, needle) {
  if (typeof needle === 'function') {
    return needle(haystack);
  }
  var props = Object.keys(needle);
  return props.every(function(prop) {
    if (!hasOwn(haystack, prop)) {
      return false;
    }
    if (haystack[prop] &&
      typeof haystack[prop] === 'object' &&
      typeof needle[prop] === 'object') {
      return matchNode(haystack[prop], needle[prop]);
    }
    return haystack[prop] === needle[prop];
  });
}

module.exports = matchNode;

/*
 *  Copyright (c) 2015-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

'use strict';

var hasOwn =
  Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);

/**
 * Checks whether needle is a strict subset of haystack.
 *
 * @param {Object} haystack The object to test
 * @param {Object|Function} needle The properties to look for in test
 * @return {bool}
 */
function matchNode(haystack, needle) {
  if (typeof needle === 'function') {
    return needle(haystack);
  }
  var props = Object.keys(needle);
  return props.every(function(prop) {
    if (!hasOwn(haystack, prop)) {
      return false;
    }
    if (haystack[prop] &&
        needle[prop] &&
        typeof haystack[prop] === 'object' &&
        typeof needle[prop] === 'object') {
      return matchNode(haystack[prop], needle[prop]);
    }
    return haystack[prop] === needle[prop];
  });
}

module.exports = matchNode;

Fix fatal when matching null values in needle


const R = require('ramda')

export default async () => {
  console.log('1...2...3...')
  return R.range(1, 4)
  // return [1, 2, 3]
}

const R = require('ramda')

export default async () => {
  return R.range(1, 4)
}

Remove the console log from a fixture.


var hostname = location.hostname.replace(/^www\./, '');

var style = document.createElement('link');
style.rel = 'stylesheet';
style.href = chrome.extension.getURL('styles/' + hostname + '.css');
document.documentElement.insertBefore(style);

var defaultStyle = document.createElement('link');
defaultStyle.rel = 'stylesheet';
defaultStyle.href = chrome.extension.getURL('styles/default.css');
document.documentElement.insertBefore(defaultStyle);

var script = document.createElement('script');
script.src = chrome.extension.getURL('scripts/' + hostname + '.js');
document.documentElement.insertBefore(script);

var defaultScript = document.createElement('script');
defaultScript.src = chrome.extension.getURL('scripts/default.js');
document.documentElement.insertBefore(defaultScript);

var hostname = location.hostname.replace(/^www\./, '');

var style = document.createElement('link');
style.rel = 'stylesheet';
style.href = chrome.extension.getURL('styles/' + hostname + '.css');
document.documentElement.appendChild(style);

var defaultStyle = document.createElement('link');
defaultStyle.rel = 'stylesheet';
defaultStyle.href = chrome.extension.getURL('styles/default.css');
document.documentElement.appendChild(defaultStyle);

var script = document.createElement('script');
script.src = chrome.extension.getURL('scripts/' + hostname + '.js');
document.documentElement.appendChild(script);

var defaultScript = document.createElement('script');
defaultScript.src = chrome.extension.getURL('scripts/default.js');
document.documentElement.appendChild(defaultScript);

Use appendChild instead of insertBefore for a small perfomance boost


import _ from 'lodash';
import {Graph, alg} from 'graphlib';

const dijkstra = alg.dijkstra;

export function setupGraph(relationships) {
  let graph = new Graph({
    directed: true
  });
  _.each(relationships, function (relationship) {
    graph.setEdge(relationship.from, relationship.to, relationship.method);
  });
  return graph;
}

export function getPath(graph, source, destination, path) {
  let map = dijkstra(graph, source);
  let predecessor = map[destination].predecessor;
  if (_.isEqual(predecessor, source)) {
    path.push(graph.edge(predecessor, destination));
    return path.reverse();
  } else {
    path.push(graph.edge(predecessor, destination));
    return getPath(graph, source, predecessor, path);
  }
}

import _ from 'lodash';
import {Graph, alg} from 'graphlib';

_.memoize.Cache = WeakMap;
let dijkstra = _.memoize(alg.dijkstra);

export function setupGraph(pairs) {
  let graph = new Graph({
    directed: true
  });
  _.each(pairs, ({from, to, method}) => graph.setEdge(from, to, method));
  return graph;
}

export function getPath(graph, source, destination, path) {
  let map = dijkstra(graph, source);
  let predecessor = map[destination].predecessor;
  if (_.isEqual(predecessor, source)) {
    path.push(graph.edge(predecessor, destination));
    return path.reverse();
  } else {
    path.push(graph.edge(predecessor, destination));
    return getPath(graph, source, predecessor, path);
  }
}

Use ES2015 destructuring and add memoization to dijkstra


import constant from './constant';
import freeze from './freeze';
import is from './is';
import _if from './if';
import ifElse from './ifElse';
import map from './map';
import omit from './omit';
import reject from './reject';
import update from './update';
import updateIn from './updateIn';
import withDefault from './withDefault';
import { _ } from './util/curry';

const u = update;

u._ = _;
u.constant = constant;
u.if = _if;
u.ifElse = ifElse;
u.is = is;
u.freeze = freeze;
u.map = map;
u.omit = omit;
u.reject = reject;
u.update = update;
u.updateIn = updateIn;
u.withDefault = withDefault;

export default u;

import constant from './constant';
import freeze from './freeze';
import is from './is';
import _if from './if';
import ifElse from './ifElse';
import map from './map';
import omit from './omit';
import reject from './reject';
import update from './update';
import updateIn from './updateIn';
import withDefault from './withDefault';
import { _ } from './util/curry';

const u = update;

u._ = _;
u.constant = constant;
u.if = _if;
u.ifElse = ifElse;
u.is = is;
u.freeze = freeze;
u.map = map;
u.omit = omit;
u.reject = reject;
u.update = update;
u.updateIn = updateIn;
u.withDefault = withDefault;

module.exports = u;

Allow updeep to be require()’d from CommonJS


'use strict';
var path = require('path');
var BinWrapper = require('bin-wrapper');
var pkg = require('../package.json');

var url = 'https://raw.githubusercontent.com/jihchi/giflossy-bin/v' + pkg.version + '/vendor/';

module.exports = new BinWrapper()
	.src(url + 'macos/giflossy', 'darwin')
	.src(url + 'linux/x86/giflossy', 'linux', 'x86')
	.src(url + 'linux/x64/giflossy', 'linux', 'x64')
	.src(url + 'freebsd/x86/giflossy', 'freebsd', 'x86')
	.src(url + 'freebsd/x64/giflossy', 'freebsd', 'x64')
	.src(url + 'win/x86/giflossy.exe', 'win32', 'x86')
	.src(url + 'win/x64/giflossy.exe', 'win32', 'x64')
	.dest(path.join(__dirname, '../vendor'))
	.use(process.platform === 'win32' ? 'giflossy.exe' : 'giflossy');

'use strict';
var path = require('path');
var BinWrapper = require('bin-wrapper');
var pkg = require('../package.json');

var url = 'https://raw.githubusercontent.com/jihchi/giflossy-bin/v' + pkg.version + '/vendor/';

module.exports = new BinWrapper()
	.src(url + 'macos/gifsicle', 'darwin')
	.src(url + 'linux/x86/gifsicle', 'linux', 'x86')
	.src(url + 'linux/x64/gifsicle', 'linux', 'x64')
	.src(url + 'freebsd/x86/gifsicle', 'freebsd', 'x86')
	.src(url + 'freebsd/x64/gifsicle', 'freebsd', 'x64')
	.src(url + 'win/x86/gifsicle.exe', 'win32', 'x86')
	.src(url + 'win/x64/gifsicle.exe', 'win32', 'x64')
	.dest(path.join(__dirname, '../vendor'))
	.use(process.platform === 'win32' ? 'gifsicle.exe' : 'gifsicle');

Rename binary filename to gifsicle


'use strict';

var config = require('../config/configuration.js');

function htmlReplace(str) {
  return str.replace(/<\/?[a-z1-9]+(\s+[a-z]+=["'](.*)["'])*\/?>/g, ' ').replace(/ +/g, ' ').replace(/ ?\n ?/g, '\n').trim();
}

module.exports = function(path, document, changes, finalCb) {
  if(document.data.html === undefined) {
    changes.data.html = document.metadata.text;
  }
  else if(document.metadata.text === undefined) {
    changes.metadata.text = htmlReplace(document.data.html);
  }

  changes.metadata.text = (changes.metadata.text) ? changes.metadata.text : document.metadata.text;

  if(document.data.html) {
    config.separators_html.some(function(separator) {
      var tmpHTML = document.data.html.split(separator)[0];

      if(tmpHTML !== document.data.html) {
        changes.metadata.text = htmlReplace(tmpHTML);
        return true;
      }
      return false;
    });
  }

  if(changes.metadata.text === document.metadata.text) {
    config.separators_text.some(function(separator) {
      var tmpText = changes.metadata.text.split(separator)[0];

      if(tmpText !== changes.metadata.text) {
        changes.metadata.text = tmpText;
        return true;
      }
      return false;
    });
  }

  finalCb(null, changes);
};

'use strict';

var config = require('../config/configuration.js');

function htmlReplace(str) {
  return str.replace(/<\/?[^>]+\/?>/g, ' ').replace(/ +/g, ' ').replace(/ ?\n ?/g, '\n').trim();
}

module.exports = function(path, document, changes, finalCb) {
  if(document.data.html === undefined) {
    changes.data.html = document.metadata.text;
  }
  else if(document.metadata.text === undefined) {
    changes.metadata.text = htmlReplace(document.data.html);
  }

  changes.metadata.text = (changes.metadata.text) ? changes.metadata.text : document.metadata.text;

  if(document.data.html) {
    config.separators_html.some(function(separator) {
      var tmpHTML = document.data.html.split(separator)[0];

      if(tmpHTML !== document.data.html) {
        changes.metadata.text = htmlReplace(tmpHTML);
        return true;
      }
      return false;
    });
  }

  if(changes.metadata.text === document.metadata.text) {
    config.separators_text.some(function(separator) {
      var tmpText = changes.metadata.text.split(separator)[0];

      if(tmpText !== changes.metadata.text) {
        changes.metadata.text = tmpText;
        return true;
      }
      return false;
    });
  }

  finalCb(null, changes);
};

Update regexp for HTML strip


describe("About Expects", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should expect true", function() {
    expect(false).toBeTruthy(); //This should be true
  });

  //To understand reality, we must compare our expectations against reality.
  it("should expect equality", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = 1 + 1;

	  expect(actualValue === expectedValue).toBeTruthy();
  });

  //Some ways of asserting equality are better than others.
  it("should assert equality a better way", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = 1 + 1;

  // toEqual() compares using common sense equality.
	  expect(actualValue).toEqual(expectedValue);
  });

  //Sometimes you need to be really exact about what you "type".
  it("should assert equality with ===", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = (1 + 1).toString();

  // toBe() will always use === to compare.
	  expect(actualValue).toBe(expectedValue);
  });

  //Sometimes we will ask you to fill in the values.
  it("should have filled in values", function () {
	  expect(1 + 1).toEqual(FILL_ME_IN);
  });
});

describe("About Expects", function() {

  // We shall contemplate truth by testing reality, via spec expectations.
  it("should expect true", function() {
    expect(false).toBeTruthy(); // This should be true
  });

  // To understand reality, we must compare our expectations against reality.
  it("should expect equality", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = 1 + 1;

	  expect(actualValue === expectedValue).toBeTruthy();
  });

  // Some ways of asserting equality are better than others.
  it("should assert equality a better way", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = 1 + 1;

  // toEqual() compares using common sense equality.
	  expect(actualValue).toEqual(expectedValue);
  });

  // Sometimes you need to be precise about what you "type".
  it("should assert equality with ===", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = (1 + 1).toString();

  // toBe() will always use === to compare.
	  expect(actualValue).toBe(expectedValue);
  });

  // Sometimes we will ask you to fill in the values.
  it("should have filled in values", function () {
	  expect(1 + 1).toEqual(FILL_ME_IN);
  });
});

Correct spacing and language in comments


export class OHIFPlugin {
    // TODO: this class is still under development and will
    // likely change in the near future
    constructor () {
        this.name = "Unnamed plugin";
        this.description = "No description available";
    }

    // load an individual script URL
    static loadScript(scriptURL) {
        const script = document.createElement("script");

        script.src = scriptURL;
        script.type = "text/javascript";
        script.async = false;

        const head = document.getElementsByTagName("head")[0];
        head.appendChild(script);
        head.removeChild(script);

        return script;
    }

    // reload all the dependency scripts and also
    // the main plugin script url.
    static reloadPlugin(plugin) {
        console.warn(`reloadPlugin: ${plugin.name}`);
        if (plugin.scriptURLs && plugin.scriptURLs.length) {
            plugin.scriptURLs.forEach(scriptURL => {
                this.loadScript(scriptURL).onload = function() {}
            });
        }

        let scriptURL = plugin.url;

        if (plugin.allowCaching === false) {
            scriptURL += "?" + performance.now();
        }

        this.loadScript(scriptURL).onload = function() {
            const entryPointFunction = OHIF.plugins.entryPoints[plugin.name];

            if (entryPointFunction) {
                entryPointFunction();
            }
        }
    }
}

export class OHIFPlugin {
    // TODO: this class is still under development and will
    // likely change in the near future
    constructor () {
        this.name = "Unnamed plugin";
        this.description = "No description available";
    }

    // load an individual script URL
    static loadScript(scriptURL, type = "text/javascript") {
        const script = document.createElement("script");

        script.src = scriptURL;
        script.type = type;
        script.async = false;

        const head = document.getElementsByTagName("head")[0];
        head.appendChild(script);
        head.removeChild(script);

        return script;
    }

    // reload all the dependency scripts and also
    // the main plugin script url.
    static reloadPlugin(plugin) {
        if (plugin.scriptURLs && plugin.scriptURLs.length) {
            plugin.scriptURLs.forEach(scriptURL => {
                this.loadScript(scriptURL).onload = function() {}
            });
        }

        // TODO: Later we should probably merge script and module URLs
        if (plugin.moduleURLs && plugin.moduleURLs.length) {
            plugin.moduleURLs.forEach(moduleURLs => {
                this.loadScript(moduleURLs, "module").onload = function() {}
            });
        }

        let scriptURL = plugin.url;

        if (plugin.allowCaching === false) {
            scriptURL += "?" + performance.now();
        }

        this.loadScript(scriptURL).onload = function() {
            const entryPointFunction = OHIF.plugins.entryPoints[plugin.name];

            if (entryPointFunction) {
                entryPointFunction();
            }
        }
    }
}

Add moduleURLs in addition to scriptURLs


import { Factory, faker } from 'ember-cli-mirage';

export default Factory.extend({
  fund: () => faker.random.arrayElement(["WNYC", "WQXR", "Radiolab"]),
  orderPrice: () => faker.random.arrayElement([60, 72, 120, 12, 90, 100]),
  orderDate: faker.date.past,
  orderCode: () => faker.random.arrayElement([1234567,2345678,3456789]),
  orderType: () => faker.random.arrayElement(["onetime", "sustainer"]),
  orderKey: () => faker.random.uuid(),
  premium: () => faker.random.arrayElement(['Brian Lehrer Animated Series', 'BL Mug', 'WNYC Hoodie', '']),
  creditCardType: 'VISA',
  creditCardLast4Digits: '0302',
  isActiveMember: faker.random.boolean,
  isSustainer: faker.random.boolean,
});

import { Factory, faker } from 'ember-cli-mirage';

export default Factory.extend({
  fund: () => faker.random.arrayElement(["WNYC", "WQXR", "Radiolab", "J.Schwartz"]),
  orderPrice: () => faker.random.arrayElement([60, 72, 120, 12, 90, 100]),
  orderDate: faker.date.past,
  orderCode: () => faker.random.arrayElement([1234567,2345678,3456789]),
  orderType: () => faker.random.arrayElement(["onetime", "sustainer"]),
  orderKey: () => faker.random.uuid(),
  premium: () => faker.random.arrayElement(['Brian Lehrer Animated Series', 'BL Mug', 'WNYC Hoodie', '']),
  creditCardType: 'VISA',
  creditCardLast4Digits: '0302',
  isActiveMember: faker.random.boolean,
  isSustainer: faker.random.boolean,
});

Add Jonathan Schwartz as fund in mirage factory


var _ = require('lodash');
var path = require('path');
var exec = require('child_process').exec;

var LOG_TYPES = [
	"ERROR", "WARNING"
];

module.exports = function(filepath, options, callback) {
	if (!callback) {
		callback = options;
		options = {};
	}

	options = _.defaults(options || {}, {
		epubcheck: "epubcheck"
	});

	filepath = path.resolve(process.cwd(), filepath);

	var command = options.epubcheck+" "+filepath+" -q";
	exec(command, function (error, stdout, stderr) {
		var output = stderr.toString();
		var lines = stderr.split("\n");
		error = null;

		lines = _.chain(lines)
		.map(function(line) {
			var parts = line.split(":");
			if (!_.contains(LOG_TYPES, parts[0])) return null;

			var type = parts[0].toLowerCase();
			var content = parts.slice(1).join(":");

			if (type == "error") {
				error = new Error(content);
			}

			return {
				'type': type,
				'content': content
			};
		})
		.compact()
		.value();

		callback(error, {
			messages: lines
		});
	});
};

var _ = require('lodash');
var path = require('path');
var exec = require('child_process').exec;

var LOG_TYPES = [
	"ERROR", "WARNING"
];

module.exports = function(filepath, options, callback) {
	if (!callback) {
		callback = options;
		options = {};
	}

	options = _.defaults(options || {}, {
		epubcheck: "epubcheck"
	});

	filepath = path.resolve(process.cwd(), filepath);

	var command = options.epubcheck+" "+filepath+" -q";
	exec(command, function (error, stdout, stderr) {
		var output = stderr.toString();
		var lines = stderr.split("\n");
		var err = null;

		lines = _.chain(lines)
		.map(function(line) {
			var parts = line.split(":");
			if (!_.contains(LOG_TYPES, parts[0])) return null;

			var type = parts[0].toLowerCase();
			var content = parts.slice(1).join(":");

			if (type == "error") {
				err = new Error(content);
			}

			return {
				'type': type,
				'content': content
			};
		})
		.compact()
		.value();

		if (error && !err) err = error;

		callback(err, {
			messages: lines
		});
	});
};

Handle correctly error from epubcheck


function show_download_menu() {
  $('#download-menu').slideDown();
  setTimeout(hide_download_menu, 20000);
  $('#download-link').html('cancel');
}

function hide_download_menu() {
  $('#download-menu').slideUp();
  $('#download-link').html('download');
}

function toggle_download_menu() {
  if ($('#download-link').html() === 'download') {
    show_download_menu();
  } else {
    hide_download_menu();
  }
}

function show_download_menu() {
  $('#download-menu').slideDown({ duration: 200 });
  setTimeout(hide_download_menu, 20000);
  $('#download-link').html('cancel');
}

function hide_download_menu() {
  $('#download-menu').slideUp({ duration: 200 });
  $('#download-link').html('download');
}

function toggle_download_menu() {
  if ($('#download-link').html() === 'download') {
    show_download_menu();
  } else {
    hide_download_menu();
  }
}

Speed up the download menu appear/disappear a bit


module.exports = {
  Urls: {
    vault_base_url: '',
    base_url: process.env.BASE_URL || process.env.HUBOT_ROOT_URL
  },
  Strings: {
    sorry_dave: 'I\'m sorry %s, I\'m afraid I can\'t do that.'
  },
};

module.exports = {
  Urls: {
    vault_base_url: process.env.HUBOT_VAULT_URL,
    base_url: process.env.BASE_URL || process.env.HUBOT_ROOT_URL
  },
  Strings: {
    sorry_dave: 'I\'m sorry %s, I\'m afraid I can\'t do that.'
  },
};

Add vault url config environment variable


utils = {
  startsAtMomentWithOffset: function (game) {
    var offset = game.location.utc_offset;
    if (! Match.test(offset, UTCOffset)) {
      offset: -8; // Default to California
    }
    // UTC offsets returned by Google Places API,
    // which is the source of game.location.utc_offset,
    // differ in sign from what is expected by moment.js
    return moment(game.startsAt).zone(-offset);
  },
  displayTime: function (game) {
    return utils.startsAtMomentWithOffset(game).format('ddd h:mma');
  },
  // Same-day-ness depends on the known timezone of the game,
  // not the timezone of the system executing this function.
  isToday: function (game) {
    var gameWhen = utils.startsAtMomentWithOffset(game);
    var now = utils.startsAtMomentWithOffset(
      // clone of game that starts now
      _.extend({startsAt: new Date()}, _.omit(game, 'startsAt'))
    );
    return gameWhen.isSame(now, 'day');
  },
  // Markdown->HTML
  converter: new Showdown.converter()
};

utils = {
  startsAtMomentWithOffset: function (game) {
    var offset = game.location.utc_offset;
    if (! Match.test(offset, UTCOffset)) {
      offset = -8; // Default to California
    }
    // UTC offsets returned by Google Places API,
    // which is the source of game.location.utc_offset,
    // differ in sign from what is expected by moment.js
    return moment(game.startsAt).zone(-offset);
  },
  displayTime: function (game) {
    return utils.startsAtMomentWithOffset(game).format('ddd h:mma');
  },
  // Same-day-ness depends on the known timezone of the game,
  // not the timezone of the system executing this function.
  isToday: function (game) {
    var gameWhen = utils.startsAtMomentWithOffset(game);
    var now = utils.startsAtMomentWithOffset(
      // clone of game that starts now
      _.extend({startsAt: new Date()}, _.omit(game, 'startsAt'))
    );
    return gameWhen.isSame(now, 'day');
  },
  // Markdown->HTML
  converter: new Showdown.converter()
};

Fix typo in setting default time zone for game


// @flow
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import App from './containers/App';
import VerticalTree from './containers/VerticalTree';

export default (
  <Route path="/" component={App}>
    <IndexRoute component={VerticalTree} />
  </Route>
);

// @flow
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import App from './containers/App';
import Menu from './components/Menu';
import VerticalTree from './containers/VerticalTree';
import AVLTree from './containers/AVLTree';

export default (
  <Route path="/" component={App}>
    <IndexRoute component={Menu} />
    <Route path="usertree" component={VerticalTree} />
    <Route path="treeExamples" component={AVLTree} />
  </Route>
);

Add route for example structures, and home page


if (self.importScripts) {
    importScripts('/resources/testharness.js');
    importScripts('worker-helpers.js');
}

async_test(function(test) {
    if (Notification.permission != 'granted') {
        assert_unreached('No permission has been granted for displaying notifications.');
        return;
    }

    var notification = new Notification('My Notification', { tag: 'notification-test' });
    notification.addEventListener('show', function() {
        var updatedNotification = new Notification('Second Notification', { tag: 'notification-test' });
        updatedNotification.addEventListener('show', function() {
            test.done();
        });
    });

    // FIXME: Replacing a notification should fire the close event on the
    // notification that's being replaced.

    notification.addEventListener('error', function() {
        assert_unreached('The error event should not be thrown.');
    });

}, 'Replacing a notification will discard the previous notification.');

if (isDedicatedOrSharedWorker())
    done();

if (self.importScripts) {
    importScripts('/resources/testharness.js');
    importScripts('worker-helpers.js');
}

async_test(function(test) {
    if (Notification.permission != 'granted') {
        assert_unreached('No permission has been granted for displaying notifications.');
        return;
    }

    // We require two asynchronous events to happen when a notification gets updated, (1)
    // the old instance should receive the "close" event, and (2) the new notification
    // should receive the "show" event, but only after (1) has happened.
    var closedOriginalNotification = false;

    var notification = new Notification('My Notification', { tag: 'notification-test' });
    notification.addEventListener('show', function() {
        var updatedNotification = new Notification('Second Notification', { tag: 'notification-test' });
        updatedNotification.addEventListener('show', function() {
            assert_true(closedOriginalNotification);
            test.done();
        });
    });

    notification.addEventListener('close', function() {
        closedOriginalNotification = true;
    });

    notification.addEventListener('error', function() {
        assert_unreached('The error event should not be thrown.');
    });

}, 'Replacing a notification will discard the previous notification.');

if (isDedicatedOrSharedWorker())
    done();

Verify in a layout test that replacing a notification closes the old one.


#!/usr/bin/env node

var oust = require('../index');
var pkg = require('../package.json');
var fs = require('fs');

var argv = require('minimist')((process.argv.slice(2)))

var printHelp = function() {
	console.log('oust');
	console.log(pkg.description);
	console.log('');
	console.log('Usage:');
	console.log('  $ oust --file <filename> --selector <selector>');
};

if(argv.h || argv.help) {
	printHelp();
	return;
}

if(argv.v || argv.version) {
	console.log(pkg.version);
	return;
}

var file = argv.f || argv.file;
var selector = argv.s || argv.selector;

fs.readFile(file, function(err, data) {
	if(err) {
		console.log('Error opening file:', err.code);
		return;
	}
	var res = oust(data, selector);
	console.log(res.join("\n"));
});

#!/usr/bin/env node

var oust = require('../index');
var pkg = require('../package.json');
var fs = require('fs');

var argv = require('minimist')((process.argv.slice(2)))

var printHelp = function() {
	console.log('oust');
	console.log(pkg.description);
	console.log('');
	console.log('Usage:');
	console.log('  $ oust <filename> <selector>');
};

if(argv.h || argv.help) {
	printHelp();
	return;
}

if(argv.v || argv.version) {
	console.log(pkg.version);
	return;
}

var file = argv._[0];
var selector = argv._[1];

fs.readFile(file, function(err, data) {
	if(err) {
		console.error('Error opening file:', err.message);
		process.exit(1);
	}
	var res = oust(data, selector);
	console.log(res.join("\n"));
});

Update CLI based on @sindresorhus feedback


const mongoose = require('mongoose');
const Schema = mongoose.Schema;

module.exports = new Schema({
  merge_request: {
    id: Number,
    url: String,
    target_branch: String,
    source_branch: String,
    created_at: String,
    updated_at: String,
    title: String,
    description: String,
    status: String,
    work_in_progress: Boolean
  },
  last_commit: {
    id: Number,
    message: String,
    timestamp: String,
    url: String,
    author: {
      name: String,
      email: String
    }
  },
  project: {
    name: String,
    namespace: String
  },
  author: {
    name: String,
    username: String
  },
  assignee: {
    claimed_on_slack: Boolean,
    name: String,
    username: String
  }
});

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

module.exports = {
  name: 'MergeRequest',
  schema: new Schema({
    merge_request: {
      id: Number,
      url: String,
      target_branch: String,
      source_branch: String,
      created_at: String,
      updated_at: String,
      title: String,
      description: String,
      status: String,
      work_in_progress: Boolean
    },
    last_commit: {
      id: Number,
      message: String,
      timestamp: String,
      url: String,
      author: {
        name: String,
        email: String
      }
    },
    project: {
      name: String,
      namespace: String
    },
    author: {
      name: String,
      username: String
    },
    assignee: {
      claimed_on_slack: Boolean,
      name: String,
      username: String
    }
  })
}

Merge request now exports its desired collection name


describe('pingPongOutput', function() {
  it("is the number for most input numbers", function() {
    expect(pingPongOutput(2)).to.equal(2);
  });

  it("is 'ping' for numbers divisible by 3", function() {
    expect(pingPongOutput(6)).to.equal("ping");
  });
});

describe('pingPongOutput', function() {
  it("is the number for most input numbers", function() {
    expect(pingPongOutput(2)).to.equal(2);
  });

  it("is 'ping' for numbers divisible by 3", function() {
    expect(pingPongOutput(6)).to.equal("ping");
  });

  it("is 'pong' for numbers divisible by 5", function() {
    expect(pingPongOutput(5)).to.equal("pong");
  });
});

Add spec for numbers divisible by 5