<commit_before>/* creates gulpfile in project so the built in gulp commands can be used */

var local = process.cwd().replace(/(\\)/g,'/'),
    fs = require('fs');

var stream = fs.createWriteStream(local+"/../../gulpfile.js");
stream.once('open', function(fd) {
  stream.write("require('konnekt')();\n");
  stream.end();
});

fs.mkdirSync(local+'/../../config');
var config = fs.createWriteStream(local+"/../../config/config.js");
config.once('open', function(fd) {
  config.write("Konnekt.configs({\r\n\r\n});\n");
  config.end();
});<commit_msg>fix postinstall in the case that config exists<commit_after>/* creates gulpfile in project so the built in gulp commands can be used */

var local = process.cwd().replace(/(\\)/g,'/'),
    fs = require('fs');

var stream = fs.createWriteStream(local+"/../../gulpfile.js");
stream.once('open', function(fd) {
  stream.write("require('konnekt')();\n");
  stream.end();
});

if(!fs.existsSync(local+'/../../config')) fs.mkdirSync(local+'/../../config');

if(!fs.existsSync(local+'/../../config/config.js'))
{
  var config = fs.createWriteStream(local+"/../../config/config.js");
  config.once('open', function(fd) {
    config.write("Konnekt.configs({\r\n\r\n});\n");
    config.end();
  });
}<|endoftext|>


<commit_before>
$(document).ready(function () {
    console.log("document ready");

    $("[rel='tooltip']").tooltip({ html: true });
});

$(document).on("click", ".table-clickable > tbody > tr", function (event) {
    var href = $(this).find("a").attr("href");
    if (href) {
        window.location = href;
        event.stopPropagation();
    }
});

function findWinner() {
    var setsNeeded = $("#SetsNeededToWin").val();
    var setsCount = 0;
    var found = false;
    var homewins = 0;
    var awaywins = 0;
    var draws = 0;
    var homeCount = 0;
    var homeTeam = "";
    var awayCount = 0;
    var awayTeam = "";

    $(".checkbox-home:checked").each(function () {
        var name = $(this).data("name");
        homeTeam = homeTeam + name + ",";
        homeCount++;
    });
    homeTeam = homeTeam.substring(0, homeTeam.length - 2)

    $(".checkbox-away:checked").each(function () {
        var name = $(this).data("name");
        awayTeam = awayTeam + name + ", ";
        awayCount++;
    });
    awayTeam = awayTeam.substring(0, awayTeam.length - 2)

    $(".result-home").each(function (index) {
        var self = $(this);

        if (self.val() && $('.' + self.data('ref')).val()) {
            setsCount++;

            var homescore = Number(self.val());
            var awayscore = Number($('.' + self.data('ref')).val());

            if (homescore > awayscore)
                homewins++;
            else if (awayscore > homescore)
                awaywins++;
            else if (homescore == awayscore)
                draws++;
        }
    });

    if (homewins >= setsNeeded || awaywins >= setsNeeded || draws >= setsNeeded)
        found = true;

    if (homeCount == 0 || awayCount == 0)
        found = false;

    if (found) {
        var text = homewins == awaywins ? "draws" : homewins > awaywins ? "wins against" : "looses to";

        //var textArray = ['{0} wins {1}', '{0} beats {1}', '{0} kicks {1} asses', '{0} takes a piss on {1}'];
        //var randomNumber = Math.floor(Math.random()*textArray.length);

        $('.player-home').html(homeTeam);
        $('.player-away').html(awayTeam);
        $('.text-winloose').html(text);

        $('.result-winner').fadeIn();
        $('.btn-submit').prop("disabled", false);
    }
    else {
        $('.result-winner').fadeOut();
        $('.btn-submit').prop("disabled", true);
    }
}
<commit_msg>Added support for Mobile IE10<commit_after>
if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
	var msViewportStyle = document.createElement("style")
	msViewportStyle.appendChild(
		document.createTextNode(
			"@-ms-viewport{width:auto!important}"
		)
	)

	document.getElementsByTagName("head")[0].appendChild(msViewportStyle)
}

$(document).ready(function () {
    console.log("document ready");

    $("[rel='tooltip']").tooltip({ html: true });
});

$(document).on("click", ".table-clickable > tbody > tr", function (event) {
    var href = $(this).find("a").attr("href");
    if (href) {
        window.location = href;
        event.stopPropagation();
    }
});

function findWinner() {
    var setsNeeded = $("#SetsNeededToWin").val();
    var setsCount = 0;
    var found = false;
    var homewins = 0;
    var awaywins = 0;
    var draws = 0;
    var homeCount = 0;
    var homeTeam = "";
    var awayCount = 0;
    var awayTeam = "";

    $(".checkbox-home:checked").each(function () {
        var name = $(this).data("name");
        homeTeam = homeTeam + name + ",";
        homeCount++;
    });
    homeTeam = homeTeam.substring(0, homeTeam.length - 2)

    $(".checkbox-away:checked").each(function () {
        var name = $(this).data("name");
        awayTeam = awayTeam + name + ", ";
        awayCount++;
    });
    awayTeam = awayTeam.substring(0, awayTeam.length - 2)

    $(".result-home").each(function (index) {
        var self = $(this);

        if (self.val() && $('.' + self.data('ref')).val()) {
            setsCount++;

            var homescore = Number(self.val());
            var awayscore = Number($('.' + self.data('ref')).val());

            if (homescore > awayscore)
                homewins++;
            else if (awayscore > homescore)
                awaywins++;
            else if (homescore == awayscore)
                draws++;
        }
    });

    if (homewins >= setsNeeded || awaywins >= setsNeeded || draws >= setsNeeded)
        found = true;

    if (homeCount == 0 || awayCount == 0)
        found = false;

    if (found) {
        var text = homewins == awaywins ? "draws" : homewins > awaywins ? "wins against" : "looses to";

        //var textArray = ['{0} wins {1}', '{0} beats {1}', '{0} kicks {1} asses', '{0} takes a piss on {1}'];
        //var randomNumber = Math.floor(Math.random()*textArray.length);

        $('.player-home').html(homeTeam);
        $('.player-away').html(awayTeam);
        $('.text-winloose').html(text);

        $('.result-winner').fadeIn();
        $('.btn-submit').prop("disabled", false);
    }
    else {
        $('.result-winner').fadeOut();
        $('.btn-submit').prop("disabled", true);
    }
}
<|endoftext|>


<commit_before>'use strict';
/**
 * This module is repsonsible for creating & configuring an instance of knex.
 * Knex will be used to interact with the database.
 */

/**
 * Required modules
 */
var knexConfig = require('../data/knexfile.js'); // require knex configuration object

// Set our mode, falling back to development if not provided.
var mode = process.env.NODE_ENV || 'development';
var dbConfig = knexConfig[mode];

console.log('Database mode used: ' + mode);
console.log('dbConfig used:');
console.log(dbConfig.connection);
var knex = require('knex')(dbConfig);

module.exports = knex;<commit_msg>Tidying console logs<commit_after>'use strict';
/**
 * This module is repsonsible for creating & configuring an instance of knex.
 * Knex will be used to interact with the database.
 */

/**
 * Required modules
 */
var knexConfig = require('../data/knexfile.js'); // require knex configuration object

// Set our mode, falling back to development if not provided.
var mode = process.env.NODE_ENV || 'development';
var dbConfig = knexConfig[mode];

console.log('Database mode used:', mode);
console.log('dbConfig used:', dbConfig.connection);
var knex = require('knex')(dbConfig);

module.exports = knex;<|endoftext|>


<commit_before>'use strict';

const _awsSdk = require('aws-sdk');
const _clone = require('clone');

/**
 * Utility class that can be used to query dynamo db for records, and
 * additionally track temporary records created in dynamo
 * db during testing. Provides the ability to register newly created records,
 * add records for testing, lookup records and ultimately clean up all of the
 * temporary records when testing is complete.
 */
class AwsDynamoDbHelper {
    /**
     * @param {String} tableName The name of the table that this client will be
     *        accessing.
     * @param {Object} options Connection options for the AWS client.
     */
    constructor(tableName, options) {
        if (typeof tableName !== 'string' || tableName.length <= 0) {
            throw new Error('Invalid table name specified (arg #1)');
        }
        if (!options || (options instanceof Array) || typeof options !== 'object') {
            throw new Error('Invalid options specified (arg #3)');
        }

        this._tableName = tableName;
        this._docClient = new _awsSdk.DynamoDB.DocumentClient(options);
        this._keys = [];
    }

    /**
     * Record a primary key for cleanup at a later point.
     *
     * @param {Object} keys A map containing the record keys.
     */
    track(keys) {
        if (!keys || (keys instanceof Array) || typeof keys !== 'object') {
            throw new Error('Invalid keys specified (arg #2)');
        }
        this._keys.push(keys);
    }

    /**
     * Loads a single record of data from dynamodb.
     * @return {Promise} A promise that is rejected/resolved based on the
     *         outcome of the fetch operation.
     */
    getRecord(keys) {
        if (!keys || (keys instanceof Array) || typeof keys !== 'object') {
            throw new Error('Invalid keys specified (arg #1)');
        }
        return new Promise((resolve, reject) => {
            this._docClient.get({
                TableName: this._tableName,
                Key: keys
            }, (err, data) => {
                if (err) {
                    reject(`Error fetching dynamo db record: [${err}]`);
                    return;
                }
                resolve(data);
            });
        });
    }

    /**
     * Creates a single record of data in dynamodb. This record is
     * automatically tracked for deletion during cleanup.
     *
     * @param {Object} keys A map containing the record keys.
     * @param {Object} properties An object containing properties for the
     *        record to write.
     * @return {Promise} A promise that is rejected/resolved based on the
     *         outcome of the put operation.
     */
    createRecord(keys, properties) {
        if (!keys || (keys instanceof Array) || typeof keys !== 'object') {
            throw new Error('Invalid keys specified (arg #1)');
        }
        if (!properties || (properties instanceof Array) || typeof properties !== 'object') {
            throw new Error('Invalid properties specified (arg #2)');
        }
        this.track(keys);
        return new Promise((resolve, reject) => {
            const item = Object.assign(properties, keys);
            this._docClient.put({
                TableName: this._tableName,
                Item: item
            }, (err, data) => {
                if (err) {
                    reject(`Error creating dynamo db record: [${err}]`);
                    return;
                }
                resolve(item);
            });
        });
    }

