<commit_before>'use strict';

const connection = require("../../database/database");
const config = require("../../config");
const utils = require("../../util/utils");
const logger = require("../../util/logger");

const FeatureList = require("../../model/realtime/FeatureList");
const LineUtils = require("../line/LineUtils");

module.exports = class Positions {

    constructor() {
        this.outputFormat = config.coordinate_etrs89;
    }

    setLines(lines) {
        this.lines = lines;
    }

    setVehicle(vehicle) {
        this.vehicle = vehicle;
    }

    getBuses() {
        return Promise.resolve()
            .then(() => {
                let lineFilter = '';
                let vehicleFilter = '';

                if (!utils.isEmpty(this.lines)) {
                    logger.info(`Line filter is enabled: lines='${JSON.stringify(this.lines)}'`);
                    lineFilter = " AND (" + LineUtils.buildForSql('rec_frt.line', 'rec_frt.variant', this.lines) + ")";
                }

                // noinspection EqualityComparisonWithCoercionJS
                if (this.vehicle != null) {
                    logger.info(`Vehicle filter is enabled: vehicle='${this.vehicle}'`);
                    vehicleFilter = ` AND SPLIT_PART(vehicle, ' ', 1) IN (${this.vehicle})`;
                }

                return `
                    SELECT DISTINCT ON (vehicle) vehicle,
                        remark AS bemerkung,
                        delay_sec,
                        ROUND(delay_sec / 60::DECIMAL) AS delay_min,
                        depot AS fzg_depot,
                        direction AS li_ri_nr,
                        EXTRACT(EPOCH FROM TIMEZONE('Europe/Rome', NOW()))::INT % 86400 - departure AS fahrzeit,
                        rec_frt.trip_time_group AS fgr_nr,
                        trip_time_group_text AS fgr_text,
                        rec_frt.trip::int AS frt_fid,
                        departure % 86400 AS frt_start,
                        vehicle AS fzg_nr,
                        rec_frt.service AS leistungsart_nr,
                        leistungsart_text,
                        JSON_AGG(lid_verlauf_paths.ort_nr ORDER BY lid_verlauf_paths.li_lfd_nr) AS lid_verlauf,
                        upper(hex) AS hexcolor,
                        hue,
                        insert_date AS gps_enabled_at,
                        rec_frt.line AS li_nr,
                        rec_frt.variant AS str_li_var,
                        line_name AS lidname,
                        li_kuerzel,
                        vehicle_positions.li_lfd_nr + 1 AS li_lfd_nr,
                        next_rec_ort.ort_name,
                        next_rec_ort.ort_nr,
                        next_rec_ort.ort_ref_ort,
                        next_rec_ort.ort_ref_ort_kuerzel,
                        next_rec_ort.ort_ref_ort_name,
                        -- status,
                        ST_AsGeoJSON(ST_Transform(vehicle_positions.the_geom, ${this.outputFormat})) AS json_geom,
                        ST_AsGeoJSON(ST_Transform(vehicle_positions.extrapolation_geom, ${this.outputFormat})) AS json_extrapolation_geom,
                        gps_date AS gps_updated_at,
                        red AS li_r,
                        green AS li_g,
                        blue AS li_b

                    FROM data.vehicle_positions

                    INNER JOIN data.rec_frt
                        ON vehicle_positions.trip=rec_frt.teq

                    INNER JOIN data.rec_lid
                        ON rec_frt.line=rec_lid.line
                        AND rec_frt.variant=rec_lid.variant

                    LEFT JOIN data.lid_verlauf lid_verlauf_paths
                        ON lid_verlauf_paths.line=rec_frt.line
                        AND lid_verlauf_paths.variant=rec_frt.variant

                    LEFT JOIN data.lid_verlauf lid_verlauf_next
                        ON rec_frt.line=lid_verlauf_next.line
                        AND rec_frt.variant=lid_verlauf_next.variant
                        AND vehicle_positions.li_lfd_nr + 1 = lid_verlauf_next.li_lfd_nr

                    LEFT JOIN data.rec_ort next_rec_ort
                        ON lid_verlauf_next.onr_typ_nr=next_rec_ort.onr_typ_nr
                        AND lid_verlauf_next.ort_nr=next_rec_ort.ort_nr

                    LEFT JOIN data.line_colors
                        ON rec_frt.line=line_colors.line

                    LEFT JOIN data.menge_fgr
                        ON rec_frt.trip_time_group=menge_fgr.trip_time_group

                    LEFT JOIN data.menge_leistungsart
                        ON rec_frt.service=menge_leistungsart.service

                    LEFT JOIN data.rec_frt_bedienung
                        ON rec_frt.trip=rec_frt_bedienung.trip

                    WHERE gps_date > NOW() - interval '${config.realtime_bus_timeout_minutes} minute'

                    ${lineFilter}
                    ${vehicleFilter}

                    GROUP BY vehicle, bemerkung, delay_sec, delay_min, departure, depot, li_ri_nr, fgr_nr, fgr_text,
                        frt_fid, frt_start, fzg_nr, leistungsart_nr, leistungsart_text, hexcolor, hue, gps_enabled_at,
                        li_nr, str_li_var, lidname, li_kuerzel, vehicle_positions.li_lfd_nr + 1, next_rec_ort.ort_name,
                        next_rec_ort.ort_nr, next_rec_ort.ort_ref_ort, next_rec_ort.ort_ref_ort_kuerzel,
                        next_rec_ort.ort_ref_ort_name, json_geom, json_extrapolation_geom, gps_updated_at, li_r, li_g, li_b

                    ORDER BY vehicle DESC, gps_updated_at DESC
               `
            })
            .then(sql => connection.query(sql))
            .then(result => {
                let featureList = new FeatureList();

                for (let row of result.rows) {
                    // noinspection EqualityComparisonWithCoercionJS
                    let geometry = row.json_extrapolation_geom != null ? JSON.parse(row.json_extrapolation_geom) : JSON.parse(row.json_geom);
                    let hex = ((1 << 24) + (row.li_r << 16) + (row.li_g << 8) + row.li_b).toString(16).slice(1);

                    row.hexcolor2 = hex.toUpperCase();

                    delete row.json_geom;
                    delete row.json_extrapolation_geom;

                    delete row.trip;
                    delete row.line;
                    delete row.line_name;
                    delete row.li_r;
                    delete row.li_g;
                    delete row.li_b;
                    delete row.vehicle;

                    featureList.add(row, geometry);
                }

                return featureList.getFeatureCollection();
            });
    }
};<commit_msg>Fixed SQL GeoJSON real-time query<commit_after>'use strict';

const connection = require("../../database/database");
const config = require("../../config");
const utils = require("../../util/utils");
const logger = require("../../util/logger");

const FeatureList = require("../../model/realtime/FeatureList");
const LineUtils = require("../line/LineUtils");

module.exports = class Positions {

    constructor() {
        this.outputFormat = config.coordinate_etrs89;
    }

    setLines(lines) {
        this.lines = lines;
    }

    setVehicle(vehicle) {
        this.vehicle = vehicle;
    }

    getBuses() {
        return Promise.resolve()
            .then(() => {
                let lineFilter = '';
                let vehicleFilter = '';

                if (!utils.isEmpty(this.lines)) {
                    logger.info(`Line filter is enabled: lines='${JSON.stringify(this.lines)}'`);
                    lineFilter = " AND (" + LineUtils.buildForSql('rec_frt.line', 'rec_frt.variant', this.lines) + ")";
                }

                // noinspection EqualityComparisonWithCoercionJS
                if (this.vehicle != null) {
                    logger.info(`Vehicle filter is enabled: vehicle='${this.vehicle}'`);
                    vehicleFilter = ` AND SPLIT_PART(vehicle, ' ', 1) IN (${this.vehicle})`;
                }

                return `
                    SELECT DISTINCT ON (vehicle) vehicle,
                        remark AS bemerkung,
                        delay_sec,
                        ROUND(delay_sec / 60::DECIMAL)::INT AS delay_min,
                        depot AS fzg_depot,
                        direction AS li_ri_nr,
                        EXTRACT(EPOCH FROM TIMEZONE('Europe/Rome', NOW()))::INT % 86400 - departure AS fahrzeit,
                        rec_frt.trip_time_group AS fgr_nr,
                        trip_time_group_text AS fgr_text,
                        rec_frt.trip::int AS frt_fid,
                        departure % 86400 AS frt_start,
                        vehicle AS fzg_nr,
                        rec_frt.service AS leistungsart_nr,
                        leistungsart_text,
                        JSON_AGG(lid_verlauf_paths.ort_nr ORDER BY lid_verlauf_paths.li_lfd_nr) AS lid_verlauf,
                        upper(hex) AS hexcolor,
                        hue,
                        insert_date AS gps_enabled_at,
                        rec_frt.line AS li_nr,
                        rec_frt.variant AS str_li_var,
                        line_name AS lidname,
                        li_kuerzel,
                        vehicle_positions.li_lfd_nr + 1 AS li_lfd_nr,
                        next_rec_ort.ort_name,
                        next_rec_ort.ort_nr,
                        next_rec_ort.ort_ref_ort,
                        next_rec_ort.ort_ref_ort_kuerzel,
                        next_rec_ort.ort_ref_ort_name,
                        -- status,
                        ST_AsGeoJSON(ST_Transform(vehicle_positions.the_geom, ${this.outputFormat})) AS json_geom,
                        ST_AsGeoJSON(ST_Transform(vehicle_positions.extrapolation_geom, ${this.outputFormat})) AS json_extrapolation_geom,
                        gps_date AS gps_updated_at,
                        red AS li_r,
                        green AS li_g,
                        blue AS li_b

                    FROM data.vehicle_positions

                    INNER JOIN data.rec_frt
                        ON vehicle_positions.trip=rec_frt.teq

                    INNER JOIN data.rec_lid
                        ON rec_frt.line=rec_lid.line
                        AND rec_frt.variant=rec_lid.variant

                    LEFT JOIN data.lid_verlauf lid_verlauf_paths
                        ON lid_verlauf_paths.line=rec_frt.line
                        AND lid_verlauf_paths.variant=rec_frt.variant

                    LEFT JOIN data.lid_verlauf lid_verlauf_next
                        ON rec_frt.line=lid_verlauf_next.line
                        AND rec_frt.variant=lid_verlauf_next.variant
                        AND vehicle_positions.li_lfd_nr + 1 = lid_verlauf_next.li_lfd_nr

                    LEFT JOIN data.rec_ort next_rec_ort
                        ON lid_verlauf_next.onr_typ_nr=next_rec_ort.onr_typ_nr
                        AND lid_verlauf_next.ort_nr=next_rec_ort.ort_nr

                    LEFT JOIN data.line_colors
                        ON rec_frt.line=line_colors.line

                    LEFT JOIN data.menge_fgr
                        ON rec_frt.trip_time_group=menge_fgr.trip_time_group

                    LEFT JOIN data.menge_leistungsart
                        ON rec_frt.service=menge_leistungsart.service

                    LEFT JOIN data.rec_frt_bedienung
                        ON rec_frt.trip=rec_frt_bedienung.trip

                    WHERE gps_date > NOW() - interval '${config.realtime_bus_timeout_minutes} minute'

                    ${lineFilter}
                    ${vehicleFilter}

                    GROUP BY vehicle, bemerkung, delay_sec, delay_min, departure, depot, li_ri_nr, fgr_nr, fgr_text,
                        frt_fid, frt_start, fzg_nr, leistungsart_nr, leistungsart_text, hexcolor, hue, gps_enabled_at,
                        li_nr, str_li_var, lidname, li_kuerzel, vehicle_positions.li_lfd_nr + 1, next_rec_ort.ort_name,
                        next_rec_ort.ort_nr, next_rec_ort.ort_ref_ort, next_rec_ort.ort_ref_ort_kuerzel,
                        next_rec_ort.ort_ref_ort_name, json_geom, json_extrapolation_geom, gps_updated_at, li_r, li_g, li_b

                    ORDER BY vehicle DESC, gps_updated_at DESC
               `
            })
            .then(sql => connection.query(sql))
            .then(result => {
                let featureList = new FeatureList();

                for (let row of result.rows) {
                    // noinspection EqualityComparisonWithCoercionJS
                    let geometry = row.json_extrapolation_geom != null ? JSON.parse(row.json_extrapolation_geom) : JSON.parse(row.json_geom);
                    let hex = ((1 << 24) + (row.li_r << 16) + (row.li_g << 8) + row.li_b).toString(16).slice(1);

                    row.hexcolor2 = hex.toUpperCase();

                    delete row.json_geom;
                    delete row.json_extrapolation_geom;

                    delete row.trip;
                    delete row.line;
                    delete row.line_name;
                    delete row.li_r;
                    delete row.li_g;
                    delete row.li_b;
                    delete row.vehicle;

                    featureList.add(row, geometry);
                }

                return featureList.getFeatureCollection();
            });
    }
};<|endoftext|>


