const expect = require('chai').expect
const nunjucks = require('nunjucks')
const components = require('../../../lib/components')

const expectComponentRenders = (name, input) => {
  let componentPath = components.templatePathFor(name)
  expect(() => {
    nunjucks.render(componentPath, input)
  }).to.not.throw()
}

describe('Components render examples without errors', () => {
  Object.keys(components.all).map(name => {
    it(`${name} component renders all variants without errors`, () => {
      let component = components.get(name)
      let variants = [component.context].concat(component.variants)
      for (let variant of variants) {
        expectComponentRenders(name, variant)
      }
    })
  })
})

const expect = require('chai').expect
const nunjucks = require('nunjucks')
const components = require('../../../lib/components')

const expectComponentRenders = (name, input) => {
  let componentPath = components.templatePathFor(name)
  expect(() => {
    nunjucks.render(componentPath, input)
  }).to.not.throw()
}

describe('Components render examples without errors', () => {
  Object.keys(components.all).map(name => {
    it(`${name} component renders all variants without errors`, () => {
      let component = components.get(name)
      let variants = [{context: component.context}].concat(component.variants)
      for (let variant of variants) {
        expectComponentRenders(name, variant.context)
      }
    })
  })
})

Fix bug in component smoke tests


/**
 * `modules/analytics-4` base data store
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://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.
 */

/**
 * Internal dependencies
 */
import Modules from 'googlesitekit-modules';
import { STORE_NAME } from './constants';

const baseModuleStore = Modules.createModuleStore( 'analytics-4', {
	storeName: STORE_NAME,
	settingSlugs: [
		// TODO: This can be uncommented when Analytics and Analytics 4 modules are officially separated.
		// 'accountID',
		'adsConversionID',
		'propertyID',
		'webDataStreamID',
		'measurementID',
		'useSnippet',
	],
} );

export default baseModuleStore;

/**
 * `modules/analytics-4` base data store
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://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.
 */

/**
 * Internal dependencies
 */
import Modules from 'googlesitekit-modules';
import { STORE_NAME } from './constants';

const baseModuleStore = Modules.createModuleStore( 'analytics-4', {
	storeName: STORE_NAME,
	settingSlugs: [
		// TODO: These can be uncommented when Analytics and Analytics 4 modules are officially separated.
		// 'accountID',
		// 'adsConversionID',
		'propertyID',
		'webDataStreamID',
		'measurementID',
		'useSnippet',
	],
} );

export default baseModuleStore;

Convert adsConversionID setting for GA4 to placeholder.


import React from 'react';
import { DocgenButton } from '../../components/DocgenButton';
import { ButtonGroup } from '../../components/ButtonGroup';

export default {
  title: 'Addons/Docs/ButtonGroup',
  component: ButtonGroup,
  parameters: { viewMode: 'docs' },
  subcomponents: { DocgenButton },
  argTypes: {
    background: {
      control: { type: 'color' },
    },
  },
};

export const Basic = (args) => (
  <ButtonGroup {...args}>
    <DocgenButton label="foo" />
    <DocgenButton label="bar" />
  </ButtonGroup>
);

import React from 'react';
import { DocgenButton } from '../../components/DocgenButton';
import { ButtonGroup } from '../../components/ButtonGroup';

export default {
  title: 'Addons/Docs/ButtonGroup',
  component: ButtonGroup,
  parameters: { viewMode: 'docs' },
  subcomponents: { DocgenButton },
  argTypes: {
    background: {
      control: { type: 'color' },
    },
  },
};

export const Args = (args) => (
  <ButtonGroup {...args}>
    <DocgenButton label="foo" />
    <DocgenButton label="bar" />
  </ButtonGroup>
);

export const NoArgs = () => (
  <ButtonGroup background="#eee">
    <DocgenButton label="foo" />
    <DocgenButton label="bar" />
  </ButtonGroup>
);

Test case for args breaking on non-primary story


/*
 * HomePage
 * This is the first thing users see of our App
 */

import { asyncChangeProjectName, asyncChangeOwnerName } from '../../actions/AppActions';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';

class HomePage extends Component {
  render() {
    const dispatch = this.props.dispatch;
    const { projectName, ownerName } = this.props.data;
    return (

Hello World!

This is the demo for the { projectName } by @{ ownerName }

        Change to your project name:
          <input className="home__input" type="text" onChange={(evt) => { dispatch(asyncChangeProjectName(evt.target.value)); }} defaultValue="React.js Boilerplate" value={projectName} />

        Change to your name:
          <input className="home__input" type="text" onChange={(evt) => { dispatch(asyncChangeOwnerName(evt.target.value)); }} defaultValue="mxstbr" value={ownerName} />

        <Link className="btn" to="/readme">Setup</Link>

    );
  }
}

// REDUX STUFF

// Which props do we want to inject, given the global state?
function select(state) {
  return {
    data: state
  };
}

// Wrap the component to inject dispatch and state into it
export default connect(select)(HomePage);

/*
 * HomePage
 * This is the first thing users see of our App
 */

import { asyncChangeProjectName, asyncChangeOwnerName } from '../../actions/AppActions';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';

class HomePage extends Component {
  render() {
    const dispatch = this.props.dispatch;
    const { projectName, ownerName } = this.props.data;
    return (

Hello World!

        <Link className="btn" to="/login">Login</Link>

        <Link className="btn" to="/register">Register</Link>

    );
  }
}

// REDUX STUFF

// Which props do we want to inject, given the global state?
function select(state) {
  return {
    data: state
  };
}

// Wrap the component to inject dispatch and state into it
export default connect(select)(HomePage);

Add login & logout link


import Ember from 'ember';
import layout from '../templates/components/more-menu';

export default Ember.Component.extend({
  layout,
  classNames: ['dropdown-button'],

  didRender() {
    this._super(...arguments);
    this._setupDropdown();
  },

  _setupDropdown() {
    // needed until the Materialize.dropdown plugin is replaced
    this.$().attr('data-activates', this.get('_dropdownContentId'));
    this.$().dropdown({
      belowOrigin: false,
      alignment: 'right',
      constrain_width: false,
      gutter: 100
    });
  },

  _dropdownContentId: Ember.computed(function() {
    return `${this.get('elementId')}-dropdown-content`;
  })
});

import Ember from 'ember';
import layout from '../templates/components/more-menu';

export default Ember.Component.extend({
  layout,
  classNames: ['dropdown-button'],

  didRender() {
    this._super(...arguments);
    this._setupDropdown();
  },

  _setupDropdown() {
    // needed until the Materialize.dropdown plugin is replaced
    this.$().attr('data-activates', this.get('_dropdownContentId'));
    this.$().dropdown({
      belowOrigin: false,
      alignment: 'right',
      constrain_width: false
    });
  },

  _dropdownContentId: Ember.computed(function() {
    return `${this.get('elementId')}-dropdown-content`;
  })
});

Remove gutter from the more menu


/* eslint-env mocha */
const binarysearch = require('../../../src').Algorithms.Searching.binarysearch;
const assert = require('assert');

describe('Binary Search', () => {
  it('should return -1 for empty array', () => {
    const index = binarysearch([], 1);

    assert.equal(index, -1);
  });
});

/* eslint-env mocha */
const binarysearch = require('../../../src').Algorithms.Searching.binarysearch;
const assert = require('assert');

describe('Binary Search', () => {
  it('should return -1 for empty array', () => {
    const index = binarysearch([], 1);

    assert.equal(index, -1);
  });

  it('should return -1 for no element found in array', () => {
    const index = binarysearch([2, 3, 4, 5, 6], 1);

    assert.equal(index, -1);
  });

  it('should return index of mid element', () => {
    const index = binarysearch([2, 3, 4, 5, 6], 4);

    assert.equal(index, 2);
  });

  it('should return index of first element', () => {
    const index = binarysearch([2, 3, 4, 5, 6], 2);

    assert.equal(index, 0);
  });

  it('should return index of last element', () => {
    const index = binarysearch([2, 3, 4, 5, 6], 6);

    assert.equal(index, 4);
  });
});

Test Binary Search: 100% coverage


declare type JSON = string | number | boolean | null | JSONObject | JSONArray;
declare type JSONObject = { [key:string]: JSON };
declare type JSONArray = Array<JSON>;

declare type JSONValue = string | number | boolean | null | JSONObject | JSONArray;
declare type JSONObject = { [key:string]: JSONValue };
declare type JSONArray = Array<JSONValue>;

Rename type `JSON` to `JSONValue` since `JSON` is already defined


import { Localization } from './base';
import { overlayElement } from './overlay';

export { contexts } from './base';

const allowed = {
  attributes: {
    global: ['aria-label', 'aria-valuetext', 'aria-moz-hint'],
    button: ['accesskey'],
    tab: ['label'],
    textbox: ['placeholder'],
  }
};

export class XULLocalization extends Localization {
  overlayElement(element, translation) {
    return overlayElement(this, element, translation);
  }

  isElementAllowed(element) {
    return false;
  }

  isAttrAllowed(attr, element) {
    const attrName = attr.name.toLowerCase();
    const tagName = element.tagName.toLowerCase();
    // is it a globally safe attribute?
    if (allowed.attributes.global.indexOf(attrName) !== -1) {
      return true;
    }
    // are there no allowed attributes for this element?
    if (!allowed.attributes[tagName]) {
      return false;
    }
    // is it allowed on this element?
    // XXX the allowed list should be amendable; https://bugzil.la/922573
    if (allowed.attributes[tagName].indexOf(attrName) !== -1) {
      return true;
    }
    return false;
  }
}

import { Localization } from './base';
import { overlayElement } from './overlay';

export { contexts } from './base';

const ns = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';

const allowed = {
  attributes: {
    global: ['aria-label', 'aria-valuetext', 'aria-moz-hint'],
    button: ['accesskey'],
    tab: ['label'],
    textbox: ['placeholder'],
  }
};

export class XULLocalization extends Localization {
  overlayElement(element, translation) {
    return overlayElement(this, element, translation);
  }

  isElementAllowed(element) {
    return false;
  }

  isAttrAllowed(attr, element) {
    if (element.namespaceURI !== ns) {
      return false;
    }

    const tagName = element.localName;
    const attrName = attr.name;

    // is it a globally safe attribute?
    if (allowed.attributes.global.indexOf(attrName) !== -1) {
      return true;
    }

    // are there no allowed attributes for this element?
    if (!allowed.attributes[tagName]) {
      return false;
    }

    // is it allowed on this element?
    // XXX the allowed list should be amendable; https://bugzil.la/922573
    if (allowed.attributes[tagName].indexOf(attrName) !== -1) {
      return true;
    }

    return false;
  }
}

Use element.localName and check namespaceURI


;(function(){

  angular.module('flockTogether')

    .controller('detailCtrl', function($scope, $http, $location) {
      var id = $location.path().split('/')[2]-1;//pulls event_id out of path for reference
      $http.get("api/event.json")
      .then(function(response){
        $scope.thisEvent = response.data[id];
        $scope.directions = $scope.thisEvent.location.split(" ").join("+");
      })//END get event.json

      $scope.joinEvent=function(){
        console.log("Add code to put user to attending list");
      }
    })//END eventDetail controller
})();

