const request = require('request');

request({
  url: 'https://maps.googleapis.com/maps/api/geocode/json?address=68%20Oktyabrskaya%20street%20Kvasnikovka',
  json: true
}, (error, response, body) => {
  console.log(JSON.stringify(body, undefined, 2));
});

const request = require('request');

request({
  url: 'https://maps.googleapis.com/maps/api/geocode/json?address=68%20Oktyabrskaya%20street%20Kvasnikovka',
  json: true
}, (error, response, body) => {
  console.log(body.results[0].formatted_address);
  console.log(`Latitude: ${body.results[0].geometry.location.lat}`);
  console.log(`Longitude: ${body.results[0].geometry.location.lng}`);
});

Print addres, latitude and longitude


"use strict";

angular.module('arethusa.morph').directive('formSelector', function() {
  return {
    restrict: 'E',
    replace: true,
    controller: function($scope, $element, $attrs) {
      var id = $scope.id;
      var form = $scope.form;
      $scope.selected = function() {
        return $scope.plugin.isFormSelected(id, form);
      };
      $scope.text = function() {
        return $scope.selected() ? 'Deselect' : 'Select';
      };
      $scope.action = function(event) {
        event.stopPropagation();
        if ($scope.selected()) {
          $scope.plugin.unsetState(id);
        } else {
          $scope.plugin.setState(id, form);
        }
      };
    },
    template: '{{ text() }}'
  };

});

"use strict";

angular.module('arethusa.morph').directive('formSelector', function() {
  return {
    restrict: 'AE',
    replace: true,
    controller: function($scope, $element, $attrs) {
      var id = $scope.id;
      var form = $scope.form;
      $scope.selected = function() {
        return $scope.plugin.isFormSelected(id, form);
      };
      $scope.text = function() {
        return $scope.selected() ? 'Deselect' : 'Select';
      };
      $scope.action = function(event) {
        event.stopPropagation();
        if ($scope.selected()) {
          $scope.plugin.unsetState(id);
        } else {
          $scope.plugin.setState(id, form);
        }
      };
    },
    template: '{{ text() }}'
  };

});

Allow formSelector directive as attribute


// ==UserScript==
// @name        FA Cleanup
// @author      Erra Boothale <erra@boothale.net>
// @namespace   http://boothale.net/
// @description Fixes various annoyances with FA's user interface
// @include     http://www.furaffinity.net/view/*
// @include     https://www.furaffinity.net/view/*
// ==/UserScript==

var tables = document.querySelectorAll('.maintable'),
    descTable = tables[2],
    descHead = descTable.querySelectorAll('td')[0],
    description = descTable.querySelectorAll('tr')[1],
    sideTable = tables[3],
    sideRow = sideTable.parentNode,
    sideContent = sideTable.querySelectorAll('td')[1];

description.appendChild(sideContent);
sideRow.parentNode.removeChild(sideRow);
descHead.setAttribute('colspan', '2');

// ==UserScript==
// @name        FA Cleanup
// @author      Erra Boothale <erra@boothale.net>
// @namespace   http://boothale.net/
// @description Fixes various annoyances with FA's user interface
// @include     http://www.furaffinity.net/view/*
// @include     https://www.furaffinity.net/view/*
// @include     http://www.furaffinity.net/full/*
// @include     https://www.furaffinity.net/full/*
// ==/UserScript==

var tables = document.querySelectorAll('.maintable'),
    descTable = tables[2],
    descHead = descTable.querySelectorAll('td')[0],
    description = descTable.querySelectorAll('tr')[1],
    sideTable = tables[3],
    sideRow = sideTable.parentNode,
    sideContent = sideTable.querySelectorAll('td')[1];

description.appendChild(sideContent);
sideRow.parentNode.removeChild(sideRow);
descHead.setAttribute('colspan', '2');

Update to work on full view


import { addons } from '@storybook/addons';
import { create } from '@storybook/theming';
import { COLOR } from '../src/constants';
import pkg from '../package';

addons.setConfig({
  panelPosition: 'right',
  theme: create({
    base: 'light',
    brandTitle: `UI Version ${pkg.version}`,
    colorPrimary: COLOR.TEAL.DARKEST,
    colorSecondary: COLOR.MINT.NORMAL,
    textColor: COLOR.TEAL.DARKEST,
  }),
});

import { addons } from '@storybook/addons';
import { create } from '@storybook/theming';
import { COLOR } from '../src/constants';
import pkg from '../package';

addons.setConfig({
  panelPosition: 'right',
  theme: create({
    brandTitle: `AHOY Version ${pkg.version}`,
    colorPrimary: COLOR.TEAL.DARKEST,
    colorSecondary: COLOR.MINT.NORMAL,
    textColor: COLOR.TEAL.DARKEST,
  }),
});

Adjust brand title and remove base


const latexExtension = (showdown) => {
  const latexInlineRegex = /\s~D([^~D\n].*[^~D\n])~D/g
  const latexDisplayRegex =/~D~D(.*)~D~D/g
    showdown.extension('latex' , () => {
      return [
        {
          type: "lang",
          filter: (text, converter, options) => {
            return text.replace(latexInlineRegex, (match, exp) => {
              return `<span class="latex"> ${exp}</span>`;
            });
          }
        },
        {
          type: "lang",
          filter: (text, converter, options) => {
            return text.replace(latexDisplayRegex, (match, exp) => {
              return `<div class="latex">${exp}</div>`;
            });
          }
        }
      ];
  });
}

export default latexExtension

const latexExtension = (showdown) => {
  const latexInlineRegex = /(\s)~D([^~D\n].*[^~D\n])~D/g
  const latexDisplayRegex =/~D~D(.*)~D~D/g
    showdown.extension('latex' , () => {
      return [
        {
          type: "lang",
          filter: (text, converter, options) => {
            return text.replace(latexInlineRegex, (match, space, exp) => {
              return `${space}<span class="latex">${exp}</span>`;
            });
          }
        },
        {
          type: "lang",
          filter: (text, converter, options) => {
            return text.replace(latexDisplayRegex, (match, exp) => {
              return `<div class="latex">${exp}</div>`;
            });
          }
        }
      ];
  });
}

export default latexExtension

Change the way to handle space followed by $inline$


var Box = function(topLeft, width, height) {
    this.topLeft = topLeft;
    this.width = width;
    this.height = height;
};

Box.prototype = {
    getLeftX: function() {
        return this.topLeft.x;
    },
    getRightX: function() {
        return this.topLeft.x + this.width;
    },
    getTopY: function() {
        return this.topLeft.y;
    },
    getBottomY: function() {
        return this.topLeft.y + this.height;
    },

    getTopLeft: function() {
        return new Point(this.getLeftX(), this.getTopY());
    },
    getTopRight: function() {
        return new Point(this.getRightX(), this.getTopY());
    },
    getBottomLeft: function() {
        return new Point(this.getLeftX(), this.getBottomY());
    },
    getBottomRight: function() {
        return new Point(this.getRightX(), this.getBottomY());
    }
};

var Box = function(topLeft, width, height) {
    this.topLeft = topLeft;
    this.width = width;
    this.height = height;
};

Box.prototype = {
    getLeftX: function() {
        return this.topLeft.x;
    },
    getRightX: function() {
        return this.topLeft.x + this.width;
    },
    getTopY: function() {
        return this.topLeft.y;
    },
    getBottomY: function() {
        return this.topLeft.y + this.height;
    },

    getTopLeft: function() {
        return new Point(this.getLeftX(), this.getTopY());
    },
    getTopRight: function() {
        return new Point(this.getRightX(), this.getTopY());
    },
    getBottomLeft: function() {
        return new Point(this.getLeftX(), this.getBottomY());
    },
    getBottomRight: function() {
        return new Point(this.getRightX(), this.getBottomY());
    },
    getCenter: function() {
        return new Point(this.topLeft.x + this.width / 2, this.topLeft.y + this.height / 2);
    },

    squaredDistance: function(point) {
        var deltaX = Math.max(
            Math.abs(point.x - (this.topLeft.x + this.width / 2)) - this.width / 2,
            0
        );
        var deltaY = Math.max(
            Math.abs(point.y - (this.topLeft.y + this.height / 2)) - this.height / 2,
            0
        );
        return square(deltaX) + square(deltaY);
    },

    distance: function(point) {
        return Math.sqrt(this.squaredDistance(point));
    },
};

Add a way to get the distance between a point and a box


"use strict";

const Table = require('./table');

class Revision extends Table {
  constructor(engine, relationship, name='revision', alias=null) {
    super(engine, relationship.name + '.' + name, alias);
    this.id = name;
    this.relationship = relationship;
    return this;
  }

  schema() {
    let schema = super.schema();
    schema.columns.push({
      name: 'entityId',
      dataType: 'INTEGER',
      // NOTE: Ideally, this field should be notNull.  Unfortunately, we need
      // to procure the revisionId *before* we know the entityId (when saving
      // a new entity).  Therefore, we must allow for null values.
      notNull: false,
    }, {
      name: 'date',
      dataType: 'INTEGER',
      notNull: true,
    });
    schema.keys.push('entityId');
    return schema;
  }
}

module.exports = Revision;

"use strict";

const Table = require('./table');

class Revision extends Table {
  constructor(engine, relationship, name='revision', alias=null) {
    super(engine, relationship.name + '__' + name, alias);
    this.id = name;
    this.relationship = relationship;
    return this;
  }

  schema() {
    let schema = super.schema();
    schema.columns.push({
      name: 'entityId',
      dataType: 'INTEGER',
      // NOTE: Ideally, this field should be notNull.  Unfortunately, we need
      // to procure the revisionId *before* we know the entityId (when saving
      // a new entity).  Therefore, we must allow for null values.
      notNull: false,
    }, {
      name: 'date',
      dataType: 'INTEGER',
      notNull: true,
    });
    schema.keys.push('entityId');
    return schema;
  }
}

module.exports = Revision;

Change Entity Revision name separator from . to __


import React, {Component} from 'react';
import io from 'socket.io-client';

import './App.css';

class App extends Component {

    state = {messages: []};
    socket = io('http://localhost:8080');

    componentDidMount() {
        this.socket
            .on('connect', () => {
                //console.log('CONNECT');
            })
            .on('messages', (messages) => {
                this.setState({messages: messages});
            })
            .on('message-added', (message) => {
                this.setState({messages: [...this.state.messages, message]});
            })
            .on('message-toggled', (message) => {
                const messages = [...this.state.messages];
                messages[message.id] = message;
                this.setState({messages: messages});
            })
            .on('disconnect', () => {
                //console.log('DISCONNECT');
            });
        this.socket.emit('get-messages');
    }

    renderMessages() {
        return this.state.messages.map(message =>

                {message.message}
                <button onClick={() => this.socket.emit('toggle-message', message.id)}>toggle</button>

        )
    }

    render() {
        return

                {this.renderMessages()}
                <button onClick={() => this.socket.emit('add-message')}>add message</button>

;
    }
}

export default App;

import React, {Component} from 'react';
import io from 'socket.io-client';

import './App.css';

class App extends Component {

    state = {messages: []};
    socket = io('http://localhost:8080');

    componentDidMount() {
        this.socket
            .on('connect', () => {
                //console.log('CONNECT');
            })
            .on('messages', (messages) => {
                this.setState({messages: messages});
            })
            .on('message-added', (message) => {
                this.setState({messages: [...this.state.messages, message]});
            })
            .on('message-toggled', (message) => {
                const messages = [...this.state.messages];
                messages[message.id] = message;
                this.setState({messages: messages});
            })
            .on('disconnect', () => {
                //console.log('DISCONNECT');
            });
        this.socket.emit('get-messages');
    }

    renderMessages() {
        return this.state.messages.map(message =>

                {message.message}
                <button onClick={() => this.socket.emit('toggle-message', message.id)}>toggle</button>

        )
    }