    /**
     * Deletes all records that are currently being tracked from the dynamo
     * db table.
     *
     * @return {Promise} A promise that is rejected/resolved based on the
     *         outcome of the fetch operation.
     */
    cleanup() {
        const promises = this._keys.map((keys) => {
            return new Promise((resolve, reject) => {
                this._docClient.delete({
                    TableName: this._tableName,
                    Key: keys
                }, (err, data) => {
                    if (err) {
                        reject(`Error deleting dynamo db record: [${err}]`);
                        return;
                    }
                    resolve(data);
                });
            });
        });
        return Promise.all(promises);
    }
}

module.exports = AwsDynamoDbHelper;
<commit_msg>Add helper method to retrieve record and compare with expected value<commit_after>'use strict';

const _chai = require('chai');
const expect = _chai.expect;

const _awsSdk = require('aws-sdk');
const _clone = require('clone');

/**
 * Utility class that can be used to query dynamo db for records, and
 * additionally track temporary records created in dynamo
 * db during testing. Provides the ability to register newly created records,
 * add records for testing, lookup records and ultimately clean up all of the
 * temporary records when testing is complete.
 */
class AwsDynamoDbHelper {
    /**
     * @param {String} tableName The name of the table that this client will be
     *        accessing.
     * @param {Object} options Connection options for the AWS client.
     */
    constructor(tableName, options) {
        if (typeof tableName !== 'string' || tableName.length <= 0) {
            throw new Error('Invalid table name specified (arg #1)');
        }
        if (!options || (options instanceof Array) || typeof options !== 'object') {
            throw new Error('Invalid options specified (arg #3)');
        }

        this._tableName = tableName;
        this._docClient = new _awsSdk.DynamoDB.DocumentClient(options);
        this._keys = [];
    }

    /**
     * Record a primary key for cleanup at a later point.
     *
     * @param {Object} keys A map containing the record keys.
     */
    track(keys) {
        if (!keys || (keys instanceof Array) || typeof keys !== 'object') {
            throw new Error('Invalid keys specified (arg #2)');
        }
        this._keys.push(keys);
    }

    /**
     * Loads a single record of data from dynamodb.
     * @return {Promise} A promise that is rejected/resolved based on the
     *         outcome of the fetch operation.
     */
    getRecord(keys) {
        if (!keys || (keys instanceof Array) || typeof keys !== 'object') {
            throw new Error('Invalid keys specified (arg #1)');
        }
        return new Promise((resolve, reject) => {
            this._docClient.get({
                TableName: this._tableName,
                Key: keys
            }, (err, data) => {
                if (err) {
                    reject(`Error fetching dynamo db record: [${err}]`);
                    return;
                }
                resolve(data);
            });
        });
    }

    /**
     * Creates a single record of data in dynamodb. This record is
     * automatically tracked for deletion during cleanup.
     *
     * @param {Object} keys A map containing the record keys.
     * @param {Object} properties An object containing properties for the
     *        record to write.
     * @return {Promise} A promise that is rejected/resolved based on the
     *         outcome of the put operation.
     */
    createRecord(keys, properties) {
        if (!keys || (keys instanceof Array) || typeof keys !== 'object') {
            throw new Error('Invalid keys specified (arg #1)');
        }
        if (!properties || (properties instanceof Array) || typeof properties !== 'object') {
            throw new Error('Invalid properties specified (arg #2)');
        }
        this.track(keys);
        return new Promise((resolve, reject) => {
            const item = Object.assign(properties, keys);
            this._docClient.put({
                TableName: this._tableName,
                Item: item
            }, (err, data) => {
                if (err) {
                    reject(`Error creating dynamo db record: [${err}]`);
                    return;
                }
                resolve(item);
            });
        });
    }

    /**
     * Returns a function that Retrieves a record from the database and tests it
     * for expected values.
     *
     * @param {Object} keys The keys to use to retrieve the record from the
     *        database.
     * @param {Object} expected A hash containing expected values in the
     *        record. Comparison will only check that the key/value pairs in
     *        the expected object exist in the DB record, but does not consider
     *        any additional properties in the db record that have not been
     *        defined in the expected object.
     *
     * @return {Function} A function that when executed retrieves a record from
     *         the database and performs checks.
     */
    getDbRecordChecker(keys, expected) {
        if(!keys || (keys instanceof Array) || typeof keys !== 'object') {
            throw new Error('Invalid keys specified (arg #1)');
        }
        if(!expected || (expected instanceof Array) || typeof expected !== 'object') {
            expected = {};
        }

        return () => {
            return this.getRecord(keys).then((data) => {
                expect(data).to.be.an('object');
                const item = data.Item;

                expect(item).to.be.an('object');
                for(let prop in expected) {
                    let value = expected[prop];
                    if(typeof value === 'function') {
                        value(item[prop]);
                    } else if(value && typeof value === 'object') {
                        expect(item[prop]).to.deep.equal(value, `[${prop}]`);
                    } else {
                        expect(item[prop]).to.equal(value, `[${prop}]`);
                    }
                }
                return item;
            });
        };
    }

    /**
     * Deletes all records that are currently being tracked from the dynamo
     * db table.
     *
     * @return {Promise} A promise that is rejected/resolved based on the
     *         outcome of the fetch operation.
     */
    cleanup() {
        const promises = this._keys.map((keys) => {
            return new Promise((resolve, reject) => {
                this._docClient.delete({
                    TableName: this._tableName,
                    Key: keys
                }, (err, data) => {
                    if (err) {
                        reject(`Error deleting dynamo db record: [${err}]`);
                        return;
                    }
                    resolve(data);
                });
            });
        });
        return Promise.all(promises);
    }
}

module.exports = AwsDynamoDbHelper;
<|endoftext|>


<commit_before>const platformParams = ['--platform', 'iOS']

const childProcess = require('child_process')
const parentModulePackageJson = require('../../package.json')

if (process.platform === 'darwin' && shouldUseCarthage()) {
  var carthageVersionProcessResult = childProcess.spawnSync('carthage', ['version'], {
    stdio: 'pipe'
  })

  if (carthageVersionProcessResult.status != 0) {
    // `carthage` not found (probably)
    errorExitProcess(
      'carthage is required to compile frameworks for iOS backend. You can install it with brew: "brew install carthage". After installation go to ./node_modules/react-native-ble-plx and run "./postinstall.js" or reinstall node module'
    )
  }

  const bleClientManagerDirectory = __dirname + '/ios/BleClientManager'
  try {
    process.chdir(bleClientManagerDirectory)
  } catch (err) {
    errorExitProcess(`${bleClientManagerDirectory} directory not found. Cannot proceed with building the library.`)
  }

  spawnSyncProcessAndExitOnError('carthage', ['bootstrap', '--no-build', ...platformParams])

  const carthageVersionString = carthageVersionProcessResult.output[1].toString()
  spawnSyncProcessAndExitOnError('carthage', getCarthageBuildParams(carthageVersionString))

  process.exit(0)
}

function shouldUseCarthage() {
  const reactNativeBlePlxOptions = parentModulePackageJson.react_native_ble_plx
  if (!reactNativeBlePlxOptions) return true
  const useCarthage = reactNativeBlePlxOptions.carthage
  return useCarthage != undefined ? useCarthage : true
}

function errorExitProcess(errorMessage) {
  console.error(`Error: ${errorMessage}`)
  process.exit(1)
}

function spawnSyncProcessAndExitOnError(command, params) {
  const result = childProcess.spawnSync(command, params, {
    stdio: 'inherit'
  })

  if (result.status != 0) {
    errorExitProcess(`"${command} ${params.join(' ')}"  command failed with status=${result.status}`)
  }
}

function getCarthageBuildParams(carthageVersionString) {
  // check version of `carthage` to alter build params
  const majorMinorPatch = carthageVersionString.split('.')
  const major = parseInt(majorMinorPatch[0])
  const minor = parseInt(majorMinorPatch[1])
  const buildParams = ['build', '--no-skip-current', ...platformParams]
  if (major > 0 || minor > 20) {
    // --cache-builds should be available (unless version 1.x.x will remove it)
    buildParams.push('--cache-builds')
  }
  return buildParams
}
<commit_msg>Fixed retrieving options.<commit_after>const platformParams = ['--platform', 'iOS']

const childProcess = require('child_process')
const parentModulePackageJson = require('../../package.json')

if (process.platform === 'darwin' && shouldUseCarthage()) {
  var carthageVersionProcessResult = childProcess.spawnSync('carthage', ['version'], {
    stdio: 'pipe'
  })

  if (carthageVersionProcessResult.status != 0) {
    // `carthage` not found (probably)
    errorExitProcess(
      'carthage is required to compile frameworks for iOS backend. You can install it with brew: "brew install carthage". After installation go to ./node_modules/react-native-ble-plx and run "./postinstall.js" or reinstall node module'
    )
  }

  const bleClientManagerDirectory = __dirname + '/ios/BleClientManager'
  try {
    process.chdir(bleClientManagerDirectory)
  } catch (err) {
    errorExitProcess(`${bleClientManagerDirectory} directory not found. Cannot proceed with building the library.`)
  }

  spawnSyncProcessAndExitOnError('carthage', ['bootstrap', '--no-build', ...platformParams])

  const carthageVersionString = carthageVersionProcessResult.output[1].toString()
  spawnSyncProcessAndExitOnError('carthage', getCarthageBuildParams(carthageVersionString))

  process.exit(0)
}

function shouldUseCarthage() {
  const reactNativeBlePlxOptions = parentModulePackageJson["react-native-ble-plx"]
  if (!reactNativeBlePlxOptions) return true
  const useCarthage = reactNativeBlePlxOptions.carthage
  return useCarthage != undefined ? useCarthage : true
}

function errorExitProcess(errorMessage) {
  console.error(`Error: ${errorMessage}`)
  process.exit(1)
}