;(function(){
  var BASE_URL = "api/event.json";

  angular.module('flockTogether')

  .controller('detailCtrl', function($scope, $http, $location) {
    var id = $location.path().split('/')[2]-1;//pulls event_id out of path and translates to index number
    $http.get(BASE_URL)
    .then(function(response){
      $scope.thisEvent = response.data[id];
      $scope.directions = $scope.thisEvent.location.split(" ").join("+");
    });//END get event.json

    $scope.joinEvent=function(){
      console.log("Add code to put user to attending list");
      $http.get("https://flockapi.herokuapp.com/")
      .then(function successCallback(response) {
        console.log("Success");
      },
      function errorCallback(response) {
        console.log(response.data);
      })
    }//END joinEvent
  })//END eventDetail controller
})();

Add BASE URL var and dummy code for joinEvent.


class MainController {
  constructor($log, $state, $localStorage, baseMusic, audioOn, AudioService) {
    'ngInject';

    this.$state = $state;
    this.$storage = $localStorage.$default({
      audioStatus: audioOn
    });

    if (AudioService.music == null) {
      var music = AudioService.prepareMusic(baseMusic);
      AudioService.setMusic(music);
    }

    if (!AudioService.music.isPlaying && this.$storage.audioStatus === audioOn) {
      AudioService.playMusic();
    }
  }

  play() {
    this.$state.go('select');
  }
}

export default MainController;

class MainController {
  constructor($log, $state, $localStorage, baseMusic, audioOn, AudioService) {
    'ngInject';

    this.$state = $state;
    this.$storage = $localStorage.$default({
      audioStatus: audioOn
    });

    if (AudioService.music == null || AudioService.music._src !== baseMusic) {
      var music = AudioService.prepareMusic(baseMusic);
      AudioService.setMusic(music);
    }

    if (!AudioService.music.isPlaying && this.$storage.audioStatus === audioOn) {
      AudioService.playMusic();
    }
  }

  play() {
    this.$state.go('select');
  }
}

export default MainController;

Fix music not changing in main page


import React from 'react';

const Offseason = () => (

Boilermake

        As the sun sets on BoilerMake V, we're looking for passionate students to join the BoilerMake VI (Fall 2018) Exec Board.

        <button className="application-link">Apply Now!</button>

        Questions? team@boilermake.org

);

export default Offseason;

import React from 'react';

const Offseason = () => (

Boilermake

        As the sun sets on BoilerMake V, we're looking for passionate students to join the BoilerMake VI (Fall 2018) Exec Board.

      <button className="application-link">Applications are closed</button>

        Questions? team@boilermake.org

);

export default Offseason;

Remove link from button and change text


// Release 2
// Pseudocode

// Sum Function:
// define a sum function that takes in an array of integers.
// create a result variable equal to 0.
// iterate through the array and add each array value to the result variable.
// return the result variable.

// Mean Function: (you can copy paste the sum function, then just change what it returns)
// define a mean function that takes in an array of integers.
// create a result variable equal to 0.
// iterate through the array and add each array value to the result variable.
// return the result variable divided by the array's length.

// Median Function:
// define a median function that takes in an array of integers.
// create an if/else statement to check if the arrays length is even.
// inside that if statement, set the result equal to: the two middle values of the array, that have been added together and divided by 2.
// inside the else statement, set the result equal to: the middle value of the array.
// return the result variable.

// Release 3

function sum (array) {
  var sum = 0;
  for (var i =0 ; i < array.length; i++) {
    sum += array[i];
  }
  return sum;
}

function mean (array) {
  var result = 0;
  for (var i =0 ; i < array.length; i++) {
    result += array[i];
  }
  return result/array.length;
}

function median (array) {
  if (array.length%2 == 0){
    var median_index = array.length / 2;
    var median = (array[median_index - 1] + array[median_index]) / 2;
    return median;
  }
  else {
    var median_index = Math.floor(array.length / 2);
    var median = array[median_index];
    return median;
  }
}

Add code for release 3


var keijibanApp = angular.module('keijiban', ['ngMaterial', 'ngRoute']);

keijibanApp.directive('infoMenu', function() {
    return {
        templateUrl: 'app/common/infoMenu/infoMenuView.html',
        controller: 'infoMenuController'
    };
});

keijibanApp.directive('listButton', function() {
    return {
        templateUrl: 'app/common/boardButton/boardButtonView.html',
        controller: 'boardButtonController'
    };
});

keijibanApp.directive('editMenu', function() {
    return {
        templateUrl: 'app/common/editMenu/editMenuView.html',
        controller: 'editMenuController'
    };
});

keijibanApp.filter('stripHyphen', function() {
    return function(string) {
        return string.replace(/-/g, ' ');
    };
});

keijibanApp.filter('titleCase', function() {
    return function(string) {
        string = string || '';
        return string.replace(/\w\S*/g, function(txt) {
            return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
        });
    };
});

keijibanApp.filter('range', function() {
    return function(input, total) {
        total = parseInt(total);
        for (var i=0; i<total; i++) {
            input.push(i);
        }
        return input;
    };
});

var keijibanApp = angular.module('keijiban', ['ngMaterial', 'ngRoute']);

keijibanApp.directive('infoMenu', function() {
    return {
        templateUrl: 'app/common/infoMenu/infoMenuView.html',
        controller: 'infoMenuController'
    };
});

keijibanApp.directive('boardButton', function() {
    return {
        templateUrl: 'app/common/boardButton/boardButtonView.html',
        controller: 'boardButtonController'
    };
});

keijibanApp.directive('editMenu', function() {
    return {
        templateUrl: 'app/common/editMenu/editMenuView.html',
        controller: 'editMenuController'
    };
});

keijibanApp.filter('stripHyphen', function() {
    return function(string) {
        return string.replace(/-/g, ' ');
    };
});

keijibanApp.filter('titleCase', function() {
    return function(string) {
        string = string || '';
        return string.replace(/\w\S*/g, function(txt) {
            return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
        });
    };
});

keijibanApp.filter('range', function() {
    return function(input, total) {
        total = parseInt(total);
        for (var i=0; i<total; i++) {
            input.push(i);
        }
        return input;
    };
});

Change the name of a button directive that was missed to match the updated terminology


// function to create the singleton options object that can be shared
// throughout an application
function createUrlQueryOptions() {
  // default options
  return {
    // add in `props.params` from react-router to the url object
    addRouterParams: true,

    // use this history if no history is specified
    history: undefined,

    // reads in location from react-router-redux if available and passes it
    // to the reducer in the urlQueryMiddleware
    readLocationFromStore(state) {
      if (state && state.routing) {
        return state.routing.locationBeforeTransitions;
      }

      return undefined;
    },
  };
}

export default createUrlQueryOptions();

// function to create the singleton options object that can be shared
// throughout an application
function createUrlQueryOptions() {
  // default options
  return {
    // add in `props.params` from react-router to the url object
    addRouterParams: true,

    // use this history if no history is specified
    history: {
      push() {
        // eslint-disable-next-line
        console.error('No history provided to react-url-query. Please provide one via setUrlQueryOptions.');
      },
      replace() {
        // eslint-disable-next-line
        console.error('No history provided to react-url-query. Please provide one via setUrlQueryOptions.');
      },
    },

    // reads in location from react-router-redux if available and passes it
    // to the reducer in the urlQueryMiddleware
    readLocationFromStore(state) {
      if (state && state.routing) {
        return state.routing.locationBeforeTransitions;
      }

      return undefined;
    },
  };
}

export default createUrlQueryOptions();

Add in error messages if trying to push/replace and no history provided


import prefix from '../prefix'
import pascalize from '../utils/pascalize'

// Test if property is supported with vendor prefix.
export default {
  supportedProperty: (prop, style) => {
    const pascalized = pascalize(prop)
    // Return custom CSS variable or already prefixed value without prefixing.
    if (prop[0] === '-' || prop[1] === '-') return prop
    if (prefix.js + pascalized in style) return prefix.css + prop
    // Try webkit fallback.
    if (prefix.js !== 'Webkit' && `Webkit${pascalized}` in style) return `-webkit-${prop}`
    return false
  }
}

import prefix from '../prefix'
import pascalize from '../utils/pascalize'

// Test if property is supported with vendor prefix.
export default {
  supportedProperty: (prop, style) => {
    const pascalized = pascalize(prop)
    // Return custom CSS variable without prefixing.
    if (prop[0] === '-') return prop
    // Return already prefixed value without prefixing.
    if (prop[0] === '-' && prop[1] === '-') return prop
    if (prefix.js + pascalized in style) return prefix.css + prop
    // Try webkit fallback.
    if (prefix.js !== 'Webkit' && `Webkit${pascalized}` in style) return `-webkit-${prop}`
    return false
  }
}

Cover case, where prefix goes on seconds position in string


var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var url = 'mongodb://localhost:27017/test';

var express = require("express");
var app     = express();
var path    = require("path");

app.use(express.static(__dirname + '/'));

app.get('/',function(req,res){

  res.sendFile(path.join(__dirname+'/index.html'));

  MongoClient.connect(url, function(err, db) {
    assert.equal(null, err);
    db.collection('videos', function(err, coll) {
       coll.count(function(err, result){
        db.collection('youtubes').findOne({_id: Math.floor(Math.random() * (result-1)) + 1}, function(err, document) {
          console.log(document);
          console.log(document["Video UR"]);
          db.close();
        });
      });
    });
  });
});

app.listen(3000);

var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var url = 'mongodb://localhost:27017/test';

var express = require("express");
var app     = express();
var path    = require("path");

app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/'));

app.get('/',function(req,res){
  var randomID;
  MongoClient.connect(url, function(err, db) {
    assert.equal(null, err);
    db.collection('videos', function(err, coll) {
       coll.count(function(err, result){
        db.collection('youtubes').findOne({_id: Math.floor(Math.random() * (result-1)) + 1}, function(err, document) {
          console.log(document);
          randomID = document["Video UR"];
          console.log(randomID);
          db.close();
          res.render(path.join(__dirname+'/index'), { videoID: randomID});
        });
      });
    });
  });
});

app.listen(3000);

Use ejs templates to serve random video


import path from 'path'

export default {
  module: {
    loaders: [{
      test: /\.jsx?$/,
      loaders: ['babel-loader'],
      exclude: /node_modules/,
    }, {
      test: /\.json$/,
      loader: 'json-loader',
    },
    {
      test: /\.(png|woff|woff2|eot|ttf|svg)$/,
      loader: 'url-loader?limit=100000',
    },
    ],
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    libraryTarget: 'commonjs2',
  },
  resolve: {
    extensions: ['', '.js', '.jsx'],
    packageMains: ['webpack', 'browser', 'web', 'browserify', ['jam', 'main'], 'main'],
  },
  plugins: [

  ],
  externals: [

    // put your node 3rd party libraries which can't be built with webpack here
    // (mysql, mongodb, and so on..)
  ],
}

import path from 'path'
import nodeExternals from 'webpack-node-externals'

