angular.module('cat-buddy', [
  'ngRoute'
])
.config(function($routeProvider) {
  $routeProvider
    .when('/search/cats', {
      templateUrl: 'app/search/cat/searchCats.html',
      controller: ''
    })
    .when('/saved/cats', {
      templateUrl: 'app/saved/cat/savedCats.html',
      controller: ''
    })
    .otherwise({
      redirectTo: '/search/cats'
    });
});

angular.module('cat-buddy', [
  'ngRoute',
  'cat-buddy.services',
  'cat-buddy.search-cats',
  'cat-buddy.saved-cats'
])
.config(function($routeProvider) {
  $routeProvider
    .when('/search/cats', {
      templateUrl: 'app/search/cat/searchCats.html',
      controller: 'SearchCatsController'
    })
    .when('/saved/cats', {
      templateUrl: 'app/saved/cat/savedCats.html',
      controller: 'SavedCatsController'
    })
    .otherwise({
      redirectTo: '/search/cats'
    });
});

Add dependencies and controllers for cat-buddy app


Template.body.onRendered(function () {
  console.log("Body Rendered");
  Meteor.call('deleteFlaggedTransactions', false);
  $("#page-header").headroom({
    "offset": 0,
    "tolerance": 35
  });
});

Template.vendor.onRendered(function () {
  Meteor.typeahead.inject($(this.find('.typeahead')));
});

Template.category.onRendered(function () {
  Meteor.typeahead.inject($(this.find('.typeahead')));
});

Template.date.onRendered(function () {
  $(".datepicker").datepicker();
});

Template.body.onRendered(function () {
  console.log("Body Rendered");
  Meteor.call('deleteFlaggedTransactions', false);
  if(Meteor.Device.isPhone() || Meteor.DeviceisTablet()){
    $("#page-header").headroom({
      "offset": 0,
      "tolerance": 35
    });
  }
});

Template.vendor.onRendered(function () {
  Meteor.typeahead.inject($(this.find('.typeahead')));
});

Template.category.onRendered(function () {
  Meteor.typeahead.inject($(this.find('.typeahead')));
});

Template.date.onRendered(function () {
  $(".datepicker").datepicker();
});

Add conditional for headroom (desktop)


// Exercise 3
//
// 1. Building on Exercise 2, implement the following methods:
//
// age() - returns the age of the car.
// setYear()
// getYear()
// setMake()
// getMake()
// setModel()
// getModel()
// setColor()
// getColor()
// Include validity checking for setYear().

// 2. Modify the constructor you have written so that the mileage is
//    passed in as a parameter and recorded as an attribute.

// 3.  Add accessors for the new mileage.  For validity, ensure that the
//     mileage for a car can never be decreased.

// Exercise 3
//
// 1. Building on Exercise 2, implement the
// following methods:
//
// setYear()
// getYear()
// setMake()
// getMake()
// setModel()
// getModel()
// setColor()
// getColor()
// Include validity checking for setYear().

// 2. Modify the constructor you have written so
// that the mileage is passed in as a parameter
// and recorded as an attribute.

// 3.  Add accessors for the new mileage.  For
// validity, ensure that the mileage for a car
// can never be decreased.

// 4. The database backing our list of cars only
// recognizes seven colors, plus none.
//
// Make sure that when a car color is set, it is
// in the list: red, orange, black, green, blue,
// purple, and white.  "None" is also allowed and
// should be the default.
//
// Modify the constructor so that if you pass it
// an unrecognized color, it stores the string
// "none" instead. If a programmer passes an
// unrecognized color to the accessor function,
// you should write a message to the console and
// make no change to the object.

Add one more exercise, clean up the format


import buffer from '../buffer';

function eventsource({ url, bufferTime = 0 }, { feed, reset, onFinish }) {
  let es;
  let buf;

  function initBuffer() {
    if (buf !== undefined) buf.stop();
    buf = buffer(feed, bufferTime);
  }

  return {
    start: () => {
      es = new EventSource(url);

      es.addEventListener('open', () => {
        console.debug('eventsource: opened');
        initBuffer();
      });

      es.addEventListener('message', event => {
        const e = JSON.parse(event.data);

        if (e.cols !== undefined || e.width !== undefined) {
          initBuffer();
          reset(e.cols ?? e.width, e.rows ?? e.height);
        } else {
          buf.pushEvent(e);
        }
      });

      es.addEventListener('done', () => {
        console.debug('eventsource: closed');
        es.close();
        onFinish();
      });
    },

    stop: () => {
      if (buf !== undefined) buf.stop();
      if (es !== undefined) es.close();
    }
  }
}

export { eventsource };

import buffer from '../buffer';

function eventsource({ url, bufferTime = 0 }, { feed, reset, setWaiting, onFinish }) {
  let es;
  let buf;

  function initBuffer() {
    if (buf !== undefined) buf.stop();
    buf = buffer(feed, bufferTime);
  }

  return {
    start: () => {
      es = new EventSource(url);

      es.addEventListener('open', () => {
        console.debug('eventsource: opened');
        setWaiting(false);
        initBuffer();
      });

      es.addEventListener('error', e => {
        console.debug('eventsource: errored');
        console.debug(e);
        setWaiting(true);
      });

      es.addEventListener('message', event => {
        const e = JSON.parse(event.data);

        if (e.cols !== undefined || e.width !== undefined) {
          initBuffer();
          reset(e.cols ?? e.width, e.rows ?? e.height);
        } else {
          buf.pushEvent(e);
        }
      });

      es.addEventListener('done', () => {
        console.debug('eventsource: closed');
        es.close();
        onFinish();
      });
    },

    stop: () => {
      if (buf !== undefined) buf.stop();
      if (es !== undefined) es.close();
    }
  }
}

export { eventsource };

Use loading indicator with EventSource (SSE) driver


var dataSource = require('./modules/db');

dataSource.discoverSchema('account', {owner: 'demo'}, function (err, schema) {
    console.log(JSON.stringify(schema, null, '  '));
});

dataSource.discoverAndBuildModels('account', {}, function (err, models) {
    models.Account.find(function (err, act) {
        if (err) {
            console.error(err);
        } else {
            console.log(act);
        }
    });
});

var dataSource = require('./modules/db');

dataSource.discoverSchema('account', {owner: 'demo'}, function (err, schema) {
    console.log(JSON.stringify(schema, null, '  '));
});

dataSource.discoverAndBuildModels('account', {owner: 'demo'}, function (err, models) {
    models.Account.find(function (err, act) {
        if (err) {
            console.error(err);
        } else {
            console.log(act);
        }
    });
});

Add onwer option to avoid confusions over other dbs


(function() {
    'use strict';

    openerp.Tour.register({
        id: 'test_instance_introspection',
        name: 'Complete a basic order trough the Front-End',
        path: '/instance_introspection',
        mode: 'test',
        steps: [
            {
                title: 'Wait for the main screen',
                waitFor: 'h3:contains("Addons Paths"),#accordion.results',
                element: '.btn-reload',
                wait: 200,
            },
            {
                title:  'Load Repositories',
                waitFor: '#accordion.results',
            },
        ],
    });

})();

(function() {
    'use strict';

    openerp.Tour.register({
        id: 'test_instance_introspection',
        name: 'Complete a basic order trough the Front-End',
        path: '/instance_introspection',
        mode: 'test',
        steps: [
            {
                title: 'Wait for the main screen',
                waitFor: 'h3:contains("Addons Paths"),#accordion.results',
                element: '.btn-reload',
            },
            {
                title:  'Load Repositories',
                waitFor: '#accordion.results',
            },
        ],
    });

})();

Test should not have wait if thy are long by default.


'use strict';

// Formulas are deprecated, we're now using meter, accumulate, aggregate
// and rate Javascript functions instead

module.exports = {
  resource_id: 'analytics',
  measures: [
    {
      name: 'classifiers',
      unit: 'INSTANCE'
    },
    {
      name: 'classifier_api_calls',
      unit: 'CALL'
    },
    {
      name: 'training_event_api_calls',
      unit: 'CALL'
    }],
  metrics: [
    {
      name: 'classifier_instances',
      unit: 'INSTANCE',
      formula: 'AVG({classifier})'
    },
    {
      name: 'classifier_api_calls',
      unit: 'CALL',
      formula: 'SUM({classifier_api.calls})'
    },
    {
      name: 'training_event_api_calls',
      unit: 'CALL',
      formula: 'SUM({training_event_api_calls})'
    }]
};

'use strict';

// A sample analytics service that uses metering formulas

// Formulas are deprecated, we're now using meter, accumulate, aggregate
// and rate Javascript functions instead

module.exports = {
  resource_id: 'analytics',
  measures: [
    {
      name: 'classifiers',
      unit: 'INSTANCE'
    },
    {
      name: 'classifier_api_calls',
      unit: 'CALL'
    },
    {
      name: 'training_event_api_calls',
      unit: 'CALL'
    }],
  metrics: [
    {
      name: 'classifier_instances',
      unit: 'INSTANCE',
      formula: 'AVG({classifier})'
    },
    {
      name: 'classifier_api_calls',
      unit: 'CALL',
      formula: 'SUM({classifier_api.calls})'
    },
    {
      name: 'training_event_api_calls',
      unit: 'CALL',
      formula: 'SUM({training_event_api_calls})'
    }]
};

Add header comment to sample resource config


"use strict";

var yeoman = require("yeoman-generator");
var incSay = require("incubator-say");
var util   = require("util");
var path   = require("path");

var IncubatorGenerator = module.exports = function IncubatorGenerator (args) {
	yeoman.generators.Base.apply(this, arguments);

	this.argument("appname", { type : String, required : false });
	this.appname = this.appname || path.basename(process.cwd());
	this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname)));

	this.option("skip-welcome-message", {
		desc     : "Do not print out the welcome message.",
		type     : Boolean,
		defaults : true
	});

	this.option("skip-core", {
		desc     : "Skip core installation.",
		type     : Boolean,
		defaults : true
	});

	if (!this.options["skip-welcome-message"]) {
		this.log(incSay("Welcome to the Incubator Generator!"));
		this.log("By default I will create a Gruntfile and all dotfiles required to work");
		this.log("with the Bandwidth Incubator build pipeline.");
		this.log();
	}

	if (!this.options["skip-core"]) {
		this.invoke("incubator:core", args);
	}
};

util.inherits(IncubatorGenerator, yeoman.generators.Base);

"use strict";

var yeoman = require("yeoman-generator");
var incSay = require("incubator-say");
var util   = require("util");
var path   = require("path");

var IncubatorGenerator = module.exports = function IncubatorGenerator () {
	yeoman.generators.Base.apply(this, arguments);

	this.argument("appname", { type : String, required : false });
	this.appname = this.appname || path.basename(process.cwd());
	this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname)));

	this.option("skip-welcome-message", {
		desc : "Do not print out the welcome message.",
		type : Boolean
	});

	this.option("skip-core", {
		desc : "Skip core installation.",
		type : Boolean
	});
};

util.inherits(IncubatorGenerator, yeoman.generators.Base);

IncubatorGenerator.prototype.greeting = function greeting () {
	if (!this.options["skip-welcome-message"]) {
		this.log(incSay("Welcome to the Incubator Generator!"));
		this.log("By default I will create a Gruntfile and all dotfiles required to work");
		this.log("with the Bandwidth Incubator build pipeline.");
		this.log();
	}
};