function spawnSyncProcessAndExitOnError(command, params) {
  const result = childProcess.spawnSync(command, params, {
    stdio: 'inherit'
  })

  if (result.status != 0) {
    errorExitProcess(`"${command} ${params.join(' ')}"  command failed with status=${result.status}`)
  }
}

function getCarthageBuildParams(carthageVersionString) {
  // check version of `carthage` to alter build params
  const majorMinorPatch = carthageVersionString.split('.')
  const major = parseInt(majorMinorPatch[0])
  const minor = parseInt(majorMinorPatch[1])
  const buildParams = ['build', '--no-skip-current', ...platformParams]
  if (major > 0 || minor > 20) {
    // --cache-builds should be available (unless version 1.x.x will remove it)
    buildParams.push('--cache-builds')
  }
  return buildParams
}
<|endoftext|>


<commit_before>PDRClient = angular.module("PDRClient", [
  'ngResource',
  'ngRoute',
  'ngSanitize',
  'templates',
  'angular-redactor',
  'angularMoment',
  'angularFileUpload',
  'ui.utils',
  'ui.router',
  'ui.bootstrap']);

angular.module("PDRClient").run(function ($rootScope, $state, $stateParams) {
    $rootScope.$state       = $state;
    $rootScope.$stateParams = $stateParams;
});

angular.module("PDRClient").run([
  '$rootScope',
  '$state',
  '$stateParams',
  '$anchorScroll',
  function ($rootScope, $state, $stateParams, $anchorScroll) {
    $rootScope.$on('$stateChangeStart', function() {
      $rootScope.$broadcast('start_change');
    });
    $rootScope.$on('$stateChangeSuccess', function() {
      $rootScope.$broadcast('success_change');
      $anchorScroll();
    });
}]);

angular.module("PDRClient").run(
  ['$rootScope', '$state', '$location', 'SessionService',
  function ($rootScope, $state, $location, SessionService) {
    $rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams){
      $rootScope.showFullWidth = toState.showFullWidth;
      $rootScope.showFluid     = toState.showFluid;
    });
  }]);

angular.module("PDRClient").run(
  ['$rootScope', '$state', '$location', 'SessionService',
  function ($rootScope, $state, $location, SessionService) {
    $rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams){
      if (toState.authenticate && !SessionService.getUserAuthenticated()){
        $rootScope.$broadcast('success_change');
        $state.go("login", {redirect: $location.url()});
        event.preventDefault();
      }
    });
  }]);

angular.module("PDRClient").config(['$tooltipProvider', function($tooltipProvider){
  $tooltipProvider.setTriggers({
    'mouseenter': 'blur',
    'click': 'click',
    'focus': 'blur',
  });
}]);
<commit_msg>Disable SCE<commit_after>PDRClient = angular.module("PDRClient", [
  'ngResource',
  'ngRoute',
  'ngSanitize',
  'templates',
  'angular-redactor',
  'angularMoment',
  'angularFileUpload',
  'ui.utils',
  'ui.router',
  'ui.bootstrap']);

angular.module("PDRClient").run(function ($rootScope, $state, $stateParams) {
    $rootScope.$state       = $state;
    $rootScope.$stateParams = $stateParams;
});

angular.module("PDRClient").run([
  '$rootScope',
  '$state',
  '$stateParams',
  '$anchorScroll',
  function ($rootScope, $state, $stateParams, $anchorScroll) {
    $rootScope.$on('$stateChangeStart', function() {
      $rootScope.$broadcast('start_change');
    });
    $rootScope.$on('$stateChangeSuccess', function() {
      $rootScope.$broadcast('success_change');
      $anchorScroll();
    });
}]);

angular.module("PDRClient").run(
  ['$rootScope', '$state', '$location', 'SessionService',
  function ($rootScope, $state, $location, SessionService) {
    $rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams){
      $rootScope.showFullWidth = toState.showFullWidth;
      $rootScope.showFluid     = toState.showFluid;
    });
  }]);

angular.module("PDRClient").run(
  ['$rootScope', '$state', '$location', 'SessionService',
  function ($rootScope, $state, $location, SessionService) {
    $rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams){
      if (toState.authenticate && !SessionService.getUserAuthenticated()){
        $rootScope.$broadcast('success_change');
        $state.go("login", {redirect: $location.url()});
        event.preventDefault();
      }
    });
  }]);

angular.module("PDRClient").config(['$tooltipProvider', function($tooltipProvider){
  $tooltipProvider.setTriggers({
    'mouseenter': 'blur',
    'click': 'click',
    'focus': 'blur',
  });
}]);

angular.module('PDRClient', []).config(function($sceProvider) {
  $sceProvider.enabled(false);
});
<|endoftext|>