export default {
  module: {
    loaders: [{
      test: /\.jsx?$/,
      loaders: ['babel-loader'],
      exclude: /node_modules/,
    }, {
      test: /\.json$/,
      loader: 'json-loader',
    },
    {
      test: /\.(png|woff|woff2|eot|ttf|svg)$/,
      loader: 'url-loader?limit=100000',
    },
    ],
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    libraryTarget: 'commonjs2',
  },
  resolve: {
    extensions: ['', '.js', '.jsx'],
    packageMains: ['webpack', 'browser', 'web', 'browserify', ['jam', 'main'], 'main'],
  },
  plugins: [

  ],
  externals: [
    nodeExternals({
      whitelist: ['webpack-hot-middleware/client?path=http://localhost:3000/__webpack_hmr', 'normalize.css'],
    }),

    // put your node 3rd party libraries which can't be built with webpack here
    // (mysql, mongodb, and so on..)
  ],
}

Update webpack config to use nodeExternals


module.exports = {
    extends: ["matrix-org", "matrix-org/react-legacy"],
    parser: "babel-eslint",

    env: {
        browser: true,
        node: true,
    },
    globals: {
        LANGUAGES_FILE: "readonly",
    },
    rules: {
        // Things we do that break the ideal style
        "no-constant-condition": "off",
        "prefer-promise-reject-errors": "off",
        "no-async-promise-executor": "off",
        "quotes": "off",
        "indent": "off",
    },

    overrides: [{
        "files": ["src/**/*.{ts,tsx}"],
        "extends": ["matrix-org/ts"],
        "rules": {
            // We're okay being explicit at the moment
            "@typescript-eslint/no-empty-interface": "off",
            // We disable this while we're transitioning
            "@typescript-eslint/no-explicit-any": "off",
            // We'd rather not do this but we do
            "@typescript-eslint/ban-ts-comment": "off",

            "quotes": "off",
            "no-extra-boolean-cast": "off",
        },
    }],
};

module.exports = {
    extends: ["matrix-org", "matrix-org/react-legacy"],
    parser: "babel-eslint",

    env: {
        browser: true,
        node: true,
    },
    globals: {
        LANGUAGES_FILE: "readonly",
    },
    rules: {
        // Things we do that break the ideal style
        "no-constant-condition": "off",
        "prefer-promise-reject-errors": "off",
        "no-async-promise-executor": "off",
        "quotes": "off",
        "indent": "off",
    },

    overrides: [{
        "files": ["src/**/*.{ts,tsx}"],
        "extends": ["matrix-org/ts"],
        "rules": {
            // We're okay being explicit at the moment
            "@typescript-eslint/no-empty-interface": "off",
            // We disable this while we're transitioning
            "@typescript-eslint/no-explicit-any": "off",
            // We'd rather not do this but we do
            "@typescript-eslint/ban-ts-comment": "off",

            "quotes": "off",
            "indent": "off",
            "no-extra-boolean-cast": "off",
        },
    }],
};

Copy indent rule to TS as well


module.exports = {
  api: [
    {
      type: 'category',
      label: 'Navigation',
      items: [
        'component',
        'root',
        'stack',
        'modal',
        'overlay'
      ]
    },
    {
      type: 'category',
      label: 'Layouts',
      items: [
        'layout-layout',
        'layout-component',
        'layout-stack',
        'layout-bottomTabs',
        'layout-sideMenu',
        'layout-splitView'
      ]
    },
    {
      type: 'category',
      label: 'Options',
      items: [
        'options-api',
        'options-root',
        'options-bottomTabs',
        'options-bottomTab',
        {
          'type': 'category',
          'label': 'Stack',
          'items': [
            'options-stack',
            'options-title',
            'options-subtitle',
            'options-background',
            'options-backButton',
            'options-button',
            'options-iconInsets',
            'options-largeTitle'
          ]
        },
        'options-statusBar',
        'options-layout',
        'options-navigationBar',
        'options-overlay',
        'options-sideMenu',
        'options-sideMenuSide',
        'options-splitView'
      ]
    },
    'events'
  ]
};

module.exports = {
  api: [
    {
      type: 'category',
      label: 'Navigation',
      items: [
        'component',
        'root',
        'stack',
        'modal',
        'overlay'
      ]
    },
    {
      type: 'category',
      label: 'Layouts',
      items: [
        'layout-layout',
        'layout-component',
        'layout-stack',
        'layout-bottomTabs',
        'layout-sideMenu',
        'layout-splitView'
      ]
    },
    {
      type: 'category',
      label: 'Options',
      items: [
        'options-api',
        'options-root',
        'options-bottomTabs',
        'options-bottomTab',
        {
          'type': 'category',
          'label': 'Stack',
          'items': [
            'options-stack',
            'options-title',
            'options-subtitle',
            'options-background',
            'options-backButton',
            'options-button',
            'options-iconInsets',
            'options-largeTitle'
          ]
        },
        'options-statusBar',
        'options-layout',
        'options-modal',
        'options-navigationBar',
        'options-overlay',
        'options-sideMenu',
        'options-sideMenuSide',
        'options-splitView'
      ]
    },
    'events'
  ]
};

Add modal options to sidebar


HTTP_METHODS = [
  'get',
  'post',
  'put',
  'delete',
  'patch'
];

HTTP_METHODS = [
  'get',
  'post',
  'put',
  'delete',
  'patch',
  'head'
];

Support `head` as an HTTP_METHOD


'use strict';

var consolidate = require('consolidate');
var path        = require('path');
var _           = require('lodash');

module.exports = {

    partials: {},

    defaults: {
        ext: '.hbs',
        name: 'handlebars'
    },

    config: null,

    configure: function(config){
        this.config = config;
    },

    /**
     * Register component view templates as partials.
     * Called every time the component file tree changes.
     */

    registerViews: function(views) {
        var self = this;
        views.forEach(function(view){
            self.partials[view.handle] = view.path;
            if (view.alias) {
                self.partials[view.alias] = view.path;
            }
        });
    },

    /**
     * Render the component view contents.
     * More work than it should be because it needs some skanky
     * partial path rewriting to make them play nicely with consolidate.
     */

    render: function(str, context, meta) {
        context.partials = {};
        var tplPath = meta.path;
        _.each(this.partials, function(partialPath, partialKey){
            if (tplPath != partialPath) {
                var relPath = path.relative(tplPath, partialPath).replace('../', '');
                var parts = path.parse(relPath);
                if ( !_.isEmpty(parts.name) && (path.extname(tplPath) == path.extname(partialPath))) {
                    context.partials[partialKey] = path.join(parts.dir, parts.name);
                }
            }
        });
        return consolidate[this.config.name](meta.path, context);
    }

};

'use strict';

var consolidate = require('consolidate');
var path        = require('path');
var _           = require('lodash');

module.exports = function(source, config){

    config = _defaultsDeep(config || {}, {
        engine: 'handlebars'
    });

    const partials = {};

    function loadViews(source) {
        for (let item of source.flatten(true)) {
            partials[item.handle] = item.content;
            if (item.alias) {
                partials[item.alias] = item.content;
            }
        }
        viewsLoaded = true;
    }

    source.on('loaded', loadViews);
    source.on('changed', loadViews);

    return {
        engine: consolidate[config.engine],
        render: function(tplPath, str, context, meta){
            if (!viewsLoaded) loadViews(source);
            context.partials = {};
            _.each(partials, function(partialPath, partialKey){
                if (tplPath != partialPath) {
                    const relPath = path.relative(tplPath, partialPath).replace('../', '');
                    const parts = path.parse(relPath);
                    if ( !_.isEmpty(parts.name) && (path.extname(tplPath) == path.extname(partialPath))) {
                        context.partials[partialKey] = path.join(parts.dir, parts.name);
                    }
                }
            });
            return Promise.resolve(consolidate[config.engine](tplPath, context));
        }
    }

};

Update to work with new API


import Relay from 'react-relay';

const relayEnvironmentPerGithubHost = new Map();

export default class RelayNetworkLayerManager {
  static getEnvironmentForHost(host, token) {
    host = host === 'github.com' ? 'https://api.github.com' : host; // eslint-disable-line no-param-reassign
    const url = host === 'https://api.github.com' ? `${host}/graphql` : `${host}/api/v3/graphql`;
    const config = relayEnvironmentPerGithubHost.get(host) || {};
    let {environment, networkLayer} = config;
    if (!environment) {
      environment = new Relay.Environment();
      networkLayer = new Relay.DefaultNetworkLayer(url, {
        headers: {
          Authorization: `bearer ${token}`,
          Accept: 'application/vnd.github.graphql-profiling+json',
        },
      });
      environment.injectNetworkLayer(networkLayer);
      relayEnvironmentPerGithubHost.set(host, {environment, networkLayer});
    } else {
      networkLayer._init.headers = {
        Authorization: `bearer ${token}`,
      };
    }
    return environment;
  }
}

import Relay from 'react-relay';

const relayEnvironmentPerGithubHost = new Map();

function override(target, method, implementation) {
  const oldImplementation = target[method].bind(target);
  target[method] = implementation(oldImplementation);
}

function sendQueriesOverride(originalSendQueries) {
  return function sendQueriesWithRateLimitReq(requests) {
    requests.forEach(request => {
      override(request, 'getQueryString', getQueryStringOverride);
      request.then(data => logRateLimitInfo(data.response));
    });
    return originalSendQueries(requests);
  };
}

