// 15: destructuring - rename
// To do: make all tests pass, leave the assert lines unchanged!

describe('rename variables while destructuring', () => {

  it('rename object key', () => {
    const {x: y} = {x: 1};
    assert.equal(y, 1);
  });

  it('object key rename with default value', () => {
    const {x: y=2} = {x: 1};
    assert.equal(y, 1);
  });

  it('rename param in a function param', () => {
    const fn = ({x: y}) => {
      assert.equal(y, 1);
    };
    fn({x: 1});
  });

  it('rename param in a function param with default value', () => {
    const fn = ({x: y=3}) => {
      assert.equal(y, 3);
    };
    fn({});
  });

});

// 15: destructuring - rename
// To do: make all tests pass, leave the assert lines unchanged!

describe('rename variables while destructuring', () => {

  it('rename object key', () => {
    const {x: y} = {x: 1};
    assert.equal(y, 1);
  });

  it('object key rename with default value', () => {
    const {x: y=2} = {y: 23};
    assert.equal(y, 42);
  });

  it('rename param in a function param', () => {
    const fn = ({x}) => {
      assert.equal(y, 1);
    };
    fn({x: 1});
  });

  it('rename param in a function param with default value', () => {
    const fn = ({x: z=3}) => {
      assert.equal(y, 3);
    };
    fn({});
  });

});

Make things fail, so it becomes a kata.


function getCurrentUserEmail() {
    var currentUser = Meteor.user();
    var emailsArray = currentUser.emails;
    var firstEmail = emailsArray[0];
    return firstEmail.address;
}

Template.skills.helpers({
    hasSkills: function () {
        var skillService = new SkillService();
        var skillsArray = skillService.getSkills(getCurrentUserEmail());
        return skillsArray.length > 0;
    },

    getSkills: function () {
        var skillService = new SkillService();
        return skillService.getSkills(getCurrentUserEmail());
    }
});

Template.skillEntry.events({
    'click button#add-skill-button': function (evt) {
        evt.preventDefault();
        var skill = Template.instance().$('#add-skill-input').val();
        Meteor.call('PutSkill', getCurrentUserEmail(), skill, function (err) {
            if (err) {
                alert('Error: ' + err);
            }
        });
    }
});

function getCurrentUserEmail() {
    var currentUser = Meteor.user();
    var emailsArray = currentUser.emails;
    var firstEmail = emailsArray[0];
    return firstEmail.address;
}

Template.skills.helpers({
    hasSkills: function () {
        var skillService = new SkillService();
        var skillsArray = skillService.getSkills(getCurrentUserEmail());
        return skillsArray.length > 0;
    },

    getSkills: function () {
        var skillService = new SkillService();
        return skillService.getSkills(getCurrentUserEmail());
    }
});

Template.skillEntry.events({
    'click button#add-skill-button': function (evt) {
        evt.preventDefault();
        var template = Template.instance();
        var skill = template.$('#add-skill-input').val();
        Meteor.call('PutSkill', getCurrentUserEmail(), skill, function (err) {
            if (err) {
                alert('Error: ' + err);
            } else {
                template.$('#add-skill-input').val('');
            }
        });
    }
});

Clear input value after submission


module.exports = function(opts) {
  var implicit = (opts && opts.implicit == false) ? false : true;
  return function(style){
    style.include(__dirname);
    if (implicit) { style.import('typographic'); }
  }
}

module.exports = function(opts) {
  return function(style) {
    style.include(__dirname);
  }
}

Disable implicit import by default


import DS from "ember-data";

export default DS.RESTSerializer.extend({
  serialize: function(section) {
    var bounds = section.get('bounds'),
        json = {
          title: section.get('title'),
          page_ordinal: section.get('pageOrdinal'),
          bounds: {
            x: bounds.x,
            y: bounds.y,
            width: bounds.width,
            height: bounds.height
          }
        },
    physicalBounds = section.get('physicalBounds');

    if (physicalBounds) {
      json.physicalBounds = {
        x: physicalBounds.x,
        y: physicalBounds.y,
        width: physicalBounds.width,
        height: physicalBounds.height
      };
    }
    return json;
  }
});

import DS from "ember-data";

export default DS.RESTSerializer.extend({
  normalize: function(type, hash, prop) {

    hash.bounds = hash.bounds || {x: 0, y: 0, width: 1, height: 1};
    return this._super(type, hash, prop);
  },
  serialize: function(section) {
    var bounds = section.get('bounds'),
        json = {
          title: section.get('title'),
          page_ordinal: section.get('pageOrdinal'),
          bounds: {
            x: bounds.x,
            y: bounds.y,
            width: bounds.width,
            height: bounds.height
          }
        },
    physicalBounds = section.get('physicalBounds');

    if (physicalBounds) {
      json.physicalBounds = {
        x: physicalBounds.x,
        y: physicalBounds.y,
        width: physicalBounds.width,
        height: physicalBounds.height
      };
    }
    return json;
  }
});

Add default bounds value if missing


/**
 * @file cat command
 * @author Sankarsan Kampa (a.k.a k3rn31p4nic)
 * @license GPL-3.0
 */

const request = xrequire('request-promise-native');

exports.exec = async (Bastion, message) => {
  try {
    let options = {
      method: 'HEAD',
      url: 'https://thecatapi.com/api/images/get',
      followAllRedirects: true
    };
    let pic;
    await request(options, function (error, response) { pic = response.request.uri.href; });

    await message.channel.send({
      files: [ pic ]
    });
  }
  catch (e) {
    if (e.response) {
      return Bastion.emit('error', e.response.statusCode, e.response.statusMessage, message.channel);
    }
    Bastion.log.error(e);
  }
};

exports.config = {
  aliases: [],
  enabled: true
};

exports.help = {
  name: 'cat',
  description: 'Shows a random picture of a cat.',
  botPermission: '',
  userTextPermission: '',
  userVoicePermission: '',
  usage: 'cat',
  example: []
};

/**
 * @file cat command
 * @author Sankarsan Kampa (a.k.a k3rn31p4nic)
 * @license GPL-3.0
 */

const request = xrequire('request-promise-native');

exports.exec = async (Bastion, message) => {
  try {
    let options = {
      method: 'HEAD',
      url: 'https://thecatapi.com/api/images/get',
      followAllRedirects: true,
      resolveWithFullResponse: true
    };
    let response = await request(options);

    await message.channel.send({
      files: [ response.request.uri.href ]
    });
  }
  catch (e) {
    if (e.response) {
      return Bastion.emit('error', e.response.statusCode, e.response.statusMessage, message.channel);
    }
    Bastion.log.error(e);
  }
};

exports.config = {
  aliases: [],
  enabled: true
};

exports.help = {
  name: 'cat',
  description: 'Shows a random picture of a cat.',
  botPermission: '',
  userTextPermission: '',
  userVoicePermission: '',
  usage: 'cat',
  example: []
};

Update code to use promises


/* eslint-disable no-underscore-dangle */
/* global window */

export const setJSONDoc = jsondoc => {
  window.__EMBER_GENERATED_DOC_JSON__ = jsondoc;
};
export const getJSONDoc = () => {
  return window.__EMBER_GENERATED_DOC_JSON__;
};

export const extractProps = componentName => {
  const json = getJSONDoc();
  const componentDoc = json.included.find(doc => doc.attributes.name === componentName);
  const rows = componentDoc.attributes.arguments.map(prop => {
    return {
      name: prop.name,
      type: prop.type,
      required: prop.tags.length ? prop.tags.some(tag => tag.name === 'required') : false,
      defaultValue: prop.defaultValue,
      description: prop.description,
    };
  });
  return { rows };
};

export const extractComponentDescription = componentName => {
  const json = getJSONDoc();
  const componentDoc = json.included.find(doc => doc.attributes.name === componentName);
  return componentDoc.attributes.description;
};

/* eslint-disable no-underscore-dangle */
/* global window */

export const setJSONDoc = jsondoc => {
  window.__EMBER_GENERATED_DOC_JSON__ = jsondoc;
};
export const getJSONDoc = () => {
  return window.__EMBER_GENERATED_DOC_JSON__;
};

export const extractProps = componentName => {
  const json = getJSONDoc();
  const componentDoc = json.included.find(doc => doc.attributes.name === componentName);
  const rows = componentDoc.attributes.arguments.map(prop => {
    return {
      name: prop.name,
      type: prop.type,
      required: prop.tags.length ? prop.tags.some(tag => tag.name === 'required') : false,
      defaultValue: prop.defaultValue,
      description: prop.description,
    };
  });
  return { rows };
};

export const extractComponentDescription = componentName => {
  const json = getJSONDoc();
  const componentDoc = json.included.find(doc => doc.attributes.name === componentName);
  if (!componentDoc) {
    return '';
  }
  return componentDoc.attributes.description;
};

FIX ember docs generation if the component parameter is missing (for whatever reason)


module.exports = {
    plugins: ['ghost'],
    extends: [
        'plugin:ghost/test',
    ]
};

module.exports = {
    plugins: ['ghost'],
    extends: [
        'plugin:ghost/test'
    ]
};

Remove dangling comma in array [test file]


'use strict';

const AWS = require('aws-sdk');

const dynamoDb = new AWS.DynamoDB.DocumentClient();

const validateResponses = function(responsesList) {

  if (!(Array.isArray(questionList))) return false;

  for (var i=0; i < responsesList.length; i++) {
    if (typeof responsesList[i].question !== 'string' ||
        !(Array.isArray(responsesList[i].answers)) ) return false;
    for (var j=0; j < responsesList[i].answers.length; j++) {
      if (typeof responsesList[i].answers[j] !== 'string') return false;
    }
  }
  return true;
}

module.exports.create = (event, context, callback) => {
  const timestamp = new Date().getTime();
  const data = JSON.parse(event.body);
  if (typeof data.surveyId !== 'number' || !(validateResponses(data.responses))) {
    console.error('Validation Failed');
    callback(new Error('Could not create survey response'));
    return;
  }

  const params = {
    TableName: process.env.RESPONSES_TABLE,
    Item: {
      surveyId: data.surveyId,
      MapAttribute: data.responses,
      createdAt: timestamp,
      updatedAt: timestamp
    },
    ConditionExpression: 'attribute_not_exists(surveyId)'
  };

  dynamoDb.put(params, (error, result) => {
    if (error) {
      console.error(error);
      callback(new Error('Could not create survey response'));
      return;
    }

    const response = {
      statusCode: 200,
      body: JSON.stringify(params.Item),
    };
    callback(null, response);
  });
};

'use strict';

const AWS = require('aws-sdk');

const dynamoDb = new AWS.DynamoDB.DocumentClient();

const validateResponses = function(responsesList) {

  if (!(Array.isArray(responsesList))) return false;

  for (var i=0; i < responsesList.length; i++) {
    if (typeof responsesList[i].question !== 'string' ||
        typeof responsesList[i].response !== 'string' ) return false;
  }
  return true;
}

module.exports.create = (event, context, callback) => {
  const timestamp = new Date().getTime();
  const data = JSON.parse(event.body);
  if (typeof data.surveyId !== 'number' || !(validateResponses(data.responses))
      || typeof data.id !== 'number') {
    console.error('Validation Failed');
    callback(new Error('Could not create survey response'));
    return;
  }

  const params = {
    TableName: process.env.RESPONSES_TABLE,
    Item: {
      id: data.id,
      surveyId: data.surveyId,
      MapAttribute: data.responses,
      createdAt: timestamp,
      updatedAt: timestamp
    },
    ConditionExpression: 'attribute_not_exists(surveyId)'
  };

  dynamoDb.put(params, (error, result) => {
    if (error) {
      console.error(error);
      callback(new Error('Could not create survey response'));
      return;
    }

    const response = {
      statusCode: 200,
      body: JSON.stringify(params.Item),
    };
    callback(null, response);
  });
};