    render() {
        return

                <button onClick={() => this.socket.emit('add-message')}>Add message</button>
                {this.renderMessages()}

;
    }
}

export default App;

Move "Add message" button to top


// // create a new parser
var parser = emmet.require('abbreviationParser');
var emmetString = "ul>li{List Item $}*3>a";
var parsed = parser.parse(emmetString);
// the parser returns an object
console.log(parsed);
//
// logElems(parsed);
//
// function logElems(nodes) {
// 	$.each(nodes.children, function(index, element) {
// 		// get the tag name
// 		console.log(element.name());
// 	})
// 	// this has to be done recursively, just a proof of concept
// 	if(nodes.children.length>0) logElems(nodes.children[0]);
// }

function Zen() {
	var element = document.createElement('div');
	element.classList.add('a-class');
	return element;
}

// // create a new parser
var parser = emmet.require('abbreviationParser'),
output,
emmetString, parsed;

// the parser returns an object
console.log(parsed);
//
// logElems(parsed);
//
// function logElems(nodes) {
// 	$.each(nodes.children, function(index, element) {
// 		// get the tag name
// 		console.log(element.name());
// 	})
// 	// this has to be done recursively, just a proof of concept
// 	if(nodes.children.length>0) logElems(nodes.children[0]);
// }

function Zen() {
	var element = document.createElement('div');
	element.classList.add('a-class');
	return element;
}

function run() {
	output = document.getElementById("output"),
	output.innerHTML="--- Go! ---
"
	var input = document.getElementById("emmet-string");
	emmetString = input.value;
	parsed = parser.parse(emmetString);
	DOMBuilder.traverseTree(parsed)
}

var DOMBuilder = {}

DOMBuilder.traverseTree = function(base) {
	for (var node=0; node < base.children.length; node++) {
			DOMBuilder.output(base.children[node]._name);
			DOMBuilder.traverseTree(base.children[node]);
	}
}

DOMBuilder.output = function(node) {
	output.innerHTML+=node +"
";
}

Set up basic tree traversal function.


module.exports = {
  plugins: [
    ["@fullhuman/postcss-purgecss", { content: ["src/**/*.{html,ts,tsx}"] }],
    ["postcss-preset-env", {}],
    ["cssnano", { preset: "default" }],
  ],
};

module.exports = {
  plugins: [
    [
      "@fullhuman/postcss-purgecss",
      {
        contentFunction: (src) => {
          if (src.endsWith("src/popup/index.scss")) {
            return ["src/popup/**/*.{html,ts,tsx}"];
          }
          if (src.endsWith("src/options/index.scss")) {
            return ["src/options/**/*.{html,ts,tsx}"];
          }
          return ["src/**/*.{html,ts,tsx}"];
        },
      },
    ],
    ["postcss-preset-env", {}],
    ["cssnano", { preset: "default" }],
  ],
};

Set purged files based on source path


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

const InputField = ({ label, secureTextEntry, placeholder, onChangeText, value, autoCorrect, autoFocus }) => {

	return(
		<View>
			<Text style={styles.labelText}>
				{label}
			</Text>
			<TextInput style={styles.inputBox}
				secureTextEntry={secureTextEntry}
				placeholder={placeholder}
				onChangeText={onChangeText}
				value={value}
				autoCorrect={false}
				autoFocus={autoFocus}
				/>
		</View>
	);
};

const styles = StyleSheet.create ({
	inputBox: {
		marginBottom: 20,
		fontSize: 24
	},
	labelText: {
		fontSize: 18
	}
})

export default InputField;

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

const InputField = ({ label, secureTextEntry, placeholder, onChangeText, value, autoCorrect, autoFocus }) => {

	return(
		<View>
			<Text style={styles.labelText}>
				{label}
			</Text>
			<TextInput style={styles.inputBox}
				secureTextEntry={secureTextEntry}
				placeholder={placeholder}
				onChangeText={onChangeText}
				value={value}
				autoCorrect={false}
				autoFocus={autoFocus}
				/>
		</View>
	);
};

const styles = StyleSheet.create ({
	inputBox: {
		marginBottom: 20,
		fontSize: 20
	},
	labelText: {
		fontSize: 16
	}
})

export default InputField;

Change font sizes on form


define([
    'js-whatever/js/base-page',
    'text!about-page/templates/about-page.html',
    'datatables.net-bs'
], function(BasePage, template) {

    return BasePage.extend({
        template: _.template(template),

        initialize: function(options) {
            this.options = options;

            this.options.icon = this.options.icon || 'icon icon-cog';
        },

        render: function() {
            this.$el.html(this.template(this.options));

            this.$('table.table').dataTable({
                autoWidth: false,
                language: {
                    search: ''
                }
            });

            this.$('.dataTables_filter input')
                .prop('placeholder', this.options.strings.search);
        },

        getTemplateParameters: $.noop
    });
});

define([
    'js-whatever/js/base-page',
    'text!about-page/templates/about-page.html',
    'datatables.net-bs'
], function(BasePage, template) {

    return BasePage.extend({
        template: _.template(template),

        initialize: function(options) {
            this.options = options;

            this.options.icon = this.options.icon || 'fa fa-cog';
        },

        render: function() {
            this.$el.html(this.template(this.options));

            this.$('table.table').dataTable({
                autoWidth: false,
                language: {
                    search: ''
                }
            });

            this.$('.dataTables_filter input')
                .prop('placeholder', this.options.strings.search);
        },

        getTemplateParameters: $.noop
    });
});

Use Fontawesome 4 for default icon. [rev: matthew.gordon]


const express = require('express')
const config = require('./config')
const allTrendsController = require('./controllers/all-trends')
const trendController = require('./controllers/trend')

const api = {
  start: function () {
    let app = express()

    app.get('/v1/alltrends', allTrendsController)

    app.get('/v1/trend/:name', trendController)

    app.listen(config.apiPort, () => {
      console.log('Api listening on port ' + config.apiPort.toString())
    })
  }
}

module.exports = api

const express = require('express')
const config = require('./config')
const allTrendsController = require('./controllers/all-trends')
const trendController = require('./controllers/trend')

const api = {
  start: function () {
    let app = express()

    app.get('/alltrends', allTrendsController)

    app.get('/trend/:name', trendController)

    app.listen(config.apiPort, () => {
      console.log('Api listening on port ' + config.apiPort.toString())
    })
  }
}

module.exports = api

Remove /v1 from the start of all endpoint names


// Configuration
module.exports = function(grunt) {
    // include time-grunt
    require('time-grunt')(grunt);

    // Initialize config
    grunt.initConfig({
        pkg: '<json:package.json>',
    });

    // Load required tasks from submodules
    grunt.loadTasks('grunt');

    // Default
    grunt.registerTask('default', [
        'connect',
        'watch'
    ]);

    // Testing
    grunt.registerTask('test', [
        'htmlhint',
        'jshint',
        'scsslint'
    ]);

    // Deployment
    grunt.registerTask('deploy', [
        'clean:deploy',
        'fontello:build',
        'copy:deploy',
        'concat',
        'sass:deploy',
        'uglify',
        'imagemin:deploy',
        'favicons:deploy',
        'modernizr',
        'hashres:deploy'
    ]);
};

// Configuration
module.exports = function(grunt) {
    // include time-grunt
    require('time-grunt')(grunt);

    // Initialize config
    grunt.initConfig({
        pkg: '<json:package.json>',
    });

    // Load required tasks from submodules
    grunt.loadTasks('grunt');

    // Default
    grunt.registerTask('default', [
        'connect',
        'watch'
    ]);

    // Testing
    grunt.registerTask('test', [
        'htmlhint',
        'jshint',
        'scsslint'
    ]);

    // Deployment
    grunt.registerTask('deploy', [
        'clean:deploy',
        'fontello:build',
        'assemble:deploy',
        'copy:deploy',
        'concat',
        'sass:deploy',
        'uglify',
        'imagemin:deploy',
        'favicons:deploy',
        'modernizr',
        'hashres:deploy'
    ]);
};

Add assemble to deploy task.


/**
 * sw.js
 */

let CACHE_NAME = 'yk-blog'

self.oninstall = event => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => cache.addAll([
      '/',
      '/offline.html',
      '/assets/css/main.css',
      '/assets/js/func.js',
      '/assets/js/particles.js',
      '/assets/js/anchor.js'
    ]))
  )
}

self.onfetch = event => {
  event.respondWith(
    caches.open(CACHE_NAME).then(cache => {
      return cache.match(event.request).then(response => {
        let fetchPromise = fetch(event.request).then(networkResponse => {
          if (networkResponse.ok && networkResponse.type == 'basic') {
            cache.put(event.request, networkResponse.clone())
          }
          return networkResponse
        }).catch(() => cache.match('offline.html'))
        return response || fetchPromise
      })
    })
  )
}

self.onactivate = event => {
  return event.waitUntil(
    caches.keys().then(keys => Promise.all(
      keys.map(key => {
        if (key == CACHE_NAME) {
          return caches.delete(key)
        } else {
          return Promise.resolve()
        }
      })
    ))
  )
}

/**
 * sw.js
 */

let CACHE_NAME = 'yk-blog'

self.oninstall = event => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      cache.addAll([
        '/assets/js/particles.js',
        '/assets/js/anchor.js'
      ])
      return cache.addAll([
        '/',
        '/assets/css/main.css',
        '/assets/js/func.js'
      ])
    })
  )
}

self.onfetch = event => {
  event.respondWith(
    caches.open(CACHE_NAME).then(cache => {
      return cache.match(event.request).then(response => {
        let fetchPromise = fetch(event.request).then(networkResponse => {
          if (networkResponse.ok && networkResponse.type == 'basic') {
            cache.put(event.request, networkResponse.clone())
          }
          return networkResponse
        }).catch(() => cache.match('offline.html'))
        return response || fetchPromise
      })
    })
  )
}

self.onactivate = event => {
  return event.waitUntil(
    caches.keys().then(keys => Promise.all(
      keys.map(key => {
        if (key == CACHE_NAME) {
          return caches.delete(key)
        } else {
          return Promise.resolve()
        }
      })
    ))
  )
}

Reduce the installation time of Service Worker


var express = require('express');
var path = require('path');
var app = express();
var router = require('./router.js');
var comms = require('./communication');

app.use(express.static('bower_components'));
app.use(express.static('client'));

app.set('view engine', 'jade');
app.set('views', path.resolve(__dirname + '/views'));

router(app);

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

var io = require('socket.io')(server);
comms.setIO(io);

var express = require('express');
var path = require('path');
var app = express();
var router = require('./router.js');
var comms = require('./communication');

app.use(express.static('bower_components'));
app.use(express.static('client'));

app.set('view engine', 'jade');
app.set('views', path.resolve(__dirname + '/views'));

router(app);

var port = process.env.PORT || process.env.NODE_PORT || 3000;