function getQueryStringOverride(originalGetQueryString) {
  return function getQueryStringInjectingRateLimitReq() {
    const str = originalGetQueryString();
    return str.replace(/query (.*\{)/, 'query $1 ghRateLimit:relay { rateLimit { limit cost remaining resetAt } } ');
  };
}

function logRateLimitInfo(response) {
  if (response && response.ghRateLimit) {
    console.table(response.ghRateLimit); // eslint-disable-line no-console
  }
}

export default class RelayNetworkLayerManager {
  static getEnvironmentForHost(host, token) {
    host = host === 'github.com' ? 'https://api.github.com' : host; // eslint-disable-line no-param-reassign
    const url = host === 'https://api.github.com' ? `${host}/graphql` : `${host}/api/v3/graphql`;
    const config = relayEnvironmentPerGithubHost.get(host) || {};
    let {environment, networkLayer} = config;
    if (!environment) {
      environment = new Relay.Environment();
      networkLayer = new Relay.DefaultNetworkLayer(url, {
        headers: {
          Authorization: `bearer ${token}`,
          Accept: 'application/vnd.github.graphql-profiling+json',
        },
      });
      if (atom && atom.inDevMode()) {
        override(networkLayer, 'sendQueries', sendQueriesOverride);
      }
      environment.injectNetworkLayer(networkLayer);
      relayEnvironmentPerGithubHost.set(host, {environment, networkLayer});
    } else {
      networkLayer._init.headers = {
        Authorization: `bearer ${token}`,
      };
    }
    return environment;
  }
}

Add dev mode logging of GitHub API rate limits


'use strict';

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

module.exports = {
  'name': 'extends-before-mixins',
  'defaults': {},
  'detect': function (ast, parser) {
    var result = [];

    ast.traverseByType('block', function (block) {
      var lastMixin = null;
      block.traverse(function (item, j) {
        if (item.type === 'extend') {
          if (j > lastMixin && lastMixin !== null) {
            result = helpers.addUnique(result, {
              'ruleId': parser.rule.name,
              'line': item.start.line,
              'column': item.start.column,
              'message': 'Extends should come before mixins',
              'severity': parser.severity
            });
          }
        }
        if (item.type === 'include') {
          lastMixin = j;
        }
      });
      lastMixin = null;
    });

    return result;
  }
};

'use strict';

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

module.exports = {
  'name': 'extends-before-mixins',
  'defaults': {},
  'detect': function (ast, parser) {
    var result = [];

    ast.traverseByType('block', function (block) {
      var lastMixin = null;

      block.forEach(function (item, j) {
        if (item.type === 'include' || item.type === 'extend') {
          if (item.first('atkeyword')) {
            var atkeyword = item.first('atkeyword');

            if (atkeyword.first('ident')) {
              var ident = atkeyword.first('ident');

              if (ident.content === 'extend') {
                if (j > lastMixin && lastMixin !== null) {
                  result = helpers.addUnique(result, {
                    'ruleId': parser.rule.name,
                    'line': item.start.line,
                    'column': item.start.column,
                    'message': 'Extends should come before mixins',
                    'severity': parser.severity
                  });
                }
              }
            }
          }
        }

        if (item.type === 'include') {
          lastMixin = j;
        }
      });

      lastMixin = null;
    });

    return result;
  }
};

Fix Sass issue with extends before mixins


import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import initialReducers from './initialReducers';

const logger = createLogger({
  predicate: function(action) {
    const show = window.reduxLog;
    // Show loggig, unless explicitly set false
    return show === undefined || show;
  },
});

export default function configureStore(initialState) {
  const finalCreateStore = compose(
    applyMiddleware(thunk),
    applyMiddleware(logger),
  )(createStore);

  const reducer = combineReducers(initialReducers);
  const store = finalCreateStore(reducer, initialState);

  return store;
}

import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import initialReducers from './initialReducers';

const logger = createLogger({
  // Show logging unless explicitly set false
  predicate: () => window.reduxLog === undefined || window.reduxLog,
});

export default function configureStore(initialState) {
  const finalCreateStore = compose(
    applyMiddleware(thunk),
    applyMiddleware(logger),
  )(createStore);

  const reducer = combineReducers(initialReducers);
  const store = finalCreateStore(reducer, initialState);

  return store;
}

Simplify and fix ESLint errors.


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

// create the controller and inject Angular's $scope
app.controller('mainController', function($scope) {

    // create a message to display in our view
    $scope.message = 'Everyone come and see how good I look!';

    $scope.loginClicked = function() {
        console.log('click! ' + $scope.username);
    };
});

app.config(function($routeProvider){
      $routeProvider
          .when('/',{
                templateUrl: 'login.html'
          })
          .when('/list',{
                templateUrl: 'list.html'
          });
});

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

// create the controller and inject Angular's $scope
app.controller('mainController', function($scope) {

    // create a message to display in our view
    $scope.message = 'Everyone come and see how good I look!';

    $scope.loginClicked = function() {
        window.location.href = "/#/list";
    };
});

app.config(function($routeProvider){
      $routeProvider
          .when('/',{
                templateUrl: 'login.html'
          })
          .when('/list',{
                templateUrl: 'list.html'
          });
});

Add some links and things


var api = require("../api"),
    fs = require("fs-extra"),
    path = require("path"),
    mkdirp = require("mkdirp"),
    templates = require("./templates"),
    cwd = process.cwd();

module.exports = function compile(options) {
  for (var key in api.dsl) {
    global[key] = api.dsl[key];
  }

  require("coffee-script/register");
  var grammar = require(path.join(cwd, "grammar"));

  var code;
  try {
    code = api.compile(grammar)
  } catch (e) {
    if (e.isGrammarError) {
      console.warn("Error: " + e.message);
      return 1;
    } else {
      throw e;
    }
  }

  mkdirp.sync(path.join(cwd, "src"));
  fs.writeFileSync(path.join(cwd, "src", "parser.c"), code);
  fs.writeFileSync(path.join(cwd, "src", "binding.cc"), templates.bindingCC(grammar.name));
  fs.writeFileSync(path.join(cwd, "binding.gyp"), templates.bindingGyp(grammar.name));
  fs.writeFileSync(path.join(cwd, "index.js"), templates.indexJS(grammar.name));

  return 0;
}

var api = require("../api"),
    fs = require("fs-extra"),
    path = require("path"),
    mkdirp = require("mkdirp"),
    templates = require("./templates"),
    cwd = process.cwd();

module.exports = function compile(options) {
  for (var key in api.dsl) {
    global[key] = api.dsl[key];
  }

  require("coffee-script/register");
  var grammar = require(path.join(cwd, "grammar"));

  var code;
  try {
    code = api.compile(grammar)
  } catch (e) {
    if (e.isGrammarError) {
      console.warn("Error: " + e.message);
      return 1;
    } else {
      throw e;
    }
  }

  mkdirp.sync(path.join(cwd, "src"));
  fs.writeFileSync(path.join(cwd, "src", "grammar.json"), JSON.stringify(grammar, null, 2));
  fs.writeFileSync(path.join(cwd, "src", "parser.c"), code);
  fs.writeFileSync(path.join(cwd, "src", "binding.cc"), templates.bindingCC(grammar.name));
  fs.writeFileSync(path.join(cwd, "binding.gyp"), templates.bindingGyp(grammar.name));
  fs.writeFileSync(path.join(cwd, "index.js"), templates.indexJS(grammar.name));

  return 0;
}

Write out grammar JSON to a file when compiling


'use strict';

angular.module('memexLinkerApp')
  .controller('NavbarCtrl', function ($scope, $location, Auth) {

    $scope.logo = 'http://icons.iconarchive.com/icons/icons8/ios7/256/Very-Basic-Paper-Clip-icon.png';

    $scope.menu = [{
      'title': 'Search',
      'link': '/'
    },
    {
      'title': 'Saved Entities',
      'link': '/savedEntities'
    },
    {
      'title': 'Image Stream',
      'link': '/imagestream'
    },
    {
      'title': 'FAQ',
      'link': '/faq'
    }]
    ;

    $scope.isCollapsed = true;
    $scope.isLoggedIn = Auth.isLoggedIn;
    $scope.isAdmin = Auth.isAdmin;
    $scope.getCurrentUser = Auth.getCurrentUser;

    $scope.logout = function() {
      Auth.logout();
      $location.path('/login');
    };

    $scope.isActive = function(route) {
      return route === $location.path();
    };
  });

'use strict';

angular.module('memexLinkerApp')
  .controller('NavbarCtrl', function ($scope, $location, Auth) {

    $scope.logo = 'http://icons.iconarchive.com/icons/icons8/ios7/256/Very-Basic-Paper-Clip-icon.png';

    $scope.menu = [{
      'title': 'Search',
      'link': '/'
    },
    {
      'title': 'Saved Entities',
      'link': '/savedEntities'
    },
    // {
    //   'title': 'Image Stream',
    //   'link': '/imagestream'
    // },
    {
      'title': 'FAQ',
      'link': '/faq'
    }]
    ;

    $scope.isCollapsed = true;
    $scope.isLoggedIn = Auth.isLoggedIn;
    $scope.isAdmin = Auth.isAdmin;
    $scope.getCurrentUser = Auth.getCurrentUser;

    $scope.logout = function() {
      Auth.logout();
      $location.path('/login');
    };

    $scope.isActive = function(route) {
      return route === $location.path();
    };
  });

Remove images tab for current version of Link HT


if (typeof require.context === "undefined") {
  const fs = require("fs");
  const path = require("path");

  require.context = (
    base = ".",
    scanSubDirectories = false,
    regularExpression = /\.js$/
  ) => {
    const files = {};

    function readDirectory(directory) {
      fs.readdirSync(directory).forEach(file => {
        const fullPath = path.resolve(directory, file);

        if (fs.statSync(fullPath).isDirectory()) {
          if (scanSubDirectories) readDirectory(fullPath);

          return;
        }

        if (!regularExpression.test(fullPath)) return;

        files[fullPath] = true;
      });
    }

    readDirectory(path.resolve(__dirname, base));

    function Module(file) {
      return require(file);
    }

    Module.keys = () => Object.keys(files);

    return Module;
  };
}

function importAll(r) {
  return r
    .keys()
    .map(k => ({ path: k, image: r(k) }))
    .reduce((prev, next) => {
      const key = next.path.replace("./", "").replace(".svg", "");
      prev[key] = next.image;
      return prev;
    }, {});
}

const images = importAll(
  require.context("./parts", false, /\.(png|jpe?g|svg|JPE?G|PNG|SVG)$/)
);

export default images;

Add a mock for require.context


(function() {
   "use strict";

    angular.module("angular.jsgrid", [])
        .directive("ngJsgrid", function() {
            return {
                restrict: "A",
                replace: false,
                transclude: false,
                scope: {
                    config: "=ngJsgrid"
                },
                link: function(scope, $element, attrs) {
                    $element.jsGrid(scope.config);

                    $.each(scope.config, function(key) {
                        scope.$watch("config." + key, function(value) {
                            $element.jsGrid("option", key, value);
                        });
                    });
                }
            };
        });
})();

(function() {
   'use strict';

    angular.module('angular.jsgrid', [])
        .directive('ngJsgrid', function() {
            return {
                restrict: 'A',
                replace: false,
                transclude: false,
                scope: {
                    config: '=ngJsgrid'
                },
                link: function(scope, $element, attrs) {
                    $element.jsGrid(scope.config);

                    $.each(scope.config, function(key) {
                        scope.$watch('config.' + key, function(value) {
                            $element.jsGrid('option', key, value);
                        });
                    });
                }
            };
        });
})();

Replace double quotes with single quotes


import mysql from './mysql';
import postgresql from './postgresql';
import sqlserver from './sqlserver';
import cassandra from './cassandra';

/**
 * List of supported database clients
 */
export const CLIENTS = [
  {
    key: 'mysql',
    name: 'MySQL',
    defaultPort: 3306,
  },
  {
    key: 'postgresql',
    name: 'PostgreSQL',
    defaultDatabase: 'postgres',
    defaultPort: 5432,
  },
  {
    key: 'sqlserver',
    name: 'Microsoft SQL Server',
    defaultPort: 1433,
  },
  {
    key: 'cassandra',
    name: 'Cassandra',
    defaultPort: 9042,
    disabledFeatures: [
      'scriptCreateTable',
    ],
  },
];

export default {
  mysql,
  postgresql,
  sqlserver,
  cassandra,
};

import mysql from './mysql';
import postgresql from './postgresql';
import sqlserver from './sqlserver';
import cassandra from './cassandra';

/**
 * List of supported database clients
 */
export const CLIENTS = [
  {
    key: 'mysql',
    name: 'MySQL',
    defaultPort: 3306,
  },
  {
    key: 'postgresql',
    name: 'PostgreSQL',
    defaultDatabase: 'postgres',
    defaultPort: 5432,
  },
  {
    key: 'sqlserver',
    name: 'Microsoft SQL Server',
    defaultPort: 1433,
  },
  {
    key: 'cassandra',
    name: 'Cassandra',
    defaultPort: 9042,
    disabledFeatures: [
      'server:ssl',
      'server:socketPath',
      'server:user',
      'server:password',
      'scriptCreateTable',
    ],
  },
];

export default {
  mysql,
  postgresql,
  sqlserver,
  cassandra,
};

Add some missing disabled features for Cassandra


[1,"Before data cleaning: Importing the data"],
 [2,"Check for importing issues such as broken lines when importing .csv files"],
 [2,"Make sure you have unique IDs"],
 [2,"De-identify all data and save in a new .dta file"],
 [2,"Never make any changes to the raw data"],
[1,"Important steps for data cleaning"],
 [2,"Label variables, don’t use special characters"],
 [2,"Recode and label missing values: your data set should not have observations with -777, -88 or -9 values, for example"],
 [2,"Encode variables: all categorical variables should be saved as labeled numeric variables, no strings"],
 [2,"Don’t change variable names from questionnaire, except for nested repeat groups and reshaped roster data"],
 [2,"Test variables consistency"],
 [2,"Identify and document outliers"],
 [2,"Compress dataset so it is saved in the most efficient format"],
 [2,"Save cleaned data set with an informative name. Avoid saving in a very recent Stata version"],
[1,"Optional steps in data cleaning"],
 [2,"Order variables – unique ID always first, then same order as questionnaire"],
[2,"Drop variables that only make sense for questionnaire review (duration, notes, calculates)"],
 [2,"Rename roster variables"],
 [2,"Categorize variables listed as “others”"],
 [2,"Add metadata as notes: original survey question, relevance, constraints, etc"]

[1,"Before data cleaning: Importing the data"],
 [2,"Check for importing issues such as broken lines when importing .csv files"],
 [2,"Make sure you have unique IDs"],
 [2,"De-identify all data and save in a new .dta file"],
 [2,"Never make any changes to the raw data"],
[1,"Important steps for data cleaning"],
 [2,"Label variables, don’t use special characters"],
 [2,"Recode and label missing values: your data set should not have observations with -777, -88 or -9 values, for example"],
 [2,"Encode variables: all categorical variables should be saved as labeled numeric variables, no strings"],
 [2,"Don’t change variable names from questionnaire, except for nested repeat groups and reshaped roster data"],
 [2,"Check sample representativeness of age, gender, urban/rural, region and religion"],
 [2,"Check administrative data such as date, time, interviewer variables included"],
 [2,"Test variables consistency"],
 [2,"Identify and document outliers"],
 [2,"Compress dataset so it is saved in the most efficient format"],
 [2,"Save cleaned data set with an informative name. Avoid saving in a very recent Stata version"],
[1,"Optional steps in data cleaning"],
 [2,"Order variables – unique ID always first, then same order as questionnaire"],
[2,"Drop variables that only make sense for questionnaire review (duration, notes, calculates)"],
 [2,"Rename roster variables"],
 [2,"Categorize variables listed as “others”"],
 [2,"Add metadata as notes: original survey question, relevance, constraints, etc"]

Update Checking List for internal purposes


Links = new Mongo.Collection("links");

Meteor.methods({
  addLink:function(link, description, type){
    // Insert a links into the collection
    Links.insert({
      description: description,
      link: link,
      type: type,
      createdAt: new Date()
    });
  }
});

Router.route('/', function () {
  this.render('home');
});

if(Meteor.isServer){
  Meteor.publish("links", function(argument){
    return Links.find();
  });
}

if (Meteor.isClient) {
  Meteor.subscribe("links");

  Template.main.helpers({
    links: function () {
      return Links.find({}, {sort: {createdAt: -1}});
    }
  });
  Template.main.events({
    'submit .new-link': function (event) {
      // Prevent default browser form submit
      event.preventDefault();

      // Get value from form element
      var description = event.target.description.value;
      var link        = event.target.link.value;
      var type        = event.target.type.value;
      if (type ==="Select type.") {
        type = null;
      }
      //Add Link via Meteor method
      Meteor.call("addLink", link, description, type);

      // Clear form
      event.target.description.value = "";
      event.target.link.value = "";
      event.target.type.value = "Select type.";
    }
  });
}

Links = new Mongo.Collection("links");

Meteor.methods({
  addLink:function(link, description, type){
    // Insert a links into the collection
    Links.insert({
      description: description,
      link: link,
      type: type,
      createdAt: new Date()
    });
  }
});

Router.route('/', function () {
  this.render('home');
});

if(Meteor.isServer){
  Meteor.publish("links", function(argument){
    return Links.find();
  });
  Houston.methods("links", {
  "Reset Type": function (link) {
    Links.update(link._id, {$set: {type: "Select type."}});
    return "add type success";
  }
});
}

if (Meteor.isClient) {
  Meteor.subscribe("links");

  Template.main.helpers({
    links: function () {
      return Links.find({}, {sort: {createdAt: -1}});
    }
  });
  Template.main.events({
    'submit .new-link': function (event) {
      // Prevent default browser form submit
      event.preventDefault();

      // Get value from form element
      var description = event.target.description.value;
      var link        = event.target.link.value;
      var type        = event.target.type.value;
      if (type ==="Select type.") {
        type = null;
      }
      //Add Link via Meteor method
      Meteor.call("addLink", link, description, type);

      // Clear form
      event.target.description.value = "";
      event.target.link.value = "";
      event.target.type.value = "Select type.";
    }
  });
}

Add backend function to reset type.


'use strict'

export const FETCH_EVENTS = 'FETCH_EVENTS'
export const EVENTS_SUCCESS = 'EVENTS_SUCCESS'
export const EVENTS_FAILED = 'EVENTS_FAILED'

export const FILL_FILTER_SELECTS = 'FILL_FILTER_SELECTS'

export {
  fetchEvents,
  eventsSuccess,
  eventsFailed
} from './events'

export {
  prepareFilterSelects
} from './filter'

'use strict'

export const FETCH_EVENTS = 'FETCH_EVENTS'
export const EVENTS_SUCCESS = 'EVENTS_SUCCESS'
export const EVENTS_FAILED = 'EVENTS_FAILED'

export const FILL_FILTER_SELECTS = 'FILL_FILTER_SELECTS'
export const CHOOSE_FILTER_SELECT = 'CHOOSE_FILTER_SELECT'

export {
  fetchEvents,
  eventsSuccess,
  eventsFailed
} from './events'

export {
  prepareFilterSelects,
  chooseFilterSelect
} from './filter'

Add actions for filter events


import Ember from 'ember';
import layout from '../templates/components/roundcube-notifications-main';
import Notify from 'ember-notify';

export default Ember.Component.extend({
  layout: layout,
  pubsub: Ember.inject.service(),
  notify: Ember.inject.service('notify'),
  setup: function() {
    var pubsub = this.get('pubsub'),
        notify = this.get('notify');

    pubsub.on('shell.notify', function (message) {
      notify.info(message + '', {
        closeAfter: 100000
      });
    });
  }.on('init')
});

import Ember from 'ember';
import layout from '../templates/components/roundcube-notifications-main';
import Notify from 'ember-notify';

export default Ember.Component.extend({
  layout: layout,
  pubsub: Ember.inject.service(),
  notify: Ember.inject.service('notify'),
  setup: function() {
    var pubsub = this.get('pubsub'),
        notify = this.get('notify');

    pubsub.on('shell.notify', function (message) {
      notify.info(message + '', {
        closeAfter: 5000
      });
    });
  }.on('init')
});

Set notification time to 5 seconds


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

const plugins = [];
const entry = {};

const filenamePrefix = process.env.DEV_SERVER ? 'contribs/gmf/apps/' : '';

for (const filename of ls('contribs/gmf/apps/*/index.html')) {
  const name = path.basename(filename.path);
  entry[name] = `./${filename.path}/js/Controller.js`;
  plugins.push(
    new HtmlWebpackPlugin({
      template: filename.full,
      chunksSortMode: 'manual',
      filename: filenamePrefix + name,
      chunks: ['commons', name]
    })
  );
}

module.exports = {
  entry: entry,
  optimization: {
    splitChunks: {
      chunks: 'all',
      name: 'commons',
    }
  },
  plugins: plugins,
};

if (!process.env.DEV_SERVER) {
  Object.assign(module.exports, {
    output: {
      path: path.resolve(__dirname, '../.build/contribs-gmf-apps'),
    },
  });
}

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

const plugins = [];
const entry = {};

const filenamePrefix = process.env.DEV_SERVER ? 'contribs/gmf/apps/' : '';

for (const filename of ls('contribs/gmf/apps/*/index.html')) {
  const name = path.basename(filename.path);
  entry[name] = `./${filename.path}/js/Controller.js`;
  plugins.push(
    new HtmlWebpackPlugin({
      template: filename.full,
      chunksSortMode: 'manual',
      filename: filenamePrefix + name + '/index.html',
      chunks: ['commons', name]
    })
  );
}

module.exports = {
  entry: entry,
  optimization: {
    splitChunks: {
      chunks: 'all',
      name: 'commons',
    }
  },
  plugins: plugins,
};

if (!process.env.DEV_SERVER) {
  Object.assign(module.exports, {
    output: {
      path: path.resolve(__dirname, '../.build/contribs-gmf-apps'),
    },
  });
}

Add missing index.html in webpack target


const requestsController = require('../../controllers/requests.js');
const requestHelper = require('../../helpers/requestHelper.js');

module.exports = {
  '/:request/top/:size': {
    get: function get(req, res, cb) {
    	const size = parseInt(req.params.size);
    	res.setHeader('Access-Control-Allow-Origin', '*');

    	if (typeof size == 'number' && size > 5) {
    		requestsController.getRowRequest(req.params.request, size, req, res);
    	} else {
    		res.json({ success: false, message: 'Invalid size parameter'});
    	}
    },
  },
  '/game/:type': {
    get: function get (req, res, cb) {
        res.setHeader('Access-Control-Allow-Origin', '*');

        requestsController.getGameRequest(req.params.type, req, res);
    },
  },
  '/getTodayHits': {
      get: function get(req, res, cb) {
        res.setHeader('Access-Control-Allow-Origin', '*');

        requestsController.getTodaysRequests(req, res);
      },
  }
};

const requestsController = require('../../controllers/requests.js');
const requestHelper = require('../../helpers/requestHelper.js');

module.exports = {
  '/:request/top/:size': {
    get: function get(req, res, cb) {
    	const size = parseInt(req.params.size);
    	res.setHeader('Access-Control-Allow-Origin', '*');

    	if (typeof size == 'number' && size > 5) {
    		requestsController.getRowRequest(req.params.request, size, req, res);
    	} else {
    		res.json({ success: false, message: 'Invalid size parameter'});
    	}
    },
  },
  '/game/:type': {
    get: function get (req, res, cb) {
        res.setHeader('Access-Control-Allow-Origin', '*');

        requestsController.getGameRequest(req.params.type, req, res);
    },
  },
  '/getTodayHits': {
      get: function get(req, res, cb) {
        res.setHeader('Access-Control-Allow-Origin', '*');

        requestsController.getTodaysRequests(req, res);
      },
  },
  '/getTopTargets': {
      get: function get(req, res, cb) {
        res.setHeader('Access-Control-Allow-Origin', '*');

        requestsController.getTopTargets(req, res);
      }
  },
};

Add route for top targets


Package.describe({
  name: "babel-compiler",
  summary: "Parser/transpiler for ECMAScript 6+ syntax",
  // Tracks the npm version below.  Use wrap numbers to increment
  // without incrementing the npm version.
  version: '5.7.1'
});

Npm.depends({
  'meteor-babel': '0.4.3'
});

Package.onUse(function (api) {
  api.addFiles('babel.js', 'server');
  api.use('check');
  api.export('Babel', 'server');
});

Package.describe({
  name: "babel-compiler",
  summary: "Parser/transpiler for ECMAScript 6+ syntax",
  // Tracks the npm version below.  Use wrap numbers to increment
  // without incrementing the npm version.
  version: '5.7.3'
});

Npm.depends({
  'meteor-babel': '0.4.4'
});

Package.onUse(function (api) {
  api.addFiles('babel.js', 'server');
  api.use('check');
  api.export('Babel', 'server');
});

Upgrade babel-compiler to the latest meteor-babel.


import { combineReducers } from 'redux'
import auth from './auth'

const rootReducer = combineReducers({
    auth
})

export default rootReducer

import { combineReducers } from 'redux'
import auth from 'reducers/auth'

const rootReducer = combineReducers({
    auth
})

export default rootReducer

Use shortcut path to import the auth reducer


import { combineReducers } from 'redux'

import { folder, files } from './folder'
import ui from './ui'

import { TRASH_DIR_ID } from '../actions'

const filesApp = combineReducers({
  folder,
  files,
  ui
})

const sortFiles = files => files.sort((a, b) => a.name.localeCompare(b.name))

const getSortedFiles = allFiles => {
  let folders = allFiles.filter(f => f.type === 'directory' && f.id !== TRASH_DIR_ID)
  let files = allFiles.filter(f => f.type !== 'directory')
  return sortFiles(folders).concat(sortFiles(files))
}

export const getVisibleFiles = state => {
  const { files, ui } = state
  return getSortedFiles(files).map(f => {
    let additionalProps = {
      isUpdating: ui.updating.indexOf(f.id) !== -1,
      isOpening: ui.opening === f.id,
      selected: ui.selected.indexOf(f.id) !== -1
    }
    return Object.assign({}, f, additionalProps)
  })
}

export const mustShowSelectionBar = state => state.ui.showSelectionBar || state.ui.selected.length !== 0

export default filesApp

import { combineReducers } from 'redux'

import { folder, files } from './folder'
import ui from './ui'

import { TRASH_DIR_ID } from '../constants/config.js'

const filesApp = combineReducers({
  folder,
  files,
  ui
})

const sortFiles = files => files.sort((a, b) => a.name.localeCompare(b.name))

const getSortedFiles = allFiles => {
  let folders = allFiles.filter(f => f.type === 'directory' && f.id !== TRASH_DIR_ID)
  let files = allFiles.filter(f => f.type !== 'directory')
  return sortFiles(folders).concat(sortFiles(files))
}

export const getVisibleFiles = state => {
  const { files, ui } = state
  return getSortedFiles(files).map(f => {
    let additionalProps = {
      isUpdating: ui.updating.indexOf(f.id) !== -1,
      isOpening: ui.opening === f.id,
      selected: ui.selected.indexOf(f.id) !== -1
    }
    return Object.assign({}, f, additionalProps)
  })
}

export const mustShowSelectionBar = state => state.ui.showSelectionBar || state.ui.selected.length !== 0

export default filesApp

Hide trash folder after regression


// borrowed from https://github.com/keithamus/travis-ci-node-and-browser-qunit
var fs = require('fs'),
    page = new WebPage(),
    file = fs.absolute('test/test.html');
    testResults = {};

page.onConsoleMessage = function(msg) {
        console.log(page.lib + ': ' + msg);
        if (/^Tests completed in/.test(msg)) {
            testResults[page.lib] = page.evaluate(function () {
                if (window.QUnit && QUnit.config && QUnit.config.stats) {
                    return QUnit.config.stats.bad || 0;
                }
                return 1;
            });
            if (Object.keys(testResults).length === 2) {
                phantom.exit(testResults.jQuery || testResults.zepto);
            }
        }
    };

function runTests(filePath, lib) {
    filePath = 'file://' + filePath + '?lib=' + lib;
    console.log("Testing " + filePath);
    page.open( filePath, function (status) {
        page.lib = lib;
        if (status !== 'success') {
            console.log('FAIL to load the address');
            phantom.exit(1);
        }
    });
}

runTests(file, 'jQuery');
// quick and dirty: wait 1 second, then test with zepto
setTimeout(function () {
    runTests(file, 'zepto');
}, 1000);

// borrowed from https://github.com/keithamus/travis-ci-node-and-browser-qunit
var fs = require('fs'),
    page = new WebPage(),
    file = fs.absolute('test/test.html');

page.onConsoleMessage = function(msg) {
    console.log(msg);
    if (/^Tests completed in/.test(msg)) {
        phantom.exit(page.evaluate(function () {
            if (window.QUnit && QUnit.config && QUnit.config.stats) {
                return QUnit.config.stats.bad || 0;
            }
            return 1;
        }));
    }
};

page.open('file://' + file, function (status) {
    if (status !== 'success') {
        console.log('FAIL to load the address');
        phantom.exit(1);
    }
});

Revert "Run both zepto and jQuery tests"


( function( $, d, undefined )
{

    d._ = window.console.debug.bind( window.console );

    d.init = function()
    {
        d.initFontSize();
        d.initHelp();
        d.initManager();
    };

    d.initManager = function()
    {
        this.manager = new d.Manager();

        this.manager.initialize( this.initView.bind( this ) );
    };

    d.initFontSize = ( function()
    {
        var $sizes = $( '#fontSize > a' );

        return function()
        {
            if( localStorage.fontSize )
            {
                document.body.className = localStorage.fontSize;

                $sizes.removeClass( 'selected' );
                $sizes.parent().find( 'a[data-size="' + localStorage.fontSize + '"]' ).addClass( 'selected' );
            }

            $sizes.bind( 'click', function( e )
            {
                var $this = $( e.target );

                $this.siblings().removeClass( 'selected' );
                $this.addClass( 'selected' );

                document.body.className = localStorage.fontSize = $this.attr( 'data-size' );
            } );
        }
    } )();

    d.initView = function()
    {
        var self = this;

        this.manager.hasBookmarks( function( hasBoomarks )
        {
            if( hasBoomarks )
            {
                self.view = new d.View( $( '#bookmarks' ), self.manager );
                self.view.display();
            }
            else
            {
                self.showHelp();
            }
        } );
    };

    d.initHelp = function()
    {
        $( '#help' ).bind( 'click', d.toggleHelp.bind( d ) );
    };

    d.showHelp = function()
    {
        $( '#getstarted' ).show();
        $( '#bookmarks' ).hide();
    };

    d.toggleHelp = function()
    {
        $( '#getstarted' ).toggle();
        $( '#bookmarks' ).toggle();
    };

    d.init();

} )( Zepto, this.Dashboard );

( function( mdash, $ )
{

    $( document ).ready( function()
    {
        var manager  = new mdash.Manager(),
            fontCtrl = new mdash.FontCtrl( $( '#fontctrl > a' ) ),
            helpCtrl = new mdash.HelpCtrl( $( '#helpctrl' ), $( '#getstarted' ), $( '#bookmarks' ) );

        manager.init( function()
        {
            fontCtrl.init();
            helpCtrl.init();

            var leftColumn  = new mdash.Column( $( '#bookmarks > .left' ) ),
                rightColumn = new mdash.Column( $( '#bookmarks > .right' ) );

            manager.getSections( 'left', function( sections )
            {
                leftColumn.sections = sections;
                leftColumn.render();
            } );

            manager.getSections( 'right', function( sections )
            {
                rightColumn.sections = sections;
                rightColumn.render();
            } );
        } );

    } );

} )( window.mdash, Zepto );

Rewrite the main script according to the whole refactoring.


/**
 * Constant creator
 * @flow
 */

/**
 * Like keymirror, but adds name as a value prefix
 * @param {string} [name=''] Constant name prefix
 * @param {Object} constants Object of constants
 * @returns {Object} Constants object
 */
export default function constantCreator (name='', constants: Object) {
  name = name.toUpperCase()

  return Object.keys(constants).reduce((constants, constant) => {
    constant = constant.toUpperCase()
    constants[constant] = `${name}_${constant}`
    return constants
  }, {})
}

/**
 * Constant creator
 * @flow
 */

/**
 * Like keymirror, but adds name as a value prefix
 * @param {string} name Constant name prefix
 * @param {Object} constants Object of constants
 * @returns {Object} Constants object
 */
export default function constantCreator (name: string, constants: Object) {
  name = name.toUpperCase()

  return Object.keys(constants).reduce((constants, constant) => {
    constant = constant.toUpperCase()
    constants[constant] = `${name}_${constant}`
    return constants
  }, {})
}

Remove useless default value from constant creator


// Handle node, amd, and global systems
if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
        exports = module.exports = $rdf;
    }
    exports.$rdf = $rdf;
}
else {
    if (typeof define === 'function' && define.amd) {
        define('rdflib', function() {
            return $rdf;
        });
    }

    // Leak a global regardless of module system
    root['$rdf'] = $rdf;
}