Align validation. Only allow one response. Fix variable name, Include hash key in row insertion


/**
 *
 * ProductCarousel.js
 *
 */

import React from 'react';
import 'style!css!./ProductCarousel.css';

class ProductCarousel extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedItem: 0,
    };
    this.updateImage = this.updateImage.bind(this);
  }

  updateImage(newIndex) {
    this.setState({
      selectedItem: newIndex,
    });
  }
  /* eslint-disable jsx-a11y/href-no-hash */
  /* Ideally we wouldn't need to disable this, but our internal component is not ready for release yet */
  render() {
    const { selectedItem } = this.state;
    return (

          {this.props.children[selectedItem]}

          {this.props.children.map((child, index) => (
             this.updateImage(index)}
            >
              {child}

          ))}

    );
  }
}

ProductCarousel.propTypes = {
  children: React.PropTypes.node,
};

export default ProductCarousel;

/**
 *
 * ProductCarousel.js
 *
 */

import React from 'react';
import 'style!css!./ProductCarousel.css';

class ProductCarousel extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedItem: 0,
    };
    this.updateImage = this.updateImage.bind(this);
  }

  updateImage(newIndex) {
    this.setState({
      selectedItem: newIndex,
    });
  }

  render() {
    const { selectedItem } = this.state;
    return (

          {this.props.children[selectedItem]}

          {this.props.children.map((child, index) => (
            <a
              key={index}
              className="carousel--thumbnail"
              href={`#carousel-${index}`}
              onClick={() => this.updateImage(index)}
            >
              {child}

          ))}

    );
  }
}

ProductCarousel.propTypes = {
  children: React.PropTypes.node,
};

export default ProductCarousel;

Make links work in ProductCarousel


/**
 * Basics
 */
describe('Basics', () => {
  beforeEach(beforeEachHook);
  afterEach(afterEachHook);

  /**
   * Absolute tracking
   */
  it('absolute tracking', async () => {
    let times = 0;
    const targetOne = createTarget({ marginLeft: '-30px' });
    const targetTwo = createTarget({ marginTop: '30px' });
    const targetThree = createTarget({ marginTop: '-30px' });

    new Tracker({
      targets: document.getElementsByClassName('target'),
      snapshots: [
        {
          callback({ DOMElement }) {
            animate(DOMElement);
            times++;
          }
        }
      ]
    });

    await scroll(0, 10);
    expect(times).to.equal(1);
  });

  /**
   * Relative tracking
   */
  it('relative tracking', async () => {
    let times = 0;
    let poolCopy;
    const targetOne = createTarget({ left: '-20px' }, bounds);
    const targetTwo = createTarget({ top: '-20px' }, bounds);
    const targetThree = createTarget({}, bounds);

    new Tracker({
      targets: document.getElementsByClassName('target'),
      bounds,
      snapshots: [
        {
          callback({ DOMElement, pool }) {
            animate(DOMElement);
            times++;
            poolCopy = pool;
          }
        }
      ]
    });

    await scroll(0, 10);
    expect(times).to.equal(1);
    expect(poolCopy).to.include(targetThree);
  });
});

/**
 * Basics
 */
describe('Basics', () => {
  beforeEach(beforeEachHook);
  afterEach(afterEachHook);

  /**
   * Absolute tracking
   */
  it('absolute tracking', async () => {
    let times = 0;
    let poolCopy;
    const targetOne = createTarget({ marginLeft: '-30px' });
    const targetTwo = createTarget({ marginTop: '30px' });
    const targetThree = createTarget({ marginTop: '-30px' });

    new Tracker({
      targets: document.getElementsByClassName('target'),
      snapshots: [
        {
          callback({ DOMElement, pool }) {
            animate(DOMElement);
            times++;
            poolCopy = pool;
          }
        }
      ]
    });

    await scroll(0, 10);
    expect(times).to.equal(1);
    expect(poolCopy).to.include(targetTwo);
  });

  /**
   * Relative tracking
   */
  it('relative tracking', async () => {
    let times = 0;
    let poolCopy;
    const targetOne = createTarget({ left: '-20px' }, bounds);
    const targetTwo = createTarget({ top: '-20px' }, bounds);
    const targetThree = createTarget({}, bounds);

    new Tracker({
      targets: document.getElementsByClassName('target'),
      bounds,
      snapshots: [
        {
          callback({ DOMElement, pool }) {
            animate(DOMElement);
            times++;
            poolCopy = pool;
          }
        }
      ]
    });

    await scroll(0, 10);
    expect(times).to.equal(1);
    expect(poolCopy).to.include(targetThree);
  });
});

Test (basics): Require target being in the tracked pool


import React from 'react';
import './CommandBar.css';

export default class CommandBar extends React.Component {
  onTextChange(eventArgs) {
    const { onCommandChange } = this.props;

    if (eventArgs.keyCode === 13) { //return
      onCommandChange(this.refs.commandText.value);
    }
  }
  render() {
    const { commandError, modal } = this.props;

    const classNames = modal ? "commandbar modal" : "commandbar inline";

    return (

          >
          <input ref="commandText" type="text" onKeyDown={this.onTextChange.bind(this)} />

          {commandError}

    );
  }
}

import React from 'react';
import './CommandBar.css';

export default class CommandBar extends React.Component {
  onTextChange(eventArgs) {
    const { onCommandChange } = this.props;

    if (eventArgs.keyCode === 13) { //return
      onCommandChange(this.refs.commandText.value);
      this.refs.commandText.value = '';
    }
  }
  render() {
    const { commandError, modal } = this.props;

    const classNames = modal ? "commandbar modal" : "commandbar inline";

    return (

          >
          <input ref="commandText" type="text" onKeyDown={this.onTextChange.bind(this)} />

          {commandError}

    );
  }
}

Reset commandbar input after pressing return


Template.home.rendered = function() {
  // Probably erroneous way to clear the previous Famous canvas.
  // But it works.
  var mainContext = Engine.createContext();

  var contentView = new Scrollview({
    size: [undefined, undefined]
  });

  window.content = new Surface({
    size: [undefined, undefined],
    content: UI.render(Template.homecontent).render().toHTML()
  });

  content.pipe(contentView);
  contentView.sequenceFrom([content]);

  mainContext.add(contentView);

  setTimeout(function() {
    var h = $('.famous-container .container')[0].scrollHeight + 72;
    content.setSize([undefined, h]);
  }, 1000);
};

Template.home.rendered = function() {
  // Probably erroneous way to clear the previous Famous canvas.
  // But it works.
  var mainContext = Engine.createContext();

  var contentView = new Scrollview();

  var content = new Surface({
    size: [undefined, undefined],
    content: UI.render(Template.homecontent).render().toHTML()
  });

  content.pipe(contentView);
  contentView.sequenceFrom([content]);

  mainContext.add(contentView);

  // size: [undefined, true] is borked in ScrollViews,
  // so we have to hack around it a bit.
  content.on('deploy', function() {
    var h = $('.famous-container .container')[0].scrollHeight + 72;
    content.setSize([undefined, h]);
  });
};

Fix homepage scrolling. Can’t test on phone just now, but it should be fine.


/* eslint-disable @typescript-eslint/no-var-requires */
"use strict";
var resolve = require("path").resolve;
var webpack = require("webpack");

module.exports = {
  mode: "production",
  entry: ["regenerator-runtime/runtime", resolve(__dirname, "src/web.js")],
  devtool: "source-map",
  output: {
    path: resolve(__dirname, "build"),
    filename: "web.js",
    library: "arangojs",
    libraryTarget: "umd",
  },
  module: {
    rules: [
      // NOTE: these rules apply in reverse order
      {
        test: /\.(ts|js)$/,
        loader: "babel-loader",
      },
    ],
  },
  resolve: {
    extensions: [".web.js", ".web.ts", ".js", ".ts", ".json"],
    fallback: {
      url: require.resolve("url/"),
      querystring: require.resolve("querystring/"),
    },
  },
  plugins: [
    new webpack.DefinePlugin({
      "process.env": { NODE_ENV: '"production"' },
    }),
  ],
};

/* eslint-disable @typescript-eslint/no-var-requires */
"use strict";
var resolve = require("path").resolve;
var webpack = require("webpack");

module.exports = {
  mode: "production",
  entry: ["regenerator-runtime/runtime", resolve(__dirname, "src/web.js")],
  devtool: "source-map",
  output: {
    path: resolve(__dirname, "build"),
    filename: "web.js",
    library: { name: "arangojs", type: "umd" },
  },
  module: {
    rules: [
      // NOTE: these rules apply in reverse order
      {
        test: /\.(ts|js)$/,
        loader: "babel-loader",
      },
    ],
  },
  resolve: {
    extensions: [".web.js", ".web.ts", ".js", ".ts", ".json"],
    fallback: {
      url: require.resolve("url/"),
      querystring: require.resolve("querystring/"),
    },
  },
  plugins: [
    new webpack.DefinePlugin({
      "process.env": { NODE_ENV: '"production"' },
    }),
  ],
};

Fix webpack 5 library type


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

module.exports = {
  devtool: 'eval',
  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'],
      include: path.join(__dirname, 'src')
    }]
  }
};

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

module.exports = {
  devtool: 'eval',
  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?presets[]=es2015&presets[]=react'],
      include: path.join(__dirname, 'src')
    }]
  }
};

Fix babel loader to specify react as a preset


/*jslint browser: true*/
/*globals $, FB, gapi, fbLogin, setSettings, gGetEmail*/

"use strict";

function populateRentRoll(email) {
    if (email === '') {
        console.log("populateRentRoll - empty email!");
        return;
    }
    $.ajax({
        url: '/tenants',
        data: { 'email': email },
        success: function (tenants) {
            document.getElementById('tenants').innerHTML = tenants;
        }
    });
}

function gRentRoll(resp) {
    populateRentRoll(gGetEmail(resp));
}

function fbRentRoll() {
    FB.api('/me', function (response) {
        populateRentRoll(response.email);
    });
}

function rentRollNotLoggedIn() {
    window.location.href = "/submit";
    /*var signinForm = document.getElementById("signinform");
    if (signinForm == null) {
        console.log("rentRollNotLoggedIn - ERROR NO SIGNIN FORM ELEMENT");
        return;
    }
    $.ajax({
        url: '/signinform',
        success: function( form ) {
            signinForm.innerHTML = form;
        }
    });*/
}

function rentRollTemplateNotLoggedIn() { }}
function gRentRollTemplate(resp) { }
function fbRentRollTemplate() { }

Add blank (g, fb)RentRollTemplate js functions


import React from 'react'
import InventoryContainer from '../containers/InventoryContainer'
import ShadowBox from '../Components/ShadowBox'
import FlexDiv from '../Components/FlexDiv'

const InventoryBox = ShadowBox.extend`
  width:100%;
  margin:10px;
`

const InventoryDiv = FlexDiv.extend`
  width:50%;
  margin-top: 50px;
`

const InventoryScene = () => {

  const maltColumns = [
    {name: "Malt Name", type: "text"},
    {name: "Amount", type: "number"}
  ]

  const yeastColumns = [
    {name: "Yeast Name", type: "text"},
    {name: "Amount", type: "number"}
  ]

  const hopColumns = [
    {name: "Hop Name", type: "text"},
    {name: "Amount", type: "number"}
  ]

  return(
    <InventoryDiv>
      <InventoryBox>
        <InventoryContainer name="malt" columns={maltColumns} displayLimit={5} />
      </InventoryBox>
      <InventoryBox>
        <InventoryContainer name="yeast" columns={yeastColumns} displayLimit={5} />
      </InventoryBox>
      <InventoryBox>
        <InventoryContainer name="hops" columns={hopColumns} displayLimit={5} />
      </InventoryBox>
    </InventoryDiv>
  )
}