IncubatorGenerator.prototype.components = function components () {
	if (!this.options["skip-core"]) {
		this.invoke("incubator:core", this.args);
	}
};

Move greeting and invocation of sub generators to methods


import { createStore, combineReducers } from 'redux'

import Tasks from './reducers/Tasks'

export default createStore(
  combineReducers(
    {
      tasks: Tasks
    }
  )
)

import { applyMiddleware, combineReducers, createStore } from 'redux'

import Tasks from './reducers/Tasks'

export default createStore(
  combineReducers(
    {
      tasks: Tasks
    }
  ),
  applyMiddleware(

  )
)

Add a place to the middlewares.


import React from 'react';

const PaymentInfoPanel = ({
  removeCardHandler,
  paymentInfo: {merchant, lastFour}
}) => {
  return (

Default Payment Method

Merchant

{merchant}

Card Number

**** **** **** {lastFour}

            <button onClick={removeCardHandler}
              className="btn btn-action btn-red">
                Remove Card
            </button>

  );
};

export default PaymentInfoPanel;

Move HTML here so logic on billing/index.js is cleaner


import 'angular-material/angular-material.min.css';

import '../styles/main.scss';

import angular from 'angular';
import uiRouter from 'angular-ui-router';
import ngMaterial from 'angular-material';
import ngResource from 'angular-resource';
import lbServices from './lb-services.js';
import CartRouters from './routers.js';
import Theming from './theme.js';

// Angular application initialization
let app = angular.module('app', [
  uiRouter, ngMaterial, ngResource, lbServices
]);

// Angular UI router config
app.config(['$stateProvider', '$urlRouterProvider', CartRouters]);

// Angular Material Theme config
app.config(['$mdThemingProvider', Theming]);

import 'angular-material/angular-material.min.css';

import '../styles/main.scss';

import angular from 'angular';
import uiRouter from 'angular-ui-router';
import ngMaterial from 'angular-material';
import ngResource from 'angular-resource';
import lbServices from './lb-services.js';
import CartRouters from './routers.js';
import CartTheming from './theme.js';

// Angular application initialization
let app = angular.module('app', [
  uiRouter, ngMaterial, ngResource, lbServices
]);

// Angular UI router config
app.config(CartRouters);

// Angular Material Theme config
app.config(CartTheming);

Use injector to do angular config function.


import React from 'react'

const Nav = () => {
  return (

Home

Households

Sign Up

Login

  )
}

export default Nav

import React from 'react'
import {
  Link
} from 'react-router-dom'

const Nav = () => {
  return (

<Link to="/">Home</Link>

<Link to="/households">Households</Link>

Sign Up

Login

  )
}

export default Nav

Update nav links to use Link component


describe("Control.Rotation", function () {
  var map, baseLayer;

  beforeEach(function () {
    baseLayer = L.PolarMap.tileLayer("http://{s}.tiles.arcticconnect.org/osm_3573/{z}/{x}/{y}.png", {
      name: "ac_3573",
      crs: "EPSG:3573",
      minZoom: 0,
      maxZoom: 18,
      tms: false,
      origin: [-extent, extent],
      maxResolution: ((extent - -extent) / 256),
      projectedBounds: L.bounds(L.point(-extent, extent),L.point(extent, -extent)),
      center: [90, 0],
      zoom: 4,
      continuousWorld: false,
      noWrap: true,
      attribution: 'Map © ArcticConnect. Data © OpenStreetMap contributors'
    });

    map = L.PolarMap.map(document.createElement('div'), {
      baseLayer: baseLayer,
      center: [90, 0],
      zoom: 2
    });
  });

  it("can be added to an unloaded map", function () {
    new L.PolarMap.Control.Rotation().addTo(map);
  });
});

describe("Control.Rotation", function () {
  var map, baseLayer;

  beforeEach(function () {
    baseLayer = L.PolarMap.layer3573;

    map = L.PolarMap.map(document.createElement('div'), {
      baseLayer: baseLayer,
      center: [90, 0],
      zoom: 2
    });
  });

  it("can be added to an unloaded map", function () {
    new L.PolarMap.Control.Rotation().addTo(map);
  });
});

Update spec to use predefined layer


import React, { Component } from "react";
import { Row } from "react-bootstrap";
import Axios from "axios";
import PullRequest from "./PullRequest";
import Load from "./Load";
class User extends Component {
  state = {
    loading: true
  };
  async componentDidMount() {
    const { user } = this.props.match.params;
    const query = "type:pr author:" + user + " -user:" + user;
    const url = "https://api.github.com/search/issues";

    try {
      const response = await Axios.get(url, {
        params: { q: query }
      });
      this.setState({ data: response.data, loading: false });
    } catch(err) {
      console.log(err);
      alert("There is something wrong, open log for more information!");
      this.props.history.push("/");
    }
  }
  render() {
    console.log(this.props);
    if (this.state.loading) { return (<Load />); };
    return (
      <Row>
        {this.state.data.items.map((pullrequest, idx) => {
          return <PullRequest data={pullrequest} key={idx} />;
        })}
      </Row>
    );
  }
}
export default User;

import React, { Component } from "react";
import { Row, Col } from "react-bootstrap";
import Axios from "axios";
import PullRequest from "./PullRequest";
import Load from "./Load";

const style = {
  border: "1px solid black",
  marginTop: "1em",
  borderRadius: "5px",
  fontSize: "1.2em",
  paddingTop: "0.5em",
  paddingBottom: "0.5em"
};

class User extends Component {
  state = {
    loading: true
  };
  async componentDidMount() {
    const { user } = this.props.match.params;
    const query = "type:pr author:" + user + " -user:" + user;
    const url = "https://api.github.com/search/issues";

    try {
      const response = await Axios.get(url, {
        params: { q: query }
      });
      this.setState({ data: response.data, loading: false });
    } catch(err) {
      console.log(err);
      alert("There is something wrong, open log for more information!");
      this.props.history.push("/");
    }
  }
  render() {
    console.log(this.props);
    if (this.state.loading) { return (<Load />); };
    const { items } = this.state.data
    const { user } = this.props.match.params;
    return items.length === 0
      ? (
          <Col className="Col" xs={10} sm={8} md={4} style={style}>
            There are no pull requests associated with user {user}
          </Col>
        )
      : (
          <Row>
            {this.state.data.items.map((pullrequest, idx) => {
              return <PullRequest data={pullrequest} key={idx} />;
            })}
          </Row>
        );
  }
}
export default User;

Add message for no pull requests


const pino = require('pino')
const serializers = require('./serializers.js')
const getConfig = require('../../config.js').get

function createLogger (shardID) {
  const config = getConfig()
  const prettyPrint = {
    translateTime: 'yyyy-mm-dd HH:MM:ss',
    messageFormat: '[{shardID}] \x1b[0m{msg}',
    ignore: 'hostname,shardID'
  }

  const pinoConfig = {
    base: {
      shardID: String(shardID)
    },
    customLevels: {
      owner: 35
    },
    prettyPrint,
    serializers: {
      guild: serializers.guild,
      channel: serializers.channel,
      role: serializers.channel,
      user: serializers.user,
      message: serializers.message,
      error: pino.stdSerializers.err
    },
    enabled: process.env.NODE_ENV !== 'test'
  }

  let destination
  if (pinoConfig.enabled) {
    destination = config.log.destination || undefined
    pinoConfig.level = config.log.level
    pinoConfig.prettyPrint = !destination
  }

  return pino(pinoConfig, pino.destination(destination))
}

module.exports = createLogger

const pino = require('pino')
const serializers = require('./serializers.js')
const getConfig = require('../../config.js').get

function createLogger (shardID) {
  const config = getConfig()
  const prettyPrint = {
    translateTime: 'yyyy-mm-dd HH:MM:ss',
    messageFormat: '[{shardID}] \x1b[0m{msg}',
    ignore: 'hostname,shardID'
  }

  const pinoConfig = {
    base: {
      shardID: String(shardID)
    },
    customLevels: {
      owner: 35
    },
    prettyPrint,
    serializers: {
      guild: serializers.guild,
      channel: serializers.channel,
      role: serializers.channel,
      user: serializers.user,
      message: serializers.message,
      error: pino.stdSerializers.err
    },
    enabled: process.env.NODE_ENV !== 'test'
  }

  let destination
  if (pinoConfig.enabled) {
    destination = config.log.destination || undefined
    pinoConfig.level = config.log.level
    pinoConfig.prettyPrint = !destination ? prettyPrint : false
  }

  return pino(pinoConfig, pino.destination(destination))
}

module.exports = createLogger

Fix pretty print not ignoring shardID


"use strict";

var Int64 = require('node-int64');
var HBaseTypes = require('../gen-nodejs/hbase_types');

function Put(row) {
    var self = this;

    self.row = row;
    self.columnValues = [];

    self.add = function(family, qualifier, value, timestamp) {
        var buf, data = {
            family: family,
            qualifier: qualifier
        };
        if (typeof value === "object") {
            if (value.type === "long") {
                data.value = new Int64(value.value);
            } else if (value.type === "integer") {
                buf = new Buffer(4);
                buf.writeInt32BE(value.value, 0);
                data.value = buf;
            } else if (value.type === "float") {
                buf = new Buffer(4);
                buf.writeFloatBE(value.value, 0);
                data.value = buf;
            } else {
                throw new Error('Unsupported type for put value : ' + value.type);
            }
        } else {
            data.value = value.toString();
        }
        if (timestamp)
            data.timestamp = new Int64(timestamp);
        self.columnValues.push(new HBaseTypes.TColumnValue(data));
    };
}

module.exports = Put;

"use strict";

var HBaseTypes = require('../gen-nodejs/hbase_types');

function Put(row) {
    var self = this;

    self.row = row;
    self.columnValues = [];

    self.add = function(family, qualifier, value, timestamp) {
        var buf, data = {
            family: family,
            qualifier: qualifier
        };
        if(value instanceof Buffer)
            data.value = value;
        else
            data.value = value.toString();
        if (timestamp)
            data.timestamp = new Int64(timestamp);
        self.columnValues.push(new HBaseTypes.TColumnValue(data));
    };
}

module.exports = Put;

Modify value type support for Put


//import 'babel-core/polyfill'
import React from 'react';
import { render } from 'react-dom';
import Root from './containers/Root';
import configureStore from './store';
import {songListApi, checkForExistingUser} from 'setup';
import {fetchRequests} from './actions';

const store = configureStore();
store.dispatch(fetchRequests(songListApi));
checkForExistingUser(store);

render(
  <Root store={store} />,
  document.getElementById('app')
);

//import 'babel-core/polyfill'
import React from 'react';
import { render } from 'react-dom';
import Root from './containers/Root';
import configureStore from './store';
import {songListApi, checkForExistingUser} from 'setup';
import {fetchRequests} from './actions';

const store = configureStore();
checkForExistingUser(store);
store.dispatch(fetchRequests(songListApi));

render(
  <Root store={store} />,
  document.getElementById('app')
);

Check token before initial api fetch