<commit_before>/**
 * CacheStorage
 * ============
 */
var fs = require('fs');
var dropRequireCache = require('../fs/drop-require-cache');
var Vow = require('vow');
/**
 * CacheStorage — хранилище для кэша.
 * @name CacheStorage
 * @param {String} filename Имя файла, в котором хранится кэш (в формате JSON).
 * @constructor
 */
function CacheStorage(filename) {
    this._filename = filename;
    this._data = {};
    this._mtime = 0;
}

CacheStorage.prototype = {
    /**
     * Загружает кэш из файла.
     */
    load: function () {
        if (fs.existsSync(this._filename)) {
            dropRequireCache(require, this._filename);
            try {
                this._data = require(this._filename);
            } catch (e) {
                this._data = {};
            }
            this._mtime = fs.statSync(this._filename).mtime.getTime();
        } else {
            this._data = {};
        }
    },

    /**
     * Сохраняет кэш в файл.
     */
    save: function () {
        fs.writeFileSync(this._filename, 'module.exports = ' + JSON.stringify(this._data) + ';', 'utf8');
        this._mtime = fs.statSync(this._filename).mtime.getTime();
    },

    /**
     * Сохраняет кэш в файл асинхронно.
     */
    saveAsync: function () {
        var _this = this;
        var promise = Vow.promise();
        var stream = fs.createWriteStream(this._filename)
            .on('error', function (err) {
                promise.reject(err);
            });

        // Делаем stringify() на каждый объект в кеше чтобы уменьшить потребление памяти -
        // stringify() на больших кешах может отъедать сотни МБ.
        stream.write('module.exports = {');
        Object.keys(this._data).forEach(function (key) {
            stream.write('"' + key + '":' + JSON.stringify(_this._data[key]) + ',');
        });

        stream.end('};', function () {
            _this._mtime = fs.statSync(_this._filename).mtime.getTime();
            promise.fulfill();
        });

        return promise;
    },

    /**
     * Возвращает значение по префику и ключу.
     * @param {String} prefix
     * @param {String} key
     * @returns {Object}
     */
    get: function (prefix, key) {
        return this._data[prefix] && this._data[prefix][key];
    },

    /**
     * Устанавливает значение по префиксу и ключу.
     * @param {String} prefix
     * @param {String} key
     * @param {Object} value
     */
    set: function (prefix, key, value) {
        (this._data[prefix] || (this._data[prefix] = {}))[key] = value;
    },

    /**
     * Удаляет значение по префиксу и ключу.
     * @param {String} prefix
     * @param {String} key
     */
    invalidate: function (prefix, key) {
        var prefixObj = this._data[prefix];
        if (prefixObj) {
            delete prefixObj[key];
        }
    },

    /**
     * Удаляет все значения по префиксу.
     * @param {String} prefix
     */
    dropPrefix: function (prefix) {
        delete this._data[prefix];
    },

    /**
     * Очищает кэш.
     */
    drop: function () {
        this._data = {};
    }
};

module.exports = CacheStorage;
<commit_msg>Inherited CacheStorage using inherit module instead of simple prototype assign<commit_after>/**
 * CacheStorage
 * ============
 */
var fs = require('fs');
var dropRequireCache = require('../fs/drop-require-cache');
var Vow = require('vow');
var inherit = require('inherit');

/**
 * CacheStorage — хранилище для кэша.
 * @name CacheStorage
 */
var CacheStorage = inherit(/** @lends CacheStorage.prototype */ {
    /**
     *
     * @name CacheStorage
     * @param {String} filename Имя файла, в котором хранится кэш (в формате JSON).
     * @constructor
     */
    __constructor: function (filename) {
        this._filename = filename;
        this._data = {};
        this._mtime = 0;
    },

    /**
     * Загружает кэш из файла.
     */
    load: function () {
        if (fs.existsSync(this._filename)) {
            dropRequireCache(require, this._filename);
            try {
                this._data = require(this._filename);
            } catch (e) {
                this._data = {};
            }
            this._mtime = fs.statSync(this._filename).mtime.getTime();
        } else {
            this._data = {};
        }
    },

    /**
     * Сохраняет кэш в файл.
     */
    save: function () {
        fs.writeFileSync(this._filename, 'module.exports = ' + JSON.stringify(this._data) + ';', 'utf8');
        this._mtime = fs.statSync(this._filename).mtime.getTime();
    },

    /**
     * Сохраняет кэш в файл асинхронно.
     */
    saveAsync: function () {
        var _this = this;
        var promise = Vow.promise();
        var stream = fs.createWriteStream(this._filename)
            .on('error', function (err) {
                promise.reject(err);
            });

        // Делаем stringify() на каждый объект в кеше чтобы уменьшить потребление памяти -
        // stringify() на больших кешах может отъедать сотни МБ.
        stream.write('module.exports = {');
        Object.keys(this._data).forEach(function (key) {
            stream.write('"' + key + '":' + JSON.stringify(_this._data[key]) + ',');
        });

        stream.end('};', function () {
            _this._mtime = fs.statSync(_this._filename).mtime.getTime();
            promise.fulfill();
        });

        return promise;
    },

    /**
     * Возвращает значение по префику и ключу.
     * @param {String} prefix
     * @param {String} key
     * @returns {Object}
     */
    get: function (prefix, key) {
        return this._data[prefix] && this._data[prefix][key];
    },

    /**
     * Устанавливает значение по префиксу и ключу.
     * @param {String} prefix
     * @param {String} key
     * @param {Object} value
     */
    set: function (prefix, key, value) {
        (this._data[prefix] || (this._data[prefix] = {}))[key] = value;
    },

    /**
     * Удаляет значение по префиксу и ключу.
     * @param {String} prefix
     * @param {String} key
     */
    invalidate: function (prefix, key) {
        var prefixObj = this._data[prefix];
        if (prefixObj) {
            delete prefixObj[key];
        }
    },

    /**
     * Удаляет все значения по префиксу.
     * @param {String} prefix
     */
    dropPrefix: function (prefix) {
        delete this._data[prefix];
    },

    /**
     * Очищает кэш.
     */
    drop: function () {
        this._data = {};
    }
});

module.exports = CacheStorage;
<|endoftext|>


<commit_before>'use strict';

var assert = require('assert');
var FLAGS = [
    'deep',
    'itself',
    'length', 'lengthOf',
    'not'
];
var PRIMITIVE_TYPES = [
    'undefined',
    'string',
    'number',
    'boolean',
    'function',
    'object',
    'symbol'
];

function isFirstLetterCapital (str) {
    return str.charAt(0) === str.charAt(0).toUpperCase();
}

function beginsWithExpect (node) {
    return (node.type === 'Identifier' && node.name === 'expect' ||
            (node.type === 'CallExpression' && beginsWithExpect(node.callee)) ||
            (node.type === 'MemberExpression' && beginsWithExpect(node.object)));
}

function subjects (node) {
    if (node.type === 'CallExpression') {
        if (node.callee.type === 'Identifier' && node.callee.name === 'expect') {
            return node.arguments;
        } else {
            return subjects(node.callee);
        }
    } else if (node.type === 'MemberExpression') {
        return subjects(node.object);
    } else {
        return assert(false, 'cannot be here');
    }
}

function collectFlags (node, collector) {
    if (node.type === 'CallExpression') {
        if (node.callee.type === 'Identifier' && node.callee.name === 'expect') {
            return collector;
        } else {
            return collectFlags(node.callee, collector);
        }
    } else if (node.type === 'MemberExpression') {
        if (node.property.type === 'Identifier' && FLAGS.indexOf(node.property.name) !== -1) {
            collector[node.property.name] = true;
        }
        return collectFlags(node.object, collector);
    } else {
        return assert(false, 'cannot be here');
    }
}