export default InventoryScene

import React from 'react'
import InventoryContainer from '../containers/InventoryContainer'
import ShadowBox from '../Components/ShadowBox'
import FlexDiv from '../Components/FlexDiv'

const InventoryBox = ShadowBox.extend`
  width:100%;
  margin:10px;
`

const InventoryDiv = FlexDiv.extend`
  width:50%;
  margin-top: 50px;
`

const InventoryScene = () => {

  const maltColumns = [
    {name: "Malt Name", type: "text"},
    {name: "Amount", type: "number"}
  ]

  const yeastColumns = [
    {name: "Yeast Name", type: "text"},
    {name: "Amount", type: "number"}
  ]

  const hopColumns = [
    {name: "Hop Name", type: "text"},
    {name: "Amount", type: "number"}
  ]

  return(
    <InventoryDiv>
      <InventoryBox>
        <InventoryContainer name="malt" columns={maltColumns} displayLimit={5} />
        View Full Table
      </InventoryBox>
      <InventoryBox>
        <InventoryContainer name="yeast" columns={yeastColumns} displayLimit={5} />
        View Full Table
      </InventoryBox>
      <InventoryBox>
        <InventoryContainer name="hops" columns={hopColumns} displayLimit={5} />
        View Full Table
      </InventoryBox>
    </InventoryDiv>
  )
}

export default InventoryScene

Add links to idvidual inventory scenes


/*jslint browser: true, undef: true *//*global Ext*/
Ext.define('JarvusAceDemo.view.editor.Panel', {
    extend: 'Ext.Panel',
    xtype: 'editor-panel',

    requires: [
        'Jarvus.ace.Editor'
    ],

    layout: 'fit',

    items: [{
        xtype: 'jarvus-ace-editor',

        // Ace configuration
        options: {
            theme: 'ace/theme/monokai',
            mode: 'ace/mode/javascript',
            keyboardHandler: 'ace/keyboard/vim',
            showPrintMargin: true,
            printMarginColumn: 20,
            fontSize: 24
        },

        // subcribe to ACE events
        subscribe: {
            'Document': [
                'change'
            ],
            'Editor': [
                'blur',
                'change'
            ],
            'EditSession': [
                'change'
            ],
            'Selection': [
                'selectionchange'
            ]
        }
    }]

});

/*jslint browser: true, undef: true *//*global Ext*/
Ext.define('JarvusAceDemo.view.editor.Panel', {
    extend: 'Ext.Panel',
    xtype: 'editor-panel',

    requires: [
        'Jarvus.ace.Editor'
    ],

    layout: 'fit',

    items: [{
        xtype: 'jarvus-ace-editor',

        // subcribe to ACE events
        subscribe: {
            'Document': [
                'change'
            ],
            'Editor': [
                'blur',
                'change'
            ],
            'EditSession': [
                'change'
            ],
            'Selection': [
                'selectionchange'
            ]
        }
    }]

});

Update example to reflect configuration changes


var request = require('request'),
    RoomStream = require('../room-stream');

module.exports = function (room) {
    console.log("Joining room " + room + "...");

    request.get('https://streaming.campfirenow.com/room/' + room + '/live.json')
        .auth('aba80bf92dc8adb1fe7eb438b3bf8c688de1df1b', 'X')
        .pipe(new RoomStream());
};

var request = require('request'),
    RoomStream = require('../room-stream');

module.exports = function (room) {
    console.log("Joining room " + room + "...");

    request.get('https://streaming.campfirenow.com/room/' + room + '/live.json')
        .auth('aba80bf92dc8adb1fe7eb438b3bf8c688de1df1b', 'X')
        .pipe(new RoomStream());

    process.stdin.on('data', function (chunk) {
        var line = chunk.toString().replace(/\n/, '');

        request.post({
            url: 'https://nokia-entertainment.campfirenow.com/room/' + room + '/speak.json',
            auth: {
                user: 'aba80bf92dc8adb1fe7eb438b3bf8c688de1df1b',
                pass: 'X'
            },
            json: {
                message: {
                    type: "TextMessage",
                    body: line
                }
            }
        });
    });

};

Send messages from stdin to campfire room.


import React, { Component } from 'react';
import ChatMessage from './ChatMessage';
import Scroll from 'react-scroll';

class ChatMessageList extends Component {
    getMessages = () => {
        return this.props.messages.map((message, index) => {
            return <ChatMessage key={index} message={message} person={message.from === 'me' ? this.props.me : this.props.partner} />;
        });
    }

    scrollToBottom = () => {
        var scroll = Scroll.animateScroll;
        scroll.scrollToBottom();
    }

    componentDidMount() {
        this.scrollToBottom();
    }

    componentDidUpdate() {
        this.scrollToBottom();
    }

    render() {
        return (
            <ul>
                {this.getMessages()}
            </ul>
        );
    }
}

export default ChatMessageList;

import React, { Component } from 'react';
import ChatMessage from './ChatMessage';
import Scroll from 'react-scroll';

class ChatMessageList extends Component {
    getMessages = () => {
        return this.props.messages.map((message, index) => {
            return <ChatMessage key={index} message={message} person={message.from === 'me' ? this.props.me : this.props.partner} />;
        });
    }

    scrollToBottom = () => {
        var scroll = Scroll.animateScroll;
        scroll.scrollToBottom({duration: 0});
    }

    componentDidMount() {
        this.scrollToBottom();
    }

    componentDidUpdate() {
        this.scrollToBottom();
    }

    render() {
        return (
            <ul>
                {this.getMessages()}
            </ul>
        );
    }
}

export default ChatMessageList;

Set scrolling duration to 0


import React from 'react';
import { List, ListItem } from 'material-ui/List';
import Divider from 'material-ui/Divider';
import Subheader from 'material-ui/Subheader';
import Avatar from 'material-ui/Avatar';

import * as Helper from '../../../util/helper';
import * as Colors from 'material-ui/styles/colors';

const giveawayRow = (touchTapHandler) => (ga) => (
  <ListItem
    key={ ga._id }
    primaryText={
      { ga.title }
    }
    secondaryText={

        { ga.location }

    }
    secondaryTextLines={2}
    onTouchTap={ touchTapHandler(ga) }
  />
);

export const NearbyGiveaways = (props) => (
  <List>
    <Subheader>

Nearby Giveaways

    </Subheader>
    { Helper.insertDividers(props.giveaways.map(giveawayRow(props.nearbyOnClick))) }
  </List>
);

import React from 'react';
import { List, ListItem } from 'material-ui/List';
import Divider from 'material-ui/Divider';
import Subheader from 'material-ui/Subheader';
import Avatar from 'material-ui/Avatar';

import * as Helper from '../../../util/helper';
import * as AvatarHelper from '../../../util/avatar';
import * as GiveawaysHelper from '../../../util/giveaways';
import * as Colors from 'material-ui/styles/colors';

const giveawayRow = (touchTapHandler) => (ga) => (
  <ListItem
    key={ ga._id }
    primaryText={
      { ga.title }
    }
    secondaryText={

        { ga.location }

    }
    leftAvatar={
      ga.avatarId ? <Avatar src={ AvatarHelper.getAvatar(ga.avatarId, 64) } />
                  : <Avatar icon={ GiveawaysHelper.getCategoryIcon(ga) } backgroundColor={ GiveawaysHelper.getStatusColor(ga) } />
    }
    secondaryTextLines={2}
    onTouchTap={ touchTapHandler(ga) }
  />
);

export const NearbyGiveaways = (props) => (
  <List>
    <Subheader>

Nearby Giveaways

    </Subheader>
    { Helper.insertDividers(props.giveaways.map(giveawayRow(props.nearbyOnClick))) }
  </List>
);

Add avatars for in nearby giveaway sidebar


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

module.exports = {
  devtool: 'cheap-module-source-map',
  entry: [
    'webpack-dev-server/client?http://localhost:3000',
    'webpack/hot/only-dev-server',
    './src/index'
  ],
  output: {
    path: path.join(__dirname, 'dist/static'),
    filename: 'bundle.js',
    publicPath: '/static/'
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('production')
      }
    })
  ],
  module: {
    loaders: [{
      test: /\.js$/,
      loaders: ['react-hot', 'babel'],
      include: path.join(__dirname, 'src')
    }]
  }
};

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

module.exports = {
  devtool: 'cheap-module-source-map',
  entry: [
    './src/index'
  ],
  output: {
    path: path.join(__dirname, 'dist/static'),
    filename: 'bundle.js',
    publicPath: '/static/'
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('production')
      }
    })
  ],
  module: {
    loaders: [{
      test: /\.js$/,
      loaders: ['react-hot', 'babel'],
      include: path.join(__dirname, 'src')
    }]
  }
};

Remove hot reloading and dev server for production deployment.


(function ($) {

    $(function() {
        /**
         * Adds links to songbook references on song pages.
         */
        $( "div.field-name-field-songbook-references > div > div" ).wrap(function() {
            // return "";
            return "";
        });
    });

}(jQuery));

(function ($) {

    $(function() {
        /**
         * Adds links to songbook references on song pages.
         */
        $( "div.field-name-field-songbook-references > div > div" ).wrap(function() {
            return "";
        });
    });

}(jQuery));

Change jQuery for songbook references to use clean urls.


var $ = require('zepto-browserify').$;

var name = '.COM API';

var baseUrl = 'https://public-api.wordpress.com/rest/';

function getRequestUrl(request) {
  var version = request.version || 'v1';
  return baseUrl + version + request.path;
}

function getDiscoveryUrl(version) {
  return baseUrl + version + '/help';
}

function parseEndpoints(data, version) {
  return data;
}

function loadVersions(callback) {
  // Strange having to specify a version to retrieve versions :)
  $.ajax({
    type: 'GET',
    url: baseUrl + 'v1.1/versions?include_dev=true',
    headers: $.extend({'accept':'application/json'}),
    success: function(data) {
      callback(undefined, data.versions.map(version => 'v' + version), 'v' + data.current_version);
    },
    error: function(xhr, errorType, error) {
      callback({
        status: xhr.status,
        error: error,
        errorType: errorType,
        body: xhr.response,
      });
    }
  });
}

module.exports = {
  name: name,
  baseUrl: baseUrl,
  getRequestUrl: getRequestUrl,
  getDiscoveryUrl: getDiscoveryUrl,
  parseEndpoints: parseEndpoints,
  loadVersions: loadVersions
};

var $ = require('zepto-browserify').$;

var name = '.COM API';

var baseUrl = 'https://public-api.wordpress.com/rest/';

function getRequestUrl(request) {
  var version = request.version || 'v1';
  return baseUrl + version + request.path;
}

function getDiscoveryUrl(version) {
  return baseUrl + version + '/help';
}

function parseEndpoints(data, version) {
  return data;
}

function loadVersions(callback) {
  // Strange having to specify a version to retrieve versions :)
  $.ajax({
    type: 'GET',
    url: baseUrl + 'v1.1/versions?include_dev=true',
    headers: $.extend({'accept':'application/json'}),
    success: function(data) {
      callback(
        undefined,
        data.versions.map(function(version) {
         return 'v' + version;
        }),
        'v' + data.current_version
      );
    },
    error: function(xhr, errorType, error) {
      callback({
        status: xhr.status,
        error: error,
        errorType: errorType,
        body: xhr.response,
      });
    }
  });
}