var server = app.listen(port, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

var io = require('socket.io')(server);
comms.setIO(io);

Change server port to accept heroku value.


'use strict';

/**
 * @ngdoc function
 * @name libedMeApp.controller:AboutCtrl
 * @description
 * # AboutCtrl
 * Controller of the libedMeApp
 */
angular.module('libedMeApp')
  .controller('AboutCtrl', function ($scope) {
    $scope.awesomeThings = [
      'HTML5 Boilerplate',
      'AngularJS',
      'Karma',
      'Yeoman',
      'Node.js & Express',
      'Heroku'
    ];
  });

'use strict';

/**
 * @ngdoc function
 * @name libedMeApp.controller:AboutCtrl
 * @description
 * # AboutCtrl
 * Controller of the libedMeApp
 */
angular.module('libedMeApp')
  .controller('AboutCtrl', function ($scope) {
    $scope.awesomeThings = [
      'HTML5 Boilerplate',
      'Bootstrap (clearly)',
      'AngularJS',
      'Karma',
      'Yeoman',
      'Node.js & Express',
      'Heroku'
    ];
  });

Add Bootstrap to About's awesomeThings


#!/usr/bin/env node

/**
 * @module bin/cli
 */
'use strict'

var fs = require('fs')
var program = require('commander')

class CLI {
  constructor () {
    var packageJSON = JSON.parse(fs.readFileSync('../package.json'))
    program.version(packageJSON.version)

    program
      .command('logs')
      .action(this._cmdLogs)

    program
      .command('*')
      .action(function () { program.help() })

    program.parse(process.argv)

    if (!program.args.length) {
      program.help()
    }
  }
  _cmdLogs () {
    console.log('hi!')
  }
}

module.exports = new CLI()

/*
program
  .command('logs [something]')
  .description('view logs')
  .action(function () {
    console.log('action', arguments)
  })
  .command('build-logs', 'view build logs')
  // .command('terminal', 'terminal', { isDefault: true })
  .command('status', 'container status')
  .command('list', 'list containers based on this repository')
  .command('rebuild', 'rebuild a container')
  // .command('upload', '')
  // .command('relaunch')
  .parse(process.argv)
*/

#!/usr/bin/env node

/**
 * @module lib/cli
 * @exports {Object} instanceOf CLI
 */
'use strict'

var fs = require('fs')
var program = require('commander')

var ContainerLogs = require('./container-logs')
var api = require('./api')

class CLI {
  constructor () {
    //var packageJSON = JSON.parse(fs.readFileSync('../package.json'))
    //program.version(packageJSON.version)

    program
      .command('logs')
      .action(this._cmdLogs)

    program
      .command('stop')
      .action(this._cmdStop)

    program
      .command('*')
      .action(function () { program.help() })

    program.parse(process.argv)

    if (!program.args.length) {
      program.help()
    }
  }
  /**
   * Tail the CMD logs of a container on Runnable.
   * Attempts to determine which container to use from the origin remote of the current git repo
   */
  _cmdLogs () {
    // Fetch instance from API
    // codenow:
    // Ex: http://api.runnable.io/instances/?githubUsername=codenow&name=api
    api.fetchInstanceInfo() // TODO: Add org and name args here for manual specification
      .then((data) => {
        var containerLogs = new ContainerLogs(data.dockerHost, data.dockerContainer)
        containerLogs.fetchAndPipeToStdout()
      })
      .catch((err) => {
        console.log(err.message)
      });
  }
  _cmdStop () {
  }
}

module.exports = new CLI()

Add initial working implementation of runnable logs


angular.module('orderCloud')
	.config(function(toastrConfig) {
		angular.extend(toastrConfig, {
			containerId: 'toast-container',
			maxOpened: 5,
			newestOnTop: true,
			positionClass: 'toast-top-right',
			preventDuplicates: false,
			preventOpenDuplicates: true,
			progressBar:true,
			tapToClose:true,
			target: 'body',
			extendedTimeOut: 1000,
			timeOut: 4000,
			iconClasses: {
				error: 'alert-danger',
				info: 'alert-info',
				success: 'alert-success',
				warning: 'alert-warning'
			},
			toastClass: 'alert alert-dismissable',
			closeButton:true,
			closeHtml: '<button type="button" class="close" aria-label="Close">×</button>'
		});
	})
;

angular.module('orderCloud')
	.config(function(toastrConfig) {
		angular.extend(toastrConfig, {
			containerId: 'toast-container',
			maxOpened: 5,
			newestOnTop: true,
			positionClass: 'toast-top-right',
			preventDuplicates: false,
			preventOpenDuplicates: true,
			progressBar:true,
			tapToClose:true,
			target: 'body',
			extendedTimeOut: 1000,
			timeOut: 4000,
			iconClasses: {
				error: 'alert-danger',
				info: 'alert-info',
				success: 'alert-success',
				warning: 'alert-warning'
			},
			toastClass: 'alert alert-dismissable',
			closeButton:true,
			closeHtml: '<button type="button" class="close hidden-xs" aria-label="Close">×</button>'
		});
	})
;

Hide the toastr close button on xs screen sizes


import * as types from './types'

function compileRegistry(schemaDef) {
  const registry = Object.assign(Object.create(null), types)

  const defsByName = schemaDef.types.reduce((acc, def) => {
    if (acc[def.name]) {
      throw new Error(`Duplicate type name added to schema: ${def.name}`)
    }
    acc[def.name] = def
    return acc
  }, {})

  schemaDef.types.forEach(add)

  return registry

  function ensure(typeName) {
    if (!registry[typeName]) {
      if (!defsByName[typeName]) {
        throw new Error(`Unknown type: ${typeName}`)
      }
      add(defsByName[typeName])
    }

  }
  function extendMember(memberDef) {
    ensure(memberDef.type)
    return registry[memberDef.type].extend(memberDef, extendMember).get()
  }
  function add(typeDef) {
    ensure(typeDef.type)
    if (registry[typeDef.name]) {
      return
    }
    registry[typeDef.name] = registry[typeDef.type].extend(typeDef, extendMember)
  }
}

export default class Schema {
  static compile(schemaDef) {
    return new Schema(schemaDef)
  }
  constructor(schemaDef) {
    this._original = schemaDef
    this._registry = compileRegistry(schemaDef)
  }
  get name() {
    return this._original.name
  }
  get(name) {
    return this._registry[name].get()
  }
  getTypeNames() {
    return Object.keys(this._registry)
  }
}

import * as types from './types'

function compileRegistry(schemaDef) {
  const registry = Object.assign(Object.create(null), types)

  const defsByName = schemaDef.types.reduce((acc, def) => {
    if (acc[def.name]) {
      throw new Error(`Duplicate type name added to schema: ${def.name}`)
    }
    acc[def.name] = def
    return acc
  }, {})

  schemaDef.types.forEach(add)

  return registry

  function ensure(typeName) {
    if (!registry[typeName]) {
      if (!defsByName[typeName]) {
        throw new Error(`Unknown type: ${typeName}`)
      }
      add(defsByName[typeName])
    }

  }
  function extendMember(memberDef) {
    ensure(memberDef.type)
    return registry[memberDef.type].extend(memberDef, extendMember).get()
  }
  function add(typeDef) {
    ensure(typeDef.type)
    if (registry[typeDef.name]) {
      return
    }
    registry[typeDef.name] = registry[typeDef.type].extend(typeDef, extendMember)
  }
}

export default class Schema {
  static compile(schemaDef) {
    return new Schema(schemaDef)
  }
  constructor(schemaDef) {
    this._original = schemaDef
    this._registry = compileRegistry(schemaDef)
  }
  get name() {
    return this._original.name
  }
  get(name) {
    return this._registry[name].get()
  }
  has(name) {
    return name in this._registry
  }
  getTypeNames() {
    return Object.keys(this._registry)
  }
}

Add .has(typeName) on schema instances


"use strict";

module.exports = globalOptions;

function globalOptions(yargs, { ci = false, loglevel = "info", progress = true }) {
  // the global options applicable to _every_ command
  const opts = {
    loglevel: {
      default: loglevel,
      describe: "What level of logs to report.",
      type: "string",
    },
    concurrency: {
      defaultDescription: "4",
      describe: "How many processes to use when lerna parallelizes tasks.",
      type: "number",
      requiresArg: true,
    },
    "reject-cycles": {
      describe: "Fail if a cycle is detected among dependencies.",
      type: "boolean",
    },
    progress: {
      default: !ci && progress,
      describe: "Enable progress bars. (Always off in CI)\nPass --no-progress to disable.",
      type: "boolean",
    },
    sort: {
      default: true,
      describe: "Sort packages topologically (dependencies before dependents).\nPass --no-sort to disable.",
      type: "boolean",
    },
    "max-buffer": {
      describe: "Set max-buffer (in bytes) for subcommand execution",
      type: "number",
      requiresArg: true,
    },
  };

  // group options under "Global Options:" header
  const globalKeys = Object.keys(opts).concat(["help", "version"]);

  return yargs
    .options(opts)
    .group(globalKeys, "Global Options:")
    .option("ci", {
      default: ci,
      hidden: true,
      type: "boolean",
    });
}

"use strict";

module.exports = globalOptions;

function globalOptions(yargs, { ci = false, loglevel = "info", progress = true }) {
  // the global options applicable to _every_ command
  const opts = {
    loglevel: {
      default: loglevel,
      describe: "What level of logs to report.",
      type: "string",
    },
    concurrency: {
      defaultDescription: "4",
      describe: "How many processes to use when lerna parallelizes tasks.",
      type: "number",
      requiresArg: true,
    },
    "reject-cycles": {
      describe: "Fail if a cycle is detected among dependencies.",
      type: "boolean",
    },
    progress: {
      default: !ci && progress,
      describe: "Enable progress bars. (Always off in CI)\nPass --no-progress to disable.",
      type: "boolean",
    },
    sort: {
      defaultDescription: "true",
      describe: "Sort packages topologically (dependencies before dependents).\nPass --no-sort to disable.",
      type: "boolean",
    },
    "max-buffer": {
      describe: "Set max-buffer (in bytes) for subcommand execution",
      type: "number",
      requiresArg: true,
    },
  };

  // group options under "Global Options:" header
  const globalKeys = Object.keys(opts).concat(["help", "version"]);

  return yargs
    .options(opts)
    .group(globalKeys, "Global Options:")
    .option("ci", {
      default: ci,
      hidden: true,
      type: "boolean",
    });
}

Allow --sort to be configured from file


const path = require('path');
const webpack = require('webpack');

const production = process.env.NODE_ENV === 'production';

const plugins = [
    new webpack.ProvidePlugin({
        $              : 'jquery',
        jQuery         : 'jquery',
        'window.jQuery': 'jquery',
    }),
];

const productionPlugins = production
    ? [
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: JSON.stringify('production'),
            },
        }),
        new webpack.optimize.UglifyJsPlugin({
            include  : /\.js$/,
            minimize : true,
            sourceMap: true,
            compress : {
                warnings: false,
            },
        }),
    ]
    : [];

module.exports = {
    entry: {
        bot  : path.join(__dirname, 'src', 'botPage', 'view'),
        index: path.join(__dirname, 'src', 'indexPage'),
    },
    output: {
        filename         : production ? '[name].min.js' : '[name].js',
        sourceMapFilename: production ? '[name].min.js.map' : '[name].js.map',
    },
    devtool  : 'source-map',
    watch    : false,
    target   : 'web',
    externals: {
        ws : 'WebSocket',
        CIQ: 'CIQ',
    },
    module: {
        rules: [
            {
                test   : /\.(js|jsx)$/,
                exclude: /node_modules/,
                use    : 'babel-loader',
            },
        ],
    },
    plugins: plugins.concat(productionPlugins),
};

const path = require('path');
const webpack = require('webpack');

const production = process.env.NODE_ENV === 'production';

const plugins = [
    new webpack.ProvidePlugin({
        $              : 'jquery',
        jQuery         : 'jquery',
        'window.jQuery': 'jquery',
    }),
];

const productionPlugins = production
    ? [
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: JSON.stringify('production'),
            },
        }),
        new webpack.optimize.UglifyJsPlugin({
            include  : /\.js$/,
            minimize : true,
            sourceMap: true,
            compress : {
                warnings: false,
            },
        }),
    ]
    : [];

module.exports = {
    entry: {
        bot  : path.join(__dirname, 'src', 'botPage', 'view'),
        index: path.join(__dirname, 'src', 'indexPage'),
    },
    output: {
        filename         : production ? '[name].min.js' : '[name].js',
        sourceMapFilename: production ? '[name].min.js.map' : '[name].js.map',
    },
    devtool  : 'source-map',
    watch    : !production,
    target   : 'web',
    externals: {
        ws : 'WebSocket',
        CIQ: 'CIQ',
    },
    module: {
        rules: [
            {
                test   : /\.(js|jsx)$/,
                exclude: /node_modules/,
                use    : 'babel-loader',
            },
        ],
    },
    plugins: plugins.concat(productionPlugins),
};