module.exports = function expectToAssert (file, api, options) {
    var j = api.jscodeshift;
    var ast = j(file.source);

    ast.find(j.MemberExpression, {
        type: 'MemberExpression',
        property: function (node) {
            return node.type === 'Identifier' &&
                [
                    'ok',
                    'true',
                    'false',
                    'null',
                    'finite',
                    'NaN',
                    'exist',
                    'undefined'
                ].indexOf(node.name) !== -1;
        },
        object: beginsWithExpect
    }).replaceWith(function (path) {
        var flags = collectFlags(path.value, {});
        var hasFlag = function (flag) {
            return !!flags[flag];
        };
        var negation = hasFlag('not');
        var subject = subjects(path.value)[0];
        var rhs;
        switch (path.value.property.name) {
        case 'ok':
            if (negation) {
                return j.callExpression(j.identifier('assert'), [
                    j.unaryExpression('!', subject)
                ]);
            } else {
                return j.callExpression(j.identifier('assert'), [ subject ]);
            }
        case 'finite':
            if (negation) {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '||',
                        j.binaryExpression(
                            '!==',
                            j.unaryExpression('typeof', subject),
                            j.literal('number')
                        ),
                        j.unaryExpression('!', j.callExpression(j.identifier('isFinite'), [ subject ]))
                    )
                ]);
            } else {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '&&',
                        j.binaryExpression(
                            '===',
                            j.unaryExpression('typeof', subject),
                            j.literal('number')
                        ),
                        j.callExpression(j.identifier('isFinite'), [ subject ])
                    )
                ]);
            }
        case 'NaN':
            if (negation) {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '||',
                        j.binaryExpression(
                            '!==',
                            j.unaryExpression('typeof', subject),
                            j.literal('number')
                        ),
                        j.binaryExpression(
                            '===',
                            subject,
                            subject
                        )
                    )
                ]);
            } else {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '&&',
                        j.binaryExpression(
                            '===',
                            j.unaryExpression('typeof', subject),
                            j.literal('number')
                        ),
                        j.binaryExpression(
                            '!==',
                            subject,
                            subject
                        )
                    )
                ]);
            }
        case 'exist':
            if (negation) {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '||',
                        j.binaryExpression(
                            '===',
                            subject,
                            j.literal(null)
                        ),
                        j.binaryExpression(
                            '===',
                            subject,
                            j.identifier('undefined')
                        )
                    )
                ]);
            } else {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '&&',
                        j.binaryExpression(
                            '!==',
                            subject,
                            j.literal(null)
                        ),
                        j.binaryExpression(
                            '!==',
                            subject,
                            j.identifier('undefined')
                        )
                    )
                ]);
            }
        case 'true':
            rhs = j.booleanLiteral(true);
            break;
        case 'false':
            rhs = j.booleanLiteral(false);
            break;
        case 'null':
            rhs = j.literal(null);
            break;
        case 'undefined':
            rhs = j.identifier('undefined');
            break;
        default:
            assert(false, 'cannot be here');
        }
        return j.callExpression(j.identifier('assert'), [
            j.binaryExpression(
                negation ? '!==' : '===',
                subject,
                rhs
            )
        ]);
    });

    ast.find(j.CallExpression, {
        callee: {
            type: 'MemberExpression',
            property: function (node) {
                return node.type === 'Identifier' &&
                    [
                        'a', 'an',
                        'above', 'gt', 'greaterThan',
                        'least', 'gte',
                        'below', 'lt', 'lessThan',
                        'most', 'lte',
                        'within',
                        'equal', 'equals', 'eq',
                        'eql', 'eqls',
                        'instanceof', 'instanceOf',
                        'length', 'lengthOf',
                        'match', 'matches',
                        'respondTo', 'respondsTo',
                        'string'
                    ].indexOf(node.name) !== -1;
            },
            object: beginsWithExpect
        }
    }).replaceWith(function (path) {
        var flags = collectFlags(path.value, {});
        var hasFlag = function (flag) {
            return !!flags[flag];
        };
        var negation = hasFlag('not');
        var subject = subjects(path.value)[0];
        var matcherArg = path.value.arguments[0];
        var prependBangIfNegation = function (expr) {
            return negation ? j.unaryExpression('!', expr) : expr;
        };
        var strictEquality = function (left, right) {
            return j.callExpression(j.identifier('assert'), [
                j.binaryExpression(
                    negation ? '!==' : '===',
                    left,
                    right
                )
            ]);
        };
        var inequality = function (operator) {
            return j.callExpression(j.identifier('assert'), [
                j.binaryExpression(
                    operator,
                    (hasFlag('lengthOf') || hasFlag('length')) ?
                        j.memberExpression(subject, j.identifier('length')) :
                        subject,
                    matcherArg
                )
            ]);
        };
        var deepEquality = function () {
            return j.callExpression(
                j.memberExpression(
                    j.identifier('assert'),
                    negation ? j.identifier('notDeepStrictEqual') : j.identifier('deepStrictEqual')
                ),
                [
                    subject,
                    matcherArg
                ]);
        };
        switch (path.value.callee.property.name) {
        case 'a':
        case 'an':
            if (PRIMITIVE_TYPES.indexOf(matcherArg.value) !== -1) {
                return strictEquality(j.unaryExpression('typeof', subject), matcherArg);
            } else if (matcherArg.value === 'null') {
                return strictEquality(subject, j.literal(null));
            } else {
                throw new Error('not supported yet');
            }
        case 'instanceof':
        case 'instanceOf':
            return j.callExpression(j.identifier('assert'), [
                prependBangIfNegation(j.binaryExpression(
                    'instanceof',
                    subject,
                    matcherArg
                ))
            ]);
        case 'equal':
        case 'equals':
        case 'eq':
            if (hasFlag('deep')) {
                return deepEquality();
            } else {
                return strictEquality(subject, matcherArg);
            }
        case 'eql':
        case 'eqls':
            return deepEquality();
        case 'match':
        case 'matches':
            return j.callExpression(j.identifier('assert'), [
                j.binaryExpression(
                    '===',
                    j.callExpression(j.memberExpression(matcherArg, j.identifier('test')), [ subject ]),
                    negation ? j.booleanLiteral(false) : j.booleanLiteral(true)
                )
            ]);
        case 'string':
            return j.callExpression(j.identifier('assert'), [
                j.binaryExpression(
                    negation ? '===' : '!==',
                    j.callExpression(j.memberExpression(subject, j.identifier('indexOf')), [ matcherArg ]),
                    j.unaryExpression('-', j.literal(1))
                )
            ]);
        case 'respondTo':
        case 'respondsTo':
            var receiver;
            if (subject.type === 'Identifier' && isFirstLetterCapital(subject.name) && !(hasFlag('itself'))) {
                receiver = j.memberExpression(subject, j.identifier('prototype'));
            } else {
                receiver = subject;
            }
            return strictEquality(
                j.unaryExpression('typeof', j.memberExpression(receiver, matcherArg, true)),
                j.literal('function')
            );
        case 'length':
        case 'lengthOf':
            return strictEquality(j.memberExpression(subject, j.identifier('length')), matcherArg);
        case 'above':
        case 'gt':
        case 'greaterThan':
            return inequality(negation ? '<=' : '>');
        case 'least':
        case 'gte':
            return inequality(negation ? '<' : '>=');
        case 'below':
        case 'lt':
        case 'lessThan':
            return inequality(negation ? '>=' : '<');
        case 'most':
        case 'lte':
            return inequality(negation ? '>' : '<=');
        case 'within':
            var subjectOrItsLength = (hasFlag('lengthOf') || hasFlag('length')) ?
                j.memberExpression(subject, j.identifier('length')) :
                subject;
            if (negation) {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '||',
                        j.binaryExpression(
                            '<',
                            subjectOrItsLength,
                            path.value.arguments[0]
                        ),
                        j.binaryExpression(
                            '<',
                            path.value.arguments[1],
                            subjectOrItsLength
                        )
                    )
                ]);
            } else {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '&&',
                        j.binaryExpression(
                            '<=',
                            path.value.arguments[0],
                            subjectOrItsLength
                        ),
                        j.binaryExpression(
                            '<=',
                            subjectOrItsLength,
                            path.value.arguments[1]
                        )
                    )
                ]);
            }
        default:
            assert(false, 'cannot be here');
            return null;
        }
    });

    return ast.toSource();
};
<commit_msg>refactor(chai-to-assert): simplify by ConditionalExpression<commit_after>'use strict';

var assert = require('assert');
var FLAGS = [
    'deep',
    'itself',
    'length', 'lengthOf',
    'not'
];
var PRIMITIVE_TYPES = [
    'undefined',
    'string',
    'number',
    'boolean',
    'function',
    'object',
    'symbol'
];

function isFirstLetterCapital (str) {
    return str.charAt(0) === str.charAt(0).toUpperCase();
}

function beginsWithExpect (node) {
    return (node.type === 'Identifier' && node.name === 'expect' ||
            (node.type === 'CallExpression' && beginsWithExpect(node.callee)) ||
            (node.type === 'MemberExpression' && beginsWithExpect(node.object)));
}

function subjects (node) {
    if (node.type === 'CallExpression') {
        if (node.callee.type === 'Identifier' && node.callee.name === 'expect') {
            return node.arguments;
        } else {
            return subjects(node.callee);
        }
    } else if (node.type === 'MemberExpression') {
        return subjects(node.object);
    } else {
        return assert(false, 'cannot be here');
    }
}

function collectFlags (node, collector) {
    if (node.type === 'CallExpression') {
        if (node.callee.type === 'Identifier' && node.callee.name === 'expect') {
            return collector;
        } else {
            return collectFlags(node.callee, collector);
        }
    } else if (node.type === 'MemberExpression') {
        if (node.property.type === 'Identifier' && FLAGS.indexOf(node.property.name) !== -1) {
            collector[node.property.name] = true;
        }
        return collectFlags(node.object, collector);
    } else {
        return assert(false, 'cannot be here');
    }
}