module.exports = {
  name: name,
  baseUrl: baseUrl,
  getRequestUrl: getRequestUrl,
  getDiscoveryUrl: getDiscoveryUrl,
  parseEndpoints: parseEndpoints,
  loadVersions: loadVersions
};

Remove arrow function to fix the build


'use strict';
/**
 * winston transport support
 */

var sender = require('./sender');
var util = require('util');
var winston = require('winston');
var Transport = winston.Transport;
var DEFAULT_TAG = 'winston';

function fluentTransport(tag, options) {
  if (arguments.length === 0) {
    tag = DEFAULT_TAG;
  } else {
    if (typeof(tag) === 'object') {
      options = tag;
      tag = DEFAULT_TAG;
    }
  }

  options = options || {};

  this.sender = new sender.FluentSender(tag, options);

  Transport.call(this, options);
}

util.inherits(fluentTransport, Transport);

fluentTransport.prototype.log = function(level, message, meta, callback) {
  var sender = this.sender;

  var data = {
    level: level,
    message: message,
    meta: meta
  };

  sender.emit(data, (error) => {
    if (error) {
      this.emit('error', error);
      callback(error, false);
    } else {
      this.emit('logged');
      callback(null, true);
    }
  });

};

fluentTransport.prototype.name = 'fluent';
exports.Transport = fluentTransport;

'use strict';
/**
 * winston transport support
 */

var sender = require('./sender');
var util = require('util');
var winston = require('winston');
var Transport = winston.Transport;
var DEFAULT_TAG = 'winston';

function fluentTransport(tag, options) {
  if (arguments.length === 0) {
    tag = DEFAULT_TAG;
  } else {
    if (typeof(tag) === 'object') {
      options = tag;
      tag = DEFAULT_TAG;
    }
  }

  options = options || {};

  this.sender = new sender.FluentSender(tag, options);

  Transport.call(this, options);
}

util.inherits(fluentTransport, Transport);

fluentTransport.prototype.log = function(level, message, meta, callback) {
  var sender = this.sender;

  var data = {
    level: level,
    message: message,
    meta: meta
  };

  sender.emit(data, (error) => {
    if (error) {
      this.emit('error', error);
      callback(error, false);
    } else {
      this.emit('logged');
      callback(null, true);
    }
  });

};

fluentTransport.prototype.name = 'fluent';
module.exports.Transport = fluentTransport;

Use module.exports instead of exports


var AWS = require('../core');

AWS.EC2 = AWS.Service.defineService('ec2', ['2013-06-15*', '2013-07-15*', '2013-08-15*', '2013-10-01*', '2013-10-15'], {
  setupRequestListeners: function setupRequestListeners(request) {
    request.removeListener('extractError', AWS.EventListeners.Query.EXTRACT_ERROR);
    request.addListener('extractError', this.extractError);
  },

  /**
   * @api private
   */
  extractError: function extractError(resp) {
    // EC2 nests the error code and message deeper than other AWS Query services.
    var httpResponse = resp.httpResponse;
    var data = new AWS.XML.Parser({}).parse(httpResponse.body.toString() || '');
    if (data.Errors)
      resp.error = AWS.util.error(new Error(), {
        code: data.Errors.Error.Code,
        message: data.Errors.Error.Message
      });
    else
      resp.error = AWS.util.error(new Error(), {
        code: httpResponse.statusCode,
        message: null
      });
  }
});

module.exports = AWS.EC2;

var AWS = require('../core');

AWS.EC2 = AWS.Service.defineService('ec2', ['2013-06-15*', '2013-07-15*', '2013-08-15*', '2013-10-01*', '2013-10-15'], {
  /**
   * @api private
   */
  setupRequestListeners: function setupRequestListeners(request) {
    request.removeListener('extractError', AWS.EventListeners.Query.EXTRACT_ERROR);
    request.addListener('extractError', this.extractError);
  },

  /**
   * @api private
   */
  extractError: function extractError(resp) {
    // EC2 nests the error code and message deeper than other AWS Query services.
    var httpResponse = resp.httpResponse;
    var data = new AWS.XML.Parser({}).parse(httpResponse.body.toString() || '');
    if (data.Errors)
      resp.error = AWS.util.error(new Error(), {
        code: data.Errors.Error.Code,
        message: data.Errors.Error.Message
      });
    else
      resp.error = AWS.util.error(new Error(), {
        code: httpResponse.statusCode,
        message: null
      });
  }
});

module.exports = AWS.EC2;

Add @api private on private EC2 methods


(function($){
  "use strict";

  var url = "http://devitconf.org/";

  var devit = {

    init: function () {
      devit.getSocialCounts();
      devit.setCurrentYear();
    },

    getSocialCounts: function () {
      $.getJSON(
        "http://urls.api.twitter.com/1/urls/count.json?url=" + url + "&callback=?",
        function (json) {
          $('.js-tw-count').text(devit._getK(json.count));
        }
      );

      $.getJSON(
        "http://graph.facebook.com/" + url,
        function (json) {
          $('.js-fb-count').text(devit._getK(json.shares));
        }
      );
    },

    _getK: function(n) {
      var c = parseInt(n);

      if(c > 1000)
        return ('' + c)[0] + 'k';
      else
        return c;
    },

    setCurrentYear: function () {
      var currentYear = new Date().getFullYear();
      $('.js-current-year').text(currentYear);
    }
  };

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

})(jQuery);

(function($){
  "use strict";

  var url = "http://devitconf.org/";

  var devit = {

    init: function () {
      devit.getSocialCounts();
      devit.setCurrentYear();
    },

    getSocialCounts: function () {
      $.getJSON(
        "http://urls.api.twitter.com/1/urls/count.json?url=" + url + "&callback=?",
        function (json) {
          $('.js-tw-count').text(devit._getK(json.count));
        }
      );

      $.getJSON(
        "http://graph.facebook.com/" + url,
        function (json) {
          $('.js-fb-count').text(devit._getK(json.shares));
        }
      );
    },

    _getK: function(n) {
      var c = parseInt(n);

      if (c > 9999 && c <= 999999) {
        return parseFloat((c / 1000).toFixed(1)) + 'k';
      } else if (c > 999999) {
        return parseFloat((c / 1000000).toFixed(1)) + 'm';
      } else {
        return c;
      }
    },

    setCurrentYear: function () {
      var currentYear = new Date().getFullYear();
      $('.js-current-year').text(currentYear);
    }
  };

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

})(jQuery);

Add support for abbreviating share numbers larger than 9999


var rb = require('react-bootstrap');
var React = require('react');
var _ = require('lodash');

var Table = rb.Table,
    tr = rb.tr,
    td =rb.td,
    form = rb.form,
    Input = rb.Input;

var WidgetRow = React.createClass({
  render: function() {
    return (

            <Input type="checkbox" label=" " checked={this.props.widget.options.active} onChange={this.toggleActive}/>
            {this.props.widget.getType()}
            {this.props.widget.getReactElement()}

{this.props.widget.getHandledPaths().map(function(path){
              return
{path}

            })}

    );
  },
  toggleActive: function() {
    this.props.widget.setActive(!this.props.widget.options.active);
  }
});

module.exports = WidgetRow;

var rb = require('react-bootstrap');
var React = require('react');
var _ = require('lodash');

var Table = rb.Table,
    tr = rb.tr,
    td =rb.td,
    form = rb.form,
    Input = rb.Input;

var WidgetRow = React.createClass({
  render: function() {
    return (

            <Input type="checkbox" label=" " checked={this.props.widget.options.active} onChange={this.toggleActive}/>
            {this.props.widget.getType()}
            {this.props.widget.getReactElement()}

{this.props.widget.getHandledPaths().map(function(path, i){
              return
{path}

            })}

    );
  },
  toggleActive: function() {
    this.props.widget.setActive(!this.props.widget.options.active);
  }
});

module.exports = WidgetRow;

Add key property to paths list items


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

    /**
     * with-observe uses RXJS to implement its observer/observable
     * patterns.
     * https://github.com/Reactive-Extensions/RxJS
     */
    var Rx = require('rxjs');

    return withObserveState;
    function withObserveState() {
        /* jshint validthis: true */

        this.before('initialize', function () {
            this.localSubscriptions = [];
        });

        /**
         * Observe a sequence which can be disposed of on teardown.
         *
         * Takes the sequence to observe.
         * Returns the observable sequence.
         */
        this.observe = function (upstream) {
            return Rx.Observable.create(function (o) {
                var subscription = upstream.subscribe(o);
                // Store the subscription so that the mixin can dispose on teardown.
                this.localSubscriptions.push(subscription);
                return subscription;
            }.bind(this), upstream);
        };

        this.before('teardown', function () {
            this.localSubscriptions.forEach(function (subscription) {
                subscription.dispose();
            });
        });
    }
});

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

    /**
     * with-observe uses RXJS to implement its observer/observable
     * patterns.
     * https://github.com/Reactive-Extensions/RxJS
     */
    var Rx = require('rxjs');

    return withObserve;
    function withObserve() {
        /* jshint validthis: true */

        this.before('initialize', function () {
            this.localSubscriptions = [];
        });

        /**
         * Observe a sequence which can be disposed of on teardown.
         *
         * Takes the sequence to observe.
         * Returns the observable sequence.
         */
        this.observe = function (upstream) {
            return Rx.Observable.create(function (o) {
                var subscription = upstream.subscribe(o);
                // Store the subscription so that the mixin can dispose on teardown.
                this.localSubscriptions.push(subscription);
                return subscription;
            }.bind(this), upstream);
        };

        this.before('teardown', function () {
            this.localSubscriptions.forEach(function (subscription) {
                subscription.dispose();
            });
        });
    }
});

Correct mixin name missed in refactor


import Ember from 'ember';

export default Ember.Component.extend({

  tagName: 'div',
  classNames: ['ui', 'search', 'selection', 'dropdown', 'fluid'],

  value: null,
  text: null,

  bindAttributes: ['value', 'text'],

  setup: function () {
    this.$().dropdown({
      apiSettings: {
        url: this.get('query-url'),
        onResponse: function (response) {
          var documents = Ember.ArrayProxy.create({content: Ember.A(response.documents)});
          var results = documents.map(function (item, index, enumerable) {
            return {name: item.navn, value: item._id};
          });
          return {success: true, results: results};
        }
      },
      onChange: Ember.run.bind(this, this.onChange)
    });
  }.on('didInsertElement'),

  onChange: function (value, text, $choice) {
    this.set('value', value);
  },

  updateDropdownValue: function () {
    this.$().dropdown('set value', this.get('value'));
  }.observes('value'),

  updateDropdownText: function () {
    this.$().dropdown('set text', this.get('text'));
  }.observes('text')

});

import Ember from 'ember';

export default Ember.Component.extend({

  tagName: 'div',
  classNames: ['ui', 'search', 'selection', 'dropdown', 'fluid'],

  value: null,
  text: null,

  bindAttributes: ['value', 'text'],

  setup: function () {
    this.$().dropdown({
      apiSettings: {
        url: this.get('query-url'),
        onResponse: function (response) {
          var documents = Ember.ArrayProxy.create({content: Ember.A(response.documents)});
          var results = documents.map(function (item, index, enumerable) {
            return {name: item.navn, value: item._id};
          });
          return {success: true, results: results};
        }
      },
      onChange: Ember.run.bind(this, this.onChange)
    });
  }.on('didInsertElement'),

  onChange: function (value, text, $choice) {
    if (this.get('attrs.action')) {

      if (!this.get('attrs.value')) {
        this.$().dropdown('clear');
      }

      this.sendAction('action', value);

    } else {
      this.set('value', value);
    }
  },

  updateDropdownValue: function () {
    this.$().dropdown('set value', this.get('value'));
  }.observes('value'),

  updateDropdownText: function () {
    this.$().dropdown('set text', this.get('text'));
  }.observes('text')

});