// Handle node, amd, and global systems
if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
        exports = module.exports = $rdf;
    }
    exports.$rdf = $rdf;
}
else {
    if (typeof define === 'function' && define.amd) {
        define([], function() {
            return $rdf;
        });
    }

    // Leak a global regardless of module system
    root['$rdf'] = $rdf;
}

Fix AMD define to work with RequireJS


import React, { Component } from 'react'
import { DrawerLabel } from '..'
import Avatar from 'material-ui/Avatar'
import styles from './Profile.css'

const avatarStyles = {
	width: 200,
	height: 200,
	marginLeft: 88,
    marginTop: 32,
    marginRight: 88,
    marginBottom: 6
}

class Profile extends Component {
	render () {
		const { avatar, details } = this.props
		return (
			<div style={{ overflowY: 'auto', height: '100%' }}>
				{ avatar ? <Avatar src={avatar} style={avatarStyles} /> : null}
				{
					details.map((e, i) => (
						<DrawerLabel key={i} name={e.name} value={e.value} />
					))
				}
			</div>
		)
	}
}

export default Profile

import React, { Component } from 'react'
import { DrawerLabel } from '..'
import Avatar from 'material-ui/Avatar'
import RaisedButton from 'material-ui/RaisedButton'
import styles from './Profile.css'