Revert watch if not production


// ==UserScript==
// @name         SFcomic Viewer
// @namespace
// @version      0.2.1
// @description  Auto load comic picture.
// @author       AntonioTsai
// @match        http://comic.sfacg.com/*
// @include      http://comic.sfacg.com/*
// @grant        none
// @downloadURL  https://github.com/AntonioTsai/SFcomic-Viewer/raw/master/SFcomicViewer.user.js
// ==/UserScript==

/**
 * picAy: The array store all image's url of the volume
 * hosts: The array store possible host
 * getHost(): Get the current host index
 */
(() => {
	const imgTable = document.querySelector("table tbody");
	const tempTr = document.createElement("tr");

	// remove original image & social media icon
	var tr = document.querySelector("tr");
	tr.parentElement.removeChild(tr);

	// generate all images
	for (var i = 0; i < picCount; i++) {
		var imgTr = tempTr.cloneNode(true);
		imgTr.appendChild(document.createElement("img"));
		imgTr.children[0].children[0].src = picAy[i];
		imgTable.appendChild(imgTr);
	}

})();

// ==UserScript==
// @name         SFcomic Viewer
// @namespace
// @version      0.2.1
// @description  Auto load comic picture.
// @author       AntonioTsai
// @match        http://comic.sfacg.com/*
// @include      http://comic.sfacg.com/*
// @grant        none
// @downloadURL  https://github.com/AntonioTsai/SFcomic-Viewer/raw/master/SFcomicViewer.user.js
// ==/UserScript==

/**
 * picAy: The array store all image's url of the volume
 * hosts: The array store possible host
 * getHost(): Get the current host index
 */
(() => {
	const imgTable = document.querySelector("table tbody");
	const tempTr = document.createElement("tr");

	// Remove original image & social media icon
	imgTable.querySelectorAll('td').forEach((currentValue) => {
		currentValue.remove();
	})

	// generate all images
	for (var i = 0; i < picCount; i++) {
		var imgTr = tempTr.cloneNode(true);
		imgTr.appendChild(document.createElement("img"));
		imgTr.children[0].children[0].src = picAy[i];
		imgTable.appendChild(imgTr);
	}

})();

Remove image with link & media icons


var through = require('through'),
  str2js = require('string-to-js'),
  types = ['html', 'css'];

function isValidFile (file, opts) {
  var validTypes = types;
  if (opts && opts.onlyAllow) validTypes = opts.onlyAllow;
  if (opts && opts.alsoAllow) validTypes = validTypes.concat(opts.alsoAllow);
  if (!Array.isArray(validTypes)) validTypes = [validTypes];

  return validTypes.some(function (type) {
    return file.substr(-(type.length)) === type;
  });
}

function partialify (file, opts) {

  if (!isValidFile(file, opts)) return through();

  var buffer = "";

  return through(function (chunk) {
      buffer += chunk.toString();
    },
    function () {
      if (buffer.indexOf('module.exports') === 0) {
        this.queue(buffer); // prevent "double" transforms
      } else {
        this.queue(str2js(buffer));
      }
      this.queue(null);
    });

};

exports.onlyAllow = function (extensions) {
  if (extensions) {
    if (!Array.isArray(extensions)) extensions = Array.prototype.slice.call(arguments, 0);

    types = extensions;
  }
  return partialify;
}

exports.alsoAllow = function (extensions) {
  if (!Array.isArray(extensions)) extensions = Array.prototype.slice.call(arguments, 0);
  types = types.concat(extensions);
  return partialify;
}

var through = require('through'),
  str2js = require('string-to-js'),
  types = ['html', 'css'];

function isValidFile (file, opts) {
  var validTypes = types;
  if (opts && opts.onlyAllow) validTypes = opts.onlyAllow;
  if (opts && opts.alsoAllow) validTypes = validTypes.concat(opts.alsoAllow);
  if (!Array.isArray(validTypes)) validTypes = [validTypes];

  return validTypes.some(function (type) {
    return file.substr(-(type.length + 1)) === '.' + type;
  });
}

function partialify (file, opts) {

  if (!isValidFile(file, opts)) return through();

  var buffer = "";

  return through(function (chunk) {
      buffer += chunk.toString();
    },
    function () {
      if (buffer.indexOf('module.exports') === 0) {
        this.queue(buffer); // prevent "double" transforms
      } else {
        this.queue(str2js(buffer));
      }
      this.queue(null);
    });

};

exports.onlyAllow = function (extensions) {
  if (extensions) {
    if (!Array.isArray(extensions)) extensions = Array.prototype.slice.call(arguments, 0);

    types = extensions;
  }
  return partialify;
}

exports.alsoAllow = function (extensions) {
  if (!Array.isArray(extensions)) extensions = Array.prototype.slice.call(arguments, 0);
  types = types.concat(extensions);
  return partialify;
}

Include dot when matching files so css doesn't match scss, for example


var gulp = require("gulp");
var sass = require("gulp-sass");
var nano = require('gulp-cssnano');

gulp.task("sass", function () {
    gulp.src("./sass/**/*.scss")
        .pipe(sass({
            //outputStyle: "compressed",
            includePaths: ["bower_components/bourbon/app/assets/stylesheets/"]
        }))
        .pipe(nano())
        .pipe(gulp.dest("./dist"));
});

gulp.task("sass:watch", function () {
    gulp.watch("./sass/**/*.scss", ["sass"]);
});

gulp.task("default", ["sass"]);

var gulp = require("gulp");
var sass = require("gulp-sass");
var nano = require('gulp-cssnano');

gulp.task("sass", function () {
    gulp.src("./sass/**/*.scss")
        .pipe(sass({
            //outputStyle: "compressed",
            includePaths: ["./bower_components/bourbon/app/assets/stylesheets/"]
        }))
        .pipe(nano())
        .pipe(gulp.dest("./dist"));
});

gulp.task("sass:watch", function () {
    gulp.watch("./sass/**/*.scss", ["sass"]);
});

gulp.task("sass:docs", function () {
    gulp.src("./docs/sass/**/*.scss")
        .pipe(sass({
            //outputStyle: "compressed",
            includePaths: [
                "./bower_components/bourbon/app/assets/stylesheets",
                "./sass"]
        }))
        .pipe(nano())
        .pipe(gulp.dest("./docs/css"));
});

gulp.task("sass:docs:watch", function () {
    gulp.watch("./docs/sass/**/*.scss", ["sass:docs"]);
});

gulp.task("copy:docs", function () {
    gulp.src(["./dist/civil.css", "./dist/syntax.css"])
        .pipe(gulp.dest("./docs/css"));

    gulp.src("dist/civil.js")
        .pipe(gulp.dest("./docs/js"));
});

gulp.task("default", ["build", "docs"]);
gulp.task("build", ["sass"]);
gulp.task("docs", ["copy:docs", "sass:docs"]);

Add gulp tasks to build docs assets


var elixir = require('laravel-elixir');

/*
 |--------------------------------------------------------------------------
 | Elixir Asset Management
 |--------------------------------------------------------------------------
 |
 | Elixir provides a clean, fluent API for defining some basic Gulp tasks
 | for your Laravel application. By default, we are compiling the Sass
 | file for our application, as well as publishing vendor resources.
 |
 */

elixir(function(mix) {
    mix.sass([
        'app.scss',
        'controllers.scss'
    ], 'public/assets/css');
    mix.scripts(['app.js', 'controllers/controllers.js'], 'public/js/app.js')
        .scripts(['forum.js', 'threads.js'], 'public/js/forum.js');
});

var elixir = require('laravel-elixir');

/*
 |--------------------------------------------------------------------------
 | Elixir Asset Management
 |--------------------------------------------------------------------------
 |
 | Elixir provides a clean, fluent API for defining some basic Gulp tasks
 | for your Laravel application. By default, we are compiling the Sass
 | file for our application, as well as publishing vendor resources.
 |
 */

elixir(function(mix) {
    mix.sass([
        'app.scss',
        'controllers.scss'
    ], 'public/assets/css');
    mix.scripts(['app.js', 'controllers/books.js'], 'public/js/app.js')
        .scripts([
            'vendor/angular/angular.js',
            'vendor/jquery/dist/jquery.js',
            'vendor/bootstrap/dist/js/bootstrap.js'
        ], 'public/js/vendor.js');
});

Update Elixir in gulp file.


/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

var gulp = require('gulp'),
    qunit = require('gulp-qunit');

gulp.task('test', function() {
    return gulp.src('./test/index.html')
        .pipe(qunit());
});

Include copyright comment in gulp file.


var gulp = require('gulp');

var clean = require('gulp-clean');
var zip = require('gulp-zip');

var bases = {
    root: 'dist/'
};

var paths = [
    'core/actions/*',
    'core/common/**',
    'admin/**',
    '!admin/config/*',
    'boxoffice/**',
    '!boxoffice/config/*',
    'customer/**',
    '!customer/config/*',
    'scanner/**',
    '!scanner/config/*',
    'printer/**',
    '!printer/config/*',
    'core/model/*',
    'core/services/*',
    'vendor/**',
    'composer.lock',
    'core/dependencies.php'
];

gulp.task('clean', function() {
    return gulp.src(bases.root)
        .pipe(clean({}));
});

gulp.task('collect', function() {
    return gulp.src(paths, { base: './' })
        .pipe(gulp.dest(bases.root));
});

gulp.task('zip', function() {
    return gulp.src(bases.root + '**')
        .pipe(zip('ticketbox-server-php.zip'))
        .pipe(gulp.dest(bases.root));
});

gulp.task('default', gulp.series('clean', 'collect', 'zip'));

var gulp = require('gulp');

var clean = require('gulp-clean');
var zip = require('gulp-zip');

var bases = {
    root: 'dist/'
};

var paths = [
    'core/actions/*',
    'core/common/**',
    'admin/**',
    '!admin/config/*',
    'boxoffice/**',
    '!boxoffice/config/*',
    'customer/**',
    '!customer/config/*',
    'scanner/**',
    '!scanner/config/*',
    'printer/**',
    '!printer/config/*',
    'core/model/*',
    'core/services/*',
    'vendor/**',
    'composer.lock',
    'core/dependencies.php'
];

gulp.task('clean', function() {
    return gulp.src(bases.root)
        .pipe(clean({}));
});

gulp.task('collect', function() {
    return gulp.src(paths, { base: './', dot: true })
        .pipe(gulp.dest(bases.root));
});

gulp.task('zip', function() {
    return gulp.src(bases.root + '**')
        .pipe(zip('ticketbox-server-php.zip'))
        .pipe(gulp.dest(bases.root));
});

gulp.task('default', gulp.series('clean', 'collect', 'zip'));

Copy .htaccess files to dist


var gulp = require('gulp');
var jshint = require('gulp-jshint');
var mocha = require('gulp-mocha');
var docco = require('gulp-docco');
var del = require('del');

gulp.task('docs', function () {
    del(['./docs'], function() {
        gulp.src('./lib/telegram.link.js')
            .pipe(docco(/*{'layout': 'linear'}*/))
            .pipe(gulp.dest('./docs'));
    });
});
gulp.task('quality', function () {
    return gulp.src('./lib/**')
        .pipe(jshint())
        .pipe(jshint.reporter('default'));
});
gulp.task('test', function () {
    return gulp.src('./test/*.js')
        .pipe(mocha({reporter: 'mocha-better-spec-reporter', timeout: '20s'}));
});

gulp.task('cover', function () {
    return gulp.src('./test/*.js')
        .pipe(mocha({reporter: 'mocha-lcov-reporter', timeout: '120s'}));
});

gulp.task('default', ['quality', 'test']);

var gulp = require('gulp');
var jshint = require('gulp-jshint');
var mocha = require('gulp-mocha');
var docco = require('gulp-docco');
var del = require('del');