Add support for actions to remote dropdown


const root = __dirname + '/../../../..';

require('@babel/register')({
  root,
  cwd: root,
  configFile: root + '/packages/server/babel.config.js',
  extensions: ['.js', '.jsx', '.ts', '.tsx']
});

require.extensions['.scss'] = () => {};

Object.assign(global, require('../../jest.config').globals);

const { setup } = require('@gqlapp/testing-server-ts');
require('..');

module.exports = setup;

const root = __dirname + '/../../../..';

require('@babel/register')({
  root,
  cwd: root,
  configFile: root + '/packages/server/babel.config.js',
  extensions: ['.js', '.jsx', '.ts', '.tsx']
});

require.extensions['.scss'] = () => {};
require.extensions['.css'] = () => {};
require.extensions['.less'] = () => {};

Object.assign(global, require('../../jest.config').globals);

const { setup } = require('@gqlapp/testing-server-ts');
require('..');

module.exports = setup;

Fix jest run when using Less files with Antd


exports.BattleScripts = {
	init: function () {
		for (var i in this.data.Pokedex) {
			var tier = '';
			var adjustment = 0;
			// mega evolutions get the same stat boost as their base forme
			if (this.data.FormatsData[i]) tier = this.data.FormatsData[i].tier || this.data.FormatsData[toId(this.getTemplate(i).baseSpecies)].tier;
			switch (tier) {
			case 'BL':
			case 'UU':
				adjustment = 5;
				break;
			case 'BL2':
			case 'RU':
				adjustment = 10;
				break;
			case 'BL3':
			case 'NU':
			case 'BL4':
			case 'PU':
			case 'NFE':
			case 'LC Uber':
			case 'LC':
				adjustment = 15;
			}

			if (adjustment) {
				for (var j in this.data.Pokedex[i].baseStats) {
					this.modData('Pokedex', i).baseStats[j] = this.clampIntRange(this.data.Pokedex[i].baseStats[j] + adjustment, 1, 255);
				}
			}
		}
	}
};

exports.BattleScripts = {
	init: function () {
		for (var i in this.data.Pokedex) {
			if (!this.data.FormatsData[i]) continue;
			var tier = this.data.FormatsData[i].tier;
			var adjustment = 0;

			if (!tier && this.data.Pokedex[i].baseSpecies) {
				// mega evolutions get the same stat boost as their base forme
				tier = this.data.FormatsData[toId(this.data.Pokedex[i].baseSpecies)].tier;
			}
			switch (tier) {
			case 'BL':
			case 'UU':
				adjustment = 5;
				break;
			case 'BL2':
			case 'RU':
				adjustment = 10;
				break;
			case 'BL3':
			case 'NU':
			case 'BL4':
			case 'PU':
			case 'NFE':
			case 'LC Uber':
			case 'LC':
				adjustment = 15;
			}

			if (adjustment) {
				for (var j in this.data.Pokedex[i].baseStats) {
					this.modData('Pokedex', i).baseStats[j] = this.clampIntRange(this.data.Pokedex[i].baseStats[j] + adjustment, 1, 255);
				}
			}
		}
	}
};

Support inheritance from Tier Shift The initialization script of Tier Shift was calling `getTemplate`, which poisoned the dex entries with the `cached` flag


'use strict';

const assert = require('assert');

function getMessage(service, accounts, mfaStatus) {
  return (
    mfaStatus
    ? `Users who enabled MFA on \`${service}\` are ${accounts}`
    : `Users without MFA on \`${service}\` are ${accounts}`
  );
}

/**
 * @param {secret} SLACK_WEBHOOK_URL
 * @param {secret} SLACK_CHANNEL_NAME
 * @param JSON     body
 *
 * body: [{name: 'GitHub', accounts: ['john', 'mark']}]
 */
module.exports = (ctx, cb) => {
  assert(ctx.secrets.SLACK_CHANNEL_NAME, 'SLACK_CHANNEL_NAME secret is missing!');
  assert(ctx.secrets.SLACK_WEBHOOK_URL,  'SLACK_WEBHOOK_URL secret is missing!');
  assert(Array.isArray(ctx.body.data), 'Body content is not an Array!');

  const slack = require('slack-notify')(ctx.secrets.SLACK_WEBHOOK_URL);
  const mfaStatus = !!ctx.body.mfaStatus;
  slack.onError = (err) => cb(err);

  ctx.body.data.forEach(service => {
    let accounts = service.accounts.map(account => `*${account}*`).join(', ');
    let message  = getMessage(service.name, accounts, mfaStatus);

    slack.send({
      channel: ctx.secrets.SLACK_CHANNEL_NAME,
      icon_emoji: (mfaStatus ? ':heart:' : ':warning:'),
      username: 'MFA Agent',
      text: message
    });
  });

  cb();
};

'use strict';

const assert = require('assert');

function getMessage(service, accounts, mfaStatus) {
  return (
    mfaStatus
    ? `:heart: Users who enabled MFA on \`${service}\` are: ${accounts}`
    : `:warning: Users without MFA on \`${service}\` are: ${accounts}`
  );
}

/**
 * @param {secret} SLACK_WEBHOOK_URL
 * @param {secret} SLACK_CHANNEL_NAME
 * @param JSON     body
 *
 * body: [{name: 'GitHub', accounts: ['john', 'mark']}]
 */
module.exports = (ctx, cb) => {
  assert(ctx.secrets.SLACK_CHANNEL_NAME, 'SLACK_CHANNEL_NAME secret is missing!');
  assert(ctx.secrets.SLACK_WEBHOOK_URL,  'SLACK_WEBHOOK_URL secret is missing!');
  assert(Array.isArray(ctx.body.data), 'Body content is not an Array!');

  const slack = require('slack-notify')(ctx.secrets.SLACK_WEBHOOK_URL);
  const mfaStatus = !!ctx.body.mfaStatus;
  slack.onError = (err) => cb(err);

  ctx.body.data.forEach(service => {
    let accounts = service.accounts.map(account => `*${account}*`).join(', ');
    let message  = getMessage(service.name, accounts, mfaStatus);

    slack.send({
      channel: ctx.secrets.SLACK_CHANNEL_NAME,
      username: 'MFA Agent',
      text: message
    });
  });

  cb();
};

Add mfa status icon as an inline message.


exports.addClassName = function(element, className) {
	if (!(' ' + element.className + ' ').match(' ' + className + ' ')) {
		element.className += className + ' ';
	}
}

exports.removeClassName = function(element, className) {
	className += ' ';
	var current = element.className;
	var index = current.indexOf(className);
	element.className = current.slice(0, index) + current.slice(index + className.length);
}

var base = '/css/';
var loadedStyles = {};
exports.loadStyles = function(path) {
	path = path.split('.').join('/');
	if (loadedStyles[path]) { return; }
	loadedStyles[path] = true;
	var link = document.createElement('link');
	link.rel = 'stylesheet';
	link.type = 'text/css';
	link.href = base + path + '.css';
	document.getElementsByTagName('head')[0].appendChild(link);
}

exports.addClassName = function(element, className) {
	if (!(' ' + element.className + ' ').match(' ' + className + ' ')) {
		element.className += className + ' ';
	}
}

exports.removeClassName = function(element, className) {
	className += ' ';
	var current = element.className;
	var index = current.indexOf(className);
	element.className = current.slice(0, index) + current.slice(index + className.length);
}

var base = 'css/';
var loadedStyles = {};
exports.loadStyles = function(path) {
	path = path.split('.').join('/');
	if (loadedStyles[path]) { return; }
	loadedStyles[path] = true;
	var link = document.createElement('link');
	link.rel = 'stylesheet';
	link.type = 'text/css';
	link.href = base + path + '.css';
	document.getElementsByTagName('head')[0].appendChild(link);
}

Make ubiquity work with at other paths than the base path


var habitat = require('habitat');

// Local environment in .env overwrites everything else
habitat.load('.env');

var environment = habitat.get('NODE_ENV', '').toLowerCase();

if (environment === 'production') {
  habitat.load('config/production.env');
}

habitat.load('config/defaults.env');

var config = {
  CLIENT_ID: habitat.get('CLIENT_ID'),
  API_URI: habitat.get('API_URI'),
  LOGIN_URI: habitat.get('LOGIN_URI')
};

process.stdout.write(
  '// THIS IS A GENERATED FILE. EDIT npm_tasks/build-config.js INSTEAD\n' +
  'module.exports = ' + JSON.stringify(config) + ';\n'
);

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

var defaultPath = path.join(__dirname, '../config/defaults.env');
var prodPath = path.join(__dirname, '../config/production.env');

function fileErrors() {
  process.stderr.write(
    'Looks like there is a problem with your config paths.\n' +
    'See npm_tasks/build-config.js\n'
  );
  process.exit(1);
}

// Check paths to make sure they exist
try {
  if (!fs.statSync(defaultPath).isFile() || !fs.statSync(defaultPath)) {
    fileErrors();
  }
} catch (e) {
  fileErrors();
}

// Local environment in .env overwrites everything else
habitat.load('.env');

var environment = habitat.get('NODE_ENV', '').toLowerCase();

if (environment === 'production') {
  habitat.load(prodPath);
}

habitat.load(defaultPath);

var config = {
  CLIENT_ID: habitat.get('CLIENT_ID'),
  API_URI: habitat.get('API_URI'),
  LOGIN_URI: habitat.get('LOGIN_URI')
};

process.stdout.write(
  '// THIS IS A GENERATED FILE. EDIT npm_tasks/build-config.js INSTEAD\n' +
  'module.exports = ' + JSON.stringify(config) + ';\n'
);

Use absolute paths for config


import React from 'react';
import { FontIcon } from 'material-ui';
import { colors as Colors } from 'material-ui/styles';
import Truncate from '../Truncate';

const LinkWithIcon = ({ url, iconClassName = 'synicon-launch' }) => {
  const linkStyles = {
    color: Colors.blue500,
    display: 'flex',
    alignItems: 'center'
  };
  const linkIconStyles = {
    paddingTop: 2,
    marginRight: 8,
    color: Colors.blue500,
    fontSize: 16,
    maxWidth: 16
  };
  const linkUrl = url.indexOf('http') > 0 ? url : `http://${url}`;

  return (
    <a
      href={linkUrl}
      target="_blank"
      style={linkStyles}
    >
      <FontIcon
        style={linkIconStyles}
        className={iconClassName}
      />
      <Truncate text={url} />
    </a>
  );
};

export default LinkWithIcon;

import React from 'react';
import { FontIcon } from 'material-ui';
import { colors as Colors } from 'material-ui/styles';
import Truncate from '../Truncate';

const LinkWithIcon = ({ url, iconClassName = 'synicon-launch' }) => {
  const linkStyles = {
    color: Colors.blue500,
    display: 'flex',
    alignItems: 'center'
  };
  const linkIconStyles = {
    paddingTop: 2,
    marginRight: 8,
    color: Colors.blue500,
    fontSize: 16,
    maxWidth: 16
  };
  const linkUrl = url.indexOf('http') > -1 ? url : `http://${url}`;

  return (
    <a
      href={linkUrl}
      target="_blank"
      style={linkStyles}
    >
      <FontIcon
        style={linkIconStyles}
        className={iconClassName}
      />
      <Truncate text={url} />
    </a>
  );
};

export default LinkWithIcon;

Add missing : in hosting link