const avatarStyles = {
	width: 200,
	height: 200,
	marginLeft: 88,
    marginTop: 32,
    marginRight: 88,
    marginBottom: 6
}

class Profile extends Component {
	render () {
		const { avatar, details, actions } = this.props
		return (
			<div style={{ overflowY: 'auto', height: '100%' }}>
				{ avatar ? <Avatar src={avatar} style={avatarStyles} /> : null}
				{
					details.map((e, i) => (
						<DrawerLabel key={i} name={e.name} value={e.value} />
					))
				}
				{
					actions ? actions.map((a, i) => (
						<RaisedButton key={i} {...a} style={{ marginTop: 26 }} fullWidth={true} />
					)) : null
				}
			</div>
		)
	}
}

export default Profile

Support for actions in profile


import React from 'react';
import {
    ScrollView,
} from 'react-native';
const t = require('tcomb-form-native');
const Form = t.form.Form;

const NewPollScreen = () => {
    return (
        <ScrollView style={{ padding: 20 }}>
            <Form style={styles.baseFont} type={Poll}/>
        </ScrollView>
    );
};

NewPollScreen.navigationOptions = ({ navigation }) => ({
  title: 'Propose a Motion',
});

export default NewPollScreen;

const Conditions = t.enums({
  MAJORITY: 'Majority',
  ALL_IN: 'All-in (100% Consensus)'
});