module.exports = function expectToAssert (file, api, options) {
    var j = api.jscodeshift;
    var ast = j(file.source);

    ast.find(j.MemberExpression, {
        type: 'MemberExpression',
        property: function (node) {
            return node.type === 'Identifier' &&
                [
                    'ok',
                    'true',
                    'false',
                    'null',
                    'finite',
                    'NaN',
                    'exist',
                    'undefined'
                ].indexOf(node.name) !== -1;
        },
        object: beginsWithExpect
    }).replaceWith(function (path) {
        var flags = collectFlags(path.value, {});
        var hasFlag = function (flag) {
            return !!flags[flag];
        };
        var negation = hasFlag('not');
        var subject = subjects(path.value)[0];
        var rhs;
        switch (path.value.property.name) {
        case 'ok':
            if (negation) {
                return j.callExpression(j.identifier('assert'), [
                    j.unaryExpression('!', subject)
                ]);
            } else {
                return j.callExpression(j.identifier('assert'), [ subject ]);
            }
        case 'finite':
            if (negation) {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '||',
                        j.binaryExpression(
                            '!==',
                            j.unaryExpression('typeof', subject),
                            j.literal('number')
                        ),
                        j.unaryExpression('!', j.callExpression(j.identifier('isFinite'), [ subject ]))
                    )
                ]);
            } else {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '&&',
                        j.binaryExpression(
                            '===',
                            j.unaryExpression('typeof', subject),
                            j.literal('number')
                        ),
                        j.callExpression(j.identifier('isFinite'), [ subject ])
                    )
                ]);
            }
        case 'NaN':
            return j.callExpression(j.identifier('assert'), [
                j.logicalExpression(
                    negation ? '||' : '&&',
                    j.binaryExpression(
                        negation ? '!==' : '===',
                        j.unaryExpression('typeof', subject),
                        j.literal('number')
                    ),
                    j.binaryExpression(
                        negation ? '===' : '!==',
                        subject,
                        subject
                    )
                )
            ]);
        case 'exist':
            return j.callExpression(j.identifier('assert'), [
                j.logicalExpression(
                    negation ? '||' : '&&',
                    j.binaryExpression(
                        negation ? '===' : '!==',
                        subject,
                        j.literal(null)
                    ),
                    j.binaryExpression(
                        negation ? '===' : '!==',
                        subject,
                        j.identifier('undefined')
                    )
                )
            ]);
        case 'true':
            rhs = j.booleanLiteral(true);
            break;
        case 'false':
            rhs = j.booleanLiteral(false);
            break;
        case 'null':
            rhs = j.literal(null);
            break;
        case 'undefined':
            rhs = j.identifier('undefined');
            break;
        default:
            assert(false, 'cannot be here');
        }
        return j.callExpression(j.identifier('assert'), [
            j.binaryExpression(
                negation ? '!==' : '===',
                subject,
                rhs
            )
        ]);
    });

    ast.find(j.CallExpression, {
        callee: {
            type: 'MemberExpression',
            property: function (node) {
                return node.type === 'Identifier' &&
                    [
                        'a', 'an',
                        'above', 'gt', 'greaterThan',
                        'least', 'gte',
                        'below', 'lt', 'lessThan',
                        'most', 'lte',
                        'within',
                        'equal', 'equals', 'eq',
                        'eql', 'eqls',
                        'instanceof', 'instanceOf',
                        'length', 'lengthOf',
                        'match', 'matches',
                        'respondTo', 'respondsTo',
                        'string'
                    ].indexOf(node.name) !== -1;
            },
            object: beginsWithExpect
        }
    }).replaceWith(function (path) {
        var flags = collectFlags(path.value, {});
        var hasFlag = function (flag) {
            return !!flags[flag];
        };
        var negation = hasFlag('not');
        var subject = subjects(path.value)[0];
        var matcherArg = path.value.arguments[0];
        var prependBangIfNegation = function (expr) {
            return negation ? j.unaryExpression('!', expr) : expr;
        };
        var strictEquality = function (left, right) {
            return j.callExpression(j.identifier('assert'), [
                j.binaryExpression(
                    negation ? '!==' : '===',
                    left,
                    right
                )
            ]);
        };
        var inequality = function (operator) {
            return j.callExpression(j.identifier('assert'), [
                j.binaryExpression(
                    operator,
                    (hasFlag('lengthOf') || hasFlag('length')) ?
                        j.memberExpression(subject, j.identifier('length')) :
                        subject,
                    matcherArg
                )
            ]);
        };
        var deepEquality = function () {
            return j.callExpression(
                j.memberExpression(
                    j.identifier('assert'),
                    negation ? j.identifier('notDeepStrictEqual') : j.identifier('deepStrictEqual')
                ),
                [
                    subject,
                    matcherArg
                ]);
        };
        switch (path.value.callee.property.name) {
        case 'a':
        case 'an':
            if (PRIMITIVE_TYPES.indexOf(matcherArg.value) !== -1) {
                return strictEquality(j.unaryExpression('typeof', subject), matcherArg);
            } else if (matcherArg.value === 'null') {
                return strictEquality(subject, j.literal(null));
            } else {
                throw new Error('not supported yet');
            }
        case 'instanceof':
        case 'instanceOf':
            return j.callExpression(j.identifier('assert'), [
                prependBangIfNegation(j.binaryExpression(
                    'instanceof',
                    subject,
                    matcherArg
                ))
            ]);
        case 'equal':
        case 'equals':
        case 'eq':
            if (hasFlag('deep')) {
                return deepEquality();
            } else {
                return strictEquality(subject, matcherArg);
            }
        case 'eql':
        case 'eqls':
            return deepEquality();
        case 'match':
        case 'matches':
            return j.callExpression(j.identifier('assert'), [
                j.binaryExpression(
                    '===',
                    j.callExpression(j.memberExpression(matcherArg, j.identifier('test')), [ subject ]),
                    negation ? j.booleanLiteral(false) : j.booleanLiteral(true)
                )
            ]);
        case 'string':
            return j.callExpression(j.identifier('assert'), [
                j.binaryExpression(
                    negation ? '===' : '!==',
                    j.callExpression(j.memberExpression(subject, j.identifier('indexOf')), [ matcherArg ]),
                    j.unaryExpression('-', j.literal(1))
                )
            ]);
        case 'respondTo':
        case 'respondsTo':
            var receiver;
            if (subject.type === 'Identifier' && isFirstLetterCapital(subject.name) && !(hasFlag('itself'))) {
                receiver = j.memberExpression(subject, j.identifier('prototype'));
            } else {
                receiver = subject;
            }
            return strictEquality(
                j.unaryExpression('typeof', j.memberExpression(receiver, matcherArg, true)),
                j.literal('function')
            );
        case 'length':
        case 'lengthOf':
            return strictEquality(j.memberExpression(subject, j.identifier('length')), matcherArg);
        case 'above':
        case 'gt':
        case 'greaterThan':
            return inequality(negation ? '<=' : '>');
        case 'least':
        case 'gte':
            return inequality(negation ? '<' : '>=');
        case 'below':
        case 'lt':
        case 'lessThan':
            return inequality(negation ? '>=' : '<');
        case 'most':
        case 'lte':
            return inequality(negation ? '>' : '<=');
        case 'within':
            var subjectOrItsLength = (hasFlag('lengthOf') || hasFlag('length')) ?
                j.memberExpression(subject, j.identifier('length')) :
                subject;
            if (negation) {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '||',
                        j.binaryExpression(
                            '<',
                            subjectOrItsLength,
                            path.value.arguments[0]
                        ),
                        j.binaryExpression(
                            '<',
                            path.value.arguments[1],
                            subjectOrItsLength
                        )
                    )
                ]);
            } else {
                return j.callExpression(j.identifier('assert'), [
                    j.logicalExpression(
                        '&&',
                        j.binaryExpression(
                            '<=',
                            path.value.arguments[0],
                            subjectOrItsLength
                        ),
                        j.binaryExpression(
                            '<=',
                            subjectOrItsLength,
                            path.value.arguments[1]
                        )
                    )
                ]);
            }
        default:
            assert(false, 'cannot be here');
            return null;
        }
    });

    return ast.toSource();
};
<|endoftext|>


<commit_before><commit_msg>timout<commit_after><|endoftext|>


<commit_before>import React from 'react';
import {Dimensions, StyleSheet, Text, View, TouchableHighlight, PanResponder} from 'react-native';

export default class Next extends React.Component {
  constructor(props) {
    super(props);
    this.panResponder = PanResponder.create({
      onMoveShouldSetPanResponder: this.handleMoveShouldSetPanResponder.bind(this),
      onPanResponderMove: this.handlePanResponderMove.bind(this),
      onPanResponderRelease: this.handlePanResponderEnd.bind(this),
      onPanResponderTerminate: this.handlePanResponderEnd.bind(this),
    });
  }
  handleMoveShouldSetPanResponder(e, gestureState) {
    return true;
  }
  handlePanResponderMove(e, gestureState) {
    var {moveScene} = this.props;
    moveScene({translate: Math.max(0, gestureState.dx) / Dimensions.get('window').width});
  }
  handlePanResponderEnd(e, gestureState) {
    var {moveScene, stateNavigator} = this.props;
    if (gestureState.dx / Dimensions.get('window').width < 0.5)
      moveScene(null);
    else
      stateNavigator.navigateBack(1);
  }
  render() {
    const {stateNavigator} = this.props;
    const {url} = stateNavigator.stateContext;
    return (
      <View
        style={styles.scene}
        {...this.panResponder.panHandlers}
        >
        <TouchableHighlight
          underlayColor="white"
          onPress={() => {
            if (url === stateNavigator.stateContext.url)
              stateNavigator.navigate('next');
        }}>
          <Text>Next</Text>
        </TouchableHighlight>
      </View>
    )
  }
};

const styles = StyleSheet.create({
  scene: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
    borderWidth: 1,
    borderColor: '#000',
  },
});
<commit_msg>Styled with spring for consistency<commit_after>import React from 'react';
import {Dimensions, StyleSheet, Text, View, TouchableHighlight, PanResponder} from 'react-native';
import {spring} from 'navigation-react-native';

export default class Next extends React.Component {
  constructor(props) {
    super(props);
    this.panResponder = PanResponder.create({
      onMoveShouldSetPanResponder: this.handleMoveShouldSetPanResponder.bind(this),
      onPanResponderMove: this.handlePanResponderMove.bind(this),
      onPanResponderRelease: this.handlePanResponderEnd.bind(this),
      onPanResponderTerminate: this.handlePanResponderEnd.bind(this),
    });
  }
  handleMoveShouldSetPanResponder(e, gestureState) {
    return true;
  }
  handlePanResponderMove(e, gestureState) {
    var {moveScene} = this.props;
    moveScene({translate: spring(Math.max(0, gestureState.dx) / Dimensions.get('window').width)});
  }
  handlePanResponderEnd(e, gestureState) {
    var {moveScene, stateNavigator} = this.props;
    if (gestureState.dx / Dimensions.get('window').width < 0.5)
      moveScene(null);
    else
      stateNavigator.navigateBack(1);
  }
  render() {
    const {stateNavigator} = this.props;
    const {url} = stateNavigator.stateContext;
    return (
      <View
        style={styles.scene}
        {...this.panResponder.panHandlers}
        >
        <TouchableHighlight
          underlayColor="white"
          onPress={() => {
            if (url === stateNavigator.stateContext.url)
              stateNavigator.navigate('next');
        }}>
          <Text>Next</Text>
        </TouchableHighlight>
      </View>
    )
  }
};

const styles = StyleSheet.create({
  scene: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
    borderWidth: 1,
    borderColor: '#000',
  },
});
<|endoftext|>


<commit_before>var fs = require('fs'),
    levelup = require('levelup'),
    leveldown = require('leveldown'),
    key = require('./lib/key.js');