gulp.task('docs', function () {
    del(['./docs'], function() {
        gulp.src('./lib/telegram.link.js')
            .pipe(docco(/*{'layout': 'linear'}*/))
            .pipe(gulp.dest('./docs'));
    });
});
gulp.task('quality', function () {
    return gulp.src('./lib/**')
        .pipe(jshint())
        .pipe(jshint.reporter('default'));
});
gulp.task('test', function () {
    return gulp.src('./test/telegram.link.test.js')
        .pipe(mocha({reporter: 'mocha-better-spec-reporter', timeout: '20s'}));
});

gulp.task('cover', function () {
    return gulp.src('./test/telegram.link.test.js')
        .pipe(mocha({reporter: 'mocha-lcov-reporter', timeout: '120s'}));
});

gulp.task('default', ['quality', 'test']);

Update the gulp config, test only the main module


const gulp = require('gulp');
const util = require('gulp-util');
const babel = require('gulp-babel');
const mocha = require('gulp-mocha');
const eslint = require('gulp-eslint');

const src = 'src/index.js';

gulp.task('lint', () =>
  gulp.src([src, 'test/*.js'])
  .pipe(eslint())
  .pipe(eslint.format()),
);

gulp.task('test', ['lint'], () => (
  gulp.src('test')
  .pipe(mocha())
  .on('error', util.log)
));

gulp.task('build', ['test'], () => (
  gulp.src(src)
  .pipe(babel())
  .pipe(gulp.dest('dist'))
));

gulp.task('watch', () => {
  gulp.watch(src, ['test']);
});

gulp.task('develop', ['watch']);

gulp.task('default', ['develop']);

const gulp = require('gulp');
const util = require('gulp-util');
const babel = require('gulp-babel');
const mocha = require('gulp-mocha');
const eslint = require('gulp-eslint');

const src = 'src/index.js';

gulp.task('lint', () => (
  gulp.src([src, 'test/*.js'])
  .pipe(eslint())
  .pipe(eslint.format())
));

gulp.task('test', ['lint'], () => (
  gulp.src('test')
  .pipe(mocha())
  .on('error', util.log)
));

gulp.task('build', ['test'], () => (
  gulp.src(src)
  .pipe(babel())
  .pipe(gulp.dest('dist'))
));

gulp.task('watch', () => {
  gulp.watch(src, ['test']);
});

gulp.task('develop', ['watch']);

gulp.task('default', ['develop']);

Fix travis testing on node < 8


const gulp = require("gulp");
const replace = require("gulp-replace");
const del = require("del");

const distillerCore = "src/external/chromium/components/dom-distiller/core";
const allChildren = "/**/*"

gulp.task("clean", () => {
    return del(["out"]);
});

gulp.task("extract", ["clean"], () => {
    return gulp.src([
        distillerCore + "/css" + allChildren,
        distillerCore + "/html" + allChildren,
        distillerCore + "/images" + allChildren,
        distillerCore + "/javascript" + allChildren
    ], {base: distillerCore}).pipe(gulp.dest("out/dom-distiller"));
});

const fs = require("fs");

const gulp = require("gulp");
const replace = require("gulp-replace");
const del = require("del");

const distillerCore = "src/external/chromium/components/dom-distiller/core";
const allChildren = "/**/*"

gulp.task("clean", () => {
    return del(["out"]);
});

gulp.task("extract:distillerCore", ["clean"], () => {
    return gulp.src([
        distillerCore + "/css" + allChildren,
        distillerCore + "/html" + allChildren,
        distillerCore + "/images" + allChildren,
        distillerCore + "/javascript" + allChildren
    ], {base: distillerCore}).pipe(gulp.dest("out/dom-distiller"));
});

gulp.task("extract:internal-src", ["clean"], () => {
    return gulp.src(["./**/*", "!./external/**/*"], {base: "./src"})
    .pipe(gulp.dest("./out/"));
});

gulp.task("extract", ["extract:distillerCore", "extract:internal-src"]);

gulp.task("build:dom_distiller_viewer", ["extract"], () => {
    const spinner = fs.readFileSync("out/dom-distiller/images/dom_distiller_material_spinner.svg", "utf8");
    return gulp.src("out/dom-distiller/html/dom_distiller_viewer.html", {base: "./"})
    .pipe(replace("$6", spinner))
    .pipe(replace("$2", `<link href="../css/distilledpage.css" rel="stylesheet" type="text/css">`))
    .pipe(gulp.dest("./"));
});

gulp.task("build:domdistiller", ["extract"], () => {
    const js = fs.readFileSync("src/external/dom-distiller/out/package/js/domdistiller.js", "utf8");
    return gulp.src("out/dom-distiller/javascript/domdistiller.js", {base: "./"})
    .pipe(replace(`<include src="../../../../third_party/dom_distiller_js/dist/js/domdistiller.js"/>`, js))
    .pipe(gulp.dest("./"));
});

gulp.task("build", ["build:dom_distiller_viewer", "build:domdistiller"]);

Split tasks and build files


const gulp = require('gulp');
const babel = require('gulp-babel');
const eslint = require('gulp-eslint');

gulp.task('lint', () =>
  gulp.src('index.js')
  .pipe(eslint())
  .pipe(eslint.format())
);

gulp.task('build', () => (
  gulp.src('lib/index.js')
  .pipe(babel())
  .pipe(gulp.dest('dist'))
));

const gulp = require('gulp');
const babel = require('gulp-babel');
const eslint = require('gulp-eslint');

gulp.task('lint', () =>
  gulp.src('index.js')
  .pipe(eslint())
  .pipe(eslint.format())
);

gulp.task('build', ['lint'], () => (
  gulp.src('lib/index.js')
  .pipe(babel())
  .pipe(gulp.dest('dist'))
));

Add linting before build task in gulp


var write = require('./write'),
    geojson = require('./geojson'),
    prj = require('./prj'),
    JSZip = require('jszip');

module.exports = function(gj, options) {

    var zip = new JSZip(),
        layers = zip.folder(options && options.folder ? options.folder : 'layers');

    [geojson.point(gj), geojson.line(gj), geojson.polygon(gj)]
        .forEach(function(l) {
        if (l.geometries.length) {
            write(
                // field definitions
                l.properties,
                // geometry type
                l.type,
                // geometries
                l.geometries,
                function(err, files) {
                    var fileName = options && options.types[l.type.toLowerCase()] ? options.types[l.type.toLowerCase()] : l.type;
                    layers.file(fileName + '.shp', files.shp.buffer, { binary: true });
                    layers.file(fileName + '.shx', files.shx.buffer, { binary: true });
                    layers.file(fileName + '.dbf', files.dbf.buffer, { binary: true });
                    layers.file(fileName + '.prj', prj);
                });
        }
    });

    var generateOptions = { compression:'STORE' };

    if (typeof window === 'undefined') {
      generateOptions.type = 'nodebuffer';
    }

    return zip.generate(generateOptions);
};

var write = require('./write'),
    geojson = require('./geojson'),
    prj = require('./prj'),
    JSZip = require('jszip');

module.exports = function(gj, options) {

    var zip = new JSZip(),
        layers = zip.folder(options && options.folder ? options.folder : 'layers');

    [geojson.point(gj), geojson.line(gj), geojson.polygon(gj)]
        .forEach(function(l) {
        if (l.geometries.length) {
            write(
                // field definitions
                l.properties,
                // geometry type
                l.type,
                // geometries
                l.geometries,
                function(err, files) {
                    var fileName = options && options.types[l.type.toLowerCase()] ? options.types[l.type.toLowerCase()] : l.type;
                    layers.file(fileName + '.shp', files.shp.buffer, { binary: true });
                    layers.file(fileName + '.shx', files.shx.buffer, { binary: true });
                    layers.file(fileName + '.dbf', files.dbf.buffer, { binary: true });
                    layers.file(fileName + '.prj', prj);
                });
        }
    });

    var generateOptions = { compression:'STORE' };

    if (!process.browser) {
      generateOptions.type = 'nodebuffer';
    }

    return zip.generate(generateOptions);
};

Check to see if browserify has modified process to check for browser environment.


var Comment = require('../models/index.js').Comment;

var create = function(props, callback) {
  Comment.build(props)
  .save()
  .then(function(comment) {
    callback(comment);
  }).catch(function(err) {
    console.log(err);
  });
};

var findAll = function(callback) {
  Comment.findAll().then(function(comments) {
    callback(comments);
  }).catch(function(err) {
    console.log(err);
  });
};

var findOne = function(query, callback) {
  Comment.findOne(query).done(function(comment) {
    console.log('🍊  Found one comment in db:', query);
    callback(comment);
  });
};

exports.create = create;
exports.findAll = findAll;
exports.findOne = findOne;

var Comment = require('../models/index.js').Comment;

var create = function(props, callback) {
  Comment.build(props)
  .save()
  .then(function(comment) {
    callback(comment);
  }).catch(function(err) {
    console.log(err);
  });
};

var findAll = function(query, callback) {
  Comment.findAll(query).then(function(comments) {
    callback(comments);
  }).catch(function(err) {
    console.log(err);
  });
};

var findOne = function(query, callback) {
  Comment.findOne(query).done(function(comment) {
    console.log('🍊  Found one comment in db:', query);
    callback(comment);
  });
};

var findOrCreate = function(query, callback) {
  Comment.findOrCreate(query).done(function(comment) {
    console.log('🍊  Found one comment in db:', query);
    callback(comment);
  });
};

exports.create = create;
exports.findAll = findAll;
exports.findOne = findOne;
exports.findOrCreate = findOrCreate;

Add query to find all and add findOrCreate


Meteor.publish('topics', function (categoryId) {
  return Topics.find({categoryId: categoryId});
});

Meteor.publish('topic', function (topicSlug) {
  return Topics.find({slug: topicSlug});
});

Meteor.publish('recent-topics', function () {
  return Topics.find({}, {sort: {date: -1}, limit: 10});
});

Meteor.publish('topics', function (categoryId) {
  return Topics.find({categoryId: categoryId});
});

Meteor.publish('topic', function (topicSlug) {
  return Topics.find({slug: topicSlug});
});

Meteor.publish('recent-topics', function () {
  return Topics.find({}, {sort: {createdAt: -1}, limit: 10});
});

Use correct field for sorting


import firedux from '../store/firedux'

export function addTodo(text) {
  return () => {
    firedux.push('todos', {
      completed: false,
      text
    })
  }
}

export function deleteTodo(id) {
  return () => {
    firedux.remove(`todos/${id}`)
  }
}

export function editTodo(id, text) {
  return () => {
    firedux.update(`todos/${id}`, {
      text,
      completed
    })
  }
}

export function completeTodo(id) {
  return (dispatch, getState) => {
    const state = getState()
    const completed = state.firedux.data.todos[id].completed

    firedux.set(`todos/${id}/completed`, !completed)
  }
}

export function completeAll() {
  return (dispatch, getState) => {
    const state = getState()
    const todos = state.firedux.data.todos

    const areAllMarked = _.values(todos).every(todo => todo.completed)

    _.each(todos, (todo, id) => {
      firedux.set(`todos/${id}/completed`, !areAllMarked)
    })
  }
}

export function clearCompleted() {
  return (dispatch, getState) => {
    const state = getState()
    const todos = state.firedux.data.todos

    _.each(todos, (todo, id) => {
      if (todo.completed) {
        firedux.remove(`todos/${id}`)
      }
    })
  }
}

import firedux from '../store/firedux'

export function addTodo(text) {
  return () => {
    firedux.push('todos', {
      completed: false,
      text
    })
  }
}

export function deleteTodo(id) {
  return () => {
    firedux.remove(`todos/${id}`)
  }
}

export function editTodo(id, text) {
  return () => {
    firedux.update(`todos/${id}`, {
      text
    })
  }
}

export function completeTodo(id) {
  return (dispatch, getState) => {
    const state = getState()
    const completed = state.firedux.data.todos[id].completed

    firedux.set(`todos/${id}/completed`, !completed)
  }
}