const Poll = t.struct({
  title: t.String,
  summary: t.String,
  deadline: t.Date,
  conditions: Conditions,
});

const baseFont = {
  fontFamily: 'Baskerville',
};

const styles = {
    baseFont,
    header: {
      ...baseFont,
      fontSize: 30,
    }
};

import React from 'react';
import {
  View,
  ScrollView,
} from 'react-native';
import ConcensusButton from '../components/ConcensusButton';
const t = require('tcomb-form-native');
const Form = t.form.Form;

const NewPollScreen = () => {
  function onProposePress() {
  }

  return (
    <View style={{ padding: 20 }}>
      <ScrollView>
        <Form style={styles.baseFont} type={Poll}/>
      </ScrollView>
      <ConcensusButton
        label='Propose Motion'
        onPress={onProposePress}
      />
    </View>
  );
};

NewPollScreen.navigationOptions = ({ navigation }) => ({
  title: 'Propose a Motion',
});

export default NewPollScreen;

const Conditions = t.enums({
  MAJORITY: 'Majority',
  ALL_IN: 'All-in (100% Consensus)'
});

const Poll = t.struct({
  subject: t.String,
  proposal: t.String,
  endsInMinutes: t.Number,
  concensusPercentage: t.Number,
});

const baseFont = {
  fontFamily: 'Baskerville',
};

const styles = {
    baseFont,
    header: {
      ...baseFont,
      fontSize: 30,
    }
};

Update form to input 'ends in minutes' and concensus percentage


import { PureComponent } from 'react';
import PropTypes from 'prop-types';

const isServer = typeof window === 'undefined';

class ScrollTo extends PureComponent {
  // eslint-disable-line react/prefer-stateless-function
  componentDidMount() {
    setTimeout(this.handleScroll, this.props.delay);
  }

  handleFadeOut = el => {
    el.style.backgroundColor = null; // eslint-disable-line
  };

  handleFadeIn = el => {
    const initialColor = el.style.backgroundColor;
    el.style.transition = 'background-color 1.5s linear'; // eslint-disable-line
    el.style.backgroundColor = '#fefedc'; // eslint-disable-line
    setTimeout(() => this.handleFadeOut(el, initialColor), 5000);
  };

  handleScroll = () => {
    const { target, afterScroll } = this.props;
    if (target && !isServer) {
      const targetBox = target.getBoundingClientRect();
      window.scrollTo({
        behavior: 'smooth',
        left: 0,
        top: targetBox.top - 100
      });
      this.handleFadeIn(target);
    }
    afterScroll();
  };

  render() {
    return null;
  }
}

ScrollTo.propTypes = {
  target: PropTypes.object,
  delay: PropTypes.number,
  afterScroll: PropTypes.number
};

ScrollTo.defaultProps = {
  delay: 500
};

export default ScrollTo;

import { PureComponent } from 'react';
import PropTypes from 'prop-types';

const isServer = typeof window === 'undefined';

class ScrollTo extends PureComponent {
  // eslint-disable-line react/prefer-stateless-function
  componentDidMount() {
    setTimeout(this.handleScroll, this.props.delay);
  }

  handleFadeOut = (el) => {
    el.style.backgroundColor = null; // eslint-disable-line
  };

  handleFadeIn = (el) => {
    const initialColor = el.style.backgroundColor;
    el.style.transition = 'background-color 1.5s linear'; // eslint-disable-line
    el.style.backgroundColor = '#fefedc'; // eslint-disable-line
    setTimeout(() => this.handleFadeOut(el, initialColor), 5000);
  };

  handleScroll = () => {
    const { target, afterScroll } = this.props;
    if (target && !isServer) {
      const targetBox = target.getBoundingClientRect();
      window.scrollTo({
        behavior: 'smooth',
        left: 0,
        top: targetBox.top - 100,
      });
      this.handleFadeIn(target);
    }
    afterScroll();
  };

  render() {
    return null;
  }
}

ScrollTo.propTypes = {
  target: PropTypes.object,
  delay: PropTypes.number,
  afterScroll: PropTypes.number,
};

ScrollTo.defaultProps = {
  delay: 2000,
};

export default ScrollTo;

Add bigger delay to scroll component


import ImgComponent from 'ember-cli-image/components/x-img';
import BackgroundImageComponent from 'ember-cli-image/components/background-image';
import LazyImageMixin from 'ember-cli-image-lazy/mixins/lazy-image-mixin';

export function initialize() {

  var hasDOM = typeof document !== 'undefined';

  if (typeof ImgComponent.enableLazyLoading === 'undefined') {
    ImgComponent.reopenClass({
      enableLazyLoading: hasDOM
    });
  }
  if (typeof BackgroundImageComponent.enableLazyLoading === 'undefined') {
    BackgroundImageComponent.reopenClass({
      enableLazyLoading: hasDOM
    });
  }

  if (ImgComponent.enableLazyLoading) {
    ImgComponent.reopen( LazyImageMixin );
  }
  if (BackgroundImageComponent.enableLazyLoading) {
    BackgroundImageComponent.reopen( LazyImageMixin );
  }

}

export default {
  name: 'image-lazy',
  initialize: initialize
};

import ImgComponent from 'ember-cli-image/components/img-component';
import BackgroundImageComponent from 'ember-cli-image/components/background-image-component';
import LazyImageMixin from 'ember-cli-image-lazy/mixins/lazy-image-mixin';

export function initialize() {

  var hasDOM = typeof document !== 'undefined';

  if (typeof ImgComponent.enableLazyLoading === 'undefined') {
    ImgComponent.reopenClass({
      enableLazyLoading: hasDOM
    });
  }
  if (typeof BackgroundImageComponent.enableLazyLoading === 'undefined') {
    BackgroundImageComponent.reopenClass({
      enableLazyLoading: hasDOM
    });
  }

  if (ImgComponent.enableLazyLoading) {
    ImgComponent.reopen( LazyImageMixin );
  }
  if (BackgroundImageComponent.enableLazyLoading) {
    BackgroundImageComponent.reopen( LazyImageMixin );
  }

}

export default {
  name: 'image-lazy',
  initialize: initialize
};

Use the updated file names for image components in import statements


import {
  GraphQLInputObjectType,
  GraphQLString,
  GraphQLID,
  GraphQLNonNull
} from 'graphql';

export default new GraphQLInputObjectType({
  name: 'CommentInput',
  fields: {
    _id: {
      type: new GraphQLNonNull(GraphQLID)
    },
    postId: {
      type: new GraphQLNonNull(GraphQLID)
    },
    text: {
      type: new GraphQLNonNull(GraphQLString)
    }
  }
});

import {
  GraphQLInputObjectType,
  GraphQLString,
  GraphQLID,
  GraphQLNonNull
} from 'graphql';

export default new GraphQLInputObjectType({
  name: 'CommentInput',
  fields: {
    postId: {
      type: new GraphQLNonNull(GraphQLID)
    },
    text: {
      type: new GraphQLNonNull(GraphQLString)
    }
  }
});

Remove ID in CommentInput type


export const HISTORICAL_EMISSIONS = 'HISTORICAL_EMISSIONS';
export const FUTURE_PATHWAYS = 'FUTURE_PATHWAYS';

export const emissionTabs = [
  {
    name: 'HISTORICAL EMISSIONS',
    value: HISTORICAL_EMISSIONS,
    disabled: false
  },
  {
    name: 'FUTURE PATHWAYS',
    value: FUTURE_PATHWAYS,
    disabled: false
  }
];

export const HISTORICAL_EMISSIONS = 'HISTORICAL_EMISSIONS';
export const FUTURE_PATHWAYS = 'FUTURE_PATHWAYS';

export const emissionTabs = [
  {
    name: 'HISTORICAL EMISSIONS',
    value: HISTORICAL_EMISSIONS
  },
  {
    name: 'FUTURE PATHWAYS',
    value: FUTURE_PATHWAYS
  }
];

Remove 'disable' flag from drivers of emissions data switch


#!/usr/bin/env node
/**
 * @fileOverview This sample code illustrates how one can read all collection files within a directory and run them
 * in parallel.
 */
var newman = require('../'), // require('newman')
    fs = require('fs');

fs.readdir('./examples', function (err, files) {
    if (err) { throw err; }

    // we filter all files with JSON file extension
    files = files.filter(function (file) {
        return (file !== 'package.json' && file !== 'package-lock.json' && file.substr(-5) === '.json');
    });

    // now wer iterate on each file name and call newman.run using each file name
    files.forEach(function (file) {
        newman.run({
            // we load collection using require. for better validation and handling
            // JSON.parse could be used
            collection: require(`${__dirname}/${file}`)
        }, function (err) {
            // finally, when the collection executes, print the status
            console.info(`${file}: ${err ? err.name : 'ok'}!`);
        });
    }); // the entire flow can be made more elegant using `async` module
});

#!/usr/bin/env node
/**
 * @fileOverview This sample code illustrates how one can read all collection files within a directory and run them
 * in parallel.
 */
var newman = require('../'), // require('newman')
    fs = require('fs');

fs.readdir('./examples', function (err, files) {
    if (err) { throw err; }

    // we filter all files with JSON file extension
    files = files.filter(function (file) {
    	return /^((?!(package(-lock)?))|.+)\.json/.test(file);
    });

    // now wer iterate on each file name and call newman.run using each file name
    files.forEach(function (file) {
        newman.run({
            // we load collection using require. for better validation and handling
            // JSON.parse could be used
            collection: require(`${__dirname}/${file}`)
        }, function (err) {
            // finally, when the collection executes, print the status
            console.info(`${file}: ${err ? err.name : 'ok'}!`);
        });
    }); // the entire flow can be made more elegant using `async` module
});

Use regex instead to ignore files


var browserSync = require('browser-sync'),
    config = require('./config.json'),
    bs;

process.on('message', function(message) {
  if (message.type === 'init') {
    bs = browserSync.init(null, {
      proxy: message.url,
      host: '192.168.56.101',
      browser: 'disable',
      https: true,
      ghostMode: {
        clicks: true,
        location: true,
        forms: true,
        scroll: true
      }
    });

    bs.events.on('init', function(api) {
      process.send({type: 'browserSyncInit', browserSync: api.options.urls.external});
    });
  } else if (message.type === 'location') {
    bs.io.sockets.emit('location', {url: message.url});
  } else {
    browserSync.exit();
  }
});

var browserSync = require('browser-sync'),
    config = require('./config.json'),
    bs;

process.on('message', function(message) {
  if (message.type === 'init') {
    bs = browserSync.init(null, {
      proxy: message.url,
//      host: '192.168.56.101',
      browser: 'disable',
      https: true,
      ghostMode: {
        clicks: true,
        location: true,
        forms: true,
        scroll: true
      }
    });

    bs.events.on('init', function(api) {
      process.send({type: 'browserSyncInit', browserSync: api.options.urls.external});
    });
  } else if (message.type === 'location') {
    bs.io.sockets.emit('location', {url: message.url});
  } else {
    browserSync.exit();
  }
});