(function () {
  'use strict';

  angular
    .module('colegiul-pacientilor.registries.controller')
    .controller('RegistriesShowCtrl', RegistriesShowCtrl);

  RegistriesShowCtrl.$inject = ['RegistryService', '$state'];

  function RegistriesShowCtrl(RegistryService, $state) {
    var self = this;

    this.gridOptions = {
      enableSorting: true,
      columnDefs: [
        { field: 'name' },
        { field: 'cnp' }
      ]
    };

    RegistryService.findById($state.params.id).then(function(response) {
      self.registry = response.data;

      var values = [];

      response.data.records.forEach(function(r) {
        var object = {};
        r.values.forEach(function(item) {
          for (var name in item) {
            if (name == 'name') {
              object[item.name.toString().toLowerCase()] = item.value;
            }
          }
        });
        values.push(object);
      });

      self.gridOptions.data = values;
    });
  }

})();

(function () {
  'use strict';

  angular
    .module('colegiul-pacientilor.registries.controller')
    .controller('RegistriesShowCtrl', RegistriesShowCtrl);

  RegistriesShowCtrl.$inject = ['RegistryService', '$state'];

  function RegistriesShowCtrl(RegistryService, $state) {
    var self = this;

    self.gridOptions = {
      enableSorting: true
    };

    RegistryService.findById($state.params.id).then(function(response) {
      self.registry = response.data;

      var values = [];

      response.data.records.forEach(function(r) {
        var object = {};
        r.values.forEach(function(item) {
          for (var name in item) {
            if (name == 'name') {
              object[item.name.toString().toLowerCase()] = item.value;
            }
          }
        });
        values.push(object);
      });

      console.log(values);

      var keys = [];

      values.forEach(function(item) {
        keys = Object.keys(item);
      });

      var columnDefs = [];
      keys.forEach(function(key) {
        columnDefs.push({field: key});
      });

      self.gridOptions = {
        columnDefs: columnDefs
      };

      self.gridOptions.data = values;
    });
  }

})();

Fix dinamic view for registry show


App.ProjectController = Ember.ObjectController.extend({
  isEditing: false,

  // We use the bufferedName to store the original value of
  // the model's title so that we can roll it back later in the
  // `cancelEditing` action.
  bufferedName: Ember.computed.oneWay('name'),

  actions: {
    editProjectName: function () {
      this.set('isEditing', true);
    },

    doneEditing: function () {
      var bufferedName = this.get('bufferedName').trim();

      if (Ember.isEmpty(bufferedName)) {
        // The `doneEditing` action gets sent twice when the user hits
        // enter (once via 'insert-newline' and once via 'focus-out').
        //
        // We debounce our call to 'removeTodo' so that it only gets
        // made once.
        Ember.run.debounce(this, 'deleteProject', 0);
      } else {
        var project = this.get('model');
        project.set('name', bufferedName);
        project.save();
      }

      // Re-set our newly edited name to persist its trimmed version
      this.set('bufferedName', bufferedName);
      this.set('isEditing', false);
    },

    cancelEditing: function () {
      this.set('bufferedName', this.get('name'));
      this.set('isEditing', false);
    },

    deleteProject: function () {
      this.deleteProject();
    },
  },

  deleteProject: function () {
    var project = this.get('model');
    project.destroyRecord();
  },
});

App.ProjectController = Ember.ObjectController.extend({
  needs: ['user'],
  isEditing: false,

  // We use the bufferedName to store the original value of
  // the model's title so that we can roll it back later in the
  // `cancelEditing` action.
  bufferedName: Ember.computed.oneWay('name'),

  actions: {
    editProjectName: function () {
      this.set('isEditing', true);
    },

    doneEditing: function () {
      var bufferedName = this.get('bufferedName').trim();

      if (Ember.isEmpty(bufferedName)) {
        // The `doneEditing` action gets sent twice when the user hits
        // enter (once via 'insert-newline' and once via 'focus-out').
        //
        // We debounce our call to 'removeTodo' so that it only gets
        // made once.
        Ember.run.debounce(this, 'deleteProject', 0);
      } else {
        var project = this.get('model');
        project.set('name', bufferedName);
        project.save();
      }

      // Re-set our newly edited name to persist its trimmed version
      this.set('bufferedName', bufferedName);
      this.set('isEditing', false);
    },

    cancelEditing: function () {
      this.set('bufferedName', this.get('name'));
      this.set('isEditing', false);
    },

    deleteProject: function () {
      this.deleteProject();
    },
  },

  deleteProject: function () {
    var project = this.get('model');
    project.deleteRecord();
    var user = this.get('controllers.user.content');

    project.save().then(function () {
      user.get('projects').then(function (projects) {
        projects.pullObject(project);
        user.save();
      });
    });
  },
});

Update user with new list of projects on delete


/*
*
* A simple script to create (or print) a JSON file from an XML file
*
*/

var fs = require('fs');
var path = require('path');
var xml2js = require('xml2js');
var parser = new xml2js.Parser();

var output = './';

module.exports = (function () {

    this.publishJSON = function (file, outputDir) {
        parser.parseString(file, function (err, result) {
            if (err) throw err;
            var outputFilename = outputDir + file.split(".xml")[0] + '.json';
            fs.writeFile(outputFilename, JSON.stringify(result, null, 4), function (err) {
                if (err) throw err
                console.log("JSON saved to " + outputFilename);
            });
        });
    }

    this.convertToJSON = function (file, callBack) {
        fs.readFile(file, 'utf-8', function (err, xml) {
            if (err) console.log(err)
            parser.parseString(xml, function (err, result) {
              if (err) callBack("Error!");
              else callBack({"result": result, "file": file});
            });
        });
    }

    this.convertToJSONSync = function (file) {
        fs.readFile(file, 'utf-8', function (err, xml) {
            if (err) console.log(err)
            parser.parseString(xml, function (err, result) {
                if (err);
                else return {"result": result, "file": file};
            });
        });
    }

    return this;
})();

/*
*
* A simple script to create (or print) a JSON file from an XML file
*
*/

var fs = require('fs');
var path = require('path');
var xml2js = require('xml2js');
var parser = new xml2js.Parser();

var output = './';

module.exports = (function () {

    this.publishJSON = function (file, outputDir) {
        parser.parseString(file, function (err, result) {
            if (err) throw err;
            var outputFilename = outputDir + file.split(".xml")[0] + '.json';
            fs.writeFile(outputFilename, JSON.stringify(result, null, 4), function (err) {
                if (err) throw err
                console.log("JSON saved to " + outputFilename);
            });
        });
    }

    this.convertToJSON = function (file, callBack) {
        fs.readFile(file, 'utf-8', function (err, xml) {
            if (err) console.log(err)
            parser.parseString(xml, function (err, result) {
              if (err) callBack({"file": file});
              else callBack({"result": result, "file": file});
            });
        });
    }

    this.convertToJSONSync = function (file) {
        fs.readFile(file, 'utf-8', function (err, xml) {
            if (err) console.log(err)
            parser.parseString(xml, function (err, result) {
                if (err);
                else return {"result": result, "file": file};
            });
        });
    }

    return this;
})();

Return XML path in case of errors


const ruleName = "declaration-no-important"

export const messages = {
  unexpected: `Unexpected !important (${ruleName})`,
}

/**
 * @param {boolean} options - If true, no !important;
 *   if false, do nothing
 */
export default function declarationNoImportant(options) {
  return (css, result) => {
    if (options) {
      css.eachDecl(function (decl) {
        if (!decl.important) {
          return
        }

        result.warn(
          messages.unexpected,
          { node: decl }
        )
      })
    }
  }
}

const ruleName = "declaration-no-important"

export const messages = {
  unexpected: `Unexpected !important (${ruleName})`,
}

/**
 * @param {boolean} options - If true, no !important;
 *   if false, do nothing
 */
export default function declarationNoImportant(options) {
  return (css, result) => {

    if (!options) { return }

    css.eachDecl(function (decl) {
      if (!decl.important) {
        return
      }

      result.warn(
        messages.unexpected,
        { node: decl }
      )
    })
  }
}

Return early if options not true


function NavigationController($scope, Auth) {

}

angular
  .module('fitnessTracker')
    .controller('NavigationController', NavigationController);

function NavigationController($scope, Auth) {
  $scope.signedIn = Auth.isAuthenticated;
  $scope.logout = Auth.logout;
  Auth.currentUser().then(function (user) {
    $scope.user = user;
  })

  $scope.$on('devise:new-registration', function(event, user) {
    $scope.user = user;
  });

  $scope.$on('devise:login', function(event, user) {
    $scope.user = user;
  });

  $scope.$on('devise:logout', function(event, user) {
    $scope.user = {};
  });
}

angular
  .module('fitnessTracker')
    .controller('NavigationController', NavigationController);

Add logout, signed in, and watchers for navbar


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

module.exports = {
  devtool: 'cheap-module-eval-source-map',
  entry: [
    'webpack-dev-server/client?http://0.0.0.0:3000',
    'webpack/hot/only-dev-server',
    './example/index.js'
  ],
  output: {
    path: __dirname + '/example/',
    filename: 'all.js',
    publicPath: '/example'
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  module: {
    loaders: [{
      test: /\.js$/,
      loaders: ['react-hot', 'babel'],
      exclude: /node_modules/,
      include: __dirname
    }]
  }
};

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

module.exports = {
  devtool: 'cheap-module-eval-source-map',
  entry: [
    'webpack-dev-server/client?http://0.0.0.0:8080',
    'webpack/hot/only-dev-server',
    './example/index.js'
  ],
  output: {
    path: __dirname + '/example/',
    filename: 'all.js',
    publicPath: '/example'
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  module: {
    loaders: [{
      test: /\.js$/,
      loaders: ['react-hot', 'babel'],
      exclude: /node_modules/,
      include: __dirname
    }]
  }
};

Fix webpack dev server port


var webpack = require('webpack');
var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
var env = process.env.WEBPACK_ENV;
var WebpackDevServer = require('webpack-dev-server');

var appName = 'app';
var host = '0.0.0.0';
var port = '9000';

var plugins = [], outputFile;

if (env === 'build') {
  plugins.push(new UglifyJsPlugin({ minimize: true }));
  outputFile = appName + '.min.js';
} else {
  outputFile = appName + '.js';
}

var config = {
  entry: './src/index.js',
  devtool: 'source-map',
  output: {
    path: __dirname + '/lib',
    filename: outputFile,
    publicPath: __dirname + '/public'
  },
  module: {
    loaders: [
      {
        test: /(\.jsx|\.js)$/,
        loader: 'babel',
        exclude: /(node_modules|bower_components)/
      }
    ]
  },
  plugins: plugins
};

if (env === 'dev') {
  new WebpackDevServer(webpack(config), {
    contentBase: './public',
    hot: true,
    debug: true
  }).listen(port, host, function (err, result) {
    if (err) {
      console.log(err);
    }
  });
  console.log('-------------------------');
  console.log('Local web server runs at http://' + host + ':' + port);
  console.log('-------------------------');
}

module.exports = config;

var webpack = require('webpack');
var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
var env = process.env.WEBPACK_ENV;
var WebpackDevServer = require('webpack-dev-server');

var appName = 'app';
var host = '0.0.0.0';
var port = '5000';

var plugins = [], outputFile;

if (env === 'build') {
  plugins.push(new UglifyJsPlugin({ minimize: true }));
  outputFile = appName + '.min.js';
} else {
  outputFile = appName + '.js';
}

var config = {
  entry: './src/index.js',
  devtool: 'source-map',
  output: {
    path: __dirname + '/lib',
    filename: outputFile,
    publicPath: __dirname + '/public'
  },
  module: {
    loaders: [
      {
        test: /(\.jsx|\.js)$/,
        loader: 'babel',
        exclude: /(node_modules|bower_components)/
      }
    ]
  },
  plugins: plugins
};

if (env === 'dev') {
  new WebpackDevServer(webpack(config), {
    contentBase: './public',
    hot: true,
    debug: true
  }).listen(port, host, function (err, result) {
    if (err) {
      console.log(err);
    }
  });
  console.log('-------------------------');
  console.log('Local web server runs at http://' + host + ':' + port);
  console.log('-------------------------');
}

module.exports = config;

Use port 5000 for dokku


'use strict';

var path = require('path');

module.exports = {
  context: path.join(__dirname, "public"),
  entry: "./index.js",
  output: {
      path: path.join(__dirname, "public"),
      filename: "bundle.js"
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /(node_modules|lib)/,
        loader: 'babel'
      }
    ]
  },
  externals: {
    'jquery': 'jQuery'
  },
  node: {
    fs: 'empty'
  }
};