<commit_before>exports.test_data = {
    default_options: [
        { name: "indent_size", value: "4" },
        { name: "indent_char", value: "' '" },
        { name: "preserve_newlines", value: "true" },
        { name: "jslint_happy", value: "false" },
        { name: "keep_array_indentation", value: "false" },
        { name: "brace_style", value: "'collapse'" },
        { name: "extra_liners", value: "['html', 'head', '/html']" }
    ],
    groups: [{
        name: "End With Newline",
        description: "",
        matrix: [
            {
                options: [
                    { name: "end_with_newline", value: "true" }
                ],
                eof: '\\n'
            }, {
                options: [
                    { name: "end_with_newline", value: "false" }
                ],
                eof: ''
            }

        ],
        tests: [
            { fragment: true, input: '', output: '{{eof}}' },
            { fragment: true, input: '

', output: '

{{eof}}' },
            // { fragment: true, input: '   \n\n

\n\n\n\n', output: '

{{eof}}' },
            { fragment: true, input: '\n', output: '{{eof}}' }
        ],
    }, {
        name: "Custom Extra Liners (empty)",
        description: "",
        matrix: [
            {
                options: [
                    { name: "extra_liners", value: "[]" }
                ]
            },

        ],
        tests: [
            {
                fragment: true,
                input: '<meta>

x

',
                output: '\n\n    <meta>\n\n\n
\n
x
\n
\n\n'
            }
        ],
    }, {
        name: "Custom Extra Liners (default)",
        description: "",
        matrix: [
            {
                options: [
                    { name: "extra_liners", value: "null" }
                ]
            },

        ],
        tests: [
            {
                fragment: true,
                input: '',
                output: '\n\n\n\n\n\n'
            }
        ],
    }, {
        name: "Custom Extra Liners (p, string)",
        description: "",
        matrix: [
            {
                options: [
                    { name: "extra_liners", value: "'p,/p'" }
                ]
            },

        ],
        tests: [
            {
                fragment: true,
                input: '<meta>

x

',
                output: '\n\n    <meta>\n\n\n
\n\n
x\n\n
\n
\n\n'
            }
        ],
    }, {
        name: "Custom Extra Liners (p)",
        description: "",
        matrix: [
            {
                options: [
                    { name: "extra_liners", value: "['p', '/p']" }
                ]
            },

        ],
        tests: [
            {
                fragment: true,
                input: '<meta>

x

',
                output: '\n\n    <meta>\n\n\n
\n\n
x\n\n
\n
\n\n'
            }
        ],
    }, {
        name: "Attribute Wrap",
        description: "Wraps attributes inside of html tags",
        matrix: [
          {
              options: [
                  { name: "wrap_attributes", value: "'force'" }
              ],
              eof: '\\n',
              indent_attr: '    ',
              over80: '\\n'
          }, {
              options: [
                  { name: "wrap_attributes", value: "'force'" },
                  { name: "wrap_line_length", value: "80" }
              ],
              eof: '\\n',
              indent_attr: '    ',
              over80: '\\n'
          }, {
              options: [
                  { name: "wrap_attributes", value: "'force'" },
                  { name: "wrap_attributes_indent_size", value: "8" },
              ],
              eof: '\\n',
              indent_attr: '        ',
              over80: '\\n'
          }, {
              options: [
                  { name: "wrap_attributes", value: "'auto'" },
                  { name: "wrap_line_length", value: "80" }
              ],
              eof: ' ',
              indent_attr: '',
              over80: '\\n'
          }, {
              options: [
                  { name: "wrap_attributes", value: "'auto'" },
                  { name: "wrap_line_length", value: "0" }
              ],
              eof: ' ',
              indent_attr: '',
              over80: ' '
          }
        ],
        tests: [
            {
                fragment: true,
                input: '
This is some text
',
                output: '
This is some text
'
            },
            {
                fragment: true,
                input: '
This is some text
',
                output: '
This is some text
'
            },
            {
                fragment: true,
                input: '',
                output: ''
            }
        ]
    }, {
        name: "Handlebars Indenting Off",
        description: "Test handlebar behavior when indenting is off",
        template: "^^^ $$$",
        options: [
            { name: "indent_handlebars", value: "false" }
        ],
        tests: [
            { fragment: true,
                input_:
                '{{#if 0}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}',
                output:
                '{{#if 0}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}' },
            { fragment: true,
                input_:
                '
\n' +
                '{{#each thing}}\n' +
                '    {{name}}\n' +
                '{{/each}}\n' +
                '
',
                output:
                '
\n' +
                '    {{#each thing}} {{name}} {{/each}}\n' +
                '
'}

        ]
    }, {
        name: "Handlebars Indenting On",
        description: "Test handlebar formatting",
        template: "^^^ $$$",
        matrix: [
            {
                options: [
                    { name: "indent_handlebars", value: "true" }
                ],
                content: '{{field}}'
            }, {
                options: [
                    { name: "indent_handlebars", value: "true" }
                ],
                content: '{{! comment}}'
            }, {
                options: [
                    { name: "indent_handlebars", value: "true" }
                ],
                content: '{pre{{field1}} {{field2}} {{field3}}post'
            }
            , {
                options: [
                    { name: "indent_handlebars", value: "true" }
                ],
                content: '{{! \\n mult-line\\ncomment  \\n     with spacing\\n}}'
            }
        ],
        tests: [
            { fragment: true, unchanged: '{{#if 0}}{{/if}}' },
            { fragment: true, unchanged: '{{#if 0}}^^^content$$${{/if}}' },
            { fragment: true, unchanged: '{{#if 0}}\n{{/if}}' },
            { fragment: true,
                input_: '{{#if     words}}{{/if}}',
                output: '{{#if words}}{{/if}}' },
            { fragment: true,
                input_: '{{#if     words}}^^^content$$${{/if}}',
                output: '{{#if words}}^^^content$$${{/if}}' },
            { fragment: true,
                input_: '{{#if     words}}^^^content$$${{/if}}',
                output: '{{#if words}}^^^content$$${{/if}}' },
            { fragment: true,
                unchanged:
                '{{#if 1}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}' },
            { fragment: true,
                input_:
                '{{#if 1}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}',
                output:
                '{{#if 1}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}' },
            { fragment: true,
                unchanged:
                '
\n' +
                '    {{#if 1}}\n' +
                '    {{/if}}\n' +
                '
' },
            { fragment: true,
                input_:
                '
\n' +
                '{{#if 1}}\n' +
                '{{/if}}\n' +
                '
',
                output:
                '
\n' +
                '    {{#if 1}}\n' +
                '    {{/if}}\n' +
                '
' },
            { fragment: true,
                input_:
                '{{#if}}\n' +
                '{{#each}}\n' +
                '{{#if}}\n' +
                '^^^content$$$\n' +
                '{{/if}}\n' +
                '{{#if}}\n' +
                '^^^content$$$\n' +
                '{{/if}}\n' +
                '{{/each}}\n' +
                '{{/if}}',
                output:
                '{{#if}}\n' +
                '    {{#each}}\n' +
                '        {{#if}}\n' +
                '            ^^^content$$$\n' +
                '        {{/if}}\n' +
                '        {{#if}}\n' +
                '            ^^^content$$$\n' +
                '        {{/if}}\n' +
                '    {{/each}}\n' +
                '{{/if}}' },
            { fragment: true, unchanged: '{{#if 1}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}' },

            // Test {{else}} aligned with {{#if}} and {{/if}}
            { fragment: true,
                input_:
                '{{#if 1}}\n' +
                '    ^^^content$$$\n' +
                '    {{else}}\n' +
                '    ^^^content$$$\n' +
                '{{/if}}',
                output:
                '{{#if 1}}\n' +
                '    ^^^content$$$\n' +
                '{{else}}\n' +
                '    ^^^content$$$\n' +
                '{{/if}}' },
            { fragment: true,
                input_:
                '{{#if 1}}\n' +
                '    {{else}}\n' +
                '    {{/if}}',
                output:
                '{{#if 1}}\n' +
                '{{else}}\n' +
                '{{/if}}' },
            { fragment: true,
                input_:
                '{{#if thing}}\n' +
                '{{#if otherthing}}\n' +
                '    ^^^content$$$\n' +
                '    {{else}}\n' +
                '^^^content$$$\n' +
                '    {{/if}}\n' +
                '       {{else}}\n'+
                '^^^content$$$\n' +
                '{{/if}}',
                output:
                '{{#if thing}}\n' +
                '    {{#if otherthing}}\n' +
                '        ^^^content$$$\n' +
                '    {{else}}\n' +
                '        ^^^content$$$\n' +
                '    {{/if}}\n' +
                '{{else}}\n'+
                '    ^^^content$$$\n' +
                '{{/if}}' },
                // Test {{}} inside of <> tags, which should be separated by spaces
                // for readability, unless they are inside a string.
            { fragment: true,
                input_: '

',
                output: '

' },
            { fragment: true,
                input_: '
^^^content$$$
',
                output: '
^^^content$$$
' },
            { fragment: true,
                input_: '
^^^content$$$
',
                output: '
^^^content$$$
' },
            { fragment: true,
                input_: '^^^content$$$',
                output: '^^^content$$$' },
            { fragment: true,
                unchanged: '
^^^content$$$
' },
            { fragment: true,
                unchanged: '
^^^content$$$
' },

            // Quotes found inside of Handlebars expressions inside of quoted
            // strings themselves should not be considered string delimiters.
            { fragment: true,
                unchanged: '

' },
            { fragment: true,
                unchanged: '

' },
            { fragment: true,
                unchanged: '

' },
            { fragment: true,
                unchanged: '

' }
        ],
    }, {
        name: "Unformatted tags",
        description: "Unformatted tag behavior",
        options: [],
        tests: [
            { fragment: true, input: '
\n
b
c

\n
' },
            { fragment: true, input: '
\n
bc
\n
' },
        ]
    }, {
        name: "Indent with tabs",
        description: "Use one tab instead of several spaces for indentation",
        matrix: [
            {
                options: [
                    { name: "indent_with_tabs", value: "true" }
                ],
                indent: "\t"
            }, {
                options: [
                    { name: "indent_with_tabs", value: "false" }
                ],
                indent: "    "
            }

        ],
        tests: [
            { input: "
\n
\n
\n
",
              output: "
\n{{indent}}
\n{{indent}}
\n
" },
        ],
    }, {
        name: "New Test Suite"
    }],
};
<commit_msg>JS/HTML: fix for tests<commit_after>exports.test_data = {
    default_options: [
        { name: "indent_size", value: "4" },
        { name: "indent_char", value: "' '" },
        { name: "indent_with_tabs", value: "false" },
        { name: "preserve_newlines", value: "true" },
        { name: "jslint_happy", value: "false" },
        { name: "keep_array_indentation", value: "false" },
        { name: "brace_style", value: "'collapse'" },
        { name: "extra_liners", value: "['html', 'head', '/html']" }
    ],
    groups: [{
        name: "End With Newline",
        description: "",
        matrix: [
            {
                options: [
                    { name: "end_with_newline", value: "true" }
                ],
                eof: '\\n'
            }, {
                options: [
                    { name: "end_with_newline", value: "false" }
                ],
                eof: ''
            }

        ],
        tests: [
            { fragment: true, input: '', output: '{{eof}}' },
            { fragment: true, input: '

', output: '

{{eof}}' },
            // { fragment: true, input: '   \n\n

\n\n\n\n', output: '

{{eof}}' },
            { fragment: true, input: '\n', output: '{{eof}}' }
        ],
    }, {
        name: "Custom Extra Liners (empty)",
        description: "",
        matrix: [
            {
                options: [
                    { name: "extra_liners", value: "[]" }
                ]
            },

        ],
        tests: [
            {
                fragment: true,
                input: '<meta>

x

',
                output: '\n\n    <meta>\n\n\n
\n
x
\n
\n\n'
            }
        ],
    }, {
        name: "Custom Extra Liners (default)",
        description: "",
        matrix: [
            {
                options: [
                    { name: "extra_liners", value: "null" }
                ]
            },

        ],
        tests: [
            {
                fragment: true,
                input: '',
                output: '\n\n\n\n\n\n'
            }
        ],
    }, {
        name: "Custom Extra Liners (p, string)",
        description: "",
        matrix: [
            {
                options: [
                    { name: "extra_liners", value: "'p,/p'" }
                ]
            },

        ],
        tests: [
            {
                fragment: true,
                input: '<meta>

x

',
                output: '\n\n    <meta>\n\n\n
\n\n
x\n\n
\n
\n\n'
            }
        ],
    }, {
        name: "Custom Extra Liners (p)",
        description: "",
        matrix: [
            {
                options: [
                    { name: "extra_liners", value: "['p', '/p']" }
                ]
            },

        ],
        tests: [
            {
                fragment: true,
                input: '<meta>

x

',
                output: '\n\n    <meta>\n\n\n
\n\n
x\n\n
\n
\n\n'
            }
        ],
    }, {
        name: "Attribute Wrap",
        description: "Wraps attributes inside of html tags",
        matrix: [
          {
              options: [
                  { name: "wrap_attributes", value: "'force'" }
              ],
              eof: '\\n',
              indent_attr: '    ',
              over80: '\\n'
          }, {
              options: [
                  { name: "wrap_attributes", value: "'force'" },
                  { name: "wrap_line_length", value: "80" }
              ],
              eof: '\\n',
              indent_attr: '    ',
              over80: '\\n'
          }, {
              options: [
                  { name: "wrap_attributes", value: "'force'" },
                  { name: "wrap_attributes_indent_size", value: "8" },
              ],
              eof: '\\n',
              indent_attr: '        ',
              over80: '\\n'
          }, {
              options: [
                  { name: "wrap_attributes", value: "'auto'" },
                  { name: "wrap_line_length", value: "80" }
              ],
              eof: ' ',
              indent_attr: '',
              over80: '\\n'
          }, {
              options: [
                  { name: "wrap_attributes", value: "'auto'" },
                  { name: "wrap_line_length", value: "0" }
              ],
              eof: ' ',
              indent_attr: '',
              over80: ' '
          }
        ],
        tests: [
            {
                fragment: true,
                input: '
This is some text
',
                output: '
This is some text
'
            },
            {
                fragment: true,
                input: '
This is some text
',
                output: '
This is some text
'
            },
            {
                fragment: true,
                input: '',
                output: ''
            }
        ]
    }, {
        name: "Handlebars Indenting Off",
        description: "Test handlebar behavior when indenting is off",
        template: "^^^ $$$",
        options: [
            { name: "indent_handlebars", value: "false" }
        ],
        tests: [
            { fragment: true,
                input_:
                '{{#if 0}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}',
                output:
                '{{#if 0}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}' },
            { fragment: true,
                input_:
                '
\n' +
                '{{#each thing}}\n' +
                '    {{name}}\n' +
                '{{/each}}\n' +
                '
',
                output:
                '
\n' +
                '    {{#each thing}} {{name}} {{/each}}\n' +
                '
'}

        ]
    }, {
        name: "Handlebars Indenting On",
        description: "Test handlebar formatting",
        template: "^^^ $$$",
        matrix: [
            {
                options: [
                    { name: "indent_handlebars", value: "true" }
                ],
                content: '{{field}}'
            }, {
                options: [
                    { name: "indent_handlebars", value: "true" }
                ],
                content: '{{! comment}}'
            }, {
                options: [
                    { name: "indent_handlebars", value: "true" }
                ],
                content: '{pre{{field1}} {{field2}} {{field3}}post'
            }
            , {
                options: [
                    { name: "indent_handlebars", value: "true" }
                ],
                content: '{{! \\n mult-line\\ncomment  \\n     with spacing\\n}}'
            }
        ],
        tests: [
            { fragment: true, unchanged: '{{#if 0}}{{/if}}' },
            { fragment: true, unchanged: '{{#if 0}}^^^content$$${{/if}}' },
            { fragment: true, unchanged: '{{#if 0}}\n{{/if}}' },
            { fragment: true,
                input_: '{{#if     words}}{{/if}}',
                output: '{{#if words}}{{/if}}' },
            { fragment: true,
                input_: '{{#if     words}}^^^content$$${{/if}}',
                output: '{{#if words}}^^^content$$${{/if}}' },
            { fragment: true,
                input_: '{{#if     words}}^^^content$$${{/if}}',
                output: '{{#if words}}^^^content$$${{/if}}' },
            { fragment: true,
                unchanged:
                '{{#if 1}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}' },
            { fragment: true,
                input_:
                '{{#if 1}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}',
                output:
                '{{#if 1}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}' },
            { fragment: true,
                unchanged:
                '
\n' +
                '    {{#if 1}}\n' +
                '    {{/if}}\n' +
                '
' },
            { fragment: true,
                input_:
                '
\n' +
                '{{#if 1}}\n' +
                '{{/if}}\n' +
                '
',
                output:
                '
\n' +
                '    {{#if 1}}\n' +
                '    {{/if}}\n' +
                '
' },
            { fragment: true,
                input_:
                '{{#if}}\n' +
                '{{#each}}\n' +
                '{{#if}}\n' +
                '^^^content$$$\n' +
                '{{/if}}\n' +
                '{{#if}}\n' +
                '^^^content$$$\n' +
                '{{/if}}\n' +
                '{{/each}}\n' +
                '{{/if}}',
                output:
                '{{#if}}\n' +
                '    {{#each}}\n' +
                '        {{#if}}\n' +
                '            ^^^content$$$\n' +
                '        {{/if}}\n' +
                '        {{#if}}\n' +
                '            ^^^content$$$\n' +
                '        {{/if}}\n' +
                '    {{/each}}\n' +
                '{{/if}}' },
            { fragment: true, unchanged: '{{#if 1}}\n' +
                '
\n' +
                '
\n' +
                '{{/if}}' },

            // Test {{else}} aligned with {{#if}} and {{/if}}
            { fragment: true,
                input_:
                '{{#if 1}}\n' +
                '    ^^^content$$$\n' +
                '    {{else}}\n' +
                '    ^^^content$$$\n' +
                '{{/if}}',
                output:
                '{{#if 1}}\n' +
                '    ^^^content$$$\n' +
                '{{else}}\n' +
                '    ^^^content$$$\n' +
                '{{/if}}' },
            { fragment: true,
                input_:
                '{{#if 1}}\n' +
                '    {{else}}\n' +
                '    {{/if}}',
                output:
                '{{#if 1}}\n' +
                '{{else}}\n' +
                '{{/if}}' },
            { fragment: true,
                input_:
                '{{#if thing}}\n' +
                '{{#if otherthing}}\n' +
                '    ^^^content$$$\n' +
                '    {{else}}\n' +
                '^^^content$$$\n' +
                '    {{/if}}\n' +
                '       {{else}}\n'+
                '^^^content$$$\n' +
                '{{/if}}',
                output:
                '{{#if thing}}\n' +
                '    {{#if otherthing}}\n' +
                '        ^^^content$$$\n' +
                '    {{else}}\n' +
                '        ^^^content$$$\n' +
                '    {{/if}}\n' +
                '{{else}}\n'+
                '    ^^^content$$$\n' +
                '{{/if}}' },
                // Test {{}} inside of <> tags, which should be separated by spaces
                // for readability, unless they are inside a string.
            { fragment: true,
                input_: '

',
                output: '

' },
            { fragment: true,
                input_: '
^^^content$$$
',
                output: '
^^^content$$$
' },
            { fragment: true,
                input_: '
^^^content$$$
',
                output: '
^^^content$$$
' },
            { fragment: true,
                input_: '^^^content$$$',
                output: '^^^content$$$' },
            { fragment: true,
                unchanged: '
^^^content$$$
' },
            { fragment: true,
                unchanged: '
^^^content$$$
' },

            // Quotes found inside of Handlebars expressions inside of quoted
            // strings themselves should not be considered string delimiters.
            { fragment: true,
                unchanged: '

' },
            { fragment: true,
                unchanged: '

' },
            { fragment: true,
                unchanged: '

' },
            { fragment: true,
                unchanged: '

' }
        ],
    }, {
        name: "Unformatted tags",
        description: "Unformatted tag behavior",
        options: [],
        tests: [
            { fragment: true, input: '
\n
b
c

\n
' },
            { fragment: true, input: '
\n
bc
\n
' },
        ]
      }, {
        name: "Indent with tabs",
        description: "Use one tab instead of several spaces for indentation",
        template: "^^^ $$$",
        options: [
            { name: "indent_with_tabs", value: "true" }
        ],
        tests: [
            { fragment: true,
                input_:
                '
\n' +
                '
\n' +
                '
\n' +
                '
',
                output:
                '
\n' +
                '\t
\n' +
                '\t
\n' +
                '
' }
        ]
    }, {
        name: "Indent without tabs",
        description: "Use several spaces for indentation",
        template: "^^^ $$$",
        options: [
            { name: "indent_with_tabs", value: "false" }
        ],
        tests: [
            { fragment: true,
                input_:
                '
\n' +
                '
\n' +
                '
\n' +
                '
',
                output:
                '
\n' +
                '
\n' +
                '
\n' +
                '
' }
        ]
      }, {
          name: "New Test Suite"
      }],
};
<|endoftext|>


<commit_before>'use strict';

// home.js

var
    _ = require('lodash'),
    api = require('../api'),
    db = require('../db'),
    auth = require('../auth'),
    config = require('../config'),
    cache = require('../cache'),
    helper = require('../helper'),
    constants = require('../constants'),
    searchEngine = require('../search/search').engine,
    json_schema = require('../json_schema');

var
    User = db.user,
    Article = db.article,
    Category = db.category,
    Text = db.text,
    warp = db.warp;

var
    userApi = require('./userApi'),
    wikiApi = require('./wikiApi'),
    settingApi = require('./settingApi'),
    discussApi = require('./discussApi'),
    webpageApi = require('./webpageApi'),
    articleApi = require('./articleApi'),
    categoryApi = require('./categoryApi'),
    navigationApi = require('./navigationApi');

var
    signins = _.reduce(config.oauth2, function (results, conf, oauthId) {
        results.push({
            id: oauthId,
            icon: conf.icon,
            name: conf.name
        });
        return results;
    }, []);

var
    searchTypes = [
        {
            label: 'All',
            value: ''
        },
        {
            label: 'Article',
            value: 'article'
        },
        {
            label: 'Wiki',
            value: 'wiki'
        },
        {
            label: 'Discuss',
            value: 'discuss'
        }
    ],
    searchTypeValues = _.reduce(searchTypes, function (r, t) {
        r[t.value] = t.label;
        return r;
    }, {});

var isSyncComments = config.session.syncComments;

var $getNavigations = function* () {
    return yield cache.$get(constants.cache.NAVIGATIONS, navigationApi.$getNavigations);
};

function createCommentByType(ref_type, checkFunction, req, res, next) {
    if (utils.isForbidden(req, constants.ROLE_GUEST)) {
        return next(api.notAllowed('Permission denied.'));
    }
    var content, ref_id;
    try {
        content = formatComment(utils.getRequiredParam('content', req)).trim();
        if (!content) {
            return next(api.invalidParam('content', 'Content cannot be empty.'));
        }
    } catch (e) {
        return next(e);
    }
    ref_id = req.params.id;
    checkFunction(ref_id, function (err, entity, path) {
        if (err) {
            return next(err);
        }
        commentApi.createComment(ref_type, ref_id, req.user, content, function (err, comment) {
            if (isSyncComments) {
                utils.sendToSNS(req.user, content, 'http://' + req.host + path);
            }
            return res.send(comment);
        });
    });
}

function getHotArticles(articles) {
    var arr = articles.slice(0).sort(function (a1, a2) {
        return a1.reads > a2.reads ? -1 : 1;
    });
    return arr.length > 3 ? arr.slice(0, 3) : arr;
}

var THEME = config.theme;

function* $getModel(model) {
    model.__navigations__ = yield $getNavigations();
    model.__website__ = yield settingApi.$getWebsiteSettings();
    model.__snippets__ = yield settingApi.$getSnippets();
    model.__signins__ = signins;
    return model;
}

function getView(view) {
    return 'themes/default/' + view;
}

module.exports = {

    'GET /': function* () {
        var
            i, model,
            categories = yield categoryApi.$getCategories(),
            articles = yield articleApi.$getRecentArticles(20),
            nums = yield cache.$counts(_.map(articles, function (a) {
                return a.id;
            })),
            getCategoryName = function (cid) {
                var c, i;
                for (i = 0; i < categories.length; i++) {
                    c = categories[i];
                    if (c.id === cid) {
                        return c.name;
                    }
                }
                return '';
            };
        for (i = 0; i < articles.length; i++) {
            articles[i].reads = nums[i];
        }
        model = {
            //
        };
        //    model.articles = articles;
        //    model.hotArticles = getHotArticles(articles);
        //    return processTheme('index.html', model, req, res, next);
        this.render(getView('index.html'), yield $getModel.apply(this, [model]));
    },

    'GET /category/:id': function* (id) {
        var
            page = helper.getPage(this.request, 10),
            model = {
                page: page,
                category: yield categoryApi.$getCategory(id),
                articles: yield articleApi.$getArticlesByCategory(id, page)
            },
            nums = yield cache.$counts(_.map(model.articles, function (a) {
                return a.id;
            })),
            i;
        for (i = 0; i < nums.length; i++) {
            model.articles[i].reads = nums[i];
        }
        this.render(getView('article/category.html'), yield $getModel.apply(this, [model]));
    },

    'GET /article/:id': function* (id) {
        var
            article = yield articleApi.$getArticle(id, true),
            num = yield cache.$incr(id),
            category = yield categoryApi.$getCategory(article.category_id),
            model = {
                article: article,
                category: category
            };
        article.reads = num;
        article.content = helper.md2html(article.content, true);
        this.render(getView('article/article.html'), yield $getModel.apply(this, [model]));
    },

    'GET /webpage/:alias': function* (alias) {
        var
            webpage = yield webpageApi.$getWebpageByAlias(alias, true),
            model;
        if (webpage.draft) {
            this.throw(404);
        }
        webpage.content = helper.md2html(webpage.content, true);
        model = {
            webpage: webpage
        };
        this.render(getView('webpage/webpage.html'), yield $getModel.apply(this, [model]));
    },

    'GET /wikipage/:id': function* (id) {
        var wp = yield wikiApi.$getWikiPage(id);
        this.response.redirect('/wiki/' + wp.wiki_id + '/' + wp.id);
    },

    'GET /wiki/:id': function* (id) {
        var
            model,
            wiki = yield wikiApi.$getWiki(id, true),
            tree = yield wikiApi.$getWikiTree(wiki.id, true);
        wiki.type = 'wiki';
        wiki.content = helper.md2html(wiki.content, true);
        wiki.reads = yield cache.$incr(wiki.id);
        model = {
            wiki: wiki,
            current: wiki,
            tree: tree.children
        };
        this.render(getView('wiki/wiki.html'), yield $getModel.apply(this, [model]));
    },

    'GET /wiki/:wid/:pid': function* (id, pid) {
        var
            model, wiki, tree,
            wikipage = yield wikiApi.$getWikiPage(pid, true);
        if (wikipage.wiki_id !== id) {
            this.throw(404);
        }
        wiki = yield wikiApi.$getWiki(id);
        tree = yield wikiApi.$getWikiTree(id, true);
        wikipage.type = 'wikipage';
        wikipage.reads = yield cache.$incr(wikipage.id);
        wikipage.content = helper.md2html(wikipage.content, true);
        model = {
            wiki: yield wikiApi.$getWiki(id),
            current: wikipage,
            tree: tree.children
        };
        this.render(getView('wiki/wiki.html'), yield $getModel.apply(this, [model]));
    },

    'POST /api/comments/:ref_type/:ref_id': function* (ref_type, ref_id) {
        helper.checkPermission(this.request, constants.role.SUBSCRIBER);
        var
            board,
            user = this.request.user,
            data = this.request.body;
        json_schema.validate('createComment', data);
        if (!data.content.trim()) {
            throw api.invalidParam('content', 'Empty input.');
        }
        if (ref_type === 'article') {
            yield articleApi.$getArticle(ref_id);
        }
        else if (ref_type === 'wiki') {
            yield wikiApi.$getWiki(ref_id);
        }
        else if (ref_type === 'wikipage') {
            yield wikiApi.$getWikiPage(ref_id);
        }
        else {
            this.throw(404);
        }
        board = yield discussApi.$getBoardByTag(data.tag);
        this.body = yield discussApi.$createTopic(user, board.id, ref_type, ref_id, data);
    },

    'GET /discuss': function* () {
        var
            model,
            boards = yield discussApi.$getBoards();
        model = {
            boards: boards
        };
        this.render(getView('discuss/boards.html'), yield $getModel.apply(this, [model]));
    },

    'GET /discuss/:id': function* (id) {
        var
            page = helper.getPage(this.request, 10),
            board = yield discussApi.$getBoard(id),
            topics = yield discussApi.$getTopics(id, page),
            model;
        yield userApi.$bindUsers(topics);
        model = {
            page: page,
            board: board,
            topics: topics
        };
        this.render(getView('discuss/board.html'), yield $getModel.apply(this, [model]));
    },

    'GET /discuss/:bid/:tid': function* (bid, tid) {
        var
            topic = yield discussApi.$getTopic(tid),
            page,
            board,
            replies,
            model;
        if (topic.board_id !== bid) {
            this.throw(404);
        }
        page = helper.getPage(this.request, 10);
        board = yield discussApi.$getBoard(bid);
        replies = yield discussApi.$getReplies(tid, page);
        if (page.index === 1) {
            replies.unshift(topic);
        }
        yield userApi.$bindUsers(replies);
        model = {
            page: page,
            board: board,
            topic: topic,
            replies: replies
        };
        this.render(getView('discuss/topic.html'), yield $getModel.apply(this, [model]));
    },

    'GET /discuss/:bid/topics/create': function* (bid) {
        if (this.request.user === null) {
            this.response.redirect('/auth/signin');
            return;
        }
        var
            board = yield discussApi.$getBoard(bid),
            model = {
                board: board
            };
        this.render(getView('discuss/topic_form.html'), yield $getModel.apply(this, [model]));
    },

    'GET /discuss/topic/:tid/find/:rid': function* (tid, rid) {
        var
            topic = yield discussApi.$getTopic(tid),
            p = yield discussApi.$getReplyPageIndex(tid, rid);
        this.response.redirect('/discuss/' + topic.board_id + '/' + tid + '?page=' + p + '#' + rid);
    },

    'GET /user/:id': function* (id) {
        var
            user = yield userApi.$getUser(id),
            model = {
                user: user
            };
        this.render(getView('user/profile.html'), yield $getModel.apply(this, [model]));
    },

    'GET /me/profile': function* (id) {
        var
            user = this.request.user,
            model = {
                user: user
            };
        if (user === null) {
            this.response.redirect('/auth/signin');
            return;
        }
        this.render(getView('user/profile.html'), yield $getModel.apply(this, [model]));
    },

    'GET /auth/signin': function* (id) {
        var
            referer = this.request.get('referer') || '/',
            user = this.request.user;
        console.log('Referer: ' + referer);
        if (user !== null) {

        }
        this.render(getView('signin.html'), yield $getModel.apply(this, [{}]));
    },

    'GET /search': function (req, res, next) {
        var
            page,
            q = req.query.q || '',
            type = req.query.type,
            opt = {};
        if (searchEngine.external) {
            return res.redirect(searchEngine.search(q));
        }
        console.log(JSON.stringify(searchTypeValues));
        if (!searchTypeValues[type]) {
            type = searchTypes[0].value;
        }
        if (type) {
            opt.filter = {
                field: 'type',
                value: type
            };
        }
        page = utils.getPage(req);
        opt.start = page.offset;
        opt.hit = page.itemsPerPage;

        searchEngine.search(q.replace(/\'/g, '').replace(/\"/g, ''), opt, function (err, r) {
            if (err) {
                return next(err);
            }
            if (r.status !== 'OK') {
                return res.send(500);
            }
            page.totalItems = r.result.total;
            var model = {
                searchTypes: searchTypes,
                type: type,
                page: page,
                q: q,
                results: r.result.items
            };
            return processTheme('search.html', model, req, res, next);
        });
    }
};
<commit_msg>add cache for index page<commit_after>'use strict';

// home.js

var
    _ = require('lodash'),
    api = require('../api'),
    db = require('../db'),
    auth = require('../auth'),
    config = require('../config'),
    cache = require('../cache'),
    helper = require('../helper'),
    constants = require('../constants'),
    searchEngine = require('../search/search').engine,
    json_schema = require('../json_schema');

var
    User = db.user,
    Article = db.article,
    Category = db.category,
    Text = db.text,
    warp = db.warp;

var
    userApi = require('./userApi'),
    wikiApi = require('./wikiApi'),
    settingApi = require('./settingApi'),
    discussApi = require('./discussApi'),
    webpageApi = require('./webpageApi'),
    articleApi = require('./articleApi'),
    categoryApi = require('./categoryApi'),
    navigationApi = require('./navigationApi');

var
    signins = _.reduce(config.oauth2, function (results, conf, oauthId) {
        results.push({
            id: oauthId,
            icon: conf.icon,
            name: conf.name
        });
        return results;
    }, []);

var
    searchTypes = [
        {
            label: 'All',
            value: ''
        },
        {
            label: 'Article',
            value: 'article'
        },
        {
            label: 'Wiki',
            value: 'wiki'
        },
        {
            label: 'Discuss',
            value: 'discuss'
        }
    ],
    searchTypeValues = _.reduce(searchTypes, function (r, t) {
        r[t.value] = t.label;
        return r;
    }, {});

var isSyncComments = config.session.syncComments;

var $getNavigations = function* () {
    return yield cache.$get(constants.cache.NAVIGATIONS, navigationApi.$getNavigations);
};

function createCommentByType(ref_type, checkFunction, req, res, next) {
    if (utils.isForbidden(req, constants.ROLE_GUEST)) {
        return next(api.notAllowed('Permission denied.'));
    }
    var content, ref_id;
    try {
        content = formatComment(utils.getRequiredParam('content', req)).trim();
        if (!content) {
            return next(api.invalidParam('content', 'Content cannot be empty.'));
        }
    } catch (e) {
        return next(e);
    }
    ref_id = req.params.id;
    checkFunction(ref_id, function (err, entity, path) {
        if (err) {
            return next(err);
        }
        commentApi.createComment(ref_type, ref_id, req.user, content, function (err, comment) {
            if (isSyncComments) {
                utils.sendToSNS(req.user, content, 'http://' + req.host + path);
            }
            return res.send(comment);
        });
    });
}

function getHotArticles(articles) {
    var arr = articles.slice(0).sort(function (a1, a2) {
        return a1.reads > a2.reads ? -1 : 1;
    });
    return arr.length > 3 ? arr.slice(0, 3) : arr;
}

var THEME = config.theme;

function* $getModel(model) {
    model.__navigations__ = yield $getNavigations();
    model.__website__ = yield settingApi.$getWebsiteSettings();
    model.__snippets__ = yield settingApi.$getSnippets();
    model.__signins__ = signins;
    return model;
}

function getView(view) {
    return 'themes/default/' + view;
}

function* getIndexModel() {
    var
        i, hotArticles,
        categories = yield categoryApi.$getCategories(),
        recentArticles = yield articleApi.$getRecentArticles(20),
        nums = yield cache.$counts(_.map(recentArticles, function (a) {
            return a.id;
        })),
        getCategoryName = function (cid) {
            var c, i;
            for (i = 0; i < categories.length; i++) {
                c = categories[i];
                if (c.id === cid) {
                    return c.name;
                }
            }
            return '';
        };
    for (i = 0; i < recentArticles.length; i++) {
        recentArticles[i].reads = nums[i];
    }
    hotArticles = _.take(_.sortBy(recentArticles, function (a) {
        return 0 - a.reads;
    }), 5);
    return {
        recentArticles: recentArticles,
        hotArticles: hotArticles
    };
}

module.exports = {

    'GET /': function* () {
        var model = yield cache.$get('INDEX-MODEL', getIndexModel);
        this.render(getView('index.html'), yield $getModel.apply(this, [model]));
    },

    'GET /category/:id': function* (id) {
        var
            page = helper.getPage(this.request, 10),
            model = {
                page: page,
                category: yield categoryApi.$getCategory(id),
                articles: yield articleApi.$getArticlesByCategory(id, page)
            },
            nums = yield cache.$counts(_.map(model.articles, function (a) {
                return a.id;
            })),
            i;
        for (i = 0; i < nums.length; i++) {
            model.articles[i].reads = nums[i];
        }
        this.render(getView('article/category.html'), yield $getModel.apply(this, [model]));
    },

    'GET /article/:id': function* (id) {
        var
            article = yield articleApi.$getArticle(id, true),
            num = yield cache.$incr(id),
            category = yield categoryApi.$getCategory(article.category_id),
            model = {
                article: article,
                category: category
            };
        article.reads = num;
        article.content = helper.md2html(article.content, true);
        this.render(getView('article/article.html'), yield $getModel.apply(this, [model]));
    },

    'GET /webpage/:alias': function* (alias) {
        var
            webpage = yield webpageApi.$getWebpageByAlias(alias, true),
            model;
        if (webpage.draft) {
            this.throw(404);
        }
        webpage.content = helper.md2html(webpage.content, true);
        model = {
            webpage: webpage
        };
        this.render(getView('webpage/webpage.html'), yield $getModel.apply(this, [model]));
    },

    'GET /wikipage/:id': function* (id) {
        var wp = yield wikiApi.$getWikiPage(id);
        this.response.redirect('/wiki/' + wp.wiki_id + '/' + wp.id);
    },

    'GET /wiki/:id': function* (id) {
        var
            model,
            wiki = yield wikiApi.$getWiki(id, true),
            tree = yield wikiApi.$getWikiTree(wiki.id, true);
        wiki.type = 'wiki';
        wiki.content = helper.md2html(wiki.content, true);
        wiki.reads = yield cache.$incr(wiki.id);
        model = {
            wiki: wiki,
            current: wiki,
            tree: tree.children
        };
        this.render(getView('wiki/wiki.html'), yield $getModel.apply(this, [model]));
    },

    'GET /wiki/:wid/:pid': function* (id, pid) {
        var
            model, wiki, tree,
            wikipage = yield wikiApi.$getWikiPage(pid, true);
        if (wikipage.wiki_id !== id) {
            this.throw(404);
        }
        wiki = yield wikiApi.$getWiki(id);
        tree = yield wikiApi.$getWikiTree(id, true);
        wikipage.type = 'wikipage';
        wikipage.reads = yield cache.$incr(wikipage.id);
        wikipage.content = helper.md2html(wikipage.content, true);
        model = {
            wiki: yield wikiApi.$getWiki(id),
            current: wikipage,
            tree: tree.children
        };
        this.render(getView('wiki/wiki.html'), yield $getModel.apply(this, [model]));
    },

    'POST /api/comments/:ref_type/:ref_id': function* (ref_type, ref_id) {
        helper.checkPermission(this.request, constants.role.SUBSCRIBER);
        var
            board,
            user = this.request.user,
            data = this.request.body;
        json_schema.validate('createComment', data);
        if (!data.content.trim()) {
            throw api.invalidParam('content', 'Empty input.');
        }
        if (ref_type === 'article') {
            yield articleApi.$getArticle(ref_id);
        }
        else if (ref_type === 'wiki') {
            yield wikiApi.$getWiki(ref_id);
        }
        else if (ref_type === 'wikipage') {
            yield wikiApi.$getWikiPage(ref_id);
        }
        else {
            this.throw(404);
        }
        board = yield discussApi.$getBoardByTag(data.tag);
        this.body = yield discussApi.$createTopic(user, board.id, ref_type, ref_id, data);
    },

    'GET /discuss': function* () {
        var
            model,
            boards = yield discussApi.$getBoards();
        model = {
            boards: boards
        };
        this.render(getView('discuss/boards.html'), yield $getModel.apply(this, [model]));
    },

    'GET /discuss/:id': function* (id) {
        var
            page = helper.getPage(this.request, 10),
            board = yield discussApi.$getBoard(id),
            topics = yield discussApi.$getTopics(id, page),
            model;
        yield userApi.$bindUsers(topics);
        model = {
            page: page,
            board: board,
            topics: topics
        };
        this.render(getView('discuss/board.html'), yield $getModel.apply(this, [model]));
    },

    'GET /discuss/:bid/:tid': function* (bid, tid) {
        var
            topic = yield discussApi.$getTopic(tid),
            page,
            board,
            replies,
            model;
        if (topic.board_id !== bid) {
            this.throw(404);
        }
        page = helper.getPage(this.request, 10);
        board = yield discussApi.$getBoard(bid);
        replies = yield discussApi.$getReplies(tid, page);
        if (page.index === 1) {
            replies.unshift(topic);
        }
        yield userApi.$bindUsers(replies);
        model = {
            page: page,
            board: board,
            topic: topic,
            replies: replies
        };
        this.render(getView('discuss/topic.html'), yield $getModel.apply(this, [model]));
    },

    'GET /discuss/:bid/topics/create': function* (bid) {
        if (this.request.user === null) {
            this.response.redirect('/auth/signin');
            return;
        }
        var
            board = yield discussApi.$getBoard(bid),
            model = {
                board: board
            };
        this.render(getView('discuss/topic_form.html'), yield $getModel.apply(this, [model]));
    },

    'GET /discuss/topic/:tid/find/:rid': function* (tid, rid) {
        var
            topic = yield discussApi.$getTopic(tid),
            p = yield discussApi.$getReplyPageIndex(tid, rid);
        this.response.redirect('/discuss/' + topic.board_id + '/' + tid + '?page=' + p + '#' + rid);
    },

    'GET /user/:id': function* (id) {
        var
            user = yield userApi.$getUser(id),
            model = {
                user: user
            };
        this.render(getView('user/profile.html'), yield $getModel.apply(this, [model]));
    },

    'GET /me/profile': function* (id) {
        var
            user = this.request.user,
            model = {
                user: user
            };
        if (user === null) {
            this.response.redirect('/auth/signin');
            return;
        }
        this.render(getView('user/profile.html'), yield $getModel.apply(this, [model]));
    },

    'GET /auth/signin': function* (id) {
        var
            referer = this.request.get('referer') || '/',
            user = this.request.user;
        console.log('Referer: ' + referer);
        if (user !== null) {

        }
        this.render(getView('signin.html'), yield $getModel.apply(this, [{}]));
    },

    'GET /search': function (req, res, next) {
        var
            page,
            q = req.query.q || '',
            type = req.query.type,
            opt = {};
        if (searchEngine.external) {
            return res.redirect(searchEngine.search(q));
        }
        console.log(JSON.stringify(searchTypeValues));
        if (!searchTypeValues[type]) {
            type = searchTypes[0].value;
        }
        if (type) {
            opt.filter = {
                field: 'type',
                value: type
            };
        }
        page = utils.getPage(req);
        opt.start = page.offset;
        opt.hit = page.itemsPerPage;

        searchEngine.search(q.replace(/\'/g, '').replace(/\"/g, ''), opt, function (err, r) {
            if (err) {
                return next(err);
            }
            if (r.status !== 'OK') {
                return res.send(500);
            }
            page.totalItems = r.result.total;
            var model = {
                searchTypes: searchTypes,
                type: type,
                page: page,
                q: q,
                results: r.result.items
            };
            return processTheme('search.html', model, req, res, next);
        });
    }
};
<|endoftext|>


<commit_before>var assert = require('assert'),
    ajax = require('../djax.js');

describe('Polymorphism', function() {
  it('should work as ajax({ url, success, error })', function(done) {
    ajax({
      url: '/data/1',
      success: function(data, textStatus, xhr) {
        assert.deepEqual(data.result, { data: 'abcde', id: '1' });
        assert(textStatus === 'ok');
        assert(xhr instanceof ajax.xhr);
        assert(arguments.length === 3);
        done();
      },
      error: function() {
        throw new Error('Unexpected error.');
      }
    });
  });

  it('should work as ajax(url).then(success, error)', function(done) {
    ajax('/data/1')
      .then(
        function(data, textStatus, xhr) {
          assert.deepEqual(data.result, { data: 'abcde', id: '1' });
          assert(textStatus === 'ok');
          assert(xhr instanceof ajax.xhr);
          assert(arguments.length === 3);
          done();
        },
        function() {
          throw new Error('Unexpected error.');
        });
  });

  it('should work as ajax(url).done(success).fail(error)', function(done) {
    ajax('/data/1')
      .done(
        function(data, textStatus, xhr) {
          assert.deepEqual(data.result, { data: 'abcde', id: '1' });
          assert(textStatus === 'ok');
          assert(xhr instanceof ajax.xhr);
          assert(arguments.length === 3);
          done();
        })
      .fail(
        function() {
          throw new Error('Unexpected error.');
        });
  });

  it('should work as ajax(url).fail(error).done(success)', function(done) {
    ajax('/data/1')
      .fail(
        function() {
          throw new Error('Unexpected error.');
        })
      .done(
        function(data, textStatus, xhr) {
          assert.deepEqual(data.result, { data: 'abcde', id: '1' });
          assert(textStatus === 'ok');
          assert(xhr instanceof ajax.xhr);
          assert(arguments.length === 3);
          done();
        });
  });
});

describe('HTTP verbs', function() {
  it('should work with GET calls', function(done) {
    ajax({
      url: '/data/1',
      success: function(data, textStatus, xhr) {
        assert.deepEqual(data.result, { data: 'abcde', id: '1' });
        assert(textStatus === 'ok');
        assert(xhr instanceof ajax.xhr);
        assert(arguments.length === 3);
        done();
      },
      error: function() {
        throw new Error('Unexpected error.');
      }
    });
  });

  it('should work with POST calls', function(done) {
    ajax({
      url: '/data/1',
      type: 'POST',
      contentType: 'application/json',
      data: {
        data: 'DEFGH'
      },
      success: function(data, textStatus, xhr) {
        assert.deepEqual(data.result, { data: 'DEFGH', id: '1' });
        assert(textStatus === 'ok');
        assert(xhr instanceof ajax.xhr);
        assert(arguments.length === 3);
        done();
      },
      error: function() {
        throw new Error('Unexpected error.');
      }
    });
  });

  it('should work with PUT calls', function(done) {
    ajax({
      url: '/data/',
      type: 'PUT',
      contentType: 'application/json',
      data: {
        data: 'First entry'
      },
      success: function(data, textStatus, xhr) {
        assert.deepEqual(data.result, { data: 'First entry', id: '3' });
        assert(textStatus === 'ok');
        assert(xhr instanceof ajax.xhr);
        assert(arguments.length === 3);
        done();
      },
      error: function() {
        throw new Error('Unexpected error.');
      }
    });
  });

  it('should work with DELETE calls', function(done) {
    ajax({
      url: '/data/2',
      type: 'DELETE',
      success: function(data, textStatus, xhr) {
        assert.deepEqual(data, { ok: true });
        assert(textStatus === 'ok');
        assert(xhr instanceof ajax.xhr);
        assert(arguments.length === 3);
        done();
      },
      error: function() {
        throw new Error('Unexpected error.');
      }
    });
  });

  it('should trigger the error callback when status is 404', function(done) {
    ajax({
      url: '/data/inexisting_id',
      type: 'POST',
      success: function(data, textStatus, xhr) {
        throw new Error('Unexpected success.');
      },
      error: function(xhr, textStatus, errorThrown) {
        assert(xhr instanceof ajax.xhr);
        assert(textStatus === 'error');
        assert(errorThrown === 'Bad request');
        assert(arguments.length === 3);
        done();
      }
    });
  });
});
<commit_msg>Updated tests to take into account last 2 commits<commit_after>var assert = require('assert'),
    ajax = require('../djax.js');

describe('Polymorphism', function() {
  it('should work as ajax({ url, success, error })', function(done) {
    var res = ajax({
      url: '/data/1',
      success: function(data, textStatus, xhr) {
        assert.deepEqual(data.result, { data: 'abcde', id: '1' });
        assert(textStatus === 'success');
        assert(xhr === res);
        assert(arguments.length === 3);
        done();
      },
      error: function() {
        throw new Error('Unexpected error.');
      }
    });
  });

  it('should work as ajax(url).then(success, error)', function(done) {
    var res = ajax('/data/1')
      .then(
        function(data, textStatus, xhr) {
          assert.deepEqual(data.result, { data: 'abcde', id: '1' });
          assert(textStatus === 'success');
          assert(xhr === res);
          assert(arguments.length === 3);
          done();
        },
        function() {
          throw new Error('Unexpected error.');
        });
  });

  it('should work as ajax(url).done(success).fail(error)', function(done) {
    var res = ajax('/data/1')
      .done(
        function(data, textStatus, xhr) {
          assert.deepEqual(data.result, { data: 'abcde', id: '1' });
          assert(textStatus === 'success');
          assert(xhr === res);
          assert(arguments.length === 3);
          done();
        })
      .fail(
        function() {
          throw new Error('Unexpected error.');
        });
  });

  it('should work as ajax(url).fail(error).done(success)', function(done) {
    var res = ajax('/data/1')
      .fail(
        function() {
          throw new Error('Unexpected error.');
        })
      .done(
        function(data, textStatus, xhr) {
          assert.deepEqual(data.result, { data: 'abcde', id: '1' });
          assert(textStatus === 'success');
          assert(xhr === res);
          assert(arguments.length === 3);
          done();
        });
  });

  it('should work with res.done called after success', function(done) {
    var res = ajax('/data/1')
      .fail(
        function() {
          throw new Error('Unexpected error.');
        })
      .done(
        function() {
          res.done(function(data, textStatus, xhr) {
            assert.deepEqual(data.result, { data: 'abcde', id: '1' });
            assert(textStatus === 'success');
            assert(xhr === res);
            assert(arguments.length === 3);
            done();
          });
        });
  });
});

describe('HTTP verbs', function() {
  it('should work with GET calls', function(done) {
    var res = ajax({
      url: '/data/1',
      success: function(data, textStatus, xhr) {
        assert.deepEqual(data.result, { data: 'abcde', id: '1' });
        assert(textStatus === 'success');
        assert(xhr === res);
        assert(arguments.length === 3);
        done();
      },
      error: function() {
        throw new Error('Unexpected error.');
      }
    });
  });

  it('should work with POST calls', function(done) {
    var res = ajax({
      url: '/data/1',
      type: 'POST',
      contentType: 'application/json',
      data: {
        data: 'DEFGH'
      },
      success: function(data, textStatus, xhr) {
        assert.deepEqual(data.result, { data: 'DEFGH', id: '1' });
        assert(textStatus === 'success');
        assert(xhr === res);
        assert(arguments.length === 3);
        done();
      },
      error: function() {
        throw new Error('Unexpected error.');
      }
    });
  });

  it('should work with PUT calls', function(done) {
    var res = ajax({
      url: '/data/',
      type: 'PUT',
      contentType: 'application/json',
      data: {
        data: 'First entry'
      },
      success: function(data, textStatus, xhr) {
        assert.deepEqual(data.result, { data: 'First entry', id: '3' });
        assert(textStatus === 'success');
        assert(xhr === res);
        assert(arguments.length === 3);
        done();
      },
      error: function() {
        throw new Error('Unexpected error.');
      }
    });
  });

  it('should work with DELETE calls', function(done) {
    var res = ajax({
      url: '/data/2',
      type: 'DELETE',
      success: function(data, textStatus, xhr) {
        assert.deepEqual(data, { ok: true });
        assert(textStatus === 'success');
        assert(xhr === res);
        assert(arguments.length === 3);
        done();
      },
      error: function() {
        throw new Error('Unexpected error.');
      }
    });
  });

  it('should trigger the error callback when status is 404', function(done) {
    var res = ajax({
      url: '/data/inexisting_id',
      type: 'POST',
      success: function(data, textStatus, xhr) {
        throw new Error('Unexpected success.');
      },
      error: function(xhr, textStatus, errorThrown) {
        assert(xhr === res);
        assert(textStatus === 'error');
        assert(errorThrown === 'Bad request');
        assert(arguments.length === 3);
        done();
      }
    });
  });
});
<|endoftext|>


<commit_before>(function(){
  function votes(RoundService) {
    return {
      restrict: 'E',
      replace: false,
      controller: function($scope, RoundService) {
        $scope.round = RoundService;
      },
      link: function(scope, element, attrs) {
        var container = d3.select(element[0]);

        var x = d3.scale.linear().range([0, 100]);

        var chart = container.append("ul").attr("class", "chart");

        scope.$watch('round.current.votes', function(votes) {
          if(votes) {
            console.log(votes);
            x.domain([0, d3.max(votes, function(v) {
              return v.value;
            })]);

            var vote = chart.selectAll('li').data(votes, function(v) {
              return v.id;
            });

            var li = vote.enter().append('li');
            var div = li.append('div')
              .attr('class', 'book-standing')
              .style('width', '0');

            div.append('span')
              .attr('class','title')
              .text(function(v){ return v.book.title });
            div.append('span')
              .attr('class', 'rating')
              .text(function(v){return 'Average Rating: ' + v.book.rating });
            div.append('span')
              .attr('class','votes');

            vote.exit().remove();
            vote.select('span.votes').text(function(v){return v.value + ' votes'; });
            vote.select('div.book-standing')
              .transition().duration(500)
              .style('width', function(v) {
                return x(v.value) + '%';
              });
          }
        });
      }
    };
  }

  angular
    .module('BookClubFiction')
    .directive('votes', votes);
})();
<commit_msg>vote sorting<commit_after>(function(){
  function voteSort(a, b){
    var diff = b.value - a.value;
    if(diff === 0){
      return b.book.rating - a.book.rating;
    } else {
      return diff;
    }
  }

  function votes(RoundService) {
    return {
      restrict: 'E',
      replace: false,
      controller: function($scope, RoundService) {
        $scope.round = RoundService;
      },
      link: function(scope, element, attrs) {
        var container = d3.select(element[0]);

        var x = d3.scale.linear().range([0, 100]);

        var chart = container.append("ul").attr("class", "chart");

        scope.$watch('round.current.votes', function(votes) {
          if(votes) {
            console.log(votes);
            x.domain([0, d3.max(votes, function(v) {
              return v.value;
            })]);

            var vote = chart.selectAll('li').data(votes, function(v) {
              return v.id;
            });

            var li = vote.enter().append('li');
            var div = li.append('div')
              .attr('class', 'book-standing')
              .style('width', '0');

            div.append('span')
              .attr('class','title')
              .text(function(v){ return v.book.title });
            div.append('span')
              .attr('class', 'rating')
              .text(function(v){return 'Average Rating: ' + v.book.rating });
            div.append('span')
              .attr('class','votes');

            vote.exit().remove();

            vote.sort(voteSort);
            vote.select('span.votes').text(function(v){return v.value + ' votes'; });
            vote.select('div.book-standing')
              .transition().duration(500)
              .style('width', function(v) {
                return x(v.value) + '%';
              });
          }
        });
      }
    };
  }

  angular
    .module('BookClubFiction')
    .directive('votes', votes);
})();
<|endoftext|>