export function completeAll() {
  return (dispatch, getState) => {
    const state = getState()
    const todos = state.firedux.data.todos

    const areAllMarked = _.values(todos).every(todo => todo.completed)

    _.each(todos, (todo, id) => {
      firedux.set(`todos/${id}/completed`, !areAllMarked)
    })
  }
}

export function clearCompleted() {
  return (dispatch, getState) => {
    const state = getState()
    const todos = state.firedux.data.todos

    _.each(todos, (todo, id) => {
      if (todo.completed) {
        firedux.remove(`todos/${id}`)
      }
    })
  }
}

Remove completed since undefined in editTodo action.


'use strict'

import {Runner} from '../'
import yargs from 'yargs'
import prop from 'dot-prop'
import {resolve} from 'path'
import {createLogger} from 'clout'

const {cwd} = process
const pkg = require(resolve(cwd(), 'package.json'))
const log = createLogger(pkg.name)

const {argv} = yargs
  .demand(1)
  .option('script', {
    default: 'test-main',
    describe: 'test script'
  })
const [peer] = argv._
const {script, verbose} = argv
const range = prop.get(pkg, `peerDependencies.${peer}`)

new Runner(peer, range, {script})
  .on('versions', (versions) => {
    log(`Testing ${peer} versions ${versions.join(', ')}`)
  })
  .on('preinstall', (version) => {
    log(`Installing ${peer}@${version}`)
  })
  .on('postinstall', (version) => {
    log(`Installed ${peer}@${version}`)
  })
  .on('prescript', (version) => {
    log(`Starting "${script}" for ${peer}@${version}`)
  })
  .on('result', ({passed, version}) => {
    const outcome = passed ? 'Passed' : 'Failed'
    log(`${outcome}: ${peer}@${version}`)
  })
  .run()
  .catch(fail)

function fail (err) {
  log.error(err)
  console.error(err.stack)
  process.exit(1)
}

'use strict'

import {Runner} from '../'
import yargs from 'yargs'
import prop from 'dot-prop'
import {resolve} from 'path'
import {createLogger} from 'clout'

const {cwd} = process
const pkg = require(resolve(cwd(), 'package.json'))
const log = createLogger('test-peer-range')

const {argv} = yargs
  .demand(1)
  .option('script', {
    default: 'test-main',
    describe: 'test script'
  })
const [peer] = argv._
const {script, verbose} = argv
const range = prop.get(pkg, `peerDependencies.${peer}`)

new Runner(peer, range, {script})
  .on('versions', (versions) => {
    log(`Testing ${peer} versions ${versions.join(', ')}`)
  })
  .on('preinstall', (version) => {
    log(`Installing ${peer}@${version}`)
  })
  .on('postinstall', (version) => {
    log(`Installed ${peer}@${version}`)
  })
  .on('prescript', (version) => {
    log(`Starting "${script}" for ${peer}@${version}`)
  })
  .on('result', ({passed, version}) => {
    const outcome = passed ? 'Passed' : 'Failed'
    log(`${outcome}: ${peer}@${version}`)
  })
  .run()
  .catch(fail)

function fail (err) {
  log.error(err)
  console.error(err.stack)
  process.exit(1)
}

Use test-peer-range for logs, not target peer


#!/usr/bin/env node

var conf = require("./config")
  , Box = require("cli-box")
  ;

// Set config
global.CONFIG = {
    root: __dirname
  , cli: {
        w: process.stdout.columns || 212
      , h: process.stdout.rows || 56
    }
};
CONFIG.background = new Box({
    w: CONFIG.cli.w
  , h: CONFIG.cli.h - 3
  , marks: {
        nw: "╔"
      , n:  "═"
      , ne: "╗"
      , e:  "║"
      , se: "╝"
      , s:  "═"
      , sw: "╚"
      , w:  "║"
      , b: " "
    }
});

for (var key in conf) {
    CONFIG[key] = conf[key];
}

// Dependencies
var SplashScreen = require("./lib/ui/splash-screen")
  , MainStream = require("./lib/ui/stream")
  ;

SplashScreen.show();
setTimeout(function() {
    MainStream();
}, 1000);

#!/usr/bin/env node

var conf = require("./config")
  , Box = require("cli-box")
  , GitHub = new (require("github"))({
        version: "3.0.0",
        debug: true,
        timeout: 5000
    })
  , Login = require("./lib/api/login")
  ;

  debugger;
console.log(process.env.NODE_DEBUG);

// Set config
global.CONFIG = {
    root: __dirname
  , cli: {
        w: process.stdout.columns || 212
      , h: process.stdout.rows || 56
    }
  , _github: GitHub
};
CONFIG.background = new Box({
    w: CONFIG.cli.w
  , h: CONFIG.cli.h - 3
  , marks: {
        nw: "╔"
      , n:  "═"
      , ne: "╗"
      , e:  "║"
      , se: "╝"
      , s:  "═"
      , sw: "╚"
      , w:  "║"
      , b: " "
    }
});

for (var key in conf) {
    CONFIG[key] = conf[key];
}

// Dependencies
var SplashScreen = require("./lib/ui/splash-screen")
  , MainStream = require("./lib/ui/stream")
  ;

SplashScreen.show(function (err, output) {
    if (err) { throw err; }
    SplashScreen.updateMessage("Logging in ...");
    Login(function (err, user) {
        if (err) {
            SplashScreen.updateMessage("Failed to login in: " + JSON.parse(err.message).message);
            return setTimeout(function () {
                process.exit();
            }, 1000);
        }
        CONFIG.user = user;
        SplashScreen.updateMessage("Logged in as: " + user.login);
        setTimeout(function() {
            SplashScreen.updateMessage("Fetching News Feed ...");
            MainStream();
        }, 1000);
    });
});

Integrate splash screen with login and news feeed


require('dotenv').config();

const gulp = require('gulp');

require('./tasks/browser-sync.task');
require('./tasks/typescript.task');
require('./tasks/vendor.task');
require('./tasks/views.task');
require('./tasks/tests.task');
require('./tasks/setup.task');
require('./tasks/sass.task');

gulp.task('default', [
    'typescript',
    'sass',
    'views',
    // 'tests'
]);

gulp.task('watch', [
    'browser-sync',
    'watch-sass',
    'watch-typescript',
    'watch-views',
    // 'watch-tests'
]);

require('dotenv').config();

const gulp = require('gulp');

require('./tasks/browser-sync.task');
require('./tasks/typescript.task');
require('./tasks/vendor.task');
require('./tasks/views.task');
require('./tasks/tests.task');
require('./tasks/setup.task');
require('./tasks/sass.task');

gulp.task('default', [
    'typescript',
    'sass',
    'views',
    'tests'
]);

gulp.task('watch', [
    'browser-sync',
    'watch-sass',
    'watch-typescript',
    'watch-views',
    'watch-tests'
]);

Make tests run by default when running gulp or gulp watch


var gulp = require('gulp');
var del = require('del');
var seq = require('gulp-sequence');
var zip = require('gulp-zip');
var pkg = require('./package.json');

gulp.task('clean', function (cb) {
  del(['dist/**/*'], cb);
});

gulp.task('dist', function() {
  var platform = '';
  if (process.platform === 'darwin') {
    platform = '-osx';
  } else if (process.platform === 'win32') {
    platform = '-win';
  }
  return gulp.src(
      ['./{lib,examples}/**/*.{js,glsl,png,ttf,obj}','bin/play*','LICENSE'])
    .pipe(zip('gameplay-v' + pkg.version + platform + '.zip'))
    .pipe(gulp.dest('dist'));
});

gulp.task('default', seq('clean','dist'));

var gulp = require('gulp');
var del = require('del');
var seq = require('gulp-sequence');
var zip = require('gulp-zip');
var pkg = require('./package.json');

gulp.task('clean', function (cb) {
  del(['dist/**/*'], cb);
});

gulp.task('dist', function() {
  var platform = '';
  if (process.platform === 'darwin') {
    platform = '-osx';
  } else if (process.platform === 'win32') {
    platform = '-win';
  }
  return gulp.src(
      ['./{lib,examples,bin}/**/*','LICENSE'])
    .pipe(zip('gameplay-v' + pkg.version + platform + '.zip'))
    .pipe(gulp.dest('dist'));
});

gulp.task('default', seq('clean','dist'));

Include all files in lib, examples and bin.


var gulp = require('gulp');
var less = require('gulp-less');
var exec = require('child_process').exec;
var sourcemaps = require('gulp-sourcemaps');
var csso = require('gulp-csso');
var rename = require('gulp-rename');

function run(command) {
  var child = exec(command);
  child.stdout.pipe(process.stdout);
  child.stderr.pipe(process.stderr);
  process.on('exit', function(code) {
    if (child.exit) { child.exit(code); }
  });
  child.on('exit', function(code) {
    process.exit(code);
  });
}

gulp.task('less', function() {
  gulp.src('public/less/main.less')
    .pipe(sourcemaps.init())
    .pipe(less())
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('public/css'));
});

gulp.task('cssmin', function() {
  gulp.src('public/css/main.css')
    .pipe(csso())
    .pipe(rename({
      suffix: '.min'
    }))
    .pipe(gulp.dest('public/css'));
});

gulp.task('watch', function() {
  run('npm run watchify');
  run('npm run watchify-test');
  gulp.watch('public/less/**/*.less', ['less']);
});

gulp.task('dev', ['default'], function() {
  run('npm start');
});

gulp.task('css', ['less', 'cssmin']);

gulp.task('default', ['less', 'watch']);

var gulp = require('gulp');
var less = require('gulp-less');
var exec = require('child_process').exec;
var sourcemaps = require('gulp-sourcemaps');
var csso = require('gulp-csso');
var rename = require('gulp-rename');

function run(command) {
  var child = exec(command);
  child.stdout.pipe(process.stdout);
  child.stderr.pipe(process.stderr);
  process.on('exit', function(code) {
    if (child.exit) { child.exit(code); }
  });
  child.on('exit', function(code) {
    process.exit(code);
  });
}

gulp.task('less', function() {
  return gulp.src('public/less/main.less')
    .pipe(sourcemaps.init())
    .pipe(less())
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('public/css'));
});

gulp.task('cssmin', ['less'], function() {
  return gulp.src('public/css/main.css')
    .pipe(csso())
    .pipe(rename({
      suffix: '.min'
    }))
    .pipe(gulp.dest('public/css'));
});

gulp.task('watch', function() {
  run('npm run watchify');
  run('npm run watchify-test');
  gulp.watch('public/less/**/*.less', ['less']);
});

gulp.task('dev', ['default'], function() {
  run('npm start');
});

gulp.task('css', ['less', 'cssmin']);

gulp.task('default', ['less', 'watch']);

Add correct dependencies to gulp tasks


import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

import "malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar";
import "malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.css";
import "jquery-mousewheel/jquery.mousewheel";

const mountApp = () => {
  ReactDOM.render(<App />, document.getElementById("root"));
};

if (window.fin) {
  window.fin.desktop.main(mountApp);
} else {
  console.error("This application can only be run in an OpenFin container.");
}

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

const mountApp = () => {
  ReactDOM.render(<App />, document.getElementById("root"));
};

if (window.fin) {
  window.fin.desktop.main(mountApp);
} else {
  console.error("This application can only be run in an OpenFin container.");
}

Remove malihu custom scrollbar plugin usage from watchlist


require("./spec_helper.js");