function fixed(callback) {

    var dbs = fs.readdirSync('./ldb/').filter(function(item) {
       return item.indexOf('.ldb') > -1;
    });

    if (!fs.existsSync('./fixed')) {
        fs.mkdirSync('./fixed');
    }

    dbs.forEach(function(ldb, idx) {
        levelup('./ldb/' + ldb, {
            createIfMissing: false,
            max_open_files: 500
        }, function(err, db) {
            if (err) return console.log(err);
            var file = fs.createWriteStream('./fixed/' + ldb.split('.ldb')[0]);
            file.once('open', function() {
                db.createReadStream({lt: '0001'})
                    .on('data', function(data) {
                        file.write(key.decompose(data.key).hash + '\n');
                    })
                    .on('end', function(data) {
                        file.end();
                        if (callback) callback(null);
                    });
            });
        });
    });
}

module.exports = fixed;

if (require.main === module) { fixed(); }
<commit_msg>release leveldb object properly<commit_after>var fs = require('fs'),
    levelup = require('levelup'),
    leveldown = require('leveldown'),
    key = require('./lib/key.js');

function fixed(callback) {

    var dbs = fs.readdirSync('./ldb/').filter(function(item) {
       return item.indexOf('.ldb') > -1;
    });

    if (!fs.existsSync('./fixed')) {
        fs.mkdirSync('./fixed');
    }

    dbs.forEach(function(ldb, idx) {
        levelup('./ldb/' + ldb, {
            createIfMissing: false,
            max_open_files: 500
        }, function(err, db) {
            if (err) return console.log(err);
            var file = fs.createWriteStream('./fixed/' + ldb.split('.ldb')[0]);
            file.once('open', function() {
                db.createReadStream({lt: '0001'})
                    .on('data', function(data) {
                        file.write(key.decompose(data.key).hash + '\n');
                    })
                    .on('end', function(data) {
                        file.end();
                        db.close(function(){
                            if (callback) callback(null);
                        });
                    });
            });
        });
    });
}

module.exports = fixed;

if (require.main === module) { fixed(); }
<|endoftext|>


<commit_before>define(function (require) {
  'use strict';

  var $ = require('jquery'),
    _ = require('underscore'),
    Backbone = require('backbone'),
    React = require('react/addons'),
    SplashScreen = require('components/SplashScreen.react'),
    MaintenanceScreen = require('components/MaintenanceScreen.react'),
    modernizr = require('lib/modernizr-latest.js');

  // Disconnect all Backbone Events from Models and Collections
  Object.keys(Backbone.Events).forEach(function (functionName) {
    Backbone.Model.prototype[functionName] = function () {
    };
    Backbone.Collection.prototype[functionName] = function () {
    };
  });

  //Backbone.Model.prototype.parse = function(resp, options) {
  //  if(resp.id) resp.id = String(resp.id);
  //  return resp;
  //};

  Backbone.Collection.prototype.get = function (obj) {
    if (obj == null) return void 0;
    return _.find(this.models, function (model) {
      return model.id == obj || model.id === obj.id || model.cid === obj.cid;
      //return model.id == String(obj) || model.id === String(obj.id) || model.cid === obj.cid;
    });
  };

  // Register which stores the image should use
  var stores = require('stores');
  stores.AllocationStore = require('stores/AllocationStore');
  stores.BadgeStore = require('stores/BadgeStore');
  stores.ImageStore = require('stores/ImageStore');
  stores.ImageVersionStore = require('stores/ImageVersionStore');
  stores.ImageVersionMembershipStore = require('stores/ImageVersionMembershipStore');
  stores.ImageVersionLicenseStore = require('stores/ImageVersionLicenseStore');
  stores.ImageVersionScriptStore = require('stores/ImageVersionScriptStore');
  stores.IdentityStore = require('stores/IdentityStore');
  stores.ImageBookmarkStore = require('stores/ImageBookmarkStore');
  stores.InstanceHistoryStore = require('stores/InstanceHistoryStore');
  stores.ImageRequestStore = require('stores/ImageRequestStore');
  stores.InstanceStore = require('stores/InstanceStore');
  stores.InstanceTagStore = require('stores/InstanceTagStore');
  stores.LicenseStore = require('stores/LicenseStore');
  stores.ScriptStore = require('stores/ScriptStore');
  stores.MaintenanceMessageStore = require('stores/MaintenanceMessageStore');
  stores.MyBadgeStore = require('stores/MyBadgeStore');
  stores.MembershipStore = require('stores/MembershipStore');
  stores.ProfileStore = require('stores/ProfileStore');
  stores.ProjectStore = require('stores/ProjectStore');
  stores.ProjectInstanceStore = require('stores/ProjectInstanceStore');
  stores.ProjectVolumeStore = require('stores/ProjectVolumeStore');
  stores.ProviderMachineStore = require('stores/ProviderMachineStore');
  stores.ProviderStore = require('stores/ProviderStore');
  stores.ResourceRequestStore = require('stores/ResourceRequestStore');
  stores.StatusStore = require('stores/StatusStore');
  stores.QuotaStore = require('stores/QuotaStore');
  stores.SizeStore = require('stores/SizeStore');
  stores.TagStore = require('stores/TagStore');
  stores.UserStore = require('stores/UserStore');
  stores.VersionStore = require('stores/VersionStore');
  stores.VolumeStore = require('stores/VolumeStore');

  var actions = require('actions');
  actions.BadgeActions = require('actions/BadgeActions');
  actions.HelpActions = require('actions/HelpActions');
  actions.ImageActions = require('actions/ImageActions');
  actions.ImageVersionActions = require('actions/ImageVersionActions');
  actions.ImageVersionMembershipActions = require('actions/ImageVersionMembershipActions');
  actions.ImageVersionLicenseActions = require('actions/ImageVersionLicenseActions');
  actions.ImageVersionScriptActions = require('actions/ImageVersionScriptActions');
  actions.ImageBookmarkActions = require('actions/ImageBookmarkActions');
  actions.InstanceActions = require('actions/InstanceActions');
  actions.InstanceTagActions = require('actions/InstanceTagActions');
  actions.InstanceVolumeActions = require('actions/InstanceVolumeActions');
  //actions.MembershipActions     = require('actions/MembershipActions');
  actions.LicenseActions = require('actions/LicenseActions');
  actions.ScriptActions = require('actions/ScriptActions');
  actions.NullProjectActions = require('actions/NullProjectActions');
  actions.ProfileActions = require('actions/ProfileActions');
  actions.ProjectActions = require('actions/ProjectActions');
  actions.ProviderMachineActions = require('actions/ProviderMachineActions');
  actions.ProjectInstanceActions = require('actions/ProjectInstanceActions');
  actions.ProjectVolumeActions = require('actions/ProjectVolumeActions');
  actions.TagActions = require('actions/TagActions');
  //actions.UserActions             = require('actions/UserActions');
  actions.VolumeActions = require('actions/VolumeActions');

  var modals = require('modals');
  modals.BadgeModals = require('modals/BadgeModals');
  modals.HelpModals = require('modals/HelpModals');
  modals.InstanceModals = require('modals/InstanceModals');
  modals.InstanceVolumeModals = require('modals/InstanceVolumeModals');
  modals.ProjectModals = require('modals/ProjectModals');
  modals.TagModals = require('modals/TagModals');
  modals.VersionModals = require('modals/VersionModals');
  modals.VolumeModals = require('modals/VolumeModals');

  return {
    run: function () {

      // Make sure the Authorization header is added to every AJAX request
      $.ajaxSetup({
        headers: {
          "Authorization": "Token " + window.access_token,
          "Content-Type": "application/json"
        }
      });

      // We're wrapping Backbone.sync so that we can observe every AJAX request.
      // If any request returns a 503 (service unavailable) then we're going to
      // throw up the maintenance splash page. Otherwise, just pass the response
      // up to chain.
      var originalSync = Backbone.sync;
      Backbone.sync = function (attrs, textStatus, xhr) {
        // NOTE: a conceptually simpler solution would be to do this:
        //
        //    var xhr = originalSync.apply(this, arguments).catch(function(response){
        //      if(response.status === 503) {
        //        $('.splash-image').remove();
        //        var MaintenanceComponent = React.createFactory(MaintenanceScreen);
        //        React.render(MaintenanceComponent(), document.getElementById('application'));
        //      }
        //    });
        //
        //    return xhr;
        //
        // However, since we're using jQuery deferred objects for the promise chain, and they
        // don't have a way to cancel promise propagation, we can end up in a scenario where we
        // display a toast with an error on the maintenance splash screen (because other error
        // handlers can still get called).  To get around that, we need to create our own promise
        // and, based on the result of the AJAX request, either manually resolve or reject it.

        var dfd = $.Deferred();

        originalSync.apply(this, arguments).then(function () {
          dfd.resolve.apply(this, arguments);
        }).fail(function (response) {
          if (response.status === 503) {
            // need to make sure we remove the splash-image element is included in the HTML
            // template by default but re-apply the splash screen-class to body so that the
            // splash page displays correctly
            $('.splash-image').remove();
            $('body').addClass('splash-screen');

            // replace the current view with the
            var MaintenanceComponent = React.createFactory(MaintenanceScreen);
            React.render(MaintenanceComponent(), document.getElementById('application'));
          } else {
            dfd.reject.apply(this, arguments);
          }
        });

        return dfd.promise();
      };

      // render the splash page which will load the rest of the application
      $(document).ready(function () {
        var SplashScreenComponent = React.createFactory(SplashScreen);
        React.render(SplashScreenComponent(), document.getElementById('application'));
      });
    }
  }

});
<commit_msg>Altered `access_token` to assure only truthy tokens are included.<commit_after>define(function (require) {
  'use strict';

  var $ = require('jquery'),
    _ = require('underscore'),
    Backbone = require('backbone'),
    React = require('react/addons'),
    SplashScreen = require('components/SplashScreen.react'),
    MaintenanceScreen = require('components/MaintenanceScreen.react'),
    modernizr = require('lib/modernizr-latest.js');

  // Disconnect all Backbone Events from Models and Collections
  Object.keys(Backbone.Events).forEach(function (functionName) {
    Backbone.Model.prototype[functionName] = function () {
    };
    Backbone.Collection.prototype[functionName] = function () {
    };
  });

  //Backbone.Model.prototype.parse = function(resp, options) {
  //  if(resp.id) resp.id = String(resp.id);
  //  return resp;
  //};

  Backbone.Collection.prototype.get = function (obj) {
    if (obj == null) return void 0;
    return _.find(this.models, function (model) {
      return model.id == obj || model.id === obj.id || model.cid === obj.cid;
      //return model.id == String(obj) || model.id === String(obj.id) || model.cid === obj.cid;
    });
  };

  // Register which stores the image should use
  var stores = require('stores');
  stores.AllocationStore = require('stores/AllocationStore');
  stores.BadgeStore = require('stores/BadgeStore');
  stores.ImageStore = require('stores/ImageStore');
  stores.ImageVersionStore = require('stores/ImageVersionStore');
  stores.ImageVersionMembershipStore = require('stores/ImageVersionMembershipStore');
  stores.ImageVersionLicenseStore = require('stores/ImageVersionLicenseStore');
  stores.ImageVersionScriptStore = require('stores/ImageVersionScriptStore');
  stores.IdentityStore = require('stores/IdentityStore');
  stores.ImageBookmarkStore = require('stores/ImageBookmarkStore');
  stores.InstanceHistoryStore = require('stores/InstanceHistoryStore');
  stores.ImageRequestStore = require('stores/ImageRequestStore');
  stores.InstanceStore = require('stores/InstanceStore');
  stores.InstanceTagStore = require('stores/InstanceTagStore');
  stores.LicenseStore = require('stores/LicenseStore');
  stores.ScriptStore = require('stores/ScriptStore');
  stores.MaintenanceMessageStore = require('stores/MaintenanceMessageStore');
  stores.MyBadgeStore = require('stores/MyBadgeStore');
  stores.MembershipStore = require('stores/MembershipStore');
  stores.ProfileStore = require('stores/ProfileStore');
  stores.ProjectStore = require('stores/ProjectStore');
  stores.ProjectInstanceStore = require('stores/ProjectInstanceStore');
  stores.ProjectVolumeStore = require('stores/ProjectVolumeStore');
  stores.ProviderMachineStore = require('stores/ProviderMachineStore');
  stores.ProviderStore = require('stores/ProviderStore');
  stores.ResourceRequestStore = require('stores/ResourceRequestStore');
  stores.StatusStore = require('stores/StatusStore');
  stores.QuotaStore = require('stores/QuotaStore');
  stores.SizeStore = require('stores/SizeStore');
  stores.TagStore = require('stores/TagStore');
  stores.UserStore = require('stores/UserStore');
  stores.VersionStore = require('stores/VersionStore');
  stores.VolumeStore = require('stores/VolumeStore');

  var actions = require('actions');
  actions.BadgeActions = require('actions/BadgeActions');
  actions.HelpActions = require('actions/HelpActions');
  actions.ImageActions = require('actions/ImageActions');
  actions.ImageVersionActions = require('actions/ImageVersionActions');
  actions.ImageVersionMembershipActions = require('actions/ImageVersionMembershipActions');
  actions.ImageVersionLicenseActions = require('actions/ImageVersionLicenseActions');
  actions.ImageVersionScriptActions = require('actions/ImageVersionScriptActions');
  actions.ImageBookmarkActions = require('actions/ImageBookmarkActions');
  actions.InstanceActions = require('actions/InstanceActions');
  actions.InstanceTagActions = require('actions/InstanceTagActions');
  actions.InstanceVolumeActions = require('actions/InstanceVolumeActions');
  //actions.MembershipActions     = require('actions/MembershipActions');
  actions.LicenseActions = require('actions/LicenseActions');
  actions.ScriptActions = require('actions/ScriptActions');
  actions.NullProjectActions = require('actions/NullProjectActions');
  actions.ProfileActions = require('actions/ProfileActions');
  actions.ProjectActions = require('actions/ProjectActions');
  actions.ProviderMachineActions = require('actions/ProviderMachineActions');
  actions.ProjectInstanceActions = require('actions/ProjectInstanceActions');
  actions.ProjectVolumeActions = require('actions/ProjectVolumeActions');
  actions.TagActions = require('actions/TagActions');
  //actions.UserActions             = require('actions/UserActions');
  actions.VolumeActions = require('actions/VolumeActions');

  var modals = require('modals');
  modals.BadgeModals = require('modals/BadgeModals');
  modals.HelpModals = require('modals/HelpModals');
  modals.InstanceModals = require('modals/InstanceModals');
  modals.InstanceVolumeModals = require('modals/InstanceVolumeModals');
  modals.ProjectModals = require('modals/ProjectModals');
  modals.TagModals = require('modals/TagModals');
  modals.VersionModals = require('modals/VersionModals');
  modals.VolumeModals = require('modals/VolumeModals');

  return {
    run: function () {
      let authHeaders = {
          "Content-Type": "application/json"
      }

      // Assure that an auth header is only included when we have
      // an actually `access_token` to provide.
      if (window.access_token) {
        authHeaders["Authorization"] = "Token " + window.access_token;
      }

      // Make sure the Authorization header is added to every AJAX request
      $.ajaxSetup({
        headers: authHeaders
      });

      // We're wrapping Backbone.sync so that we can observe every AJAX request.
      // If any request returns a 503 (service unavailable) then we're going to
      // throw up the maintenance splash page. Otherwise, just pass the response
      // up to chain.
      var originalSync = Backbone.sync;
      Backbone.sync = function (attrs, textStatus, xhr) {
        // NOTE: a conceptually simpler solution would be to do this:
        //
        //    var xhr = originalSync.apply(this, arguments).catch(function(response){
        //      if(response.status === 503) {
        //        $('.splash-image').remove();
        //        var MaintenanceComponent = React.createFactory(MaintenanceScreen);
        //        React.render(MaintenanceComponent(), document.getElementById('application'));
        //      }
        //    });
        //
        //    return xhr;
        //
        // However, since we're using jQuery deferred objects for the promise chain, and they
        // don't have a way to cancel promise propagation, we can end up in a scenario where we
        // display a toast with an error on the maintenance splash screen (because other error
        // handlers can still get called).  To get around that, we need to create our own promise
        // and, based on the result of the AJAX request, either manually resolve or reject it.

        var dfd = $.Deferred();

        originalSync.apply(this, arguments).then(function () {
          dfd.resolve.apply(this, arguments);
        }).fail(function (response) {
          if (response.status === 503) {
            // need to make sure we remove the splash-image element is included in the HTML
            // template by default but re-apply the splash screen-class to body so that the
            // splash page displays correctly
            $('.splash-image').remove();
            $('body').addClass('splash-screen');

            // replace the current view with the
            var MaintenanceComponent = React.createFactory(MaintenanceScreen);
            React.render(MaintenanceComponent(), document.getElementById('application'));
          } else {
            dfd.reject.apply(this, arguments);
          }
        });

        return dfd.promise();
      };

      // render the splash page which will load the rest of the application
      $(document).ready(function () {
        var SplashScreenComponent = React.createFactory(SplashScreen);
        React.render(SplashScreenComponent(), document.getElementById('application'));
      });
    }
  }

});
<|endoftext|>