Disable host on browsersync server


export default {
  template: require('./draw-layer-metadata.html'),
  bindings: {
    layer: '<',
  },
  controller: function ($scope, $timeout, HsDrawService) {
    'ngInject';
    this.modalVisible = true;
    const vm = this;
    $timeout(() => {
      vm.title = $scope.$ctrl.layer.get('title');
      vm.path = $scope.$ctrl.layer.get('path');
    }, 0);
    angular.extend(vm, {
      newLayerPath: '',
      attributes: [],
      titleChanged() {
        vm.layer.set('title', vm.title);
      },
      confirm() {
        const dic = {};
        vm.attributes.forEach((a) => (dic[a.name] = a.value));
        let editorConfig = vm.layer.get('editor');
        if (angular.isUndefined(editorConfig)) {
          editorConfig = {};
          vm.layer.set('editor', editorConfig);
        }
        editorConfig.defaultAttributes = dic;
        HsDrawService.addDrawLayer(vm.layer);
        HsDrawService.fillDrawableLayers();
        vm.modalVisible = false;
      },
      pathChanged() {
        vm.layer.set('path', vm.path);
      },
      addAttr() {
        vm.attributes.push({id: Math.random(), name: '', value: ''});
      },
    });
  },
};

export default {
  template: require('./draw-layer-metadata.html'),
  bindings: {
    layer: '<',
  },
  controller: function ($scope, $timeout, HsDrawService, HsMapService) {
    'ngInject';
    this.modalVisible = true;
    const vm = this;
    $timeout(() => {
      vm.title = $scope.$ctrl.layer.get('title');
      vm.path = $scope.$ctrl.layer.get('path');
    }, 0);
    angular.extend(vm, {
      newLayerPath: '',
      attributes: [],
      titleChanged() {
        vm.layer.set('title', vm.title);
      },
      confirm() {
        const dic = {};

        let tmpLayer = HsMapService.findLayerByTitle('tmpDrawLayer') || null;
        if (tmpLayer) {
          HsMapService.map.removeLayer(tmpLayer)
        }

        vm.attributes.forEach((a) => (dic[a.name] = a.value));
        let editorConfig = vm.layer.get('editor');
        if (angular.isUndefined(editorConfig)) {
          editorConfig = {};
          vm.layer.set('editor', editorConfig);
        }
        editorConfig.defaultAttributes = dic;

        vm.layer.getSource().forEachFeature((f)=>{
          f.setProperties(dic)
        })

        HsDrawService.addDrawLayer(vm.layer);
        HsDrawService.fillDrawableLayers();
        vm.modalVisible = false;
        HsDrawService.tmpDrawLayer = false;
      },
      pathChanged() {
        vm.layer.set('path', vm.path);
      },
      addAttr() {
        vm.attributes.push({id: Math.random(), name: '', value: ''});
      },
    });
  },
};

Remove tmp layer after saving


angular
  .module('app')
  .controller('projectListController', [
    '$scope',
    'projectService',
    'flash',
    'MetaMachine',
    '$location',
    function($scope, projectAPI, notification, MetaMachine, $location) {

        $scope.projects = projectAPI.getAll();

        MetaMachine.title("Projects", "Admin");

        $scope.remove = function(item) {

            var confirm = confirm('Are you sure you want to delete this Project?');

            if(confirm) {
                item.$remove(function() {
                    notification.set({
                        body: 'Your Project has been successfully removed',
                        type: 'success'
                    });
                    $location.path('admin').replace();
                });
            }
        };

        $scope.publish = function(id, status) {

            projectAPI.getById(id).then(function(response) {

                var project = response;

                project.publish = status;
                projectAPI.updateById(id, project).then(function(response) {

                    $scope.projects = projectAPI.getAll();

                    notification.pop({
                        body: 'Your Project has been successfully ' + (status) ? 'published' : 'unpublished',
                        type: 'success'
                    });
                });
            });
        };
    }
  ]);

angular
  .module('app')
  .controller('projectListController', [
    '$scope',
    'projectService',
    'flash',
    'MetaMachine',
    '$location',
    function($scope, projectAPI, notification, MetaMachine, $location) {

        $scope.projects = projectAPI.getAll();

        MetaMachine.title("Projects", "Admin");

        $scope.remove = function(item) {

            if(confirm('Are you sure you want to delete this Project?')) {
                item.$remove(function() {

                    $scope.projects = projectAPI.getAll();

                    notification.set({
                        body: 'Your Project has been successfully removed',
                        type: 'success'
                    });
                });
            }
        };

        $scope.publish = function(id, status) {

            projectAPI.getById(id).then(function(response) {

                var project = response;

                project.publish = status;
                projectAPI.updateById(id, project).then(function(response) {

                    $scope.projects = projectAPI.getAll();

                    notification.pop({
                        body: 'Your Project has been successfully ' + (status) ? 'published' : 'unpublished',
                        type: 'success'
                    });
                });
            });
        };
    }
  ]);

Fix delete project in admin list


var express = require('express');
var app = express();
var mongoose = require('mongoose');
var Scheme = mongoose.Schema;
var morgan = require('morgan');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');

// MongoDB stuff
mongoose.connect('mongodb://127.0.0.1:27017/uwO3mypu');
var db = mongoose.connection;

db.on('error', console.err.bind(console, 'connection error:'));
db.once('open', function (callback) {
  console.log('Mongo database opened');
});

/* var Sound = mongoose.model('Sound', {
    data: Buffer,
    bpm : {type: Number, min: 0, max: 300},
    contentType: String
});
*/

// Express stuff
app.use(express.static(__dirname + '/spa'));                 // set the static files location /public/img will be /img for users
app.use(morgan('dev'));                                         // log every request to the console
app.use(bodyParser.urlencoded({'extended':'true'}));            // parse application/x-www-form-urlencoded
app.use(bodyParser.json());                                     // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());

// Start server
app.listen(8080);
console.log("App listening on port 8080");

var express = require('express');
var app = express();
var mongoose = require('mongoose');
var Scheme = mongoose.Schema;
var morgan = require('morgan');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');

/*
// MongoDB stuff
mongoose.connect('mongodb://localhost:27017/test');
var db = mongoose.connection;

db.on('error', console.log('Database connection error'));
db.once('open', function (callback) {
  console.log('Mongo database opened');
});

var Sound = mongoose.model('Sound', {
    data: Buffer,
    bpm : {type: Number, min: 0, max: 300},
    contentType: String
});
*/

// Express stuff
app.use(express.static(__dirname + '/spa'));                 // set the static files location /public/img will be /img for users
app.use(morgan('dev'));                                         // log every request to the console
app.use(bodyParser.urlencoded({'extended':'true'}));            // parse application/x-www-form-urlencoded
app.use(bodyParser.json());                                     // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());

// Start server
app.listen(8080);
console.log("App listening on port 8080");

Remove MongoDB functionality for now


module.exports = {
  moduleNameMapper: {
    "\\.(css|scss|svg)$": "<rootDir>/support/jest/fileMock.js"
  },
  modulePaths: ["node_modules"],
  moduleFileExtensions: ["js", "jsx", "json"],
  setupFiles: ["raf/polyfill"],
  setupTestFrameworkScriptFile: "<rootDir>/support/jest/setupTests.js",
  unmockedModulePathPatterns: ["node_modules"]
};

module.exports = {
  moduleNameMapper: {
    "\\.(css|scss|svg)$": "<rootDir>/packages/storybook/support/jest/fileMock.js"
  },
  modulePaths: ["node_modules"],
  moduleFileExtensions: ["js", "jsx", "json"],
  rootDir: "../../",
  setupFiles: ["raf/polyfill"],
  setupTestFrameworkScriptFile: "<rootDir>/packages/storybook/support/jest/setupTests.js",
  unmockedModulePathPatterns: ["node_modules"]
};

Configure repo root as Jest context


(function () {
    'use strict';

    define(
        [
        ],
        function () {
            return function (string) {
                try {
                    return JSON.parse(string);
                } catch (e) {
                    if (console && typeof console.error === 'function') {
                        console.error(e);
                    }
                    return '';
                }
            };
        }
    );
}());

(function () {
    'use strict';

    define(
        [
        ],
        function () {
            return function (string) {
                try {
                    return JSON.parse(string);
                } catch (e) {
                    if (console && typeof console.error === 'function') {
                        console.error('Could not parse string as JSON', string, e);
                    }
                    return '';
                }
            };
        }
    );
}());

Improve logging of invalid JSON data.


(function(){
    'use strict';
    angular
        .module('SAKapp')
        .controller('UuidController', ['$scope', '$http', '$log', '$q',  'toaster', UuidController]);

        function UuidController ($scope, $http, $log, $q, toaster) {

                $scope.getUUIDs = function () {
                    $scope.uuids = "";
                    $scope.errorMsg = "";
                    var url = 'http://pz-discover.cf.piazzageo.io/api/v1/resources/pz-uuidgen';
                    var posturl = '';
                    $http({
                        method: "GET",
                        url: url
                    }).then(function(result) {
                       if ($scope.uuidCount === undefined){
                           posturl = "http://"+result.data.host +"/v1/uuids"
                        }
                        else {
                           posturl = "http://"+result.data.host +"/v1/uuids?count="+$scope.uuidCount;
                        }

                        console.log(posturl);
                        $http({
                            method: "POST",
                            url: posturl,
                        }).then(function successCallback( html ) {
                            $scope.uuids = html.data.data;
                            /*angular.forEach($scope.logs, function(item){
                             console.log(item);
                             })*/
                        }, function errorCallback(response){
                            console.log("fail");
                            toaster.pop('error', "Error", "There was an issue retrieving UUID(s)");
                            //$scope.errorMsg = "There was an issue with your request.  Please make sure ..."
                        });

                    });

                };

        }

})();

(function(){
    'use strict';
    angular
        .module('SAKapp')
        .controller('UuidController', ['$scope', '$http', '$log', '$q',  'toaster', UuidController]);

        function UuidController ($scope, $http, $log, $q, toaster) {

                $scope.getUUIDs = function () {
                    $scope.uuids = "";
                    $scope.errorMsg = "";
                    var url = '/proxy?url=http://pz-discover.cf.piazzageo.io/api/v1/resources/pz-uuidgen';
                    var posturl = '';
                    $http({
                        method: "GET",
                        url: url
                    }).then(function(result) {
                       if ($scope.uuidCount === undefined){
                           posturl = "/proxy?url=http://"+result.data.host +"/v1/uuids"
                        }
                        else {
                           posturl = "/proxy?url=http://"+result.data.host +"/v1/uuids%3Fcount="+$scope.uuidCount;
                        }

                        console.log(posturl);
                        $http({
                            method: "POST",
                            url: posturl,
                        }).then(function successCallback( html ) {
                            $scope.uuids = html.data.data;
                            /*angular.forEach($scope.logs, function(item){
                             console.log(item);
                             })*/
                        }, function errorCallback(response){
                            console.log("fail");
                            toaster.pop('error', "Error", "There was an issue retrieving UUID(s)");
                            //$scope.errorMsg = "There was an issue with your request.  Please make sure ..."
                        });

                    });

                };

        }

})();

Fix proxy urls for main uuid functions