describe('Initializer', function() {
  var initializer;
  var recordType  = 'salesorder';
  var blankRecord = { 'recordtype': recordType };
  global.nlapiInitializeRecord = function () {};

  beforeEach(function() {
    initializer = new Initializer(recordType);
    spyOn(global, 'nlapiInitializeRecord').andReturn(blankRecord);
  });

  describe('#init', function() {
    it("should set the record type", function(){
      expect(initializer.recordType).toEqual(recordType);
    });
  });

  describe('#initializeRecord', function() {
    it("should call initialize record from the Netsuite API", function() {
      initializer.initializeRecord();
      expect(global.nlapiInitializeRecord).toHaveBeenCalled();
    });
  });

  describe('#reply', function() {
    it("should return the blank record in a formatted reply", function() {
      initializer.initializeRecord();
      var formattedReply = initializer.common.formatReply(initializer.recordType,
                                                          initializer.initializedRecord,
                                                          initializer.exception)
      expect(initializer.reply()).toEqual(formattedReply);
    });
  });
});

require("./spec_helper.js");

describe('Initializer', function() {
  var initializer;
  var recordType  = 'salesorder';
  var blankRecord = { 'recordtype': recordType };
  global.nlapiInitializeRecord = function () {};

  beforeEach(function() {
    initializer = new Initializer(recordType);
    spyOn(global, 'nlapiInitializeRecord').andReturn(blankRecord);
  });

  describe('#init', function() {
    it("should set the record type", function(){
      expect(initializer.recordType).toEqual(recordType);
    });
  });

  describe('#initializeRecord', function() {
    beforeEach(function() {
      initializer.initializeRecord();
    });

    it("should call initialize record from the Netsuite API", function() {
      expect(global.nlapiInitializeRecord).toHaveBeenCalled();
    });

    it("should update the initializedRecord field with the new record", function() {
      expect(initializer.initializedRecord).toEqual(blankRecord);
    });
  });

  describe('#reply', function() {
    it("should return the blank record in a formatted reply", function() {
      initializer.initializeRecord();
      var formattedReply = initializer.common.formatReply(initializer.recordType,
                                                          initializer.initializedRecord,
                                                          initializer.exception)
      expect(initializer.reply()).toEqual(formattedReply);
    });
  });
});

Add test to check intializedRecord value


(function() {
	'use strict';
	angular.module('pagespeedApp').controller('pagespeedQueryFormController', pagespeedQueryForm);

	pagespeedQueryForm.$inject = ['pagespeedApi'];

	function pagespeedQueryForm(pagespeedApi) {
		var vm = this;

		vm.url = '';
		vm.submit = submit;

		function submit() {
			pagespeedApi.run(vm.url);
		}
	}
})();

(function() {
	'use strict';
	angular.module('pagespeedApp').controller('pagespeedQueryFormController', pagespeedQueryForm);

	pagespeedQueryForm.$inject = ['pagespeedApi'];

	function pagespeedQueryForm(pagespeedApi) {
		var vm = this;

		vm.url = '';
		vm.submit = submit;
		vm.canNotSubmit = canNotSubmit;

		function submit() {
			pagespeedApi.run(vm.url);
		}

		function canNotSubmit() {
			// On chrome since input[type=url] remains undefined unless value is actually a valid URL
			return !vm.url; // FIXME also check if API key is set
		}
	}
})();

Disable query form submissions when invalid


import React from 'react';
import PropTypes from 'prop-types';
import Input from 'react-toolbox/lib/input/Input';

const sectionStyle = {
  marginLeft: "2.5rem",
  marginRight: "2.5rem",
}
const SearchForm = (props) => (
  <section style={sectionStyle}>
    <form onSubmit={props.handleSubmit}>
      <Input
        type='text'
        label='Search by City'
        value={props.city}
        onChange={props.handleInputChange}
        maxLength={200} />
    </form>
  </section>
);

export default SearchForm;

SearchForm.propTypes = {
  city: PropTypes.string.isRequired,
  handleSubmit: PropTypes.func.isRequired,
  handleInputChange: PropTypes.func.isRequired
}

import React from 'react';
import PropTypes from 'prop-types';
import Input from 'react-toolbox/lib/input/Input';

const sectionStyle = {
  marginLeft: "2.5rem",
  marginRight: "2.5rem",
}
const SearchForm = (props) => (
  <section style={sectionStyle}>
    <form onSubmit={props.handleSubmit}>
      <Input
        type='text'
        aria-label='Search'
        label='Search by City'
        value={props.city}
        onChange={props.handleInputChange}
        maxLength={200} />
    </form>
  </section>
);

export default SearchForm;

SearchForm.propTypes = {
  city: PropTypes.string.isRequired,
  handleSubmit: PropTypes.func.isRequired,
  handleInputChange: PropTypes.func.isRequired
}

Add an aria-label attr to our input control for better accessibility.


import React from 'react'

import styles from './event-bets.module.styl'

export default ({ betTypes }) => (

      {betTypes.map((betType, idx) => (

          {betType.name}

            {betType.options.map((option, idx) => (

                    {option.map((nameValue, idx) => (

                        <button type='button' title={nameValue.name}>
                          {nameValue.value}
                        </button>

                    ))}

            ))}

      ))}

)

import React from 'react'

import styles from './event-bets.module.styl'

export default ({ betTypes, optionClickHandler = () => {} }) => (

      {betTypes.map((betType, idx) => (

          {betType.name}

            {betType.options.map((option, idx) => (

                    {option.map((nameValue, idx) => (

                        <button
                          type='button'
                          title={nameValue.name}
                          onClick={optionClickHandler({
                            betTypeName: betType.name,
                            oddName: nameValue.name,
                            oddValue: nameValue.value
                          })}
                        >
                          {nameValue.value}
                        </button>

                    ))}

            ))}

      ))}

)

Handle events' odd button click: - pass values to parent using props function;


import { MicroState } from 'ember-microstates';

export default MicroState.extend({

  initialValueFor([array]) {
    if (array === undefined) {
      return [];
    } else if (array && array.length != null && array.forEach) {
      return array;
    } else {
      return [ array ];
    }
  },

  prototypeFor(value = []) {
    let wrapped = value.slice();

    Object.defineProperty(wrapped, 'valueOf', {
      value() {
        return value;
      }
    });

    return wrapped;
  },

  actions: {
    add(list, item) {
      return list.concat(item);
    },
    remove(list, item) {
      return list.filter(i => i !== item);
    },
    push(list, item) {
      return list.concat(item);
    },
    pop(list) {
      return list.slice(0, list.length - 1);
    },
    shift(list) {
      return list.slice(1);
    },
    unshift(list, item) {
      return [item].concat(list);
    }
  }
});

import { MicroState } from 'ember-microstates';

export default MicroState.extend({

  initialValueFor([array]) {
    if (array === undefined) {
      return [];
    } else if (array instanceof Array) {
      return array;
    } else {
      return [ array ];
    }
  },

  prototypeFor(value = []) {
    let wrapped = value.slice();

    Object.defineProperty(wrapped, 'valueOf', {
      value() {
        return value;
      }
    });

    return wrapped;
  },

  actions: {
    add(list, item) {
      return list.concat(item);
    },
    remove(list, item) {
      return list.filter(i => i !== item);
    },
    push(list, item) {
      return list.concat(item);
    },
    pop(list) {
      return list.slice(0, list.length - 1);
    },
    shift(list) {
      return list.slice(1);
    },
    unshift(list, item) {
      return [item].concat(list);
    }
  }
});

Use instanstanceof Array when checking for array


import React from 'react';
import assign from 'object-assign';
import History from './History';
import Location from './Location';
import { getWindowScrollPosition } from './DOMUtils';

/**
 * A history interface that assumes a DOM environment.
 */
class DOMHistory extends History {

  static propTypes = assign({
    getScrollPosition: React.PropTypes.func.isRequired
  }, History.propTypes);

  static defaultProps = assign({
    getScrollPosition: getWindowScrollPosition
  }, History.defaultProps);

  static childContextTypes = assign({}, History.childContextTypes);

  constructor(props, context) {
    super(props, context);
    this.scrollHistory = {};
  }

  createLocation(path, query, navigationType, key) {
    var fullPath = this.makePath(path, query);
    var scrollPosition = this.scrollHistory[fullPath];

    return new Location(path, query, navigationType, key, scrollPosition);
  }

  go(n) {
    if (n === 0)
      return;

    window.history.go(n);
  }

  recordScrollPosition() {
    var renderedLocation = this.state.location;
    var renderedFullPath = this.makePath(renderedLocation.path, renderedLocation.query);

    this.scrollHistory[renderedFullPath] = this.props.getScrollPosition();
  }

}

export default DOMHistory;

import React from 'react';
import assign from 'object-assign';
import History from './History';
import Location from './Location';
import { getWindowScrollPosition } from './DOMUtils';

/**
 * A history interface that assumes a DOM environment.
 */
class DOMHistory extends History {

  static propTypes = assign({
    getScrollPosition: React.PropTypes.func.isRequired
  }, History.propTypes);

  static defaultProps = assign({
    getScrollPosition: getWindowScrollPosition
  }, History.defaultProps);

  static childContextTypes = assign({}, History.childContextTypes);

  constructor(props, context) {
    super(props, context);
    this.scrollHistory = {};
  }

  getScrollKey(path, query, key) {
    return key || this.makePath(path, query);
  }

  createLocation(path, query, navigationType, key) {
    var scrollKey = this.getScrollKey(path, query, key);
    var scrollPosition = this.scrollHistory[scrollKey];

    return new Location(path, query, navigationType, key, scrollPosition);
  }

  go(n) {
    if (n === 0)
      return;

    window.history.go(n);
  }

  recordScrollPosition() {
    var location = this.state.location;
    var scrollKey = this.getScrollKey(location.path, location.query, location.key);

    this.scrollHistory[scrollKey] = this.props.getScrollPosition();
  }

}

export default DOMHistory;

Use location.key for storing scroll position when available


// find longest phrase
// input is array of strings
// create variable longest, set it equal to empty strings
// for each string in the array, check to see if its length is longer than longest
// if so, replace longest with that word
// return longest after loop

function longestFinder(array) {
  longest = ""
  for (i = 0; i < array.length; i++) {
    if (array[i].length > longest.length) {
      longest = array[i]
    }
  }
  console.log(longest)
  return longest
}

// driver code to test longestFinder
longestFinder(["long phrase","longest phrase","longer phrase"])
longestFinder(["cat", "kitten", "pterodactyl"])
longestFinder(["is this", "that it is", "that which it is is that"])

// LONGEST PHASE ALGO
// input is array of strings
// create variable longest, set it equal to empty strings
// for each string in the array, check to see if its length is longer than longest
// if so, replace longest with that word
// return longest after loop

function longestFinder(array) {
  longest = ""
  for (i = 0; i < array.length; i++) {
    if (array[i].length > longest.length) {
      longest = array[i]
    }
  }
  console.log(longest)
  return longest
}

// SHARED KEY VALUE PAIR ALGO
// input is two objects
// create sameKey object, which is empty
// create pairMatch variable and set to false
// for each item in the first object,
//   check to see if it matches any of the items in the second object (nested for loop)
//   if it does, add both objects to sameKey
// then for each even + odd index in sameKey, check if those keys have the same value
// if they do change pairMatch to true
// once a true pair has been found, stop looking
// return pairMatch

// function pairChecker(firstObj, secondObj) {
//   sameKey = {};
//   var pairMatch = false;
//   for (i = 0; i < firstObj.length; i++) {
//     for (i = 0; i < secondObj.length; i++) {
//       if firstObj
//     };

//   }

// }

// ———————————————————————————————————— DRIVER CODE ———————————————————————————————————— //

// testing longest phrase
longestFinder(["long phrase","longest phrase","longer phrase"])
longestFinder(["cat", "kitten", "pterodactyl"])
longestFinder(["is this", "that it is", "that which it is is that"])

Add pseduocode for key value pair algo


CRM.$(function ($) {
// Code goes here!
  $('.fast-action-link').click(function () {
    // Suppress the link-following behavior
    alert('hello');
    return false;
  });
});

CRM.$(function ($) {
// Code goes here!
  $('.fast-action-link').click(function () {
    // Suppress the link-following behavior
    console.log($(this));
    return false;
  });
});

Improve my JS debugging statement