(function($) {
    $(document).ready(function() {

        /**
         * Site section navigation
         */

        var navLink = $('.nav__link'),
            navLinkActiveName = 'nav__link--active';

        navLink.click(function(e)
        {
            // Get the link we clicked
            var element = $(e.target);

            // Only run the code if we clicked on an inactive section
            if(element.hasClass(navLinkActiveName)) {
                return;
            };

            // Activate the nav item we clicked
            navLink.removeClass(navLinkActiveName);
            element.addClass(navLinkActiveName);

            // Get the name of the section we want to navigate to
            var section = $('.' + element.data('section'));

            // Go to it, yo
            Section.goTo(section);

            // Temporary
            if(section.hasClass('site-section--intro'))
            {
                $('body').css({
                    overflowY: 'hidden'
                });
            }
            else
            {
                $('body').css({
                    overflowY: 'visible'
                });
            }
        });

    });
})(jQuery);

(function($) {
    $(document).ready(function() {

        /**
         * Site section navigation
         */

        var navLink = $('.nav__link'),
            navLinkActiveName = 'nav__link--active';

        navLink.click(function(e)
        {
            // Get the link we clicked
            var element = $(e.target);

            // Only run the code if we clicked on an inactive section
            if(element.hasClass(navLinkActiveName)) {
                return;
            };

            // Activate the nav item we clicked
            navLink.removeClass(navLinkActiveName);
            element.addClass(navLinkActiveName);

            // Get the name of the section we want to navigate to
            var section = $('.' + element.data('section'));

            // Go to it, yo
            Section.goTo(section);
        });

    });
})(jQuery);

Remove tempary fix. Need to actually fix this


'use strict';

// MODULES //

var isnan = require( '@stdlib/math/base/utils/is-nan' );
var exp = require( '@stdlib/math/base/special/exp' );
var nan = require( './nan.js' );

// MAIN //

/**
* Returns a function for evaluating the moment-generating function (MGF) of a degenerate distribution centered at a provided mean value.
*
* @param {number} mu - value at which to center the distribution
* @returns {Function} MGF
*
* @example
* var mgf = factory( 2.0 );
* var y = mgf( 0.0 );
* // returns 1.0
* y = mgf( 2.0 );
* // returns ~54.598
*/
function factory( mu ) {
	if ( isnan( mu ) ) {
		return nan;
	}
	/**
	* Evaluates the moment-generating function (MGF) of a degenerate distribution.
	*
	* @private
	* @param {number} t - input value
	* @returns {number} evaluated MGF
	*
	* @example
	* var y = mgf( 10.0 );
	* // returns <number>
	*/
	return function mgf( t ) {
		if ( isnan( t ) ) {
			return NaN;
		}
		return exp( mu * t );
	}; // end FUNCTION mgf()
} // end FUNCTION factory()

// EXPORTS //

module.exports = factory;

'use strict';

// MODULES //

var isnan = require( '@stdlib/math/base/utils/is-nan' );
var exp = require( '@stdlib/math/base/special/exp' );
var nan = require( './nan.js' );

// MAIN //

/**
* Returns a function for evaluating the moment-generating function (MGF) of a degenerate distribution centered at a provided mean value.
*
* @param {number} mu - value at which to center the distribution
* @returns {Function} MGF
*
* @example
* var mgf = factory( 2.0 );
* var y = mgf( 0.0 );
* // returns 1.0
*
* y = mgf( 2.0 );
* // returns ~54.598
*/
function factory( mu ) {
	if ( isnan( mu ) ) {
		return nan;
	}
	/**
	* Evaluates the moment-generating function (MGF) of a degenerate distribution.
	*
	* @private
	* @param {number} t - input value
	* @returns {number} evaluated MGF
	*
	* @example
	* var y = mgf( 10.0 );
	* // returns <number>
	*/
	return function mgf( t ) {
		if ( isnan( t ) ) {
			return NaN;
		}
		return exp( mu * t );
	}; // end FUNCTION mgf()
} // end FUNCTION factory()

// EXPORTS //

module.exports = factory;

Add blank line as a separator


import Application from '@ember/application';
import Engine from '@ember/engine';
import require from 'require';
import { gte } from 'ember-compatibility-helpers';

import ExternalLinkComponent from '../components/link-to-external';

Engine.reopen({
  buildRegistry() {
    let registry = this._super(...arguments);

    if (!(this instanceof Application)) {
      if (!gte('ember-source', '3.24.1')) {
        const EngineScopedLinkComponent = require('../components/link-to-component').default;
        registry.register('component:link-to', EngineScopedLinkComponent);
      }
      registry.register('component:link-to-external', ExternalLinkComponent);
    }

    return registry;
  },
});

import Application from '@ember/application';
import Engine from '@ember/engine';
import require from 'require';
import { gte } from 'ember-compatibility-helpers';

import ExternalLinkComponent from '../components/link-to-external';

Engine.reopen({
  buildRegistry() {
    let registry = this._super(...arguments);

    if (!(this instanceof Application)) {
      if (!gte('ember-source', '3.24.1')) {
        const EngineScopedLinkComponent = require('ember-engines/components/link-to-component').default;
        registry.register('component:link-to', EngineScopedLinkComponent);
      }
      registry.register('component:link-to-external', ExternalLinkComponent);
    }

    return registry;
  },
});

Add addon namespace to require so module can be found in embroider


// Experimental Animated Views

FOAModel({
  name: 'ALabel',

  extendsModel: 'AbstractView',

  properties: [
    {
      name: 'data'
    },
    {
      name: 'className',
      defaultValue: 'alabel'
    },
    {
      name: 'left',
      postSet: function(_, l) {
        this.$.querySelector('.f1').style.left = l;
      }
    }
  ],

  methods: {
    toInnerHTML: function() {
      return '

';
    },
    initHTML: function() {
      this.data$.addListener(this.onDataChange);
    }
  },

  listeners: [
    {
      name: 'onDataChange',
      isAnimated: true,
      code: function() {
        if ( ! this.$ ) return;
        var f1$ = this.$.querySelector('.f1');
        var f2$ = this.$.querySelector('.f2');

        f1$.innerHTML = this.data;
        f2$.innerHTML = this.data;

        f1$.style.top  = f2$.offsetTop;
        f1$.style.left = f2$.offsetLeft;
      }
    }
  ]
});

// Experimental Animated Views

FOAModel({
  name: 'ALabel',

  extendsModel: 'View',

  properties: [
    {
      name: 'data'
    },
    {
      name: 'className',
      defaultValue: 'alabel'
    },
    {
      name: 'left',
      postSet: function(_, l) {
        this.$.querySelector('.f1').style.left = l;
      }
    }
  ],

  methods: {
    toInnerHTML: function() {
      return '

';
    },
    initHTML: function() {
      this.data$.addListener(this.onDataChange);
    }
  },

  listeners: [
    {
      name: 'onDataChange',
      isAnimated: true,
      code: function() {
        if ( ! this.$ ) return;
        var f1$ = this.$.querySelector('.f1');
        var f2$ = this.$.querySelector('.f2');

        f1$.innerHTML = this.data;
        f2$.innerHTML = this.data;

        f1$.style.top  = f2$.offsetTop;
        f1$.style.left = f2$.offsetLeft;
      }
    }
  ]
});

Switch Calc to extend View instead of AbstractView


minerva.views.JobsPanel = minerva.View.extend({

    initialize: function () {
        var columnEnum = girder.views.jobs_JobListWidget.prototype.columnEnum;
        var columns = columnEnum.COLUMN_STATUS_ICON |
                      columnEnum.COLUMN_TITLE;
        this.jobListWidget = new girder.views.jobs_JobListWidget({
            columns: columns,
            showHeader: false,
            pageLimit: 10,
            showPaging: false,
            triggerJobClick: true,
            parentView: this
        }).on('g:jobClicked', function (job) {
            // TODO right way to update specific job?
            // otherwise can get a detail that is out of sync with actual job status
            // seems weird to update the entire collection from here
            // another option is to refresh the job specifically
            this.jobListWidget.collection.on('g:changed', function () {
                job = this.jobListWidget.collection.get(job.get('id'));
                this.jobDetailsWidgetModalWrapper = new minerva.views.JobDetailsWidgetModalWrapper({
                    job: job,
                    el: $('#g-dialog-container'),
                    parentView: this
                });
                this.jobDetailsWidgetModalWrapper.render();
            }, this);
            this.jobListWidget.collection.fetch({}, true);
        }, this);

        girder.events.once('m:job.created', function () {
            this.jobListWidget.collection.fetch({}, true);
        }, this);

    },

    render: function () {
        this.$el.html(minerva.templates.jobsPanel({}));
        this.jobListWidget.setElement(this.$('.m-jobsListContainer')).render();

        return this;
    }
});

minerva.views.JobsPanel = minerva.View.extend({

    initialize: function () {
        var columnEnum = girder.views.jobs_JobListWidget.prototype.columnEnum;
        var columns = columnEnum.COLUMN_STATUS_ICON |
                      columnEnum.COLUMN_TITLE;
        this.jobListWidget = new girder.views.jobs_JobListWidget({
            columns: columns,
            showHeader: false,
            pageLimit: 10,
            showPaging: false,
            triggerJobClick: true,
            parentView: this
        }).on('g:jobClicked', function (job) {
            // TODO right way to update specific job?
            // otherwise can get a detail that is out of sync with actual job status
            // seems weird to update the entire collection from here
            // another option is to refresh the job specifically
            this.jobListWidget.collection.on('g:changed', function () {
                job = this.jobListWidget.collection.get(job.get('id'));
                this.jobDetailsWidgetModalWrapper = new minerva.views.JobDetailsWidgetModalWrapper({
                    job: job,
                    el: $('#g-dialog-container'),
                    parentView: this
                });
                this.jobDetailsWidgetModalWrapper.render();
            }, this);
            this.jobListWidget.collection.fetch({}, true);
        }, this);

        girder.events.on('m:job.created', function () {
            this.jobListWidget.collection.fetch({}, true);
        }, this);

    },

    render: function () {
        this.$el.html(minerva.templates.jobsPanel({}));
        this.jobListWidget.setElement(this.$('.m-jobsListContainer')).render();

        return this;
    }
});

Change once to on for m:job.created listener


"use strict";

const casList = [
  "addtrustexternalcaroot.crt",
  "comodorsaaddtrustca.crt",
  "comodorsadomainvalidationsecureserverca.crt"
];
const cas = require("ssl-root-cas").inject();
casList.forEach((ca) => {
  cas.addFile(__dirname + "../../../deps/cas/" + ca);
});

"use strict";

const casList = [
  "addtrustexternalcaroot.crt",
  "comodorsaaddtrustca.crt",
  "comodorsadomainvalidationsecureserverca.crt"
];
const cas = require("ssl-root-cas").inject();
casList.forEach((ca) => {
  cas.addFile(__dirname + "/../../deps/cas/" + ca);
});

Fix SSL CA files lookup crash on OSX


import app from '../app';
import { formatCurrency, convertAndFormatCurrency } from './currency';
import {
  isHiRez, isLargeWidth, isSmallHeight, getAvatarBgImage,
} from './responsive';
import { upToFixed } from './number';
import twemoji from 'twemoji';

export function polyT(...args) {
  return app.polyglot.t(...args);
}

export function parseEmojis(msg) {
  return twemoji.parse(msg,
      icon => (`../imgs/emojis/72X72/${icon}.png`));
}

export const getServerUrl = app.getServerUrl.bind(app);

export { formatCurrency };

export { convertAndFormatCurrency };

export { isHiRez };

export { isLargeWidth };