'use strict';

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

module.exports = {
  context: path.join(__dirname, "public"),
  entry: "./index.js",
  output: {
      path: path.join(__dirname, "public"),
      filename: "bundle.js"
  },
  devtool: false, //'source-map',
  target: 'web',
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /(node_modules|lib)/,
        loader: 'babel'
      }
    ]
  },
  plugins: [
    new webpack.NoErrorsPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('production'),
      }
    }),
    new webpack.optimize.UglifyJsPlugin()
  ],
  node: {
    fs: 'empty'
  },
  resolve: {
    alias: {
      'handlebars': 'handlebars/dist/cjs/handlebars.js'
    }
  }
};

Reduce size of webpack generated JavaScript using UglifyJS


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

module.exports = {
    devtool: 'cheap-module-eval-source-map',
    entry: [
        'webpack-dev-server/client?http://localhost:3000',
        'webpack/hot/only-dev-server',
        './src/index'
    ],
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js',
        publicPath: '/static/'
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ],
    module: {
        loaders: [
            {
                test: /\.js$/,
                loaders: ['react-hot', 'babel'],
                exclude: /node_modules/,
                include: __dirname
            }, {
                test: /\.css$/,
                loader: "style-loader!css-loader"
            }, {
                test: /\.png$/,
                loader: "url-loader?limit=100000"
            }, {
                test: /\.jpg$/,
                loader: "file-loader"
            }
        ]
    }
};

var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    devtool: 'cheap-module-eval-source-map',
    entry: [
        'webpack-dev-server/client?http://localhost:3000',
        'webpack/hot/only-dev-server',
        './src/index'
    ],
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js',
        publicPath: '/static/'
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: './src/index.template.html'
        }),
        new webpack.NoErrorsPlugin()
    ],
    module: {
        loaders: [
            {
                test: /\.js$/,
                loaders: ['react-hot', 'babel'],
                exclude: /node_modules/,
                include: __dirname
            }, {
                test: /\.css$/,
                loader: "style-loader!css-loader"
            }, {
                test: /\.png$/,
                loader: "url-loader?limit=100000"
            }, {
                test: /\.jpg$/,
                loader: "file-loader"
            }
        ]
    }
};

Add HtmlWebpackPlugin for generating dev html files


/**
 * Orion Helpers
 */
orion.helpers = {}

/**
 * Searchs a object with a givin string
 * you can specify if you want the searcher to
 * take the first values of array if they are
 */
orion.helpers.searchObjectWithDots = function(object, key, selectFirstIfIsArray) {
    key = key.split('.');

    try {
        for (var i = 0; i < key.length; i++) {
            if (selectFirstIfIsArray && object.length && object.length > 0) {
                object = object[0];
            }
            if (key[i] in object) {
                object = object[key[i]];
            } else {
                return null;
            }
        }
    } catch(error) {
        return null;
    }

    return object || null;
}

/**
 * Deep extend
 */
orion.helpers.deepExtend = function(target, source) {
    for (var prop in source)
        if (prop in target && typeof(target[prop]) == 'object' && typeof(source[prop]) == 'object')
            deepExtend(target[prop], source[prop]);
        else
            target[prop] = source[prop];
    return target;
}

/**
 * Orion Helpers
 */
orion.helpers = {}

/**
 * Searchs a object with a givin string
 * you can specify if you want the searcher to
 * take the first values of array if they are
 */
orion.helpers.searchObjectWithDots = function(object, key, selectFirstIfIsArray) {
    key = key.split('.');

    try {
        for (var i = 0; i < key.length; i++) {
            if (selectFirstIfIsArray && object.length && object.length > 0) {
                object = object[0];
            }
            if (key[i] in object) {
                object = object[key[i]];
            } else {
                return null;
            }
        }
    } catch(error) {
        return null;
    }

    return object || null;
}

/**
 * Deep extend
 */
orion.helpers.deepExtend = function(target, source) {
    for (var prop in source)
        if (prop in target && typeof(target[prop]) == 'object' && typeof(source[prop]) == 'object')
            orion.helpers.deepExtend(target[prop], source[prop]);
        else
            target[prop] = source[prop];
    return target;
}

Fix bug on deepExtend helper


'use strict';

var assert = require('assert');
var jsyaml = require('../../lib/js-yaml');

var _functional = require('../support/functional');
var YAMLError = require('../../lib/js-yaml/error');

_functional.generateTests({
  description: 'Test errors loading all documents from the string.',
  files: ['.loader-error'],
  test: function (errorFile) {
    assert.throws(
      function () {
        jsyaml.loadAll(
          errorFile.content,
          function () {},
          { name: errorFile.path });
      },
      YAMLError);
  }
});

_functional.generateTests({
  description: 'Test errors loading single documents from the string.',
  files: ['.single-loader-error'],
  test: function (errorFile) {
    assert.throws(
      function () {
        jsyaml.load(
          errorFile.content,
          { name: errorFile.path });
      },
      YAMLError);
  }
});

'use strict';

var assert = require('assert');
var jsyaml = require('../../lib/js-yaml');

var _functional = require('../support/functional');
var TEST_SCHEMA = require('../support/schema');
var YAMLError   = require('../../lib/js-yaml/error');

_functional.generateTests({
  description: 'Test errors loading all documents from the string.',
  files: ['.loader-error'],
  test: function (errorFile) {
    assert.throws(
      function () {
        jsyaml.loadAll(
          errorFile.content,
          function () {},
          { name: errorFile.path,
            schema: TEST_SCHEMA,
            strict: true });
      },
      YAMLError,
      'In file "' + errorFile.path + '"');
  }
});

_functional.generateTests({
  description: 'Test errors loading single documents from the string.',
  files: ['.single-loader-error'],
  test: function (errorFile) {
    assert.throws(
      function () {
        jsyaml.load(
          errorFile.content,
          { name: errorFile.path,
            schema: TEST_SCHEMA,
            strict: true });
      },
      YAMLError,
      'In file "' + errorFile.path + '"');
  }
});

Correct the "error" tests configuration.


export default ['$q', '$scope', '$http', '$stateParams', function($q, $scope, $http, $stateParams) {

  $http.get('/api/pipelines/' + $stateParams.id).then(response => {
    $scope.pipeline = response.data.data

    $http.get('/api/projects/' + response.data.data.project_id).then(response => {
      $scope.project = response.data.data
    })

  })

  let stageTypes = $http.get('/api/stage-types')
  let stageConfigs = $http.get('api/pipelines/' + $stateParams.id + '/stages')

  $q.all([stageTypes, stageConfigs])
    .then(args => {
      let types = args[0].data.data
      let stages = args[1].data.data

      $scope.stages = stages.map(stage => {
        let type = types.find(type => type.fqid === stage.type)
        if (type) {
          stage.schema = type
        }
        return stage
      })

      setTimeout(function() {
        $(function() {
          $('.pipeline-stage a.configure').on('click', function() {
            console.log('clicked')
            $(this).parent().parent().find('.panel-body').slideToggle(200)
          })
        })

      }, 1)

    })

}]

export default ['$q', '$scope', '$http', '$stateParams', '$state', function($q, $scope, $http, $stateParams, $state) {

  $http.get('/api/pipelines/' + $stateParams.id).then(response => {
    $scope.pipeline = response.data.data

    $http.get('/api/projects/' + response.data.data.project_id).then(response => {
      $scope.project = response.data.data
    })

  })

  // Get Stage Data
  let stageTypes = $http.get('/api/stage-types')
  let stageConfigs = $http.get('/api/pipelines/' + $stateParams.id + '/stages')
  $q.all([stageTypes, stageConfigs])
    .then(args => {
      let types = args[0].data.data
      let stages = args[1].data.data

      $scope.stages = stages.map(stage => {
        let type = types.find(type => type.fqid === stage.type)
        if (type) {
          stage.schema = type
        }
        return stage
      })

      setTimeout(function() {
        $(function() {
          $('.pipeline-stage a.configure').on('click', function() {
            $(this).parent().parent().find('.panel-body').slideToggle(200)
          })
        })

      }, 1)

    })

  // Delete Stage
  $scope.remove = (id) => {
    $http.delete('/api/stage/' + id)
    $state.go($state.$current, null, { reload: true });
  }

}]

Add event handler for removing stage


Divide file extensions into lists and patterns


/* global config */

module.exports = function(grunt) {
	grunt.registerTask('runValidation', function() {
		var scriptPath = config.assetPath + '/js',
			scripts = Wee.getFiles(scriptPath, 'js');

		// Validate scripts
		scripts.forEach(function(filepath) {
			if (filepath.indexOf('.min.js') == -1) {
				Wee.validate(config, grunt, filepath);
			}
		});
	});
};

/* global config */

module.exports = function(grunt) {
	grunt.registerTask('runValidation', function() {
		var scriptPath = config.assetPath + '/js',
			scripts = Wee.getFiles(scriptPath, 'js');

		// Validate scripts
		scripts.forEach(function(filepath) {
			if (filepath.indexOf('polyfill') == -1 && filepath.indexOf('.min.js') == -1) {
				Wee.validate(config, grunt, filepath);
			}
		});
	});
};

Exclude polyfill scripts in validation task


/**
 * @license
 * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */

/* eslint-env node */

module.exports = {
  staticFileGlobs: [
    'index.html',
    'preview-comms.html',
    'manifest.json',
    'bower_components/webcomponentsjs/*',
    'node_modules/dexie/dist/dexie.min.js',
    'bower_components/ace-builds/src-min-noconflict/theme-monokai.js',
    'bower_components/ace-builds/src-min-noconflict/{mode,worker}-{html,js,css}.js',
  ],
  navigateFallback: 'index.html',
};

/**
 * @license
 * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */

/* eslint-env node */

module.exports = {
  staticFileGlobs: [
    'index.html',
    'preview-comms.html',
    'manifest.json',
    'src/**/*',
    'bower_components/webcomponentsjs/*',
    'node_modules/dexie/dist/dexie.min.js',
    'bower_components/ace-builds/src-min-noconflict/theme-monokai.js',
    'bower_components/ace-builds/src-min-noconflict/{mode,worker}-{html,js,css}.js',
  ],
  navigateFallback: 'index.html',
};

Fix caching of app fragments


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

"use strict";

module.exports = ["api", "oauth"];

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

"use strict";