<commit_before>/*
Copyright 2016 First People's Cultural Council

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { Component, PropTypes } from 'react'
import Immutable, { List, Map } from 'immutable'

import classNames from 'classnames'

import { IconButton, RaisedButton, LinearProgress } from 'material-ui'

import NavigationHelpers from 'common/NavigationHelpers'
import ProviderHelpers from 'common/ProviderHelpers'
import UIHelpers from 'common/UIHelpers'
import StringHelpers from 'common/StringHelpers'

import provide from 'react-redux-provide'
import selectn from 'selectn'
import IntlService from 'views/services/intl'

const intl = IntlService.instance
const containerStyle = {
  background: 'url(/assets/games/fv-games-wordscramble/images/background.png)',
  backgroundSize: 'cover',
  padding: '10px',
  display: 'block',
  border: '3px solid #040000',
  marginBottom: '20px',
  position: 'relative',
  maxWidth: '800px',
  margin: 'auto',
}

class Answer extends React.Component {
  constructor(props) {
    super(props)
  }

  render() {
    const { data, selected, correct, disabled } = this.props

    let backgroundColor = '#fff'
    let labelColor = '#000'

    if (selected) {
      backgroundColor = 'orange'

      if (correct) {
        labelColor = '#fff'
        backgroundColor = 'green'
      }
    }

    return (

        <RaisedButton
          style={{ width: '100%' }}
          labelColor={labelColor}
          disabled={disabled}
          backgroundColor={backgroundColor}
          onClick={this.props.onSelect.bind(this, data, correct)}
          label={data ? selectn('word', data) : 'Loading...'}
        />

    )
  }
}

@provide
export default class Quiz extends Component {
  static propTypes = {
    fetchWords: PropTypes.func.isRequired,
    computeWords: PropTypes.object.isRequired,
    routeParams: PropTypes.object.isRequired,
  }

  constructor(props, context) {
    super(props, context)
    ;['_handleNavigate', '_handleAnswerSelected', '_restart', '_changeContent'].forEach(
      (method) => (this[method] = this[method].bind(this))
    )

    this.state = this.getDefaultState()
  }

  getDefaultState() {
    let totalQuestions = 10

    // Create a random list of numbers to serve as the word order for all answers (correct or wrong)
    const randomizeNumbers = new List([...Array(totalQuestions * 5).keys()]).sortBy(() => Math.random())

    // First 10 of random numbers will be questions
    const questionsOrder = randomizeNumbers.slice(0, totalQuestions)

    return {
      totalQuestions: totalQuestions,
      nowPlaying: null,
      questionsOrder: questionsOrder,
      fillerAnswers: new List(),
      answersOrder: Array.from({ length: totalQuestions }, () => Math.floor(Math.random() * 4)), // For each question determine random position of answer
      selectedAnswers: new Map(),
      currentAnswerIndex: 0,
      attempts: 0,
    }
  }

  componentDidMount() {
    this.fetchData(this.props, 0)
  }

  _changeContent(pageIndex, pageCount) {
    let nextPage = pageIndex + 1

    if (pageIndex == pageCount - 1) {
      nextPage = 0
    }

    this.fetchData(this.props, nextPage)
  }

  fetchData(props, pageIndex, pageSize, sortOrder, sortBy) {
    props.fetchWords(
      props.routeParams.dialect_path + '/Dictionary',
      ' AND fv:available_in_childrens_archive = 1' +
        ' AND ' +
        ProviderHelpers.switchWorkspaceSectionKeys('fv:related_pictures', this.props.routeParams.area) +
        '/* IS NOT NULL' +
        ' AND ' +
        ProviderHelpers.switchWorkspaceSectionKeys('fv:related_audio', this.props.routeParams.area) +
        '/* IS NOT NULL' +
        //' AND fv-word:available_in_games = 1 ' +
        '&currentPageIndex=' +
        pageIndex +
        '&pageSize=50'
    )
  }

  componentWillReceiveProps(nextProps) {
    const prevComputeWords = ProviderHelpers.getEntry(
      this.props.computeWords,
      this.props.routeParams.dialect_path + '/Dictionary'
    )
    const nextComputeWords = ProviderHelpers.getEntry(
      nextProps.computeWords,
      nextProps.routeParams.dialect_path + '/Dictionary'
    )

    if (nextComputeWords && selectn('response', nextComputeWords) != selectn('response', prevComputeWords)) {
      let resultCount = selectn('response.resultsCount', nextComputeWords)

      // Account for results being less than 10
      if (resultCount > 0 && resultCount < 50) {
        const randomizeNumbers = new List([...Array(resultCount).keys()]).sortBy(() => Math.random())

        let totalQuestions = Math.ceil(resultCount / 5)

        this.setState({
          totalQuestions: totalQuestions,
          questionsOrder: randomizeNumbers.slice(0, totalQuestions),
          answersOrder: Array.from({ length: totalQuestions }, () => Math.floor(Math.random() * 4)),
        })
      }
    }
  }

  _restart(e) {
    UIHelpers.stopAudio(
      this.state,
      function(state) {
        this.setState(state)
      }.bind(this),
      e
    )

    this.setState(this.getDefaultState())
    this.fetchData(this.props, 0)
  }

  _handleAnswerSelected(word, correct, e) {
    if (correct) {
      UIHelpers.playAudio(
        this.state,
        function(state) {
          this.setState(state)
        }.bind(this),
        selectn('audio', word),
        e
      )
    }

    this.setState({
      attempts: this.state.attempts + 1,
      selectedAnswers: this.state.selectedAnswers.set(
        this.state.currentAnswerIndex,
        new Map({
          word: word,
          correct: correct,
        })
      ),
    })
  }

  _handleNavigate(direction, e) {
    UIHelpers.stopAudio(
      this.state,
      function(state) {
        this.setState(state)
      }.bind(this),
      e
    )

    let newIndex

    if (direction == 'next') newIndex = this.state.currentAnswerIndex + 1
    else newIndex = this.state.currentAnswerIndex - 1

    if (newIndex <= this.state.totalQuestions - 1 && newIndex >= 0) {
      this.setState({
        currentAnswerIndex: newIndex,
      })
    }
  }

  _normalizeWord(wordObj) {
    return {
      uid: selectn('uid', wordObj),
      word: selectn('properties.dc:title', wordObj),
      translation:
        selectn('properties.fv:literal_translation[0].translation', wordObj) ||
        selectn('properties.fv:definitions[0].translation', wordObj),
      audio:
        NavigationHelpers.getBaseURL() +
        selectn('contextParameters.word.related_audio[0].path', wordObj) +
        '?inline=true',
      image: UIHelpers.getThumbnail(selectn('contextParameters.word.related_pictures[0]', wordObj), 'Medium'),
    }
  }

  render() {
    let selectedAnswer = null
    let questions = new List()
    let fillerAnswers = new List()
    let answers = []

    let isCorrect = false

    // All correct answers
    let correctAnswers = this.state.selectedAnswers.filter((v, k) => v.get('correct'))

    // Answer has been selected
    let isSelected = this.state.selectedAnswers.has(this.state.currentAnswerIndex)

    // Quiz complete
    let isComplete = correctAnswers.count() === this.state.totalQuestions

    const computeEntities = Immutable.fromJS([
      {
        id: this.props.routeParams.dialect_path + '/Dictionary',
        entity: this.props.computeWords,
      },
    ])

    const computeWords = ProviderHelpers.getEntry(
      this.props.computeWords,
      this.props.routeParams.dialect_path + '/Dictionary'
    )

    if (selectn('response.resultsCount', computeWords) < 40) {
      return (

          Game not available: At least 40 child-friendly words with photos and audio are required for this game... Found{' '}
          {selectn('response.resultsCount', computeWords)} words.

      )
    }

    // Seperate all correct answers from all wrong answers
    ;(selectn('response.entries', computeWords) || []).forEach(
      function(v, i) {
        // If word is a correct answer
        if (this.state.questionsOrder.includes(i)) {
          questions = questions.push(this._normalizeWord(v))
        }
        // If word is a wrong answer
        else {
          fillerAnswers = fillerAnswers.push(this._normalizeWord(v))
        }
      }.bind(this)
    )

    // Generate 4 answers
    if (questions.size > 0) {
      for (let i = 0; i < 4; ++i) {
        let answer, isAnswerCorrect, isSelectedAnswer

        // Seperate correct answer from wrong answer
        if (i === this.state.answersOrder[this.state.currentAnswerIndex]) {
          answer = questions.get(this.state.currentAnswerIndex)
          isAnswerCorrect = true
        } else {
          let key = i + this.state.currentAnswerIndex * 3

          if (!fillerAnswers.has(key)) {
            key = i
          }

          answer = fillerAnswers.get(key)
          isAnswerCorrect = false
        }

        // Get current answer if it is selected
        isSelectedAnswer =
          isSelected &&
          selectn('uid', this.state.selectedAnswers.get(this.state.currentAnswerIndex).get('word')) ===
            selectn('uid', answer)

        // Check if current selected answer is correct
        if (isSelectedAnswer) {
          selectedAnswer = answer

          if (isAnswerCorrect) {
            isCorrect = true
          }
        }

        answers.push(
          <Answer
            onSelect={this._handleAnswerSelected}
            selected={isSelectedAnswer}
            key={i + selectn('uid', answer)}
            data={answer}
            correct={isAnswerCorrect}
          />
        )
      }
    }

    // Show skill level message based on attempts.
    let skillLevel = ''

    if (this.state.attempts == this.state.totalQuestions) {
      skillLevel = intl.trans(
        'views.pages.explore.dialect.play.quiz.looks_like_your_an_expert',
        "Looks like you're an expert!"
      )
    } else if (this.state.attempts > this.state.totalQuestions && this.state.attempts < this.state.totalQuestions * 2) {
      skillLevel = intl.trans(
        'views.pages.explore.dialect.play.quiz.on_your_way_to_becoming_an_expert',
        'On your way to becoming an expert!'
      )
    }

    return (

              <LinearProgress
                style={{ height: '15px' }}
                mode="determinate"
                value={((this.state.currentAnswerIndex + 1) / this.state.totalQuestions) * 100}
              />

                {isComplete ? (

                    {intl.trans(
                      'views.pages.explore.dialect.play.quiz.completed_this_quiz',
                      "Nice! You've completed this quiz!"
                    )}{' '}
                    {skillLevel}
                    <RaisedButton
                      onClick={this._restart}
                      label={intl.trans('views.pages.explore.dialect.play.quiz.new_quiz', 'New Quiz', 'words')}
                      style={{ marginLeft: '10px' }}
                    />

                ) : (
                  ''
                )}

                {questions.size > 0 ? (
                  ''
                ) : (

                    Loading...

                )}

            {answers.map((answer, i) => {
              return isCorrect && !answer.props.correct
                ? React.cloneElement(answer, {
                    disabled: true,
                    key: i,
                  })
                : answer
            })}

              <IconButton
                style={{ backgroundColor: '#ffffff' }}
                onClick={this._handleNavigate.bind(this, 'previous')}
                iconClassName="material-icons"
                tooltip={intl.trans(
                  'views.pages.explore.dialect.play.quiz.previous_question',
                  'Previous Question',
                  'words'
                )}
              >
                chevron_left
              </IconButton>

                {isSelected ? (
                  isCorrect ? (

                      {intl.trans('good_job', 'Good Job', 'words')}! {selectn('word', selectedAnswer)}{' '}
                      {intl.trans('translates_to', 'translates to')}
                        {selectn('translation', selectedAnswer)}

                  ) : (
                    intl.trans('try_again', 'Try again', 'first') + '...'
                  )
                ) : (
                  ''
                )}

              <IconButton
                style={{ backgroundColor: '#ffffff' }}
                onClick={this._handleNavigate.bind(this, 'next')}
                disabled={!isCorrect || isComplete}
                iconClassName="material-icons"
                tooltip={intl.trans('views.pages.explore.dialect.play.quiz.next_question', 'Next Question', 'words')}
              >
                chevron_right
              </IconButton>

              {intl.trans('questions', 'Questions', 'first')}: {this.state.currentAnswerIndex + 1} /{' '}
              {this.state.totalQuestions}

    )
  }
}
<commit_msg>Reduxed/Linted: `.../dialect/play/quiz/index.js`<commit_after>/*
Copyright 2016 First People's Cultural Council

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { Component, PropTypes } from 'react'
import { List, Map } from 'immutable'

import classNames from 'classnames'

import { IconButton, RaisedButton, LinearProgress } from 'material-ui'

import NavigationHelpers from 'common/NavigationHelpers'
import ProviderHelpers from 'common/ProviderHelpers'
import UIHelpers from 'common/UIHelpers'

// REDUX
import { connect } from 'react-redux'
// REDUX: actions/dispatch/func
import { fetchWords } from 'providers/redux/reducers/fvWord'

import selectn from 'selectn'
import IntlService from 'views/services/intl'

const intl = IntlService.instance
const containerStyle = {
  background: 'url(/assets/games/fv-games-wordscramble/images/background.png)',
  backgroundSize: 'cover',
  padding: '10px',
  display: 'block',
  border: '3px solid #040000',
  marginBottom: '20px',
  position: 'relative',
  maxWidth: '800px',
  margin: 'auto',
}
const { any, bool, func, object } = PropTypes
class Answer extends React.Component {
  constructor(props) {
    super(props)
  }
  static propTypes = {
    data: any, // TODO: SET CORRECT PROPTYPE
    selected: any, // TODO: SET CORRECT PROPTYPE
    correct: any, // TODO: SET CORRECT PROPTYPE
    disabled: bool,
    onSelect: func,
  }

  render() {
    const { data, selected, correct, disabled } = this.props

    let backgroundColor = '#fff'
    let labelColor = '#000'

    if (selected) {
      backgroundColor = 'orange'

      if (correct) {
        labelColor = '#fff'
        backgroundColor = 'green'
      }
    }

    return (

        <RaisedButton
          style={{ width: '100%' }}
          labelColor={labelColor}
          disabled={disabled}
          backgroundColor={backgroundColor}
          onClick={this.props.onSelect.bind(this, data, correct)}
          label={data ? selectn('word', data) : 'Loading...'}
        />

    )
  }
}

export class Quiz extends Component {
  static propTypes = {
    routeParams: object.isRequired,
    // REDUX: reducers/state
    computeWords: object.isRequired,
    // REDUX: actions/dispatch/func
    fetchWords: func.isRequired,
  }

  constructor(props, context) {
    super(props, context)
    ;['_handleNavigate', '_handleAnswerSelected', '_restart', '_changeContent'].forEach(
      (method) => (this[method] = this[method].bind(this))
    )

    this.state = this.getDefaultState()
  }

  getDefaultState() {
    const totalQuestions = 10

    // Create a random list of numbers to serve as the word order for all answers (correct or wrong)
    const randomizeNumbers = new List([...Array(totalQuestions * 5).keys()]).sortBy(() => Math.random())

    // First 10 of random numbers will be questions
    const questionsOrder = randomizeNumbers.slice(0, totalQuestions)

    return {
      totalQuestions: totalQuestions,
      nowPlaying: null,
      questionsOrder: questionsOrder,
      fillerAnswers: new List(),
      answersOrder: Array.from({ length: totalQuestions }, () => Math.floor(Math.random() * 4)), // For each question determine random position of answer
      selectedAnswers: new Map(),
      currentAnswerIndex: 0,
      attempts: 0,
    }
  }

  componentDidMount() {
    this.fetchData(this.props, 0)
  }

  _changeContent(pageIndex, pageCount) {
    let nextPage = pageIndex + 1

    if (pageIndex === pageCount - 1) {
      nextPage = 0
    }

    this.fetchData(this.props, nextPage)
  }

  fetchData(props, pageIndex /*, pageSize, sortOrder, sortBy*/) {
    props.fetchWords(
      props.routeParams.dialect_path + '/Dictionary',
      ' AND fv:available_in_childrens_archive = 1' +
        ' AND ' +
        ProviderHelpers.switchWorkspaceSectionKeys('fv:related_pictures', this.props.routeParams.area) +
        '/* IS NOT NULL' +
        ' AND ' +
        ProviderHelpers.switchWorkspaceSectionKeys('fv:related_audio', this.props.routeParams.area) +
        '/* IS NOT NULL' +
        //' AND fv-word:available_in_games = 1 ' +
        '&currentPageIndex=' +
        pageIndex +
        '&pageSize=50'
    )
  }

  componentWillReceiveProps(nextProps) {
    const prevComputeWords = ProviderHelpers.getEntry(
      this.props.computeWords,
      this.props.routeParams.dialect_path + '/Dictionary'
    )
    const nextComputeWords = ProviderHelpers.getEntry(
      nextProps.computeWords,
      nextProps.routeParams.dialect_path + '/Dictionary'
    )

    if (nextComputeWords && selectn('response', nextComputeWords) != selectn('response', prevComputeWords)) {
      const resultCount = selectn('response.resultsCount', nextComputeWords)

      // Account for results being less than 10
      if (resultCount > 0 && resultCount < 50) {
        const randomizeNumbers = new List([...Array(resultCount).keys()]).sortBy(() => Math.random())

        const totalQuestions = Math.ceil(resultCount / 5)

        this.setState({
          totalQuestions: totalQuestions,
          questionsOrder: randomizeNumbers.slice(0, totalQuestions),
          answersOrder: Array.from({ length: totalQuestions }, () => Math.floor(Math.random() * 4)),
        })
      }
    }
  }

  _restart(e) {
    UIHelpers.stopAudio(
      this.state,
      function stopAudioState(state) {
        this.setState(state)
      }.bind(this),
      e
    )

    this.setState(this.getDefaultState())
    this.fetchData(this.props, 0)
  }

  _handleAnswerSelected(word, correct, e) {
    if (correct) {
      UIHelpers.playAudio(
        this.state,
        function playAudioState(state) {
          this.setState(state)
        }.bind(this),
        selectn('audio', word),
        e
      )
    }

    this.setState({
      attempts: this.state.attempts + 1,
      selectedAnswers: this.state.selectedAnswers.set(
        this.state.currentAnswerIndex,
        new Map({
          word: word,
          correct: correct,
        })
      ),
    })
  }

  _handleNavigate(direction, e) {
    UIHelpers.stopAudio(
      this.state,
      function stopAudioState(state) {
        this.setState(state)
      }.bind(this),
      e
    )

    let newIndex

    if (direction === 'next') newIndex = this.state.currentAnswerIndex + 1
    else newIndex = this.state.currentAnswerIndex - 1

    if (newIndex <= this.state.totalQuestions - 1 && newIndex >= 0) {
      this.setState({
        currentAnswerIndex: newIndex,
      })
    }
  }

  _normalizeWord(wordObj) {
    return {
      uid: selectn('uid', wordObj),
      word: selectn('properties.dc:title', wordObj),
      translation:
        selectn('properties.fv:literal_translation[0].translation', wordObj) ||
        selectn('properties.fv:definitions[0].translation', wordObj),
      audio:
        NavigationHelpers.getBaseURL() +
        selectn('contextParameters.word.related_audio[0].path', wordObj) +
        '?inline=true',
      image: UIHelpers.getThumbnail(selectn('contextParameters.word.related_pictures[0]', wordObj), 'Medium'),
    }
  }

  render() {
    let selectedAnswer = null
    let questions = new List()
    let fillerAnswers = new List()
    const answers = []

    let isCorrect = false

    // All correct answers
    const correctAnswers = this.state.selectedAnswers.filter((v) => v.get('correct'))

    // Answer has been selected
    const isSelected = this.state.selectedAnswers.has(this.state.currentAnswerIndex)

    // Quiz complete
    const isComplete = correctAnswers.count() === this.state.totalQuestions

    const computeWords = ProviderHelpers.getEntry(
      this.props.computeWords,
      this.props.routeParams.dialect_path + '/Dictionary'
    )

    if (selectn('response.resultsCount', computeWords) < 40) {
      return (

          Game not available: At least 40 child-friendly words with photos and audio are required for this game... Found{' '}
          {selectn('response.resultsCount', computeWords)} words.

      )
    }

    // Seperate all correct answers from all wrong answers
    ;(selectn('response.entries', computeWords) || []).forEach(
      function computeWordForEach(v, i) {
        // If word is a correct answer
        if (this.state.questionsOrder.includes(i)) {
          questions = questions.push(this._normalizeWord(v))
        } else {
          // If word is a wrong answer
          fillerAnswers = fillerAnswers.push(this._normalizeWord(v))
        }
      }.bind(this)
    )

    // Generate 4 answers
    if (questions.size > 0) {
      for (let i = 0; i < 4; ++i) {
        let answer
        let isAnswerCorrect
        let isSelectedAnswer

        // Seperate correct answer from wrong answer
        if (i === this.state.answersOrder[this.state.currentAnswerIndex]) {
          answer = questions.get(this.state.currentAnswerIndex)
          isAnswerCorrect = true
        } else {
          let key = i + this.state.currentAnswerIndex * 3

          if (!fillerAnswers.has(key)) {
            key = i
          }

          answer = fillerAnswers.get(key)
          isAnswerCorrect = false
        }

        // Get current answer if it is selected
        // eslint-disable-next-line
        isSelectedAnswer =
          isSelected &&
          selectn('uid', this.state.selectedAnswers.get(this.state.currentAnswerIndex).get('word')) ===
            selectn('uid', answer)

        // Check if current selected answer is correct
        if (isSelectedAnswer) {
          selectedAnswer = answer

          if (isAnswerCorrect) {
            isCorrect = true
          }
        }

        answers.push(
          <Answer
            onSelect={this._handleAnswerSelected}
            selected={isSelectedAnswer}
            key={i + selectn('uid', answer)}
            data={answer}
            correct={isAnswerCorrect}
          />
        )
      }
    }

    // Show skill level message based on attempts.
    let skillLevel = ''

    if (this.state.attempts == this.state.totalQuestions) {
      skillLevel = intl.trans(
        'views.pages.explore.dialect.play.quiz.looks_like_your_an_expert',
        "Looks like you're an expert!"
      )
    } else if (this.state.attempts > this.state.totalQuestions && this.state.attempts < this.state.totalQuestions * 2) {
      skillLevel = intl.trans(
        'views.pages.explore.dialect.play.quiz.on_your_way_to_becoming_an_expert',
        'On your way to becoming an expert!'
      )
    }
    let feedback = ''
    if (isSelected) {
      feedback = isCorrect ? (

          {intl.trans('good_job', 'Good Job', 'words')}! {selectn('word', selectedAnswer)}{' '}
          {intl.trans('translates_to', 'translates to')}
            {selectn('translation', selectedAnswer)}

      ) : (
        intl.trans('try_again', 'Try again', 'first') + '...'
      )
    }
    return (

              <LinearProgress
                style={{ height: '15px' }}
                mode="determinate"
                value={((this.state.currentAnswerIndex + 1) / this.state.totalQuestions) * 100}
              />

                {isComplete ? (

                    {intl.trans(
                      'views.pages.explore.dialect.play.quiz.completed_this_quiz',
                      "Nice! You've completed this quiz!"
                    )}{' '}
                    {skillLevel}
                    <RaisedButton
                      onClick={this._restart}
                      label={intl.trans('views.pages.explore.dialect.play.quiz.new_quiz', 'New Quiz', 'words')}
                      style={{ marginLeft: '10px' }}
                    />

                ) : (
                  ''
                )}

                {questions.size > 0 ? (
                  ''
                ) : (

                    Loading...

                )}

            {answers.map((answer, i) => {
              return isCorrect && !answer.props.correct
                ? React.cloneElement(answer, {
                    disabled: true,
                    key: i,
                  })
                : answer
            })}

              <IconButton
                style={{ backgroundColor: '#ffffff' }}
                onClick={this._handleNavigate.bind(this, 'previous')}
                iconClassName="material-icons"
                tooltip={intl.trans(
                  'views.pages.explore.dialect.play.quiz.previous_question',
                  'Previous Question',
                  'words'
                )}
              >
                chevron_left
              </IconButton>

                {feedback}

              <IconButton
                style={{ backgroundColor: '#ffffff' }}
                onClick={this._handleNavigate.bind(this, 'next')}
                disabled={!isCorrect || isComplete}
                iconClassName="material-icons"
                tooltip={intl.trans('views.pages.explore.dialect.play.quiz.next_question', 'Next Question', 'words')}
              >
                chevron_right
              </IconButton>

              {intl.trans('questions', 'Questions', 'first')}: {this.state.currentAnswerIndex + 1} /{' '}
              {this.state.totalQuestions}

    )
  }
}

// REDUX: reducers/state
const mapStateToProps = (state /*, ownProps*/) => {
  const { fvWord } = state

  const { computeWords } = fvWord

  return {
    computeWords,
  }
}

// REDUX: actions/dispatch/func
const mapDispatchToProps = {
  fetchWords,
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Quiz)
<|endoftext|>