export { isSmallHeight };

export { getAvatarBgImage };

export { upToFixed };

import app from '../app';
import { formatCurrency, convertAndFormatCurrency } from './currency';
import {
  isHiRez, isLargeWidth, isSmallHeight, getAvatarBgImage,
} from './responsive';
import { upToFixed } from './number';
import twemoji from 'twemoji';

export function polyT(...args) {
  return app.polyglot.t(...args);
}

export function parseEmojis(text) {
  return twemoji.parse(text,
      icon => (`../imgs/emojis/72X72/${icon}.png`));
}

export const getServerUrl = app.getServerUrl.bind(app);

export { formatCurrency };

export { convertAndFormatCurrency };

export { isHiRez };

export { isLargeWidth };

export { isSmallHeight };

export { getAvatarBgImage };

export { upToFixed };

Change parameter name in parseEmoji to text.


const mongoose = require('mongoose');

const PublisherSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    minlength: 2,
    maxlength: 256
  },
  createdBy: String
});

PublisherSchema.virtual('response').get(function() {
  return {
    id: this.id,
    name: this.name
  };
});

module.exports = mongoose.model('Publisher', PublisherSchema);

const mongoose = require('mongoose');

const PublisherSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    minlength: 2,
    maxlength: 256
  },
  createdBy: String,
  createdAt: {
    type: Date,
    default: Date.now
  },
  updatedAt: Date,
  deletedAt: Date
});

PublisherSchema.virtual('response').get(function() {
  return {
    id: this.id,
    name: this.name
  };
});

module.exports = mongoose.model('Publisher', PublisherSchema);

Add timestamp properties to Publisher resource


/**
* Permissions.js
*
* @description :: TODO: You might write a short summary of how this model works and what it represents here.
* @docs        :: http://sailsjs.org/#!documentation/models
*/

module.exports = {

  attributes: {
    id:
    {
      type: "integer",
      primaryKey: true,
      unique: true,
      autoIncrement: true,
      required: true
    },
    role_id:
    {
      type: "integer",
      required: true
    },
    model:
    {
      type: "string",
      lowercase: true,
      required: true
    },
    self:
    {
      type: "boolean",
      defaultsTo: false
    },
    other:
    {
      type: "boolean",
      defaultsTo: false
    }
  }
};

/**
* Permissions.js
*
* @description :: TODO: You might write a short summary of how this model works and what it represents here.
* @docs        :: http://sailsjs.org/#!documentation/models
*/

module.exports = {

  attributes: {
    id:
    {
      type: "integer",
      primaryKey: true,
      unique: true,
      autoIncrement: true,
    },
    role_id:
    {
      type: "integer",
      required: true
    },
    model:
    {
      type: "string",
      lowercase: true,
      required: true
    },
    self:
    {
      type: "boolean",
      defaultsTo: false
    },
    other:
    {
      type: "boolean",
      defaultsTo: false
    }
  }
};

Change permissions model to not require id


export default function materialConfig($mdThemingProvider) {
  'ngInject';
  $mdThemingProvider.theme('default')
    .primaryPalette('brown')
    .accentPalette('orange');
}

export default function materialConfig($mdThemingProvider) {
  'ngInject';
  $mdThemingProvider.theme('default')
    .primaryPalette('pink', {
      'default': '600'
    })
    .accentPalette('blue', {
      'default': '800'
    });
}

Change theme colors to pink+blue


import { Accounts } from 'meteor/accounts-base';
import { Bans } from './collection.js';
import { ForwardedWhitelist } from '../../modules/forwarded_whitelist.js';
// Check during login whether the user currently has their login disabled

// User ban callback

Accounts.validateLoginAttempt((attempt) => {
  if (!attempt.allowed) {
    return false;
  }
  if (attempt.user && attempt.user.banned && new Date(attempt.user.banned) > new Date()) {
    throw new Meteor.Error('user-banned', 'This account is banned until ' + new Date(attempt.user.banned));
  } else {
    return true;
  }
})

Accounts.validateLoginAttempt((attempt) => {
  if (!attempt.allowed) {
    return false;
  }
  const ban = Bans.findOne({ip: attempt.connection && ForwardedWhitelist.getClientIP(attempt.connection)});
  if (ban && new Date(ban.expirationDate) > new Date()) {
    // eslint-disable-next-line no-console
    console.warn("IP address is banned: ", attempt, attempt.connection, ban)
    return true;
  } else {
    return true;
  }
})

/*

Uncomment this section to allow for user-impersonation, by using the
following console commands:

Accounts.callLoginMethod({
  methodArguments: [{userId: <userId>}],
  userCallback: (err) => {console.log(err)}
});

DO NOT ACTIVATE THIS IN PRODUCTION. ONLY USE THIS IN A DEVELOPMENT CONTEXT.

*/

// Accounts.registerLoginHandler('admin', function(loginRequest) {
//   return { userId : loginRequest.userId };
// });

Add a commented-out section for impersonation


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

module.exports = {
  module: {
    rules: [{
      test: /\.less$/,
      use: [
        'style-loader',
        'css-loader?importLoaders=1&sourceMap=true&modules=true',
        'less-loader',
      ],
    }, {
      test: /\.(eot|woff|woff2|ttf)$/,
      use: {
        loader: 'file-loader',
        query: {
          name: 'static/media/[name].[ext]',
        },
      },
    }, {
      test: /\.css$/,
      use: [
        'style-loader',
        'css-loader?importLoaders=1&sourceMap=true&modules=true',
        {
          loader: 'postcss-loader',
          options: {
            plugins: () => ([
              require('postcss-import'),
              require('postcss-custom-properties'),
              require('postcss-color-function'),
              require('autoprefixer'),
            ])
          }
        },
      ]
    }],
  },
  plugins: [
    // Ignore locales for momentJS
    // see http://stackoverflow.com/questions/25384360
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
  ]
}

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

module.exports = {
  module: {
    rules: [{
      test: /\.less$/,
      use: [
        'style-loader',
        'css-loader?importLoaders=1&sourceMap=true&modules=true',
        'less-loader',
      ],
    }, {
      test: /\.(eot|woff|woff2|ttf)$/,
      use: {
        loader: 'file-loader',
        query: {
          name: 'static/media/[name].[ext]',
        },
      },
    }, {
      test: /\.css$/,
      use: [
        'style-loader',
        'css-loader?importLoaders=1&modules=true',
        {
          loader: require.resolve('postcss-loader'),
          options: {
            plugins: () => ([
              require('postcss-import'),
              require('postcss-cssnext'),
            ])
          }
        },
      ]
    }],
  },
  plugins: [
    // Ignore locales for momentJS
    // see http://stackoverflow.com/questions/25384360
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
  ]
}

Use cssnext instead of custom packages


// @flow

module.exports = {
    BASE_URL: 'https://api.twitter.com/1.1/',
    SEARCH_HASH_TAG: "search/tweets.json?q=%40",
};

// @flow

module.exports = {
    BASE_URL: 'https://api.twitter.com/1.1/',
    SEARCH_HASH_TAG: "search/tweets.json?count=50&q=%40",
};

Set the result count to 50


// Returns the contexts (short description with bolded matched words) of the
// search results. This is only a function to allow the implementation to be
// changed if Google ever changes the format of their HTML.
function getSearchContexts() {
  return document.querySelectorAll(".st");
}

function insertLinksIntoContext(context) {
  context.innerHTML = "who dat who dat?"; // Courtney you know what to do: http://xkcd.com/1288/
}

var contexts = getSearchContexts();
for (var i = 0; i < contexts.length; ++i) {
  contexts[i] = insertLinksIntoContext(contexts[i]);
}

// Returns the contexts (short description with bolded matched words) of the
// search results. This is only a function to allow the implementation to be
// changed if Google ever changes the format of their HTML.
function getSearchContexts() {
  return document.querySelectorAll(".st");
}

function forEverySubContext(context) {
  var new_innerHTML = "";
  var sub_contexts = context.innerHTML.split("...");
  for (var i = 0; i < sub_contexts.length; ++i) {
    if (sub_contexts[i].length === 0) {
      continue;
    }
    new_innerHTML += ""; // This URL needs to be changed to the result site's URL.
    new_innerHTML += sub_contexts[i];
    new_innerHTML += "";
    if (i !== sub_contexts.length - 1 || context.innerHTML.substr(context.innerHTML.length - 3) === "...") {
      new_innerHTML += "...";
    }
  }
  context.innerHTML = new_innerHTML;
}

var contexts = getSearchContexts();
for (var i = 0; i < contexts.length; ++i) {
  forEverySubContext(contexts[i]);
}

Add sub-context parsing and linking


import { MDXProvider } from '@mdx-js/react';
import components from '../utils/mdx-components';
import App, { Container } from 'next/app';
import React from 'react';

export default class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    let pageProps = {};

    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
    }

    return { pageProps };
  }

  render() {
    const { Component, pageProps } = this.props;
    return (
      <Container>
        <MDXProvider components={components}>
          <Component {...pageProps} />
        </MDXProvider>
      </Container>
    );
  }
}

import { MDXProvider } from '@mdx-js/react';
import components from '../utils/mdx-components';
import App, { Container } from 'next/app';
import React from 'react';

export default class MyApp extends App {
  render() {
    const { Component, pageProps } = this.props;
    return (
      <Container>
        <MDXProvider components={components}>
          <Component {...pageProps} />
        </MDXProvider>
      </Container>
    );
  }
}

Remove automatic static optimization opt-out


exports = module.exports = function() {

  return function() {
    return require('morgan')('common');
  };
};

exports['@implements'] = 'http://i.bixbyjs.org/http/middleware/logging';

exports = module.exports = function() {

  return function() {
    var format = 'common';

    // TODO: Implement setting to select log format, for using combined log format

    return require('morgan')(format);
  };
};

exports['@implements'] = 'http://i.bixbyjs.org/http/middleware/logging';

Add TODO item to logger.


const aggregates = require('./aggregates')
const createGeometryClause = require('./geometry').createClause
const createFieldsClause = require('./fields').createClause

function createClause (options) {
  if (options.aggregates) return aggregates(options.aggregates, options.groupBy, options.esri)
  const geometryClause = createGeometryClause(options)
  const fieldsClause = createFieldsClause(options)

  return `SELECT ${fieldsClause}, ${geometryClause} FROM ?`
}

module.exports = { createClause }

const aggregates = require('./aggregates')
const createGeometryClause = require('./geometry').createClause
const createFieldsClause = require('./fields').createClause

function createClause (options) {
  if (options.aggregates) { return aggregates(options.aggregates, options.groupBy, options.esri) }

  var fieldsClause = createFieldsClause(options)

  if (options.returnGeometry === false) {
    return (`SELECT ${fieldsClause} FROM ?`)
  }

  return (`SELECT ${fieldsClause}, ${createGeometryClause(options)} FROM ?`)
}

module.exports = { createClause }

Remove geometry in SQL Select if option passed in request.


import Ember from 'ember';

export default Ember.Route.extend({
    redirect() {
        this.transitionTo('crate.version', '');
    }
});

import Ember from 'ember';

export default Ember.Route.extend({
    redirect() {
        this.replaceWith('crate.version', '');
    }
});

Fix trailing slash redirect breaking browser back button


define([
  "underscore",
  "backbone",
  "app/config",
  "app/models/note",
  "backbone.localStorage" // Patches Backbone.
], function (_, Backbone, config, NoteModel) {
  "use strict";

  // Notes Collection
  // ----------------
  var NotesCollection;

  // Decide whether to use localStorage or REST.
  if (window._USE_LOCAL_STORAGE === true) {
    // Uses HTML `localStorage`.
    NotesCollection = Backbone.Collection.extend({
      localStorage: new Backbone.LocalStorage(config.storeName)
    });
  } else {
    // Uses real REST backend.
    NotesCollection = Backbone.Collection.extend({
      url: "/notes"
    });
  }

  // Singleton.
  NotesCollection.getInstance = _.memoize(function () {
    return new NotesCollection();
  });

  return NotesCollection;
});