module.exports = ["api",
                  "oauth",
                  "public",
                  "robots.txt",
                  "humans.txt",
                  ".well-known",
                  "sitemap.xml",
                  "favicon.ico"];

Expand list of blacklisted nicknames


// ===================================================
// IMPORTANT: only for production
// total.js - web application framework for node.js
// http://www.totaljs.com
// ===================================================

var fs = require('fs');
var options = {};

// options.ip = '127.0.0.1';
// options.port = parseInt(process.argv[2]);
// options.config = { name: 'total.js' };
// options.https = { key: fs.readFileSync('keys/agent2-key.pem'), cert: fs.readFileSync('keys/agent2-cert.pem')};
// options.sleep = 2000;

/**
 * Release notes:
 */

require('total.js').http('release', options);
// require('total.js').https('release', options);

// ===================================================
// IMPORTANT: only for production
// total.js - web application framework for node.js
// http://www.totaljs.com
// ===================================================

var fs = require('fs');
var options = {};
options.ip = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1';
options.port = parseInt(process.env.OPENSHIFT_NODEJS_PORT) || 8000;
// options.config = { name: 'total.js' };
// options.https = { key: fs.readFileSync('keys/agent2-key.pem'), cert: fs.readFileSync('keys/agent2-cert.pem')};
// options.sleep = 2000;

/**
 * Release notes:
 */

require('total.js').http('release', options);
// require('total.js').https('release', options);

Add IP, Port of Openshift for Total.js


(function () {
  'use strict';

  var mongoose = require('mongoose');

  var RoleSchema = new mongoose.Schema({
    title: {
      type: String,
      default: 'user',
      unique: true,
      enum: ['user', 'owner', 'admin', 'public']
    }
  });

  /**
   * Create all four acceptable roles when this model initializes.
   */
  RoleSchema.statics.initialize = function () {
    var role = this;
    return new Promise(function (resolve, reject) {
      var defaults = role.schema.paths.title.enumValues;
      defaults = defaults.map(function (value) {
        return {title: value};
      });

      role.create(defaults, function (err, values) {
        if (err) {
          reject(err);
        }
        resolve(values);
      });
    });
  };

  RoleSchema.statics.all = function (cb) {
    return this.find({}, cb);
  };

  module.exports = mongoose.model('Role', RoleSchema);
})();

(function () {
  'use strict';

  var mongoose = require('mongoose');

  var RoleSchema = new mongoose.Schema({
    title: {
      type: String,
      default: 'user',
      unique: true,
      enum: ['user', 'owner', 'admin', 'public']
    },
    accessLevel: {
      type: Number,
      default: 0
    }
  });

  /**
   * Associate the role with it's correct access level before saving it.
   */
  RoleSchema.pre('save', function (next) {
    var accessLevelsMap = {
      'admin': 4,
      'owner': 3,
      'user': 2,
      'public': 1
    };

    this.accessLevel = accessLevelsMap[this.title];
    next();
  });

  /**
   * Create all four acceptable roles when this model initializes.
   */
  RoleSchema.statics.initialize = function () {
    var role = this;
    return new Promise(function (resolve, reject) {
      var defaults = role.schema.paths.title.enumValues;
      defaults = defaults.map(function (value) {
        return {title: value};
      });

      role.create(defaults, function (err, values) {
        if (err) {
          reject(err);
        }
        resolve(values);
      });
    });
  };

  RoleSchema.statics.all = function (cb) {
    return this.find({}, cb);
  };

  module.exports = mongoose.model('Role', RoleSchema);
})();

Add an access level to each role


Meteor.publish('posts', function() {
  return Posts.find();
});

Meteor.publish('comments', function(postId) {
  check(postId, String);
  return Comments.find({ postId: postId });
});

Meteor.publish('notifications', function() {
  return Notifications.find({ userId: this.userId, read: false });
});

Meteor.publish('posts', function(options) {
  check(options, {
    sort: Object,
    limit: Number
  });
  return Posts.find({}, options);
});

Meteor.publish('comments', function(postId) {
  check(postId, String);
  return Comments.find({ postId: postId });
});

Meteor.publish('notifications', function() {
  return Notifications.find({ userId: this.userId, read: false });
});

Modify posts publication to receive a limit and sort order


Meteor.publish("userData", function () {
	check(arguments, [Match.Any]);
	if(this.userId){
		return [
			Users.find({_id: this.userId})
		];
	}
	this.ready();
});

Meteor.publish("jobs", function(){
	var daysAgo = new Date();
	daysAgo.setDate(daysAgo.getDate()-90);
	check(arguments, [Match.Any]);
	return [
		Jobs.find({"createdAt": { $gte: daysAgo }})
	];
});

Meteor.publish("experts", function(){
	check(arguments, [Match.Any]);
	return [
		Experts.find({})
	];
});

Meteor.publish("userData", function () {
	check(arguments, [Match.Any]);
	if(this.userId){
		return [
			Users.find({_id: this.userId})
		];
	}
	this.ready();
});

Meteor.publish("jobs", function(){
	check(arguments, [Match.Any]);
	return [
		Jobs.find({})
	];
});

Meteor.publish("experts", function(){
	check(arguments, [Match.Any]);
	return [
		Experts.find({})
	];
});

Revert "Basic implementation of expiring job posts"


var fs = require('fs');
var flatiron = require('flatiron'),
  app = flatiron.app;

app.use(flatiron.plugins.http, {
  // HTTP options
});

var text_index = fs.readFileSync('index.html');
var buff_index = new Buffer(text_index);

app.router.get('/', function () {
  this.res.end(buff_index.toString());
});

app.router.get('/version', function () {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' });
  this.res.end( 'flatiron' + flatiron.version );
});

app.start(80);

var fs = require('fs');
var flatiron = require('flatiron'),
  app = flatiron.app;

app.use(flatiron.plugins.http, {
  // HTTP options
});

var text_index = fs.readFileSync('index.html');
var buff_index = new Buffer(text_index);

app.router.get('/', function () {
  this.res.end(buff_index.toString());
});

app.router.get('/version', function () {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' });
  this.res.end( 'flatiron' + flatiron.version );
});

app.start(8080);

Change port number back to 8080


class BindInOut {
  constructor(bindIn, bindOut) {
    this.in = bindIn;
    this.out = bindOut;

    this.eventWrapper = {};
    this.eventType = /(INPUT|TEXTAREA)/.test(bindIn.tagName) ? 'keyup' : 'change';
  }

  addEvents() {
    this.eventWrapper.updateOut = this.updateOut.bind(this);

    this.in.addEventListener(this.eventType, this.eventWrapper.updateOut);

    return this;
  }

  updateOut() {
    this.out.textContent = this.in.value;

    return this;
  }

  removeEvents() {
    this.in.removeEventListener(this.eventType, this.eventWrapper.updateOut);

    return this;
  }

  static initAll() {
    const ins = document.querySelectorAll('*[data-bind-in]');

    return [].map.call(ins, anIn => BindInOut.init(anIn));
  }

  static init(anIn, anOut) {
    const out = anOut || document.querySelector(`*[data-bind-out="${anIn.dataset.bindIn}"]`);
    const bindInOut = new BindInOut(anIn, out);

    return bindInOut.addEvents().updateOut();
  }
}

export default BindInOut;

class BindInOut {
  constructor(bindIn, bindOut) {
    this.in = bindIn;
    this.out = bindOut;

    this.eventWrapper = {};
    this.eventType = /(INPUT|TEXTAREA)/.test(bindIn.tagName) ? 'keyup' : 'change';
  }

  addEvents() {
    this.eventWrapper.updateOut = this.updateOut.bind(this);

    this.in.addEventListener(this.eventType, this.eventWrapper.updateOut);

    return this;
  }

  updateOut() {
    this.out.textContent = this.in.value;

    return this;
  }

  removeEvents() {
    this.in.removeEventListener(this.eventType, this.eventWrapper.updateOut);

    return this;
  }

  static initAll() {
    const ins = document.querySelectorAll('*[data-bind-in]');

    return [].map.call(ins, anIn => BindInOut.init(anIn));
  }

  static init(anIn, anOut) {
    const out = anOut || document.querySelector(`*[data-bind-out="${anIn.dataset.bindIn}"]`);

    if (!out) return;

    const bindInOut = new BindInOut(anIn, out);

    return bindInOut.addEvents().updateOut();
  }
}

export default BindInOut;

Fix no out element case


'use strict';

var taskOpts = require('./tasks');

module.exports = function(kbox, appName) {

  var deps = kbox.core.deps;

  // Add an option
  kbox.create.add(appName, {
    option: {
      name: 'drush-version',
      task: taskOpts.drushVersion,
      properties: {
        message: 'Drush version'.green,
        required: false,
        type: 'string',
        validator: /drush(5|6|7)/,
        warning: 'Answer must be drush plus a major version. ie "drush6".',
        default: 'drush6'
      },
      conf: {
        type: 'plugin',
        plugin: 'kalabox-plugin-drush',
        key: 'drush-version'
      }
    }
  });

};

'use strict';

var taskOpts = require('./tasks');
var _ = require('lodash');

module.exports = function(kbox, drupal, appName) {

  var drushVersions = _.pluck(drupal, 'drush');

  // Add an option
  kbox.create.add(appName, {
    option: {
      name: 'drush-version',
      task: taskOpts.drushVersion,
      inquire: {
        type: 'list',
        message: 'Major Drush version?',
        default: function(answers) {
          if (answers['drupal-version']) {
            return drupal[answers['drupal-version']].drush;
          }
          else {
            return '6';
          }
        },
        choices: drushVersions
      },
      conf: {
        type: 'plugin',
        plugin: 'kalabox-plugin-drush',
        key: 'drush-version'
      }
    }
  });

};

Update to appease the inquirer


Application.Services.factory("mcFlow", mcFlowService);
function mcFlowService() {
    var self = this;
    self.flow = new Flow(
        {
            target: "/api/upload/chunk",
            testChunks: false
        }
    );

    function each(obj, callback, context) {
        if (!obj) {
            return ;
        }
        var key;
        // Is Array?
        if (typeof(obj.length) !== 'undefined') {
            for (key = 0; key < obj.length; key++) {
                if (callback.call(context, obj[key], key) === false) {
                    return ;
                }
            }
        } else {
            for (key in obj) {
                if (obj.hasOwnProperty(key) && callback.call(context, obj[key], key) === false) {
                    return ;
                }
            }
        }
    }

    function extend(dst, src) {
        each(arguments, function(obj) {
            if (obj !== dst) {
                each(obj, function(value, key){
                    dst[key] = value;
                });
            }
        });
        return dst;
    }

    self.service = {
        get: function() {
            return self.flow;
        }
    };

    return self.service;
}

Application.Services.factory("mcFlow", mcFlowService);
function mcFlowService() {
    var self = this;
    self.flow = new Flow(
        {
            target: "/api/upload/chunk",
            testChunks: false,
            fileParameterName: "chunkData"
        }
    );

    function each(obj, callback, context) {
        if (!obj) {
            return ;
        }
        var key;
        // Is Array?
        if (typeof(obj.length) !== 'undefined') {
            for (key = 0; key < obj.length; key++) {
                if (callback.call(context, obj[key], key) === false) {
                    return ;
                }
            }
        } else {
            for (key in obj) {
                if (obj.hasOwnProperty(key) && callback.call(context, obj[key], key) === false) {
                    return ;
                }
            }
        }
    }

    function extend(dst, src) {
        each(arguments, function(obj) {
            if (obj !== dst) {
                each(obj, function(value, key){
                    dst[key] = value;
                });
            }
        });
        return dst;
    }

    self.service = {
        get: function() {
            return self.flow;
        }
    };

    return self.service;
}