module.exports = (function() {

  "use strict";

  const Nodal = require('nodal');
  const zlib = require('zlib');

  class GzipMiddleware extends Nodal.Middleware {

    exec(controller, data, callback) {

      let contentType = controller.getHeader('Content-Type', '').split(';')[0];

      let acceptEncoding = controller._request.headers['accept-encoding'] || '';
      let canCompress = !!{
        'text/plain': 1,
        'text/html': 1,
        'text/xml': 1,
        'text/json': 1,
        'text/javascript': 1,
        'application/json': 1,
        'application/xml': 1,
        'application/javascript': 1,
        'application/octet-stream': 1
      }[contentType];

      if (canCompress) {

        if (acceptEncoding.match(/\bgzip\b/)) {

          zlib.gzip(data, function(err, result) {
            if (!err) {
              controller.setHeader('Content-Encoding', 'gzip');
              callback(null, result);
              return;
            }
            callback(null, data);
          });

          return true;

        } else if(acceptEncoding.match(/\bdeflate\b/)) {

          zlib.deflate(data, function(err, result) {
            if (!err) {
              controller.setHeader('Content-Encoding', 'deflate');
              callback(null, result);
              return;
            }
            callback(null, data);
          });
          return true;

        }

      }

      callback(null, data);
      return false;

    }

  }

  return GzipMiddleware;

})();

module.exports = (function() {

  "use strict";

  const Nodal = require('nodal');
  const zlib = require('zlib');

  class GzipRenderware extends Nodal.Renderware {

    exec(controller, data, callback) {

      let contentType = controller.getHeader('Content-Type', '').split(';')[0];

      let acceptEncoding = controller._request.headers['accept-encoding'] || '';
      let canCompress = !!{
        'text/plain': 1,
        'text/html': 1,
        'text/xml': 1,
        'text/json': 1,
        'text/javascript': 1,
        'application/json': 1,
        'application/xml': 1,
        'application/javascript': 1,
        'application/octet-stream': 1
      }[contentType];

      if (canCompress) {

        if (acceptEncoding.match(/\bgzip\b/)) {

          zlib.gzip(data, function(err, result) {
            if (!err) {
              controller.setHeader('Content-Encoding', 'gzip');
              callback(null, result);
              return;
            }
            callback(null, data);
          });

          return true;

        } else if(acceptEncoding.match(/\bdeflate\b/)) {

          zlib.deflate(data, function(err, result) {
            if (!err) {
              controller.setHeader('Content-Encoding', 'deflate');
              callback(null, result);
              return;
            }
            callback(null, data);
          });
          return true;

        }

      }

      callback(null, data);
      return false;

    }

  }

  return GzipRenderware;

})();

Add renderware to generated apps


/**
 * Run test specs in node environment
 * Usage:
 *   $ cd seajs
 *   $ node tests/runner-node.js
 */

require('../lib/sea')

define('./tests/node-runner', function(require) {
  var test = require('./test')

  var suites = require('./meta').map(function(suite) {
    return './' + suite + '/meta'
  })

  require.async(suites, function() {
    var args = [].slice.call(arguments)
    var specs = []

    args.forEach(function(meta, i) {
      specs = specs.concat(meta.map(function(spec) {
        return suites[i].split('/')[2] + '/' + spec
      }))
    })

    var total = specs.length
    var time = Date.now()
    test.run(specs)

    test.print('Summary')
    test.print(total + ' suites in ' + (Date.now() - time) / 1000 + 's')
    test.print('END')
  })

})

seajs.use('./tests/node-runner')

/**
 * Run test specs in node environment
 * Usage:
 *   $ cd seajs
 *   $ node tests/runner-node.js
 */

require('../lib/sea.js')

define('./tests/node-runner', function(require) {
  var test = require('./test')

  var suites = require('./meta').map(function(suite) {
    return './' + suite + '/meta'
  })

  require.async(suites, function() {
    var args = [].slice.call(arguments)
    var specs = []

    args.forEach(function(meta, i) {
      specs = specs.concat(meta.map(function(spec) {
        return suites[i].split('/')[2] + '/' + spec
      }))
    })

    var total = specs.length
    var time = Date.now()
    test.run(specs)

    test.print('Summary')
    test.print(total + ' suites in ' + (Date.now() - time) / 1000 + 's')
    test.print('END')
  })

})

seajs.use('./tests/node-runner')

Add .js extension for require


'use strict';

angular.module('ngGcHttpProviderConfig', [
  'gc.ngHttpGetParamInterceptor'
]).config([
  '$httpProvider',
  function($httpProvider) {

    var clientVersion = window.AppConfig && window.AppConfig.clientVersion;

    $httpProvider.defaults.headers.common.Accept = 'application/json';
    $httpProvider.defaults.headers.common['CLIENT-VERSION'] = clientVersion;

    $httpProvider.interceptors.push('httpGetParamInterceptor');
  }
]);

'use strict';

angular.module('ngGcHttpProviderConfig', [
  'gc.ngHttpGetParamInterceptor'
]).config([
  '$httpProvider',
  function($httpProvider) {

    var clientVersion = window.AppConfig && window.AppConfig.clientVersion;

    $httpProvider.defaults.headers.common.Accept = 'application/json';
    $httpProvider.defaults.headers.common['CLIENT-VERSION'] = clientVersion;
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRF-Token';

    $httpProvider.interceptors.push('httpGetParamInterceptor');
  }
]);

Set the right header for rails


define(function (require) {
  'use strict';

  var modules = require('modules');
  var _ = require('lodash');

  var alien4cloud = modules.get('alien4cloud');

  // defines layout controller
  alien4cloud.controller('LayoutCtrl', ['$scope', 'menu', 'authService', 'context',
    function( $scope, menu, authService, context) {
      $scope.context = context;
      _.each(menu, function(menuItem) {
        menuItem.show = false;
        if (authService.hasRole('ADMIN')) {
          menuItem.show = true;
        } else if(_.has(menuItem, 'roles')) {
          for (var role in menuItem.roles) {
            if (authService.hasRole(role)) {
              menuItem.show = true;
              break;
            }
          }
        } else { // if there is no roles requirement or if it's an ADMIN then the menu is visible
          menuItem.show = true;
        }
      });
      $scope.menu = menu;
    }
   ]);

  return alien4cloud;
});

define(function (require) {
  'use strict';

  var modules = require('modules');
  var _ = require('lodash');

  var alien4cloud = modules.get('alien4cloud');

  // defines layout controller
  alien4cloud.controller('LayoutCtrl', ['$scope', 'menu', 'authService', 'context',
    function( $scope, menu, authService, context) {
      $scope.context = context;
      _.each(menu, function(menuItem) {
        menuItem.show = false;
        if (authService.hasRole('ADMIN')) {
          menuItem.show = true;
        } else if(_.has(menuItem, 'roles')) {
          _.every(menuItem.roles, function(role){
            if (authService.hasRole(role)) {
              menuItem.show = true;
              return false; // stop the every loop
            }
          });
        } else { // if there is no roles requirement or if it's an ADMIN then the menu is visible
          menuItem.show = true;
        }
      });
      $scope.menu = menu;
    }
   ]);

  return alien4cloud;
});

Fix issue with component manager role and side menu.


'use strict';

/* jasmine specs for directives go here */

describe('directives', function() {
  beforeEach(module('myApp.directives'));

  describe('app-version', function() {
    it('should print current version', function() {
      module(function($provide) {
        $provide.value('version', 'TEST_VERSION');
      });
      inject(function($compile, $rootScope) {
        var element = $compile('')($rootScope);
        expect(element.text()).toEqual('TEST_VERSION');
      });
    });
  });

  describe('entity', function() {
    it('should make the div draggable and resizable', function() {
      inject(function($compile, $rootScope) {
        var element = $compile('

')($rootScope);
        expect(element).toHaveClass('ui-draggable')
        expect(element).toHaveClass('ui-resizable')
      });
    });
  });
});

'use strict';

/* jasmine specs for directives go here */

describe('directives', function() {
  beforeEach(module('myApp.directives'));

  describe('app-version', function() {
    it('should print current version', function() {
      module(function($provide) {
        $provide.value('version', 'TEST_VERSION');
      });
      inject(function($compile, $rootScope) {
        var element = $compile('')($rootScope);
        expect(element.text()).toEqual('TEST_VERSION');
      });
    });
  });

  describe('entity', function() {
    // source: http://docs.angularjs.org/guide/dev_guide.unit-testing
    var $compile;
    var $rootScope;
    beforeEach(inject(function(_$compile_, _$rootScope_){
      $compile = _$compile_;
      $rootScope = _$rootScope_;
    }));

    it('should make the div draggable and resizable', function() {
      var element = $compile('

')($rootScope);
      expect(element).toHaveClass('ui-draggable')
      expect(element).toHaveClass('ui-resizable')
    });

    it('should bind the element position to the scope variable', function() {
      var element = $compile('

')($rootScope);
      element.scope().entity = { x: '120', y: '90' }
      element.scope().$digest()
      expect(element.css('left')).toBe('120px')
      expect(element.css('top')).toBe('90px')
    })
  });
});

Add unit test for entity directive


/* eslint-env node */

'use strict';

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

// Semantic actions for the `mentionsThis` attribute, which returns true for a node
// if the `this` keyword appears anywhere in the node's subtree, and otherwise false.
var mentionsThisActions = {
  'this': function(_) { return true; },
  _terminal: function() { return false; },
  _default: anyNodesMentionThis,
  _iter: anyNodesMentionThis
};

function anyNodesMentionThis(nodes) {
  return nodes.some(function(n) { return n.mentionsThis; });
}

var modifiedSourceActions = {
  ArrowFunction: function(params, _, body) {
    var source = 'function ' + params.asES5 + ' ' + body.asES5;
    // Only use `bind` if necessary.
    return body.mentionsThis ? source + '.bind(this)' : source;
  },
  ArrowParameters_unparenthesized: function(id) {
    return '(' + id.asES5 + ')';
  },
  ConciseBody_noBraces: function(exp) {
    return '{ return ' + exp.asES5 + ' }';
  }
};

module.exports = function(ohm, ns, s) {
  var g = ohm.grammar(fs.readFileSync(path.join(__dirname, 'es6.ohm')).toString(), ns);
  var semantics = g.extendSemantics(s);
  semantics.extendAttribute('modifiedSource', modifiedSourceActions);
  semantics.addAttribute('mentionsThis', mentionsThisActions);

  return {
    grammar: g,
    semantics: semantics
  };
};

/* eslint-env node */

'use strict';

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

// Semantic actions for the `mentionsThis` attribute, which returns true for a node
// if the `this` keyword appears anywhere in the node's subtree, and otherwise false.
var mentionsThisActions = {
  this: function(_) { return true; },
  _terminal: function() { return false; },
  _default: anyNodesMentionThis,
  _iter: anyNodesMentionThis
};

function anyNodesMentionThis(nodes) {
  return nodes.some(function(n) { return n.mentionsThis; });
}

var modifiedSourceActions = {
  ArrowFunction: function(params, _, body) {
    var source = 'function ' + params.asES5 + ' ' + body.asES5;
    // Only use `bind` if necessary.
    return body.mentionsThis ? source + '.bind(this)' : source;
  },
  ArrowParameters_unparenthesized: function(id) {
    return '(' + id.asES5 + ')';
  },
  ConciseBody_noBraces: function(exp) {
    return '{ return ' + exp.asES5 + ' }';
  }
};

module.exports = function(ohm, ns, s) {
  var g = ohm.grammar(fs.readFileSync(path.join(__dirname, 'es6.ohm')).toString(), ns);
  var semantics = g.extendSemantics(s);
  semantics.extendAttribute('modifiedSource', modifiedSourceActions);
  semantics.addAttribute('mentionsThis', mentionsThisActions);

  return {
    grammar: g,
    semantics: semantics
  };
};

Fix jscs -- apparently `this` can be unquoted in an object literal?