define([
  "underscore",
  "backbone",
  "app/config",
  "app/models/note",
  "backbone.localStorage" // Patches Backbone.
], function (_, Backbone, config, NoteModel) {
  "use strict";

  // Notes Collection
  // ----------------
  var NotesCollection;

  // Decide whether to use localStorage or REST.
  if (window._USE_LOCAL_STORAGE === true) {
    // Uses HTML `localStorage`.
    NotesCollection = Backbone.Collection.extend({
      localStorage: new Backbone.LocalStorage(config.storeName),
      model: NoteModel
    });
  } else {
    // Uses real REST backend.
    NotesCollection = Backbone.Collection.extend({
      url: "/notes",
      model: NoteModel
    });
  }

  // Singleton.
  NotesCollection.getInstance = _.memoize(function () {
    return new NotesCollection();
  });

  return NotesCollection;
});

Fix missing model on model.


var svcMod = angular.module( "linksWeb.service-env", [] );

svcMod.factory( 'ENV', function () {
    return {
        apiRoot: "http://192.168.13.81/v1"
    };
} );

var svcMod = angular.module( "linksWeb.service-env", [] );

svcMod.factory( 'ENV', function () {
    return {
        apiRoot: "http://192.168.13.81:5000/v1"
    };
} );

Fix development API IP address


/**
 * Initialize smooth-scroll plugin.
 */

var jQuery = require('jquery')
  , config = { easing: 'swing' };

require('jquery-smooth-scroll');

if (jQuery.fn.smoothScroll) jQuery('a[href^="#"]').smoothScroll(config);

/**
 * Initialize smooth-scroll plugin.
 */

var jQuery = require('jquery')
  , config = { easing: 'swing', preventDefault: false };

require('jquery-smooth-scroll');

if (jQuery.fn.smoothScroll) jQuery('a[href^="#"]').smoothScroll(config);

Make smooth scroll update hash.


'use strict';

var GeolocationService = function ($rootScope, DeviceReadyService, $q) {
    return {
        getCurrentPosition: function(onSuccess, onError, options) {
            return DeviceReadyService.ready.then(function () {
                var deferred;
                deferred = $q.defer();
                navigator.geolocation.getCurrentPosition(function () {
                        var _this = this,
                            args = arguments;

                        if (typeof onSuccess === 'function') {
                            $rootScope.$apply(function () {
                                onSuccess.apply(_this, args);
                            });
                        }

                        deferred.resolve(args);
                    }, function () {
                        var _this = this,
                            args = arguments;

                        if (typeof onError === 'function') {
                            $rootScope.$apply(function () {
                                onError.apply(_this, args);
                            });
                        }

                        deferred.reject(args);
                    },
                    options);
                return deferred.promise;
            });
        }
    };
};

GeolocationService.$inject = ['$rootScope', 'DeviceReadyService', '$q'];

module.exports = GeolocationService;

'use strict';

var GeolocationService = function ($rootScope, DeviceReadyService, $q) {
    return {
        getCurrentPosition: function(onSuccess, onError, options) {
            return DeviceReadyService.ready.then(function () {
                var deferred;
                deferred = $q.defer();
                navigator.geolocation.getCurrentPosition(function () {
                        var _this = this,
                            args = arguments;

                        if (typeof onSuccess === 'function') {
                            $rootScope.$apply(function () {
                                onSuccess.apply(_this, args[0]);
                            });
                        }

                        deferred.resolve(args[0]);
                    }, function () {
                        var _this = this,
                            args = arguments;

                        if (typeof onError === 'function') {
                            $rootScope.$apply(function () {
                                onError.apply(_this, args[0]);
                            });
                        }

                        deferred.reject(args[0]);
                    },
                    options);
                return deferred.promise;
            });
        }
    };
};

GeolocationService.$inject = ['$rootScope', 'DeviceReadyService', '$q'];

module.exports = GeolocationService;

Fix geo location on mobile


'use strict';
const ipc = require('ipc');

ipc.on('shortcut-pressed', shortcut => {
	document.querySelector('#shortcut-title').textContent = shortcut;
});

ipc.on('shortcut-status', status => {
	document.querySelector('#shortcut-status').textContent = status;
});

'use strict';

const {ipcRenderer} = require('electron');

ipcRenderer.on('shortcut-pressed', (e, shortcut) => {
	document.querySelector('#shortcut-title').textContent = shortcut;
});

ipcRenderer.on('shortcut-status', (e, status) => {
	document.querySelector('#shortcut-status').textContent = status;
});

Update source as following update Electron


"use strict";

var db = require('../../models');
var config = require('../../config');
var authHelper = require('../../lib/auth-helper');

module.exports = function(app) {
  var logger = app.get('logger');

  app.get('/logout', function(req, res) {
    req.logout();
    res.redirect('/');
  });

  app.get('/protected', authHelper.ensureAuthenticated, function(req, res) {
    res.send('protected');
  });

  app.get('/auth', function(req, res) {
    res.render('./auth/provider_list.ejs');
  });

  if (config.identity_providers.facebook.enabled) {
    logger.info('Facebook authentication enabled');
    require('./facebook')(app);
  }

  if (config.identity_providers.github.enabled) {
    logger.info('Github authentication enabled');
    require('./github')(app);
  }

  if (config.identity_providers.local.enabled) {
    logger.info('Local authentication enabled');
    require('./local')(app);
  }
};

"use strict";

var db = require('../../models');
var config = require('../../config');
var authHelper = require('../../lib/auth-helper');

module.exports = function(app) {
  var logger = app.get('logger');

  app.get('/logout', function(req, res) {
    req.logout();
    res.redirect('/');
  });

  app.get('/protected', authHelper.ensureAuthenticated, function(req, res) {
    res.send('protected');
  });

  app.get('/auth', function(req, res) {
    res.render('./auth/provider_list.ejs');
  });

  for (var idp in config.identity_providers) {
    if (config.identity_providers[idp].enabled) {
      logger.info(idp + ' authentication enabled');
      require('./'+idp)(app);
    }
  }
};

Use config to load available id providers


class LinkButton extends Phaser.Button {

  constructor (game, x, key, url = null) {
    super(game, x, 47, 'graphics', this._openPopup, this);
    this.setFrames(`button-link-${key}-over`, `button-link-${key}-out`);

    this.anchor.set(0.5, 0);

    this.input.useHandCursor = true;
    this.url = url;
  }

  // --------------------------------------------------------------------------

  _openPopup () {
    if (this.url !== null) window.open(this.url);
  }

}

export default LinkButton;

class LinkButton extends Phaser.Button {

  constructor (game, x, key, url = null) {
    super(game, x, 47, 'graphics', () => this._openPopup());
    this.setFrames(`button-link-${key}-over`, `button-link-${key}-out`);

    this.anchor.set(0.5, 0);

    this.input.useHandCursor = true;
    this.url = url;
  }

  // --------------------------------------------------------------------------

  _openPopup () {
    if (this.url !== null) window.open(this.url);
  }

}

export default LinkButton;

Fix illegal use of this before super()


/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/**
 * A filter for transforming an object into an array of all non-inherited
 * property values.
 */
angular.module('index').filter('toArray', [function toArrayFactory() {

    return function toArrayFiter(input) {

        console.log(input)

        // If no object is available, just return an empty array
        if (!input) {
            return [];
        }

        return Object.keys(input).map(function fetchValueByKey(key) {
            return input[key];
        });
    };

}]);

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/**
 * A filter for transforming an object into an array of all non-inherited
 * property values.
 */
angular.module('index').filter('toArray', [function toArrayFactory() {

    return function toArrayFiter(input) {

        // If no object is available, just return an empty array
        if (!input) {
            return [];
        }

        return Object.keys(input).map(function fetchValueByKey(key) {
            return input[key];
        });
    };

}]);

Remove debug console.log() from toArrayFilter().


cdb.windshaft.filters.BoundingBoxFilter = cdb.core.Model.extend({

  initialize: function(bounds) {
    this.setBounds(bounds);
  },

  setBounds: function(bounds) {
    this.southLatitude = bounds[0][1];
    this.westLatitude = bounds[0][0];
    this.eastLatitude = bounds[1][1];
    this.northLatitude = bounds[1][0];
  },

  toString: function() {
    return [
      this.westLatitude,
      this.southLatitude,
      this.eastLatitude,
      this.northLatitude
    ].join(',');
  }
});

cdb.windshaft.filters.BoundingBoxFilter = cdb.core.Model.extend({

  initialize: function(bounds) {
    this.setBounds(bounds);
  },

  setBounds: function(bounds) {
    this.set({
      westLatitude: bounds[0][0],
      southLatitude: bounds[0][1],
      northLatitude: bounds[1][0],
      eastLatitude: bounds[1][1]
    });
  },

  toString: function() {
    return [
      this.get('westLatitude'),
      this.get('southLatitude'),
      this.get('eastLatitude'),
      this.get('northLatitud')
    ].join(',');
  }
});

Use model attributes instead of instance variables


'use strict';

var gulp = require('gulp');
var paths = require('./_paths');
var minifyCss = require('gulp-minify-css');
var rename = require('gulp-rename');

gulp.task('minify-css', ['sass'], function() {
  return gulp
    .src(paths.dest + 'stylesheets/**/*.css')
    .pipe(minifyCss())
    .pipe(rename({ suffix: '.min' }))
    .pipe(gulp.dest(paths.dest + 'stylesheets/'));
});

'use strict';

var gulp = require('gulp');
var paths = require('./_paths');
var minifyCss = require('gulp-minify-css');
var rename = require('gulp-rename');

gulp.task('minify-css', ['sass'], function() {
  return gulp
    .src(paths.dest + 'stylesheets/**/*.css')
    .pipe(minifyCss({ noAdvanced: true }))
    .pipe(rename({ suffix: '.min' }))
    .pipe(gulp.dest(paths.dest + 'stylesheets/'));
});

Disable advanced optimisations when minifying CSS


import React from 'react';

import SquareRow from './SquareRow';

import './Grid.css';

const Grid = ({
                  size,
              }) => {
    const [height, width] = size.split('x').map(el => Number(el));

    if (isNaN(height) || isNaN(width)) {
        return null;
    }

    if (height * width > 10_000) {
        return (

                ⚠ Sorry, there are too many elements to paint. Try again with a smaller size.

        );
    }

    const squareNodes =
        [...new Array(height)].map(
            (_, index) =>
                <SquareRow
                    key={index}
                    index={index}
                    width={width}
                />
        );

    return (

            {squareNodes}

    );
};

export default Grid;

import React from 'react';

import SquareRow from './SquareRow';

import './Grid.css';

const Grid = ({
                  size,
              }) => {
    const [height, width] = size.split('x').map(el => Number(el));

    if (isNaN(height) || isNaN(width)) {
        return null;
    }

    if (height <= 0 || width <= 0) {
        return null;
    }

    if (height * width > 10_000) {
        return (

                ⚠ Sorry, there are too many elements to paint. Try again with a smaller size.

        );
    }

    const squareNodes =
        [...new Array(height)].map(
            (_, index) =>
                <SquareRow
                    key={index}
                    index={index}
                    width={width}
                />
        );

    return (

            {squareNodes}

    );
};

export default Grid;

Check if grid dimensions are positive