Set fileParameterName for flow to the route used by the upload service.


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

CenterScout.config(function($routeProvider) {
    $routeProvider.when('/', {
        controller: 'HomeController',
        templateUrl: '/views/home.html'
    });

    $routeProvider.when('/home', {
        controller: 'HomeController',
        templateUrl: '/views/home.html'
    });

    $routeProvider.when('/class', {
        controller: 'ClassController',
        templateUrl: '/views/class.html'
    });

    $routeProvider.when('/about', {
        controller: 'AboutController',
        templateUrl: '/views/about.html'
    });

    $routeProvider.when('/404', {
        controller: 'ErrorController',
        templateUrl: '/views/404.html'
    });

    $routeProvider.otherwise({
        redirectTo: '/404'
    });
});

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

CenterScout.config(function($routeProvider) {
    $routeProvider.when('/', {
        controller: 'HomeController',
        templateUrl: 'views/home.html'
    });

    $routeProvider.when('/home', {
        controller: 'HomeController',
        templateUrl: 'views/home.html'
    });

    $routeProvider.when('/class', {
        controller: 'ClassController',
        templateUrl: 'views/class.html'
    });

    $routeProvider.when('/about', {
        controller: 'AboutController',
        templateUrl: 'views/about.html'
    });

    $routeProvider.when('/404', {
        controller: 'ErrorController',
        templateUrl: 'views/404.html'
    });

    $routeProvider.otherwise({
        redirectTo: '/404'
    });
});

Change template URLs to relative


var express = require('express');
var bodyParser = require('body-parser');
var http = require('http');
var path = require('path');
var fs = require('fs');
var quotes = require(path.join(__dirname, 'lib', 'quotes'))

var app = express();

app.set('port', 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(express.static(path.join(__dirname, 'public')));

app.get('/', function(req, res) {
    res.render('index');
});

app.get('/api/listAllOggFiles/', function(req, res) {
    fs.readdir('public/sounds/', function(err, files){
        if (err) {
            throw err;
        }

        var filenames = [];
        for (var i = 0; i < files.length; i++) {
            filenames.push(files[i].split('.')[0]);
        }
        res.json(filenames);
    });
});

app.get('/api/getQuotes/', function(req, res){
    res.json(quotes);
});

http.createServer(app).listen(app.get('port'), function(){
	console.log('Express server up and running. Listening on port ' + app.get('port'));
});

var express = require('express');
var bodyParser = require('body-parser');
var http = require('http');
var path = require('path');
var fs = require('fs');
var quotes = require(path.join(__dirname, 'lib', 'quotes'))

var app = express();

app.set('port', (process.env.PORT || 5000));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(express.static(path.join(__dirname, 'public')));

app.get('/', function(req, res) {
    res.render('index');
});

app.get('/api/listAllOggFiles/', function(req, res) {
    fs.readdir('public/sounds/', function(err, files){
        if (err) {
            throw err;
        }

        var filenames = [];
        for (var i = 0; i < files.length; i++) {
            filenames.push(files[i].split('.')[0]);
        }
        res.json(filenames);
    });
});

app.get('/api/getQuotes/', function(req, res){
    res.json(quotes);
});

http.createServer(app).listen(app.get('port'), function(){
	console.log('Express server up and running. Listening on port ' + app.get('port'));
});

Change listening port to env port with default.


import Signal from './signal'

export default class FieldLocale {

  constructor (channel, {id, locale, value}) {
    this.id = id
    this.locale = locale

    this._value = value
    this._valueSignal = new Signal()
    this._channel = channel

    channel.addHandler('valueChanged', (id, locale, value) => {
      if (id === this.id && locale === this.locale) {
        this._value = value
        this._valueSignal.dispatch(value)
      }
    })
  }

  getValue () {
    return this._value
  }

  setValue (value) {
    return this._channel.call('setValue', this.id, this.locale, value)
  }

  onValueChanged (handler) {
    return this._valueSignal.attach(handler)
  }

}

import Signal from './signal'

export default class FieldLocale {

  constructor (channel, {id, locale, value}) {
    this.id = id
    this.locale = locale

    this._value = value
    this._valueSignal = new Signal()
    this._channel = channel

    channel.addHandler('valueChanged', (id, locale, value) => {
      if (id === this.id && locale === this.locale) {
        this._value = value
        this._valueSignal.dispatch(value)
      }
    })
  }

  getValue () {
    return this._value
  }

  setValue (value) {
    this._value = value
    return this._channel.call('setValue', this.id, this.locale, value)
  }

  onValueChanged (handler) {
    return this._valueSignal.attach(handler)
  }

}

Save internal cached value when calling field.setValue()


'use strict';

(function(app) {

  /**
   * Creates a new HTML element ov-index to create an openVeo player
   * index, with a list of presentation slides.
   * It requires ovPlayerDirectory global variable to be defined and have
   * a value corresponding to the path of the openVeo Player
   * root directory.
   *
   * e.g.
   * <ov-index></ov-index>
   */
  function ovChapters(ovChaptersLink) {
    return {
      require: ['^ovPlayer', '^ovTabs'],
      restrict: 'E',
      templateUrl: ovPlayerDirectory + 'templates/chapters.html',
      scope: true,
      link: ovChaptersLink
    };
  }

  app.factory('ovChaptersLink', function() {
    return function(scope, element, attrs, controllers) {

      // toggle chapter
      scope.open = function(chapter) {
        if (chapter.description && chapter.description != '') {
          if (!chapter.isOpen)
            angular.forEach(scope.chapters, function(value) {
              value.isOpen = false;
            });
          chapter.isOpen = !chapter.isOpen;
        }
      };

      /**
       * Seeks media to the given timecode.
       * @param Number timecode The timecode to seek to
       */
      scope.goToTimecode = function(time) {
        var playerCtrl = controllers[0],
          tabsCtrl = controllers[1];
        if (time <= 1)
          playerCtrl.setTime(time * scope.duration);
        tabsCtrl.selectTabs('media');
      };

    };
  });

  app.directive('ovChapters', ovChapters);
  ovChapters.$inject = ['ovChaptersLink'];

})(angular.module('ov.player'));

'use strict';

(function(app) {

  /**
   * Creates a new HTML element ov-index to create an openVeo player
   * index, with a list of presentation slides.
   * It requires ovPlayerDirectory global variable to be defined and have
   * a value corresponding to the path of the openVeo Player
   * root directory.
   *
   * e.g.
   * <ov-index></ov-index>
   */
  function ovChapters(ovChaptersLink) {
    return {
      require: ['^ovPlayer', '^ovTabs'],
      restrict: 'E',
      templateUrl: ovPlayerDirectory + 'templates/chapters.html',
      scope: true,
      link: ovChaptersLink
    };
  }

  app.factory('ovChaptersLink', function() {
    return function(scope, element, attrs, controllers) {

      /**
       * Seeks media to the given timecode.
       * @param Number timecode The timecode to seek to
       */
      scope.goToTimecode = function(time) {
        var playerCtrl = controllers[0],
          tabsCtrl = controllers[1];
        if (time <= 1)
          playerCtrl.setTime(time * scope.duration);
        tabsCtrl.selectTabs('media');
      };

    };
  });

  app.directive('ovChapters', ovChapters);
  ovChapters.$inject = ['ovChaptersLink'];

})(angular.module('ov.player'));

Remove unused open method on ovChapters directive


CKEDITOR.editorConfig = function (config) {
  config.filebrowserImageBrowseLinkUrl = '/ckeditor/pictures';
  config.filebrowserImageBrowseUrl = '/ckeditor/pictures';
  config.filebrowserImageUploadUrl = '/ckeditor/pictures';
  config.toolbar =
  [
    {
      name: 'styles',
      items: ['Format']
    },
    {
      name: 'basicstyles',
      items: ['Bold', 'Italic', 'Underline', 'Strike', '-', 'RemoveFormat']
    },
    {
      name: 'paragraph',
      items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-']
    },
    {
      name: 'links',
      items: ['Link', 'Unlink']
    },
    {
      name: 'insert',
      items: ['Image']
    }
  ];
};

CKEDITOR.editorConfig = function (config) {
  config.filebrowserImageBrowseLinkUrl = '/ckeditor/pictures';
  config.filebrowserImageBrowseUrl = '/ckeditor/pictures';
  config.filebrowserImageUploadUrl = '/ckeditor/pictures';
  config.toolbar =
  [
    {
      name: 'styles',
      items: ['Format']
    },
    {
      name: 'basicstyles',
      items: ['Bold', 'Italic', 'Underline', '-', 'RemoveFormat']
    },
    {
      name: 'paragraph',
      items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-']
    },
    {
      name: 'links',
      items: ['Link', 'Unlink']
    },
    {
      name: 'insert',
      items: ['Image']
    }
  ];
};

Remove strike from wysiwyg tool bar


'use strict';

var _ = require('underscore');
var Backbone = require('backbone');
var Marionette = require('backbone.marionette');
var BookmarkItemView = require('./BookmarkItemView');
var template = require('../templates/bookmarks.hbs');

var EmptyView = Marionette.ItemView.extend({
  template: _.template('
No bookmarks yet!
')
});

module.exports = Marionette.CompositeView.extend({
  className: 'nm-bookmarks',
  childView: BookmarkItemView,
  childViewContainer: 'ul',
  emptyView: EmptyView,
  template: template
});

'use strict';

var _ = require('underscore');
var Backbone = require('backbone');
var Marionette = require('backbone.marionette');
var BookmarkItemView = require('./BookmarkItemView');
var template = require('../templates/bookmarks.hbs');

var EmptyView = Marionette.ItemView.extend({
  template: _.template('
No bookmarks.
')
});

module.exports = Marionette.CompositeView.extend({
  className: 'nm-bookmarks',
  childView: BookmarkItemView,
  childViewContainer: 'ul',
  emptyView: EmptyView,
  template: template
});

Change message to be shown when there are no bookmarks


import startMirage from 'ember-cli-mirage/start-mirage';
import { settled } from '@ember/test-helpers';

//
// Used to set up mirage for a test. Must be called after one of the
// `ember-qunit` `setup*Test()` methods. It starts the server and sets
// `this.server` to point to it, and shuts the server down when the test
// finishes.
//
// NOTE: the `hooks = self` is for mocha support
//
export default function setupMirage(hooks = self) {
  hooks.beforeEach(function() {
    if (!this.owner) {
      throw new Error('You must call one of the ember-qunit setupTest(),'
        + ' setupRenderingTest() or setupApplicationTest() methods before'
        + ' calling setupMirage()');
    }

    this.server = startMirage(this.owner);
  });

  hooks.afterEach(function() {
    return settled().then(() => {
      this.server.shutdown();
      delete this.server;
    });
  });
}

import startMirage from 'ember-cli-mirage/start-mirage';
import { settled } from '@ember/test-helpers';

//
// Used to set up mirage for a test. Must be called after one of the
// `ember-qunit` `setup*Test()` methods. It starts the server and sets
// `this.server` to point to it, and shuts the server down when the test
// finishes.
//
// NOTE: the `hooks = self` is for mocha support
//
export default function setupMirage(hooks = self) {
  hooks.beforeEach(function() {
    if (!this.owner) {
      throw new Error('You must call one of the ember-qunit setupTest(),'
        + ' setupRenderingTest() or setupApplicationTest() methods before'
        + ' calling setupMirage()');
    }

    this.server = startMirage(this.owner);
  });

  hooks.afterEach(function() {
    return settled().then(() => {
      if (this.server) {
        this.server.shutdown();
        delete this.server;
      }
    });
  });
}

Check if there is a server before shutting it down


'use strict';
const path = require('path');
function simpleReporter(results) {
  let passed = 0;
  let failed = 0;
  let lastPassed = true;

  results.on('pass', function (test) {
    passed++;

    clearPassed();
    lastPassed = true;
    process.stdout.write('PASS ' + test.file);
  });

  results.on('fail', function (test) {
    failed++;
    clearPassed();
    lastPassed = false;
    console.log('FAIL ' + test.file);
    console.log('  ' + test.result.message);
    console.log('');
  });

  results.on('end', function () {
    clearPassed();

    console.log('Ran ' + (passed + failed) + ' tests')
    console.log(passed + ' passed')
    console.log(failed + ' failed')
  });

  function clearPassed() {
    if (lastPassed) {
      if (process.stdout.isTTY) {
        process.stdout.clearLine();
        process.stdout.cursorTo(0);
      } else {
        process.stdout.write('\n');
      }
    }
  }
}

module.exports = simpleReporter;

'use strict';
const path = require('path');
function simpleReporter(results) {
  let passed = 0;
  let failed = 0;
  let lastPassed = true;

  results.on('pass', function (test) {
    passed++;

    clearPassed();
    lastPassed = true;
    process.stdout.write(`PASS ${test.file}`);
  });

  results.on('fail', function (test) {
    failed++;
    clearPassed();
    lastPassed = false;
    console.log(`FAIL ${test.file}${test.strictMode ? ' (strict)' : ' (non-strict)'}`);
    console.log(`  ${test.result.message}`);
    console.log('');
  });

  results.on('end', function () {
    clearPassed();

    console.log(`Ran ${(passed + failed)} tests`);
    console.log(`${passed} passed`);
    console.log(`${failed} failed`);
  });

  function clearPassed() {
    if (lastPassed) {
      if (process.stdout.isTTY) {
        process.stdout.clearLine();
        process.stdout.cursorTo(0);
      } else {
        process.stdout.write('\n');
      }
    }
  }
}

module.exports = simpleReporter;

Mark failures with "(strict)" or "(non-strict)"


/*global describe, it, before, beforeEach */
/*jshint -W030 */

'use strict';

var join = require('path').join
  , fs = require('fs')
  , expect = require('chai').expect
  , cheerio = require('cheerio')
  , bd = require('../lib/bedecked');

// Fixtures dir
var fxd = join(__dirname, 'fixtures');

describe('bedecked', function() {
  describe('api', function() {
    var err, $;
    before(function(done) {
      bd(join(fxd, '001.md'), function(e, html) {
        err = e;
        $ = cheerio.load(html);
        done();
      });
    });

    it('should not generate an error', function() {
      expect(err).to.not.be.ok;
    });

    it('should split into slides', function() {
      expect($('.slides > section').length).to.equal(4);
    });
  });
});

/*global describe, it, before, beforeEach */
/*jshint -W030 */

'use strict';

var join = require('path').join
  , fs = require('fs')
  , expect = require('chai').expect
  , cheerio = require('cheerio')
  , bd = require('../lib/bedecked');

// Fixtures dir
var fxd = join(__dirname, 'fixtures');

describe('bedecked', function() {
  describe('api basics', function() {
    var err, $;
    before(function(done) {
      bd(join(fxd, '001.md'), function(e, html) {
        err = e;
        $ = cheerio.load(html);
        done();
      });
    });

    it('should not generate an error', function() {
      expect(err).to.not.be.ok;
    });

    it('should split into slides', function() {
      expect($('.slides > section').length).to.equal(4);
    });

    it('should add styles and scripts to the page', function() {
      /**
       * @todo
       */
      expect(false).to.be.true;
    });
  });

  describe('api custom opts', function() {
    /**
     * @todo
     */
  });
});

Add some failing tests to fix...


/* ajax_windows.js.  Support for modal popup windows in Umlaut items. */
jQuery(document).ready(function($) {
  var populate_modal = function(data, textStatus, jqXHR) {
    data = $(data);
    var heading = data.find("h1, h2, h3, h4, h5, h6").eq(0).remove();
    $("#modal .modal-header h3").text(heading.text());
    var submit = data.find("form input[type=submit]").eq(0).remove();
    $("#modal .modal-body").html(data.html());
    footer = $("#modal .modal-footer")
    var old_submit = footer.find("#modal .modal-footer input[type=submit]").eq(0).remove();
    if (submit) {
      footer.prepend(submit);
    }
    $("#modal").modal("show");
  }
  var display_modal = function(event) {
    event.preventDefault();
    $.get(this.href, "", populate_modal, "html");
    return false;
  }
  var ajax_form_catch = function(event) {
    event.preventDefault();
    var form =  $("#modal form");
    $.post(form.attr("action"), form.serialize(), populate_modal, "html");
    return false;
  };
  $("a.ajax_window").live("click", display_modal);
  $("#modal .modal-footer input[type=submit]").live("click", ajax_form_catch);
  $("#modal form").live("submit", ajax_form_catch);
});

/* ajax_windows.js.  Support for modal popup windows in Umlaut items. */
jQuery(document).ready(function($) {
  var populate_modal = function(data, textStatus, jqXHR) {
    data = $(data);
    var heading = data.find("h1, h2, h3, h4, h5, h6").eq(0).remove();
    if (heading) $("#modal .modal-header h3").text(heading.text());
    var submit = data.find("form input[type=submit]").eq(0).remove();
    $("#modal .modal-body").html(data.html());
    $("#modal .modal-footer input[type=submit]").remove();
    if (submit) $("#modal .modal-footer").prepend(submit);
    $("#modal").modal("show");
  }
  var display_modal = function(event) {
    event.preventDefault();
    $.get(this.href, "", populate_modal, "html");
    return false;
  }
  var ajax_form_catch = function(event) {
    event.preventDefault();
    var form =  $("#modal form");
    $.post(form.attr("action"), form.serialize(), populate_modal, "html");
    return false;
  };
  $("a.ajax_window").live("click", display_modal);
  $("#modal .modal-footer input[type=submit]").live("click", ajax_form_catch);
  $("#modal form").live("submit", ajax_form_catch);
});

Update to handle modal window submits.


$(document).ready(function(){
 function split(val) {
    if (val){
      var arr = [];
      $.parseHTML(val).forEach(function(elem){
        arr.push($(elem).html());
      });
      return arr;
    } else {
      return val;
    }

  }

  function extract(val){
    return val.split(/,\s*/);
  }

  function extractLast( term ) {
    return extract(term).pop();
  }

  var divJoin = '

';

  $('.tags-input')
  .autocomplete({
    source: function(request, response) {
      response( $.ui.autocomplete.filter(
        availableTags, extractLast(request.term)));
    },
    select: function(event,ui){
      var terms = split($('.tags-list').html()) || [];
      var lastInput = terms[terms.length-1];
      if (availableTags.indexOf(lastInput) === -1){
        terms.pop();
      }
      terms.push(ui.item.value);
      this.value = terms.join(',');
      $('.tags-value').val(terms.join(','));
      $('.tags-list').html('
' + terms.join(divJoin) + '
');
    },
    open: function() {
      $('.ui-menu').width('42%');
    }
  });

});

$(document).ready(function(){
  function split(val) {
    if (val){
      var arr = [];
      $.parseHTML(val).forEach(function(elem){
        arr.push($(elem).html());
      });
      return arr;
    } else {
      return val;
    }

  }

  function extract(val){
    return val.split(/,\s*/);
  }

  function extractLast( term ) {
    return extract(term).pop();
  }

  var divJoin = '

';

  $('.tags-input')
  .autocomplete({
    source: function(request, response) {
      response( $.ui.autocomplete.filter(
        availableTags, extractLast(request.term)));
    },
    select: function(event,ui){
      var terms = split($('.tags-list').html()) || [];
      var lastInput = terms[terms.length-1];
      if (availableTags.indexOf(lastInput) === -1){
        terms.pop();
      }
      terms.push(ui.item.value);
      this.value = terms.join(',');
      $('.tags-value').val(terms.join(','));
      $('.tags-list').html('
' + terms.join(divJoin) + '
');
    },
    open: function() {
      $('.ui-menu').width('42%');
    }
  });

  $('.tags-list').on('click', '.tag', function(event){
    event.preventDefault();
    var tag = $(this).html();
    $(this).remove();

    var tagsList = $('.tags-value').val();
    var tagsArr = extract(tagsList);
    var ind = tagsArr.indexOf(tag);
    if (ind > -1){
      tagsArr.splice(ind, 1);
    }

    $('.tags-value').val(tagsArr);
  });

});

Remove tags by clicking on them


import { updateQuery, fetchQuery, addSearch, isSearching } from '../actions';
import { search } from '../actions/SearchAPI';
import Icon from './Icon';

export default class SearchForm extends React.Component {
  constructor() {
    super()
    this._debouncedSearch = _.debounce(this._debouncedSearch, 300)
  }

  render() {
    return (
      <form onSubmit={e => e.preventDefault()}>

          <input onChange={this._handleKeyUp.bind(this)}
               id='Search'
               type='text'
               autoComplete='off'
               placeholder='Search Wikipedia'
               defaultValue={this.props.Search.queries[this.props.index]}
               className='field border-bottom search__input'/>

<Icon size="18px" icon="search" fill={'silver'} />

      </form>
    );
  }

  _handleKeyUp(e) {
    e.persist()
    this._debouncedSearch(e.target.value.trim())
  }

  _debouncedSearch(query) {
    const {dispatch, index} = this.props;
    dispatch(updateQuery(index, query))
    dispatch(isSearching(true))
    if (query) {
      search(query, this._handleResults.bind(this));
    } else {
      this._handleResults([])
    }
  }
  _handleResults(results) {
    this.props.dispatch(addSearch(results, this.props.index))
    this.props.dispatch(isSearching(false))
  }
}

import { updateQuery, fetchQuery, addSearch, isSearching } from '../actions';
import { search } from '../actions/SearchAPI';
import Icon from './Icon';

export default class SearchForm extends React.Component {
  constructor() {
    super()
    this._debouncedSearch = _.debounce(this._debouncedSearch, 300)
  }

  render() {
    return (
      <form onSubmit={e => e.preventDefault()}>

          <input onChange={this._handleInputChange.bind(this)}
               id='Search'
               type='text'
               autoComplete='off'
               placeholder='Search Wikipedia'
               defaultValue={this.props.Search.queries[this.props.index]}
               className='field border-bottom search__input'/>

<Icon size="18px" icon="search" fill={'silver'} />

      </form>
    );
  }

  _handleInputChange(e) {
    e.persist()
    this._debouncedSearch(e.target.value.trim())
  }

  _debouncedSearch(query) {
    const {dispatch, index} = this.props;
    dispatch(updateQuery(index, query))
    dispatch(isSearching(true))
    if (query) {
      search(query, this._handleResults.bind(this));
    } else {
      this._handleResults([])
    }
  }
  _handleResults(results) {
    this.props.dispatch(addSearch(results, this.props.index))
    this.props.dispatch(isSearching(false))
  }
}

Improve method name for search input change


'use strict';

var fs = require('fs');
var sass = require('node-sass');
var Eyeglass = require('eyeglass').Eyeglass;

var sassOptions = {
  file: './test/test-eyeglass.scss'
};
var eyeglass = new Eyeglass(sassOptions);

sass.render(eyeglass.sassOptions(), function(err, res){
  if (err) console.log(err);
  fs.writeFile('./test/test-eyeglass.css', res.css.toString(), function(err) {
    if (err) console.log(err);
    console.log('Wrote CSS to ./test/test-eyeglass.css');
  });
});

Fix indentation to match the rest of the project


/*global describe,it,element,by,takeScreenshot,expect*/

describe('sap.f.ShellBarVT', function() {
	'use strict';

	it('Test page loaded', function() {
		element(by.css(".sapUiBody")).click();
		expect(takeScreenshot()).toLookAs('initial');
	});

	it("Mega Menu Expanded", function() {
		element(by.id("__button3-internalBtn")).click();
		expect(takeScreenshot()).toLookAs("megaMenu_expanded");
	});

	it("ShellBar scale",function() {
		element(by.id("oTestBtnWidth")).click();
		expect(takeScreenshot()).toLookAs("shellBar-scale");
	});

	it("ShellBar click overflow button",function() {

		if (element(by.css(".sapFShellBarOverflowButton"))){
			element(by.css(".sapFShellBarOverflowButton")).click();
		}
		expect(takeScreenshot()).toLookAs("shellBar-overflow-button-clicked");
	});
});

/*global describe, it, element, by, takeScreenshot, expect, browser*/

describe('sap.f.ShellBarVT', function() {
	'use strict';

	browser.testrunner.currentSuite.meta.controlName = 'sap.f.ShellBar';

	it('Test page loaded', function() {
		element(by.css(".sapUiBody")).click();
		expect(takeScreenshot()).toLookAs('initial');
	});

	it("Mega Menu Expanded", function() {
		element(by.id("__button3-internalBtn")).click();
		expect(takeScreenshot()).toLookAs("megaMenu_expanded");
	});

	it("ShellBar scale",function() {
		element(by.id("oTestBtnWidth")).click();
		expect(takeScreenshot()).toLookAs("shellBar-scale");
	});

	it("ShellBar click overflow button",function() {

		if (element(by.css(".sapFShellBarOverflowButton"))){
			element(by.css(".sapFShellBarOverflowButton")).click();
		}
		expect(takeScreenshot()).toLookAs("shellBar-overflow-button-clicked");
	});
});

Update ownership for sap.f.ShellBar VT


import Ember from 'ember';
import config from './config/environment';
import googlePageview from './mixins/google-pageview';

const Router = Ember.Router.extend(googlePageview, {
  location: config.locationType
});

Router.map(function() {
  this.route('logout');
  this.route('login');
  this.route('github_login');
  this.route('github_authorize', { path: '/authorize/github' });
  this.route('crates');
  this.route('crate', { path: '/crates/*crate_id' }, function() {
    this.route('download');
    this.route('versions');
    this.route('reverse_dependencies');

    // Well-known routes
    this.route('docs');
  });
  this.route('me', function() {
    this.route('crates');
    this.route('following');
  });
  this.route('install');
  this.route('search');
  this.route('dashboard');
  this.route('keywords');
  this.route('keyword', { path: '/keywords/*keyword_id' }, function() {
  });
  this.route('catchAll', { path: '*path' });
});

export default Router;

import Ember from 'ember';
import config from './config/environment';
import googlePageview from './mixins/google-pageview';

const Router = Ember.Router.extend(googlePageview, {
  location: config.locationType
});

Router.map(function() {
  this.route('logout');
  this.route('login');
  this.route('github_login');
  this.route('github_authorize', { path: '/authorize/github' });
  this.route('crates');
  this.route('crate', { path: '/crates/*crate_id' }, function() {
    this.route('download');
    this.route('versions');
    this.route('reverse_dependencies');

    // Well-known routes
    this.route('docs');
  });
  this.route('me', function() {
    this.route('crates');
    this.route('following');
  });
  this.route('install');
  this.route('search');
  this.route('dashboard');
  this.route('keywords');
  this.route('keyword', { path: '/keywords/:keyword_id' }, function() {
      this.route('index', { path: '/' });
  });
  this.route('catchAll', { path: '*path' });
});

export default Router;

Use explicit "index" route for /keywords/:id


'use strict';

let gulp = require( 'gulp' );
let sequence = require( 'run-sequence' );
let plugins = require( 'gulp-load-plugins' )();

let typescript = plugins.typescript.createProject( './src/tsconfig.json', {
	typescript: require( 'typescript' ),
} );

gulp.task( 'clean', function()
{
	return gulp.src( './build/**/*', { read: false } )
		.pipe( plugins.rimraf() );
} );

gulp.task( 'js', function()
{
	return gulp.src( './src/**/*.ts' )
		.pipe( plugins.plumber() )
		.pipe( plugins.sourcemaps.init() )
		.pipe( plugins.typescript( typescript ) )
		.pipe( plugins.babel() )
		.pipe( plugins.sourcemaps.write() )
		.pipe( gulp.dest( './build' ) );
} );

gulp.task( 'build', function( cb )
{
	return sequence( 'clean', 'js', cb );
} );

gulp.task( 'watch', [ 'build' ], function()
{
	gulp.watch( [ './src/**/*' ], [ 'build' ] );
} );

'use strict';

let gulp = require( 'gulp' );
let sequence = require( 'run-sequence' );
let plugins = require( 'gulp-load-plugins' )();

let typescript = plugins.typescript.createProject( './src/tsconfig.json', {
	typescript: require( 'typescript' ),
} );

gulp.task( 'clean', function()
{
	return gulp.src( './build/**/*', { read: false } )
		.pipe( plugins.rimraf() );
} );

gulp.task( 'js', function()
{
	return gulp.src( './src/**/*.ts' )
		.pipe( plugins.plumber() )
		.pipe( plugins.sourcemaps.init() )
		.pipe( plugins.typescript( typescript ) )
		.pipe( plugins.babel() )
		.pipe( plugins.sourcemaps.write( '.', {
			sourceRoot: '../src/',
		} ) )
		.pipe( gulp.dest( './build' ) );
} );

gulp.task( 'build', function( cb )
{
	return sequence( 'clean', 'js', cb );
} );

gulp.task( 'watch', [ 'build' ], function()
{
	gulp.watch( [ './src/**/*' ], [ 'build' ] );
} );

Fix sourcemap generation and source roots.


var gulp = require('gulp');
var jshint = require('gulp-jshint');
var stylish = require('jshint-stylish');
var mocha = require('gulp-mocha');

gulp.task('lint', function () {
  return gulp
  	.src(['./*.js', './lib/**/*.js', './test/**/*.js'])
  	.pipe(jshint())
  	.pipe(jshint.reporter(stylish))
  	.pipe(jshint.reporter('fail'));
});

gulp.task('test', ['lint'], function () {
  return gulp
  	.src('./test/**/*.js', { read: false })
    .pipe(mocha({
      reporter: 'spec',
      globals: {
        should: require('should')
      }
    }));
});

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

var gulp = require('gulp');
var jshint = require('gulp-jshint');
var stylish = require('jshint-stylish');
var mocha = require('gulp-mocha');

gulp.task('lint', function () {
  return gulp
  	.src(['./*.js', './lib/**/*.js', './test/**/*.js'])
  	.pipe(jshint())
  	.pipe(jshint.reporter(stylish))
  	.pipe(jshint.reporter('fail'));
});

gulp.task('test', ['lint'], function () {
  return gulp
  	.src('./test/**/*.js', { read: false })
    .pipe(mocha({
      reporter: 'spec',
      globals: {
        should: require('should')
      }
    }));
});

gulp.task('watch', function() {
  gulp.watch('lib/**/*.js', ['test']);
  gulp.watch('test/**/*.js', ['test']);
});

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

Add watch task for continuous testing during development


var babel = require('gulp-babel');
var del = require('del');
var flatten = require('gulp-flatten');
var gulp = require('gulp');
var runSequence = require('run-sequence');

var babelOpts = require('./scripts/babel/default-options');

var paths = {
  src: [
    'src/**/*.js',
    '!src/**/__tests__/**/*.js',
    '!src/**/__mocks__/**/*.js'
  ],
  lib: 'lib'
};

gulp.task('clean', function(cb) {
  del([paths.lib], cb);
});

gulp.task('lib', function() {
  return gulp
    .src(paths.src)
    .pipe(babel(babelOpts))
    .pipe(flatten())
    .pipe(gulp.dest(paths.lib));
});

gulp.task('build', function(cb) {
  runSequence('clean', ['lib'], cb);
});

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

var babel = require('gulp-babel');
var del = require('del');
var flatten = require('gulp-flatten');
var gulp = require('gulp');
var runSequence = require('run-sequence');

var babelOpts = require('./scripts/babel/default-options');

var paths = {
  src: [
    'src/**/*.js',
    '!src/**/__tests__/**/*.js',
    '!src/**/__mocks__/**/*.js'
  ],
  lib: 'lib'
};

gulp.task('clean', function() {
  return del([paths.lib]);
});

gulp.task('lib', function() {
  return gulp
    .src(paths.src)
    .pipe(babel(babelOpts))
    .pipe(flatten())
    .pipe(gulp.dest(paths.lib));
});

gulp.task('build', function(cb) {
  runSequence('clean', ['lib'], cb);
});

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

Make Gulp wait on the Promise returned from `del`


"use strict";

const superagent = require("superagent");
const Constants = require("../Constants");

const originalRequest = superagent.Request.prototype.request;
superagent.Request.prototype.request = function() {
  this.url = Constants.API_ENDPOINT + this.url;
  return originalRequest.apply(this, arguments);
}

const originalEnd = superagent.Request.prototype.end;
superagent.Request.prototype.end = function() {
  this.set("User-Agent", "Discordie");
  return originalEnd.apply(this, arguments);
};

superagent.Request.prototype.auth = function(token) {
  return this.set("Authorization", token);
};

module.exports = superagent;

"use strict";

const superagent = require("superagent");
const Constants = require("../Constants");

function isDiscordAPI(url) {
  for (const k in Constants.Endpoints) {
    if (url.startsWith(Constants.Endpoints[k]))
      return true;
  }
  return false;
}

const originalRequest = superagent.Request.prototype.request;
superagent.Request.prototype.request = function() {
  if (isDiscordAPI(this.url))
    this.url = Constants.API_ENDPOINT + this.url;
  return originalRequest.apply(this, arguments);
}

const originalEnd = superagent.Request.prototype.end;
superagent.Request.prototype.end = function() {
  if (isDiscordAPI(this.url))
    this.set("User-Agent", "Discordie");
  return originalEnd.apply(this, arguments);
};

superagent.Request.prototype.auth = function(token) {
  return this.set("Authorization", token);
};

module.exports = superagent;

Fix endpoint api replacement in superagent