<commit_before>(function(global, undefined) {

    /**
     * Пространство имён XES
     *
     * @namespace
     * @typedef {Object} XES.Namespace
     * @property {String} $type - тип объекта (Namespace)
     * @property {String} $name - название пространства имён
     * @property {String} $fullName - полное название пространства имён
     * @property {Function} name - создаёт вложенное пространство имён (XES.Namespace)
     * @property {Function} decl - декларирует вложенный класс (XES.Class)
     */

    /**
     * Класс XES
     *
     * @class
     * @typedef {Function} XES.Class
     * @property {String} $type - тип объекта (Class)
     * @property {String} $name - название класса
     * @property {String} $fullName - полное название класса
     * @property {XES.Class} $extends - базовый класс
     * @property {Function} $instance - декларация экземпляра класса
     */

    /**
     * Класс ошибок XES
     *
     * @class
     * @typedef {Function} XES.Error
     * @property {String} name
     * @property {String} message
     * @property {String} stack
     */

    var hasOwn = Object.prototype.hasOwnProperty,
        objCreate = Object.create || function(proto) {
                var inheritance = function () {};
                inheritance.prototype = proto;
                return new inheritance();
            },

        privateStatic = {}, // хранилище приватных статических областей видимости
        namespaceProto = {}, // прототип для пространств имён
        $ = objCreate(namespaceProto); // публичный интерфейс

    /**
     * Вовзращает true, если переданное значение является функцией
     *
     * @private
     * @param {*} value
     * @returns {Boolean}
     */
    function isFunction(value) {
        return typeof value === 'function';
    }

    /**
     * Возвращает true, если переданное значение является объектом
     *
     * @private
     * @param {*} value
     * @returns {Boolean}
     */
    function isObject(value) {
        return Boolean(value) && typeof value === 'object';
    }

    /**
     * Возвращает случайную строку символов
     *
     * @private
     * @returns {String}
     */
    function randomString() {
        return '$' + ((Math.random() + 1) * 5e22).toString(36);
    }

    /**
     * Расширяет объект dest свойствами объекта source
     *
     * @private
     * @param {Object} dest
     * @param {*} source
     */
    function extend(dest, source) {
        if (!isObject(source)) {
            return;
        }

        for (var key in source) {
            if (hasOwn.call(source, key)) {
                dest[key] = source[key];
            }
        }
    }

    /**
     * Находит непереопределённый абстракный метод
     * в инстансе класса
     *
     * @private
     * @param {Object} instance
     * @returns {String|Undefined}
     */
    function findAbstractMethod(instance) {
        for (var key in instance) {
            if (hasOwn.call(instance, key) && (instance[key] === $.Abstract)) {
                return key;
            }
        }

        return undefined;
    }

    /**
     * Создаёт экземпляр класса
     *
     * @private
     * @param {XES.Class|Function} Constructor - конструктор класса
     * @param {Object} [opt] - вспомогательный агрумент для передачи общего публичного интерфейса
     * @returns {Object}
     */
    function create(Constructor, opt) {
        var base, self, pub;

        if (!opt) {
            opt = {
                base: {},
                res: {}
            };
        }

        if (!Constructor) {
            return opt;
        }

        // Если нативный конструктор
        if (!isFunction(Constructor.$instance)) {
            opt.base = new Constructor();
            opt.res = objCreate(opt.base);
            return opt;
        }

        if (Constructor.$extends) {
            opt = create(Constructor.$extends, opt);
        }

        self = objCreate(opt.res);

        base = opt.base;
        opt.base = objCreate(opt.base);

        self.static = privateStatic[Constructor.$fullName];
        pub = Constructor.$instance(self, base);

        extend(opt.res, pub);
        extend(opt.base, pub);

        return opt;
    }

    /**
     * Создаёт конструктор класса
     *
     * @private
     * @returns {XES.Class}
     */
    function createConstructor() {
        return function XES_Class() {
            var res = create(XES_Class).res,
                abstract = findAbstractMethod(res);

            if (abstract) {
                throw new $.Error('Abstract method "' + abstract + '" is not override', XES_Class);
            }

            if (isFunction(res.constructor)) {
                res.constructor.apply(res, arguments);
            }

            res.constructor = XES_Class;

            return res;
        };
    }

    /**
     * Создаёт статическую область видимости класса
     *
     * @private
     * @param {XES.Class} Constructor - конструктор класса
     * @param {Function} st - декларация статической области видимости
     * @returns {Object}
     */
    function createStatic(Constructor, st) {
        var self = privateStatic[Constructor.$fullName] = function() {
                return Constructor.apply(this, arguments);
            },
            pub = {};

        if (isFunction(st)) {
            pub = st(self);
            extend(self, pub);
        }

        return pub;
    }

    /**
     * Возвращает true, если класс Child унаследован от класса Parent
     *
     * @private
     * @param {XES.Class} Child
     * @param {XES.Class} Parent
     * @returns {Boolean}
     */
    function isExtends(Child, Parent) {
        while (Child && Child.$fullName) {
            if (Child.$fullName === Parent.$fullName) {
                return true;
            }

            Child = Child.$extends;
        }

        return false;
    }

    /**
     * Создаёт пространство имён
     *
     * @private
     * @param {XES.Namespace} base - базовое пространство имён
     * @param {String} name - название пространства имён
     * @returns {XES.Namespace}
     */
    function createNamespace(base, name) {
        if (!base || base.$type !== $.TYPES.NAMESPACE) {
            throw new $.Error(base.$fullName + ' is not namespace', namespaceProto.name);
        }

        if (hasOwn.call(base, name)) {
            return base[name];
        }

        var namespace = base[name] = objCreate(namespaceProto),
            fullName = base.$fullName + '.' + name;

        namespace.$name = name;
        namespace.$fullName = fullName;

        return namespace;
    }

    /**
     * Рекурсивно создаёт пространстро имён,
     * разделяя название по точкам
     *
     * @private
     * @param {XES.Namespace} base - базовое пространство имён
     * @param {String} name - название пространства имён
     * @returns {XES.Namespace}
     */
    function createNamespaceRecursive(base, name) {
        var names = name.split('.'), i;

        for (i = 0; i < names.length; i++) {
            base = createNamespace(base, names[i]);
        }

        return base;
    }

    /**
     * Публикует библиотеку
     *
     * @private
     * @param {Object} XES
     */
    function publish(XES) {
        if (isObject(exports)) {
            module.exports = XES;
            return;
        }

        if (isObject(modules) && isFunction(modules.define)) {
            modules.define('XES', function(provide) {
                provide(XES);
            });

            return;
        }

        if (isFunction(define)) {
            define(function(require, exports, module) {
                module.exports = XES;
            });

            return;
        }

        global.XES = XES;
    }

    /**
     * Список типов, реализованных в XES
     *
     * @public
     * @type {{NAMESPACE: string, CLASS: string}}
     * @memberOf XES
     */
    $.TYPES = {
        NAMESPACE: 'Namespace',
        CLASS: 'Class'
    };

    /**
     * Идентификатор абстракного метода
     *
     * @public
     * @type {String}
     * @memberOf XES
     */
    $.Abstract = randomString();

    /**
     * @public
     * @type {string}
     * @memberOf XES
     */
    $.$fullName = 'XES';

    /**
     * Возвращает true, если obj унаследован от Constructor
     *
     * @public
     * @memberOf XES
     * @param {*} obj
     * @param {*} Constructor
     * @returns {Boolean}
     */
    $.is = function(obj, Constructor) {
        if (obj instanceof Constructor) {
            return true;
        }

        if (!obj || !obj.constructor || obj.constructor.$type !== $.TYPES.CLASS) {
            return false;
        }

        if (!Constructor || Constructor.$type !== $.TYPES.CLASS) {
            return false;
        }

        return isExtends(obj.constructor, Constructor);
    };

    /**
     * Класс ошибок XES
     *
     * @public
     * @type {XES.Error}
     * @param {String} message - текст ошибки
     * @param {Function} func - функция, до которой собирается стек ошибок
     * @constructor
     * @memberOf XES
     */
    $.Error = function XES_Error(message, func) {
        this.name = 'XES.Error';
        this.message = message || '';

        if (Error.captureStackTrace) {
            Error.captureStackTrace(this, func);
        } else {
            this.stack = (new Error()).stack;
        }
    };

    $.Error.prototype = Error.prototype;

    /**
     * @public
     * @memberOf XES
     * @type {string}
     */
    namespaceProto.$type = $.TYPES.NAMESPACE;

    /**
     * Создает новое пространство имён
     *
     * @public
     * @memberOf XES
     * @param {String} name - название пространста имён
     * @returns {XES.Namespace}
     */
    namespaceProto.name = function(name) {
        return createNamespaceRecursive(this, name);
    };

    /**
     * Декларирует новый класс
     *
     * @public
     * @memberOf XES
     * @param {String} name - имя класса
     * @param {Object} body - тело класса
     * @returns {XES.Class}
     */
    namespaceProto.decl = function(name, body) {
        if (!this || this.$type !== $.TYPES.NAMESPACE) {
            throw new $.Error(this.$fullName + ' is not namespace', namespaceProto.decl);
        }

        var fullName = this.$fullName + '.' + name;

        if (hasOwn.call(this, name)) {
            throw new $.Error(fullName + ' is exist', namespaceProto.decl);
        }

        var Constructor = this[name] = createConstructor();

        Constructor.$name = name;
        Constructor.$fullName = fullName;
        Constructor.$type = $.TYPES.CLASS;

        body = body || {};

        Constructor.$extends = body.extends;
        Constructor.$instance = body.instance || (function() {});

        extend(Constructor, createStatic(Constructor, body.static));

        return Constructor;
    };

    // Публикуем библиотеку
    publish($);
})(this);<commit_msg>optimize randomString<commit_after>(function(global, undefined) {

    /**
     * Пространство имён XES
     *
     * @namespace
     * @typedef {Object} XES.Namespace
     * @property {String} $type - тип объекта (Namespace)
     * @property {String} $name - название пространства имён
     * @property {String} $fullName - полное название пространства имён
     * @property {Function} name - создаёт вложенное пространство имён (XES.Namespace)
     * @property {Function} decl - декларирует вложенный класс (XES.Class)
     */

    /**
     * Класс XES
     *
     * @class
     * @typedef {Function} XES.Class
     * @property {String} $type - тип объекта (Class)
     * @property {String} $name - название класса
     * @property {String} $fullName - полное название класса
     * @property {XES.Class} $extends - базовый класс
     * @property {Function} $instance - декларация экземпляра класса
     */

    /**
     * Класс ошибок XES
     *
     * @class
     * @typedef {Function} XES.Error
     * @property {String} name
     * @property {String} message
     * @property {String} stack
     */

    var hasOwn = Object.prototype.hasOwnProperty,
        objCreate = Object.create || function(proto) {
                var inheritance = function () {};
                inheritance.prototype = proto;
                return new inheritance();
            },

        privateStatic = {}, // хранилище приватных статических областей видимости
        namespaceProto = {}, // прототип для пространств имён
        $ = objCreate(namespaceProto); // публичный интерфейс

    /**
     * Вовзращает true, если переданное значение является функцией
     *
     * @private
     * @param {*} value
     * @returns {Boolean}
     */
    function isFunction(value) {
        return typeof value === 'function';
    }

    /**
     * Возвращает true, если переданное значение является объектом
     *
     * @private
     * @param {*} value
     * @returns {Boolean}
     */
    function isObject(value) {
        return Boolean(value) && typeof value === 'object';
    }

    /**
     * Возвращает случайную строку символов
     *
     * @private
     * @returns {String}
     */
    function randomString() {
        var res = '', i;

        for (i = 0; i < 4; i++) {
            res += (((Math.random() + 1) * 5e7)^0).toString(36);
        }

        return res;
    }

    /**
     * Расширяет объект dest свойствами объекта source
     *
     * @private
     * @param {Object} dest
     * @param {*} source
     */
    function extend(dest, source) {
        if (!isObject(source)) {
            return;
        }

        for (var key in source) {
            if (hasOwn.call(source, key)) {
                dest[key] = source[key];
            }
        }
    }

    /**
     * Находит непереопределённый абстракный метод
     * в инстансе класса
     *
     * @private
     * @param {Object} instance
     * @returns {String|Undefined}
     */
    function findAbstractMethod(instance) {
        for (var key in instance) {
            if (hasOwn.call(instance, key) && (instance[key] === $.Abstract)) {
                return key;
            }
        }

        return undefined;
    }

    /**
     * Создаёт экземпляр класса
     *
     * @private
     * @param {XES.Class|Function} Constructor - конструктор класса
     * @param {Object} [opt] - вспомогательный агрумент для передачи общего публичного интерфейса
     * @returns {Object}
     */
    function create(Constructor, opt) {
        var base, self, pub;

        if (!opt) {
            opt = {
                base: {},
                res: {}
            };
        }

        if (!Constructor) {
            return opt;
        }

        // Если нативный конструктор
        if (!isFunction(Constructor.$instance)) {
            opt.base = new Constructor();
            opt.res = objCreate(opt.base);
            return opt;
        }

        if (Constructor.$extends) {
            opt = create(Constructor.$extends, opt);
        }

        self = objCreate(opt.res);

        base = opt.base;
        opt.base = objCreate(opt.base);

        self.static = privateStatic[Constructor.$fullName];
        pub = Constructor.$instance(self, base);

        extend(opt.res, pub);
        extend(opt.base, pub);

        return opt;
    }

    /**
     * Создаёт конструктор класса
     *
     * @private
     * @returns {XES.Class}
     */
    function createConstructor() {
        return function XES_Class() {
            var res = create(XES_Class).res,
                abstract = findAbstractMethod(res);

            if (abstract) {
                throw new $.Error('Abstract method "' + abstract + '" is not override', XES_Class);
            }

            if (isFunction(res.constructor)) {
                res.constructor.apply(res, arguments);
            }

            res.constructor = XES_Class;

            return res;
        };
    }

    /**
     * Создаёт статическую область видимости класса
     *
     * @private
     * @param {XES.Class} Constructor - конструктор класса
     * @param {Function} st - декларация статической области видимости
     * @returns {Object}
     */
    function createStatic(Constructor, st) {
        var self = privateStatic[Constructor.$fullName] = function() {
                return Constructor.apply(this, arguments);
            },
            pub = {};

        if (isFunction(st)) {
            pub = st(self);
            extend(self, pub);
        }

        return pub;
    }

    /**
     * Возвращает true, если класс Child унаследован от класса Parent
     *
     * @private
     * @param {XES.Class} Child
     * @param {XES.Class} Parent
     * @returns {Boolean}
     */
    function isExtends(Child, Parent) {
        while (Child && Child.$fullName) {
            if (Child.$fullName === Parent.$fullName) {
                return true;
            }

            Child = Child.$extends;
        }

        return false;
    }

    /**
     * Создаёт пространство имён
     *
     * @private
     * @param {XES.Namespace} base - базовое пространство имён
     * @param {String} name - название пространства имён
     * @returns {XES.Namespace}
     */
    function createNamespace(base, name) {
        if (!base || base.$type !== $.TYPES.NAMESPACE) {
            throw new $.Error(base.$fullName + ' is not namespace', namespaceProto.name);
        }

        if (hasOwn.call(base, name)) {
            return base[name];
        }

        var namespace = base[name] = objCreate(namespaceProto),
            fullName = base.$fullName + '.' + name;

        namespace.$name = name;
        namespace.$fullName = fullName;

        return namespace;
    }

    /**
     * Рекурсивно создаёт пространстро имён,
     * разделяя название по точкам
     *
     * @private
     * @param {XES.Namespace} base - базовое пространство имён
     * @param {String} name - название пространства имён
     * @returns {XES.Namespace}
     */
    function createNamespaceRecursive(base, name) {
        var names = name.split('.'), i;

        for (i = 0; i < names.length; i++) {
            base = createNamespace(base, names[i]);
        }

        return base;
    }

    /**
     * Публикует библиотеку
     *
     * @private
     * @param {Object} XES
     */
    function publish(XES) {
        if (isObject(exports)) {
            module.exports = XES;
            return;
        }

        if (isObject(modules) && isFunction(modules.define)) {
            modules.define('XES', function(provide) {
                provide(XES);
            });

            return;
        }

        if (isFunction(define)) {
            define(function(require, exports, module) {
                module.exports = XES;
            });

            return;
        }

        global.XES = XES;
    }

    /**
     * Список типов, реализованных в XES
     *
     * @public
     * @type {{NAMESPACE: string, CLASS: string}}
     * @memberOf XES
     */
    $.TYPES = {
        NAMESPACE: 'Namespace',
        CLASS: 'Class'
    };

    /**
     * Идентификатор абстракного метода
     *
     * @public
     * @type {String}
     * @memberOf XES
     */
    $.Abstract = randomString();

    /**
     * @public
     * @type {string}
     * @memberOf XES
     */
    $.$fullName = 'XES';

    /**
     * Возвращает true, если obj унаследован от Constructor
     *
     * @public
     * @memberOf XES
     * @param {*} obj
     * @param {*} Constructor
     * @returns {Boolean}
     */
    $.is = function(obj, Constructor) {
        if (obj instanceof Constructor) {
            return true;
        }

        if (!obj || !obj.constructor || obj.constructor.$type !== $.TYPES.CLASS) {
            return false;
        }

        if (!Constructor || Constructor.$type !== $.TYPES.CLASS) {
            return false;
        }

        return isExtends(obj.constructor, Constructor);
    };

    /**
     * Класс ошибок XES
     *
     * @public
     * @type {XES.Error}
     * @param {String} message - текст ошибки
     * @param {Function} func - функция, до которой собирается стек ошибок
     * @constructor
     * @memberOf XES
     */
    $.Error = function XES_Error(message, func) {
        this.name = 'XES.Error';
        this.message = message || '';

        if (Error.captureStackTrace) {
            Error.captureStackTrace(this, func);
        } else {
            this.stack = (new Error()).stack;
        }
    };

    $.Error.prototype = Error.prototype;

    /**
     * @public
     * @memberOf XES
     * @type {string}
     */
    namespaceProto.$type = $.TYPES.NAMESPACE;

    /**
     * Создает новое пространство имён
     *
     * @public
     * @memberOf XES
     * @param {String} name - название пространста имён
     * @returns {XES.Namespace}
     */
    namespaceProto.name = function(name) {
        return createNamespaceRecursive(this, name);
    };

    /**
     * Декларирует новый класс
     *
     * @public
     * @memberOf XES
     * @param {String} name - имя класса
     * @param {Object} body - тело класса
     * @returns {XES.Class}
     */
    namespaceProto.decl = function(name, body) {
        if (!this || this.$type !== $.TYPES.NAMESPACE) {
            throw new $.Error(this.$fullName + ' is not namespace', namespaceProto.decl);
        }

        var fullName = this.$fullName + '.' + name;

        if (hasOwn.call(this, name)) {
            throw new $.Error(fullName + ' is exist', namespaceProto.decl);
        }

        var Constructor = this[name] = createConstructor();

        Constructor.$name = name;
        Constructor.$fullName = fullName;
        Constructor.$type = $.TYPES.CLASS;

        body = body || {};

        Constructor.$extends = body.extends;
        Constructor.$instance = body.instance || (function() {});

        extend(Constructor, createStatic(Constructor, body.static));

        return Constructor;
    };

    // Публикуем библиотеку
    publish($);
})(this);<|endoftext|>


<commit_before>const expect = require('chai').expect

const mergeClaimExpensesWithSubmittedResponses = require('../../../../app/routes/helpers/merge-claim-expenses-with-submitted-responses')

describe('routes/helpers/get-claim-expense-non-persisted-details', function () {
  it('should return an array of claim expenses', function (done) {
    var oldData = [
      {
        ClaimExpenseId: 1,
        status: undefined,
        cost: '19.20'
      },
      {
        ClaimExpenseId: 2,
        status: undefined,
        cost: '20.00'
      },
      {
        ClaimExpenseId: 3,
        status: undefined,
        cost: '2.00'
      }]

    var newData = [
      {
        claimExpenseId: 1,
        status: 'APPROVED'
      },
      {
        claimExpenseId: 2,
        status: 'APPROVED-DIFF-AMOUNT',
        approvedCost: '2.10'
      },
      {
        claimExpenseId: 3,
        status: 'APPROVED-DIFF-AMOUNT',
        approvedCost: ''
      }]

    var nonPersistedExpenseData = mergeClaimExpensesWithSubmittedResponses(oldData, newData)

    expect(nonPersistedExpenseData[0].ClaimExpenseId).to.equal(1)

    expect(nonPersistedExpenseData[1].ClaimExpenseId).to.equal(2)
    expect(nonPersistedExpenseData[1].ApprovedCost).to.equal('2.10')

    expect(nonPersistedExpenseData[2].ClaimExpenseId).to.equal(3)
    expect(nonPersistedExpenseData[2].ApprovedCost).to.equal('')
    expect(nonPersistedExpenseData[2].Error).to.equal(true)

    done()
  })
})
<commit_msg>Added more tests for helper<commit_after>const expect = require('chai').expect
const mergeClaimExpensesWithSubmittedResponses = require('../../../../app/routes/helpers/merge-claim-expenses-with-submitted-responses')
var oldData
var newData

describe('routes/helpers/get-claim-expense-non-persisted-details', function () {
  before(function (done) {
    oldData = [
      {
        ClaimExpenseId: 1,
        status: undefined,
        cost: '19.20'
      },
      {
        ClaimExpenseId: 2,
        status: undefined,
        cost: '20.00'
      },
      {
        ClaimExpenseId: 3,
        status: undefined,
        cost: '2.00'
      }]

    newData = [
      {
        claimExpenseId: 1,
        status: 'APPROVED'
      },
      {
        claimExpenseId: 2,
        status: 'APPROVED-DIFF-AMOUNT',
        approvedCost: '2.10'
      },
      {
        claimExpenseId: 3,
        status: 'APPROVED-DIFF-AMOUNT',
        approvedCost: ''
      }]
    done()
  })

  it('should return an array of claim expenses', function (done) {
    var nonPersistedExpenseData = mergeClaimExpensesWithSubmittedResponses(oldData, newData)
    expect(nonPersistedExpenseData[0].ClaimExpenseId).to.equal(1)
    expect(nonPersistedExpenseData[1].ClaimExpenseId).to.equal(2)
    expect(nonPersistedExpenseData[2].ClaimExpenseId).to.equal(3)
    done()
  })
  it('should set the status of each element in array', function (done) {
    var nonPersistedExpenseData = mergeClaimExpensesWithSubmittedResponses(oldData, newData)
    expect(nonPersistedExpenseData[0].Status).to.equal(newData[0].status)
    expect(nonPersistedExpenseData[1].Status).to.equal(newData[1].status)
    expect(nonPersistedExpenseData[2].Status).to.equal(newData[2].status)
    done()
  })
  it('should set the approvedCost of each element in array', function (done) {
    var nonPersistedExpenseData = mergeClaimExpensesWithSubmittedResponses(oldData, newData)
    expect(nonPersistedExpenseData[0].ApprovedCost).to.equal(newData[0].approvedCost)
    expect(nonPersistedExpenseData[1].ApprovedCost).to.equal(newData[1].approvedCost)
    expect(nonPersistedExpenseData[2].ApprovedCost).to.equal(newData[2].approvedCost)
    done()
  })

  it('should set Error in only those who have incorrect data', function (done) {
    var nonPersistedExpenseData = mergeClaimExpensesWithSubmittedResponses(oldData, newData)
    expect(nonPersistedExpenseData[0].Error).to.equal(undefined)
    expect(nonPersistedExpenseData[1].Error).to.equal(undefined)
    expect(nonPersistedExpenseData[2].Error).to.equal(true)
    done()
  })
})
<|endoftext|>


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

'use strict';

var through = require('through');
var when = require('when');
var Spec = require('../lib/reporters/spec');
var suiteRunner = require('../lib/suite_runner');
var OnMessage = require('./util/on_message');
var streamUtil = require('./util/stream');

function simulateOneTest(spec) {
  var path = { file: 'file', path: ['suite_name', 'test'] };

  spec.registerTests([path], { slowThreshold: 100 }, new Date());
  spec.gotMessage(path, { type: 'start' });
  spec.gotMessage(path, {
    type: 'finish',
    result: 'success',
    slow: true,
    duration: 123
  });
  spec.done(new Date());
}

function simulateAndWaitForLine(simulate, line) {
  var out = streamUtil.stripAnsiStream();

  var outputPromise = streamUtil.waitForStreamToEmitLine(out, line);

  var spec = new Spec({ stdout: out });
  simulate(spec);

  out.end();

  return outputPromise;
}

function simulateOneTestAndWaitForLine(line) {
  return simulateAndWaitForLine(simulateOneTest, line);
}

describe('Spec reporter', function() {
  it('should pipe test output', function() {
    var test = through();
    var out = through();

    var outputPromise = streamUtil.waitForStreamToEmitLines(out, [
      /Hello/
    ]);

    var spec = new Spec({ stdout: out });
    spec.gotMessage({ file: 'file', path: ['test'] }, {
      type: 'stdio',
      stdout: test
    });

    out.write('Hello\n');
    out.end();

    return outputPromise;
  });

  it('should mark slow tests', function() {
    return simulateOneTestAndWaitForLine(/\(123ms\)/);
  });

  it('should mark suites', function() {
    return simulateOneTestAndWaitForLine(/suite_name/);
  });

  it('should emit a summary', function() {
    return simulateOneTestAndWaitForLine(/1 passing/);
  });

  it('should print details about errors', function() {
    return simulateAndWaitForLine(function simulateFailingTest(spec) {
      var path = { file: 'file', path: ['suite_name', 'test'] };

      spec.registerTests([path], { slowThreshold: 100 }, new Date());
      spec.gotMessage(path, { type: 'start' });
      spec.gotMessage(path, {
        type: 'error',
        in: 'uncaught',
        stack: 'an_error'
      });
      spec.gotMessage(path, {
        type: 'finish',
        result: 'failure'
      });
      spec.done(new Date());
    }, /Uncaught error: an_error/);
  });

  it('should print to stdout by default', function() {
    var outputDeferred = when.defer();

    // This test can't be done within the test process, because when the test
    // runs in Mocha it's not ok to pipe stdout to something else.
    var suitePromise = suiteRunner({
      files: [__dirname + '/suite/' + 'suite_spec_should_print_to_stdout_by_default'],
      timeout: 500,
      reporters: new OnMessage(function(path, message) {
        if (message.type !== 'stdio') {
          return;
        }

        streamUtil.waitForStreamToEmitLines(message.stdout, [
          /./,
          /suite_name/,
          /test/
        ]).done(outputDeferred.resolve, outputDeferred.reject);
      }),
      internalErrorOutput: through(),
    });

    return when.all([suitePromise, outputDeferred.promise]);
  });
});
<commit_msg>Use the stdio message less in test_spec.js<commit_after>/*
 * Copyright 2014 Per Eckerdal
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

var through = require('through');
var when = require('when');
var Spec = require('../lib/reporters/spec');
var suiteRunner = require('../lib/suite_runner');
var OnMessage = require('./util/on_message');
var streamUtil = require('./util/stream');

function simulateOneTest(spec) {
  var path = { file: 'file', path: ['suite_name', 'test'] };

  spec.registerTests([path], { slowThreshold: 100 }, new Date());
  spec.gotMessage(path, { type: 'start' });
  spec.gotMessage(path, {
    type: 'finish',
    result: 'success',
    slow: true,
    duration: 123
  });
  spec.done(new Date());
}

function simulateAndWaitForLine(simulate, line) {
  var out = streamUtil.stripAnsiStream();

  var outputPromise = streamUtil.waitForStreamToEmitLine(out, line);

  var spec = new Spec({ stdout: out });
  simulate(spec);

  out.end();

  return outputPromise;
}

function simulateOneTestAndWaitForLine(line) {
  return simulateAndWaitForLine(simulateOneTest, line);
}

describe('Spec reporter', function() {
  it('should pipe test output', function() {
    var test = through();
    var out = through();

    var outputPromise = streamUtil.waitForStreamToEmitLines(out, [
      /Hello/
    ]);

    var spec = new Spec({ stdout: out });
    spec.gotMessage({ file: 'file', path: ['test'] }, {
      type: 'stdio',
      stdout: test
    });

    out.write('Hello\n');
    out.end();

    return outputPromise;
  });

  it('should mark slow tests', function() {
    return simulateOneTestAndWaitForLine(/\(123ms\)/);
  });

  it('should mark suites', function() {
    return simulateOneTestAndWaitForLine(/suite_name/);
  });

  it('should emit a summary', function() {
    return simulateOneTestAndWaitForLine(/1 passing/);
  });

  it('should print details about errors', function() {
    return simulateAndWaitForLine(function simulateFailingTest(spec) {
      var path = { file: 'file', path: ['suite_name', 'test'] };

      spec.registerTests([path], { slowThreshold: 100 }, new Date());
      spec.gotMessage(path, { type: 'start' });
      spec.gotMessage(path, {
        type: 'error',
        in: 'uncaught',
        stack: 'an_error'
      });
      spec.gotMessage(path, {
        type: 'finish',
        result: 'failure'
      });
      spec.done(new Date());
    }, /Uncaught error: an_error/);
  });

  it('should print to stdout by default', function() {
    var out = through();
    var outputPromise = streamUtil.waitForStreamToEmitLines(out, [
      /./,
      /suite_name/,
      /test/
    ]);

    // This test can't be done within the test process, because when the test
    // runs in Mocha it's not ok to pipe stdout to something else.
    var suitePromise = suiteRunner({
      files: [__dirname + '/suite/' + 'suite_spec_should_print_to_stdout_by_default'],
      timeout: 500,
      reporters: new OnMessage(function(path, message) {
        if (message.type === 'finish') {
          out.end();
        } else if (message.type === 'stdout') {
          out.write(message.data);
        }
      }),
      internalErrorOutput: through(),
    });

    return when.all([suitePromise, outputPromise]);
  });
});
<|endoftext|>


<commit_before>// Tom Robinson
// Kris Kowal

var INFLATE = require("./inflate");
var Buffer = require("buffer").Buffer;

var LOCAL_FILE_HEADER = 0x04034b50;
var CENTRAL_DIRECTORY_FILE_HEADER = 0x02014b50;
var END_OF_CENTRAL_DIRECTORY_RECORD = 0x06054b50;

var Reader = exports.Reader = function (data) {
    if (!(this instanceof Reader))
        return new Reader(data);
    this._data = data;
    this._offset = 0;
}

Reader.prototype.length = function () {
    return this._data.length;
}

Reader.prototype.position = function () {
    return this._offset;
}

Reader.prototype.seek = function (offset) {
    this._offset = offset;
}

Reader.prototype.read = function (length) {
    var bytes = this._data.slice(this._offset, this._offset+length);
    this._offset += length;
    return bytes;
}

Reader.prototype.readInteger = function (length, bigEndian) {
    if (bigEndian)
        return bytesToNumberBE(this.read(length));
    else
        return bytesToNumberLE(this.read(length));
}

Reader.prototype.readString = function (length, charset) {
    return this.read(length).toString(charset || "UTF-8");
}

Reader.prototype.readUncompressed = function (length, method) {
    var compressed = this.read(length);
    var uncompressed = null;
    if (method === 0)
        uncompressed = compressed;
    else if (method === 8)
        uncompressed = INFLATE.inflate(compressed);
    else
        throw new Error("Unknown compression method: " + structure.compression_method);
    return uncompressed;
}

Reader.prototype.readStructure = function () {
    var stream = this;
    var structure = {};

    // local file header signature     4 bytes  (0x04034b50)
    structure.signature = stream.readInteger(4);

    switch (structure.signature) {
        case LOCAL_FILE_HEADER :
            this.readLocalFileHeader(structure);
            break;
        case CENTRAL_DIRECTORY_FILE_HEADER :
            this.readCentralDirectoryFileHeader(structure);
            break;
        case END_OF_CENTRAL_DIRECTORY_RECORD :
            this.readEndOfCentralDirectoryRecord(structure);
            break;
        default:
            throw new Error("Unknown ZIP structure signature: 0x" + structure.signature.toString(16));
    }

    return structure;
}

// ZIP local file header
// Offset   Bytes   Description
// 0        4       Local file header signature = 0x04034b50
// 4        2       Version needed to extract (minimum)
// 6        2       General purpose bit flag
// 8        2       Compression method
// 10       2       File last modification time
// 12       2       File last modification date
// 14       4       CRC-32
// 18       4       Compressed size
// 22       4       Uncompressed size
// 26       2       File name length (n)
// 28       2       Extra field length (m)
// 30       n       File name
// 30+n     m       Extra field
Reader.prototype.readLocalFileHeader = function (structure) {
    var stream = this;
    structure = structure || {};

    if (!structure.signature)
        structure.signature = stream.readInteger(4);    // Local file header signature = 0x04034b50

    if (structure.signature !== LOCAL_FILE_HEADER)
        throw new Error("ZIP local file header signature invalid (expects 0x04034b50, actually 0x" + structure.signature.toString(16) +")");

    structure.version_needed       = stream.readInteger(2);    // Version needed to extract (minimum)
    structure.flags                = stream.readInteger(2);    // General purpose bit flag
    structure.compression_method   = stream.readInteger(2);    // Compression method
    structure.last_mod_file_time   = stream.readInteger(2);    // File last modification time
    structure.last_mod_file_date   = stream.readInteger(2);    // File last modification date
    structure.crc_32               = stream.readInteger(4);    // CRC-32
    structure.compressed_size      = stream.readInteger(4);    // Compressed size
    structure.uncompressed_size    = stream.readInteger(4);    // Uncompressed size
    structure.file_name_length     = stream.readInteger(2);    // File name length (n)
    structure.extra_field_length   = stream.readInteger(2);    // Extra field length (m)

    var n = structure.file_name_length;
    var m = structure.extra_field_length;

    structure.file_name            = stream.readString(n);     // File name
    structure.extra_field          = stream.read(m);           // Extra fieldFile name

    return structure;
}

// ZIP central directory file header
// Offset   Bytes   Description
// 0        4       Central directory file header signature = 0x02014b50
// 4        2       Version made by
// 6        2       Version needed to extract (minimum)
// 8        2       General purpose bit flag
// 10       2       Compression method
// 12       2       File last modification time
// 14       2       File last modification date
// 16       4       CRC-32
// 20       4       Compressed size
// 24       4       Uncompressed size
// 28       2       File name length (n)
// 30       2       Extra field length (m)
// 32       2       File comment length (k)
// 34       2       Disk number where file starts
// 36       2       Internal file attributes
// 38       4       External file attributes
// 42       4       Relative offset of local file header
// 46       n       File name
// 46+n     m       Extra field
// 46+n+m   k       File comment
Reader.prototype.readCentralDirectoryFileHeader = function (structure) {
    var stream = this;
    structure = structure || {};

    if (!structure.signature)
        structure.signature = stream.readInteger(4); // Central directory file header signature = 0x02014b50

    if (structure.signature !== CENTRAL_DIRECTORY_FILE_HEADER)
        throw new Error("ZIP central directory file header signature invalid (expects 0x04034b50, actually 0x" + structure.signature.toString(16) +")");

    structure.version                   = stream.readInteger(2);    // Version made by
    structure.version_needed            = stream.readInteger(2);    // Version needed to extract (minimum)
    structure.flags                     = stream.readInteger(2);    // General purpose bit flag
    structure.compression_method        = stream.readInteger(2);    // Compression method
    structure.last_mod_file_time        = stream.readInteger(2);    // File last modification time
    structure.last_mod_file_date        = stream.readInteger(2);    // File last modification date
    structure.crc_32                    = stream.readInteger(4);    // CRC-32
    structure.compressed_size           = stream.readInteger(4);    // Compressed size
    structure.uncompressed_size         = stream.readInteger(4);    // Uncompressed size
    structure.file_name_length          = stream.readInteger(2);    // File name length (n)
    structure.extra_field_length        = stream.readInteger(2);    // Extra field length (m)
    structure.file_comment_length       = stream.readInteger(2);    // File comment length (k)
    structure.disk_number               = stream.readInteger(2);    // Disk number where file starts
    structure.internal_file_attributes  = stream.readInteger(2);    // Internal file attributes
    structure.external_file_attributes  = stream.readInteger(4);    // External file attributes
    structure.local_file_header_offset  = stream.readInteger(4);    // Relative offset of local file header

    var n = structure.file_name_length;
    var m = structure.extra_field_length;
    var k = structure.file_comment_length;

    structure.file_name                 = stream.readString(n);     // File name
    structure.extra_field               = stream.read(m);           // Extra field
    structure.file_comment              = stream.readString(k);     // File comment

    return structure;
}

// finds the end of central directory record
// I'd like to slap whoever thought it was a good idea to put a variable length comment field here
Reader.prototype.locateEndOfCentralDirectoryRecord = function () {
    var length = this.length();
    var minPosition = length - Math.pow(2, 16) - 22;

    var position = length - 22 + 1;
    while (--position) {
        if (position < minPosition)
            throw new Error("Unable to find end of central directory record");

        this.seek(position);
        var possibleSignature = this.readInteger(4);
        if (possibleSignature !== END_OF_CENTRAL_DIRECTORY_RECORD)
            continue;

        this.seek(position + 20);
        var possibleFileCommentLength = this.readInteger(2);
        if (position + 22 + possibleFileCommentLength === length)
            break;
    }

    this.seek(position);
    return position;
};

// ZIP end of central directory record
// Offset   Bytes   Description
// 0        4       End of central directory signature = 0x06054b50
// 4        2       Number of this disk
// 6        2       Disk where central directory starts
// 8        2       Number of central directory records on this disk
// 10       2       Total number of central directory records
// 12       4       Size of central directory (bytes)
// 16       4       Offset of start of central directory, relative to start of archive
// 20       2       ZIP file comment length (n)
// 22       n       ZIP file comment
Reader.prototype.readEndOfCentralDirectoryRecord = function (structure) {
    var stream = this;
    structure = structure || {};

    if (!structure.signature)
        structure.signature = stream.readInteger(4); // End of central directory signature = 0x06054b50

    if (structure.signature !== END_OF_CENTRAL_DIRECTORY_RECORD)
        throw new Error("ZIP end of central directory record signature invalid (expects 0x04034b50, actually 0x" + structure.signature.toString(16) +")");

    structure.disk_number               = stream.readInteger(2);    // Number of this disk
    structure.central_dir_disk_number   = stream.readInteger(2);    // Disk where central directory starts
    structure.central_dir_disk_records  = stream.readInteger(2);    // Number of central directory records on this disk
    structure.central_dir_total_records = stream.readInteger(2);    // Total number of central directory records
    structure.central_dir_size          = stream.readInteger(4);    // Size of central directory (bytes)
    structure.central_dir_offset        = stream.readInteger(4);    // Offset of start of central directory, relative to start of archive
    structure.file_comment_length       = stream.readInteger(2);    // ZIP file comment length (n)

    var n = structure.file_comment_length;

    structure.file_comment              = stream.readString(n);     // ZIP file comment

    return structure;
}

Reader.prototype.readDataDescriptor = function () {
    var stream = this;
    var descriptor = {};

    descriptor.crc_32 = stream.readInteger(4);
    if (descriptor.crc_32 === 0x08074b50)
        descriptor.crc_32 = stream.readInteger(4); // CRC-32

    descriptor.compressed_size          = stream.readInteger(4);    // Compressed size
    descriptor.uncompressed_size        = stream.readInteger(4);    // Uncompressed size

    return descriptor;
}

Reader.prototype.iterator = function () {
    var stream = this;

    // find the end record and read it
    stream.locateEndOfCentralDirectoryRecord();
    var endRecord = stream.readEndOfCentralDirectoryRecord();

    // seek to the beginning of the central directory
    stream.seek(endRecord.central_dir_offset);

    var count = endRecord.central_dir_disk_records;

    return {
        next: function () {
            if ((count--) === 0)
                throw "stop-iteration";

            // read the central directory header
            var centralHeader = stream.readCentralDirectoryFileHeader();

            // save our new position so we can restore it
            var saved = stream.position();

            // seek to the local header and read it
            stream.seek(centralHeader.local_file_header_offset);
            var localHeader = stream.readLocalFileHeader();

    		// dont read the content just save the position for later use
			var start = stream.position();

            // seek back to the next central directory header
            stream.seek(saved);

            return new Entry(localHeader, stream, start, centralHeader.compressed_size, centralHeader.compression_method);
        }
    };
};

Reader.prototype.forEach = function (block, context) {
    var iterator = this.iterator();
    var next;
    while (true) {
        try {
            next = iterator.next();
        } catch (exception) {
            if (exception === "stop-iteration")
                break;
            if (exception === "skip-iteration")
                continue;
            throw exception;
        }
        block.call(context, next);
    }
};

Reader.prototype.toObject = function (charset) {
    var object = {};
    this.forEach(function (entry) {
        if (entry.isFile()) {
            var data = entry.getData();
            if (charset)
                data = data.toString(charset);
            object[entry.getName()] = data;
        }
    });
    return object;
};

Reader.prototype.close = function (mode, options) {
};

var Entry = exports.Entry = function (header, realStream, start, compressedSize, compressionMethod) {
    this._header = header;
	this._realStream = realStream;
    this._stream = null;
	this._start = start;
	this._compressedSize = compressedSize;
	this._compressionMethod = compressionMethod;
};

Entry.prototype.getName = function () {
    return this._header.file_name;
};

Entry.prototype.isFile = function () {
    return !this.isDirectory();
};

Entry.prototype.isDirectory = function () {
    return this.getName().slice(-1) === "/";
};

Entry.prototype.getData = function () {
	if (this._stream == null) {
		var bookmark = this._realStream.position();
		this._realStream.seek(this._start);
		this._stream = this._realStream.readUncompressed(this._compressedSize, this._compressionMethod);
		this._realStream.seek(bookmark);
	}
    return this._stream;
};

var bytesToNumberLE = function (bytes) {
    var acc = 0;
    for (var i = 0; i < bytes.length; i++)
        acc += bytes.get(i) << (8*i);
    return acc;
};

var bytesToNumberBE = function (bytes) {
    var acc = 0;
    for (var i = 0; i < bytes.length; i++)
        acc = (acc << 8) + bytes.get(i);
    return acc;
};

var numberToBytesLE = function (number, length) {
    var bytes = [];
    for (var i = 0; i < length; i++)
        bytes[i] = (number >> (8*i)) & 0xFF;
    return new Buffer(bytes);
};

var numberToBytesBE = function (number, length) {
    var bytes = [];
    for (var i = 0; i < length; i++)
        bytes[length-i-1] = (number >> (8*i)) & 0xFF;
    return new Buffer(bytes);
};

<commit_msg>Add FD source support (reads from file instead from memory)<commit_after>// Tom Robinson
// Kris Kowal

var INFLATE = require("./inflate");
var Buffer = require("buffer").Buffer;
var fs = require("fs");

var LOCAL_FILE_HEADER = 0x04034b50;
var CENTRAL_DIRECTORY_FILE_HEADER = 0x02014b50;
var END_OF_CENTRAL_DIRECTORY_RECORD = 0x06054b50;

var Reader = exports.Reader = function (data) {
    if (!(this instanceof Reader))
        return new Reader(data);
	if (data instanceof Buffer)
		this._source = new BufferSource(data);
	else
		this._source = new FdSource(data);
    this._offset = 0;
}

function FdSource(fd) {
	this._fileLength = fs.fstatSync(fd).size;
	this.length = function() {
		return this._fileLength;
	}
	this.read = function(start, length) {
		var result = new Buffer(length);
		while (length > 0) {
			var pos = 0;
			var toRead = length > 8192? 8192: length;
			fs.readSync(fd, result, pos, toRead, start);
			length -= toRead;
			start += toRead;
			pos += toRead;
		}
		return result;
	}
}

function BufferSource(buffer) {
	this._buffer = buffer;
	this.length = function() {
		return buffer.length;
	}
	this.read = function (start, length) {
		var bytes = this._buffer.slice(start, start+length);
		return bytes;
	}
}

Reader.prototype.length = function () {
	return this._source.length();
}

Reader.prototype.position = function () {
    return this._offset;
}

Reader.prototype.seek = function (offset) {
    this._offset = offset;
}

Reader.prototype.read = function (length) {
	var bytes = this._source.read(this._offset, length);
	this._offset += length;
	return bytes;
}

Reader.prototype.readInteger = function (length, bigEndian) {
    if (bigEndian)
        return bytesToNumberBE(this.read(length));
    else
        return bytesToNumberLE(this.read(length));
}

Reader.prototype.readString = function (length, charset) {
    return this.read(length).toString(charset || "UTF-8");
}

Reader.prototype.readUncompressed = function (length, method) {
    var compressed = this.read(length);
    var uncompressed = null;
    if (method === 0)
        uncompressed = compressed;
    else if (method === 8)
        uncompressed = INFLATE.inflate(compressed);
    else
        throw new Error("Unknown compression method: " + structure.compression_method);
    return uncompressed;
}

Reader.prototype.readStructure = function () {
    var stream = this;
    var structure = {};

    // local file header signature     4 bytes  (0x04034b50)
    structure.signature = stream.readInteger(4);

    switch (structure.signature) {
        case LOCAL_FILE_HEADER :
            this.readLocalFileHeader(structure);
            break;
        case CENTRAL_DIRECTORY_FILE_HEADER :
            this.readCentralDirectoryFileHeader(structure);
            break;
        case END_OF_CENTRAL_DIRECTORY_RECORD :
            this.readEndOfCentralDirectoryRecord(structure);
            break;
        default:
            throw new Error("Unknown ZIP structure signature: 0x" + structure.signature.toString(16));
    }

    return structure;
}

// ZIP local file header
// Offset   Bytes   Description
// 0        4       Local file header signature = 0x04034b50
// 4        2       Version needed to extract (minimum)
// 6        2       General purpose bit flag
// 8        2       Compression method
// 10       2       File last modification time
// 12       2       File last modification date
// 14       4       CRC-32
// 18       4       Compressed size
// 22       4       Uncompressed size
// 26       2       File name length (n)
// 28       2       Extra field length (m)
// 30       n       File name
// 30+n     m       Extra field
Reader.prototype.readLocalFileHeader = function (structure) {
    var stream = this;
    structure = structure || {};

    if (!structure.signature)
        structure.signature = stream.readInteger(4);    // Local file header signature = 0x04034b50

    if (structure.signature !== LOCAL_FILE_HEADER)
        throw new Error("ZIP local file header signature invalid (expects 0x04034b50, actually 0x" + structure.signature.toString(16) +")");

    structure.version_needed       = stream.readInteger(2);    // Version needed to extract (minimum)
    structure.flags                = stream.readInteger(2);    // General purpose bit flag
    structure.compression_method   = stream.readInteger(2);    // Compression method
    structure.last_mod_file_time   = stream.readInteger(2);    // File last modification time
    structure.last_mod_file_date   = stream.readInteger(2);    // File last modification date
    structure.crc_32               = stream.readInteger(4);    // CRC-32
    structure.compressed_size      = stream.readInteger(4);    // Compressed size
    structure.uncompressed_size    = stream.readInteger(4);    // Uncompressed size
    structure.file_name_length     = stream.readInteger(2);    // File name length (n)
    structure.extra_field_length   = stream.readInteger(2);    // Extra field length (m)

    var n = structure.file_name_length;
    var m = structure.extra_field_length;

    structure.file_name            = stream.readString(n);     // File name
    structure.extra_field          = stream.read(m);           // Extra fieldFile name

    return structure;
}

// ZIP central directory file header
// Offset   Bytes   Description
// 0        4       Central directory file header signature = 0x02014b50
// 4        2       Version made by
// 6        2       Version needed to extract (minimum)
// 8        2       General purpose bit flag
// 10       2       Compression method
// 12       2       File last modification time
// 14       2       File last modification date
// 16       4       CRC-32
// 20       4       Compressed size
// 24       4       Uncompressed size
// 28       2       File name length (n)
// 30       2       Extra field length (m)
// 32       2       File comment length (k)
// 34       2       Disk number where file starts
// 36       2       Internal file attributes
// 38       4       External file attributes
// 42       4       Relative offset of local file header
// 46       n       File name
// 46+n     m       Extra field
// 46+n+m   k       File comment
Reader.prototype.readCentralDirectoryFileHeader = function (structure) {
    var stream = this;
    structure = structure || {};

    if (!structure.signature)
        structure.signature = stream.readInteger(4); // Central directory file header signature = 0x02014b50

    if (structure.signature !== CENTRAL_DIRECTORY_FILE_HEADER)
        throw new Error("ZIP central directory file header signature invalid (expects 0x04034b50, actually 0x" + structure.signature.toString(16) +")");

    structure.version                   = stream.readInteger(2);    // Version made by
    structure.version_needed            = stream.readInteger(2);    // Version needed to extract (minimum)
    structure.flags                     = stream.readInteger(2);    // General purpose bit flag
    structure.compression_method        = stream.readInteger(2);    // Compression method
    structure.last_mod_file_time        = stream.readInteger(2);    // File last modification time
    structure.last_mod_file_date        = stream.readInteger(2);    // File last modification date
    structure.crc_32                    = stream.readInteger(4);    // CRC-32
    structure.compressed_size           = stream.readInteger(4);    // Compressed size
    structure.uncompressed_size         = stream.readInteger(4);    // Uncompressed size
    structure.file_name_length          = stream.readInteger(2);    // File name length (n)
    structure.extra_field_length        = stream.readInteger(2);    // Extra field length (m)
    structure.file_comment_length       = stream.readInteger(2);    // File comment length (k)
    structure.disk_number               = stream.readInteger(2);    // Disk number where file starts
    structure.internal_file_attributes  = stream.readInteger(2);    // Internal file attributes
    structure.external_file_attributes  = stream.readInteger(4);    // External file attributes
    structure.local_file_header_offset  = stream.readInteger(4);    // Relative offset of local file header

    var n = structure.file_name_length;
    var m = structure.extra_field_length;
    var k = structure.file_comment_length;

    structure.file_name                 = stream.readString(n);     // File name
    structure.extra_field               = stream.read(m);           // Extra field
    structure.file_comment              = stream.readString(k);     // File comment

    return structure;
}

// finds the end of central directory record
// I'd like to slap whoever thought it was a good idea to put a variable length comment field here
Reader.prototype.locateEndOfCentralDirectoryRecord = function () {
    var length = this.length();
    var minPosition = length - Math.pow(2, 16) - 22;

    var position = length - 22 + 1;
    while (--position) {
        if (position < minPosition)
            throw new Error("Unable to find end of central directory record");

        this.seek(position);
        var possibleSignature = this.readInteger(4);
        if (possibleSignature !== END_OF_CENTRAL_DIRECTORY_RECORD)
            continue;

        this.seek(position + 20);
        var possibleFileCommentLength = this.readInteger(2);
        if (position + 22 + possibleFileCommentLength === length)
            break;
    }

    this.seek(position);
    return position;
};

// ZIP end of central directory record
// Offset   Bytes   Description
// 0        4       End of central directory signature = 0x06054b50
// 4        2       Number of this disk
// 6        2       Disk where central directory starts
// 8        2       Number of central directory records on this disk
// 10       2       Total number of central directory records
// 12       4       Size of central directory (bytes)
// 16       4       Offset of start of central directory, relative to start of archive
// 20       2       ZIP file comment length (n)
// 22       n       ZIP file comment
Reader.prototype.readEndOfCentralDirectoryRecord = function (structure) {
    var stream = this;
    structure = structure || {};

    if (!structure.signature)
        structure.signature = stream.readInteger(4); // End of central directory signature = 0x06054b50

    if (structure.signature !== END_OF_CENTRAL_DIRECTORY_RECORD)
        throw new Error("ZIP end of central directory record signature invalid (expects 0x04034b50, actually 0x" + structure.signature.toString(16) +")");

    structure.disk_number               = stream.readInteger(2);    // Number of this disk
    structure.central_dir_disk_number   = stream.readInteger(2);    // Disk where central directory starts
    structure.central_dir_disk_records  = stream.readInteger(2);    // Number of central directory records on this disk
    structure.central_dir_total_records = stream.readInteger(2);    // Total number of central directory records
    structure.central_dir_size          = stream.readInteger(4);    // Size of central directory (bytes)
    structure.central_dir_offset        = stream.readInteger(4);    // Offset of start of central directory, relative to start of archive
    structure.file_comment_length       = stream.readInteger(2);    // ZIP file comment length (n)

    var n = structure.file_comment_length;

    structure.file_comment              = stream.readString(n);     // ZIP file comment

    return structure;
}

Reader.prototype.readDataDescriptor = function () {
    var stream = this;
    var descriptor = {};

    descriptor.crc_32 = stream.readInteger(4);
    if (descriptor.crc_32 === 0x08074b50)
        descriptor.crc_32 = stream.readInteger(4); // CRC-32

    descriptor.compressed_size          = stream.readInteger(4);    // Compressed size
    descriptor.uncompressed_size        = stream.readInteger(4);    // Uncompressed size

    return descriptor;
}

Reader.prototype.iterator = function () {
    var stream = this;

    // find the end record and read it
    stream.locateEndOfCentralDirectoryRecord();
    var endRecord = stream.readEndOfCentralDirectoryRecord();

    // seek to the beginning of the central directory
    stream.seek(endRecord.central_dir_offset);

    var count = endRecord.central_dir_disk_records;

    return {
        next: function () {
            if ((count--) === 0)
                throw "stop-iteration";

            // read the central directory header
            var centralHeader = stream.readCentralDirectoryFileHeader();

            // save our new position so we can restore it
            var saved = stream.position();

            // seek to the local header and read it
            stream.seek(centralHeader.local_file_header_offset);
            var localHeader = stream.readLocalFileHeader();

			// dont read the content just save the position for later use
			var start = stream.position();

            // seek back to the next central directory header
            stream.seek(saved);

            return new Entry(localHeader, stream, start, centralHeader.compressed_size, centralHeader.compression_method);
        }
    };
};

Reader.prototype.forEach = function (block, context) {
    var iterator = this.iterator();
    var next;
    while (true) {
        try {
            next = iterator.next();
        } catch (exception) {
            if (exception === "stop-iteration")
                break;
            if (exception === "skip-iteration")
                continue;
            throw exception;
        }
        block.call(context, next);
    }
};

Reader.prototype.toObject = function (charset) {
    var object = {};
    this.forEach(function (entry) {
        if (entry.isFile()) {
            var data = entry.getData();
            if (charset)
                data = data.toString(charset);
            object[entry.getName()] = data;
        }
    });
    return object;
};

Reader.prototype.close = function (mode, options) {
};

var Entry = exports.Entry = function (header, realStream, start, compressedSize, compressionMethod) {
    this._header = header;
	this._realStream = realStream;
    this._stream = null;
	this._start = start;
	this._compressedSize = compressedSize;
	this._compressionMethod = compressionMethod;
};

Entry.prototype.getName = function () {
    return this._header.file_name;
};

Entry.prototype.isFile = function () {
    return !this.isDirectory();
};

Entry.prototype.isDirectory = function () {
    return this.getName().slice(-1) === "/";
};

Entry.prototype.getData = function () {
	if (this._stream == null) {
		var bookmark = this._realStream.position();
		this._realStream.seek(this._start);
		this._stream = this._realStream.readUncompressed(this._compressedSize, this._compressionMethod);
		this._realStream.seek(bookmark);
	}
    return this._stream;
};

var bytesToNumberLE = function (bytes) {
    var acc = 0;
    for (var i = 0; i < bytes.length; i++)
        acc += bytes.get(i) << (8*i);
    return acc;
};

var bytesToNumberBE = function (bytes) {
    var acc = 0;
    for (var i = 0; i < bytes.length; i++)
        acc = (acc << 8) + bytes.get(i);
    return acc;
};

var numberToBytesLE = function (number, length) {
    var bytes = [];
    for (var i = 0; i < length; i++)
        bytes[i] = (number >> (8*i)) & 0xFF;
    return new Buffer(bytes);
};

var numberToBytesBE = function (number, length) {
    var bytes = [];
    for (var i = 0; i < length; i++)
        bytes[length-i-1] = (number >> (8*i)) & 0xFF;
    return new Buffer(bytes);
};

<|endoftext|>


<commit_before>angular.module("hyloControllers").controller('CommunityCtrl', ['$scope', '$rootScope', 'Post', 'growl', '$timeout', '$http', '$q', '$modal', '$analytics', '$state',
  function($scope, $rootScope, Post, growl, $timeout, $http, $q, $modal, $analytics, $state) {

    $scope.state = $state;

    $scope.community.$promise.then(function () {
      $analytics.eventTrack('Community: Load Community', {community_id: $scope.community.id, community_name: $scope.community.name, community_slug: $scope.community.slug});
    });

    var startTour = function() {
      guiders.createGuider({
        buttons: [{name: "Next"}],
        description: "Hylo is a resource sharing network for your community.",
        id: "first",
        next: "second",
        overlay: true,
        title: "Let's Get Started!"
      }).show();

      guiders.createGuider({
        attachTo: document.querySelectorAll(".post-header")[0],
        buttons: [{name: "Next"}],
        description: "Here are the seeds from your community.  You can heart a seed by clicking the , or comment on it by clicking the ",
        id: "second",
        next: 'third',
        position: 7,
        title: "Let’s create together!"
      });

      guiders.createGuider({
        attachTo: document.querySelectorAll(".filter-buttons")[0],
        buttons: [{name: "Next"}],
        description: "Filter the seeds by intention, request, offer or all.",
        id: "third",
        next: "fourth",
        position: 5,
        title: "Filter seeds by type"
      });

      guiders.createGuider({
        attachTo: "#community-addSeedButton",
        buttons: [{name: "Done", onclick: function() {
          guiders.hideAll();
        }}],
        description: "Click here to add a seed of your own.",
        id: "fourth",
        //next: "fifth",
        position: 7,
        title: "Plant a New Seed",
        onHide: function() {
          $http.post('/endtour', {}, {params: {tour:'communityTour'}});
          $rootScope.currentUser.communityTour = false;
        }
      });

      //guiders.createGuider({
      //  attachTo: "#menu-user",
      //  buttons: [{name: "Done", onclick: function() {
      //    guiders.hideAll();
      //  }}],
      //  description: "Click here to access your profile.",
      //  id: "fifth",
      //  position: 3,
      //  title: "Your Profile",
      //  onHide: function() {
      //    $http.post('/endtour', {}, {params: {tour:'communityTour'}});
      //    $rootScope.currentUser.communityTour = false;
      //  }
      //});
    }

    var startOnboarding = function() {
      var modalInstance = $modal.open({
        templateUrl: '/ui/app/onboarding.tpl.html',
        controller: "OnboardingCtrl",
        keyboard: false,
        backdrop: 'static'
      });

      modalInstance.result.then(function () {
        $rootScope.currentUser.finishedOnboarding = true;
        $http.post('/endtour', {}, {params: {tour:'onboarding'}});

        $scope.resetQuery();

        // Start the community tour if the user hasn't started yet
        if ($rootScope.currentUser.communityTour) {
          $timeout(startTour, 500);
        }

      }, function () {
        // Dismissed Modal...Do nothing
      });
    }

    $scope.currentUser.$promise.then(function(user) {
      // Start the community tour/onboarding if the user hasn't finished it.
      if (!user.finishedOnboarding) {
        $timeout(startOnboarding, 100)
      } else if (user.communityTour) {
        $timeout(startTour, 500);
      }
    });
  }]);
<commit_msg>temporary fix for onboarding. removes resetQuery function until service layer is implemented<commit_after>angular.module("hyloControllers").controller('CommunityCtrl', ['$scope', '$rootScope', 'Post', 'growl', '$timeout', '$http', '$q', '$modal', '$analytics', '$state',
  function($scope, $rootScope, Post, growl, $timeout, $http, $q, $modal, $analytics, $state) {

    $scope.state = $state;

    $scope.community.$promise.then(function () {
      $analytics.eventTrack('Community: Load Community', {community_id: $scope.community.id, community_name: $scope.community.name, community_slug: $scope.community.slug});
    });

    var startTour = function() {
      guiders.createGuider({
        buttons: [{name: "Next"}],
        description: "Hylo is a resource sharing network for your community.",
        id: "first",
        next: "second",
        overlay: true,
        title: "Let's Get Started!"
      }).show();

      guiders.createGuider({
        attachTo: document.querySelectorAll(".post-header")[0],
        buttons: [{name: "Next"}],
        description: "Here are the seeds from your community.  You can heart a seed by clicking the , or comment on it by clicking the ",
        id: "second",
        next: 'third',
        position: 7,
        title: "Let’s create together!"
      });

      guiders.createGuider({
        attachTo: document.querySelectorAll(".filter-buttons")[0],
        buttons: [{name: "Next"}],
        description: "Filter the seeds by intention, request, offer or all.",
        id: "third",
        next: "fourth",
        position: 5,
        title: "Filter seeds by type"
      });

      guiders.createGuider({
        attachTo: "#community-addSeedButton",
        buttons: [{name: "Done", onclick: function() {
          guiders.hideAll();
        }}],
        description: "Click here to add a seed of your own.",
        id: "fourth",
        //next: "fifth",
        position: 7,
        title: "Plant a New Seed",
        onHide: function() {
          $http.post('/endtour', {}, {params: {tour:'communityTour'}});
          $rootScope.currentUser.communityTour = false;
        }
      });

      //guiders.createGuider({
      //  attachTo: "#menu-user",
      //  buttons: [{name: "Done", onclick: function() {
      //    guiders.hideAll();
      //  }}],
      //  description: "Click here to access your profile.",
      //  id: "fifth",
      //  position: 3,
      //  title: "Your Profile",
      //  onHide: function() {
      //    $http.post('/endtour', {}, {params: {tour:'communityTour'}});
      //    $rootScope.currentUser.communityTour = false;
      //  }
      //});
    }

    var startOnboarding = function() {
      var modalInstance = $modal.open({
        templateUrl: '/ui/app/onboarding.tpl.html',
        controller: "OnboardingCtrl",
        keyboard: false,
        backdrop: 'static'
      });

      modalInstance.result.then(function () {
        $rootScope.currentUser.finishedOnboarding = true;
        $http.post('/endtour', {}, {params: {tour:'onboarding'}});

        // Start the community tour if the user hasn't started yet
        if ($rootScope.currentUser.communityTour) {
          $timeout(startTour, 500);
        }

      }, function () {
        // Dismissed Modal...Do nothing
      });
    }

    $scope.currentUser.$promise.then(function(user) {
      // Start the community tour/onboarding if the user hasn't finished it.
      if (!user.finishedOnboarding) {
        $timeout(startOnboarding, 100)
      } else if (user.communityTour) {
        $timeout(startTour, 500);
      }
    });
  }]);
<|endoftext|>


<commit_before>var expect = require('chai').expect;

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

describe('Suite1', function () {
  describe('inner suite', function () {
    it('should pass', function () {
      expect(true).to.be.true;
    });
  });
});
<commit_msg>remove webserver launching<commit_after>var expect = require('chai').expect;

describe('Suite1', function () {
  describe('inner suite', function () {
    it('should pass', function () {
      expect(true).to.be.true;
    });
  });
});
<|endoftext|>


<commit_before>Game = function() {
    this.e = 10000;
    this.t = 8;
};

Game.prototype = {
    randomWithinLimitOf: function(n) {
        return Math.floor(Math.random() * n);
    },
    processCommand: function(ui) {
        var enemy;
        var distance;
        var damage;
        if(ui.parameter("command") === "phaser") {
            var amount = parseInt(ui.parameter("amount"), 10);
            enemy = ui.variable("target");
            if(this.e >= amount) {
                distance = enemy.distance;
                if(distance > 4000) {
                    $("#dialogue").append("
" + "Klingon out of range of phasers at " + distance + " sectors..." + "
");
                } else {
                    damage = amount - (((amount / 20) * distance / 200) + this.randomWithinLimitOf(200));
                    if (damage < 1) {
                        damage = 1;
                    }
                    ui.writeLine("Phasers hit Klingon at " + distance + " sectors with " + damage + " units");
                    if(damage < enemy.energy) {
                        enemy.energy = enemy.energy - damage;
                        ui.writeLine("Klingon has " + enemy.energy + " remaining");
                    } else {
                        ui.writeLine("Klingon destroyed!");
                        enemy.destroy();
                    }
                }
                this.e -= amount;
            } else {
                ui.writeLine("Insufficient energy to fire phasers!");
            }
        } else if(ui.parameter("command") === "photon") {
            enemy = ui.variable("target");
            if(this.t > 0) {
                distance = enemy.distance;
                if ((this.randomWithinLimitOf(4) + ((distance / 500) + 1) > 7)) {
                    ui.writeLine("Torpedo missed Klingon at " + distance + " sectors...");
                } else {
                    damage = 800 + this.randomWithinLimitOf(50);
                    ui.writeLine("Photons hit Klingon at " + distance + " sectors with " + damage + " units");
                    if (damage < enemy.energy) {
                        enemy.energy = enemy.energy - damage;
                        ui.writeLine("Klingon has " + enemy.energy + " remaining");
                    } else {
                        ui.writeLine("Klingon destroyed!");
                        enemy.destroy();
                    }
                }
                this.t--;
            } else {
                ui.writeLine("No more photon torpedoes!");
            }
        }
    }
};<commit_msg>made game() even uglier<commit_after>Game = function() {
    this.e = 10000;
    this.t = 8;
};

Game.prototype = {
    randomWithinLimitOf: function(n) {
        return Math.floor(Math.random() * n);
    },
    processCommand: function(ui) {
        var enemy;
        var distance;
        var damage;
        if(ui.parameter("command") === "phaser") {
            var amount = parseInt(ui.parameter("amount"), 10);
            enemy = ui.variable("target");
            if(this.e >= amount) {
                distance = enemy.distance;
                if(distance > 4000) {
                    $("#dialogue").append("
" + "Klingon out of range of phasers at " + distance + " sectors..." + "
");
                } else {
                    damage = amount - (((amount / 20) * distance / 200) + this.randomWithinLimitOf(200));
                    if (damage < 1) {
                        damage = 1;
                    }
                    $("#dialogue").append("
" + "Phasers hit Klingon at " + distance + " sectors with " + damage + " units" + "
");
                    if(damage < enemy.energy) {
                        enemy.energy = enemy.energy - damage;
                        $("#dialogue").append("
" + "Klingon has " + enemy.energy + " remaining" + "
");
                    } else {
                        $("#dialogue").append("
" + "Klingon destroyed!" + "
");
                        enemy.destroy();
                    }
                }
                this.e -= amount;
            } else {
                $("#dialogue").append("
" + "Insufficient energy to fire phasers!" + "
");
            }
        } else if(ui.parameter("command") === "photon") {
            enemy = ui.variable("target");
            if(this.t > 0) {
                distance = enemy.distance;
                if ((this.randomWithinLimitOf(4) + ((distance / 500) + 1) > 7)) {
                    $("#dialogue").append("
" + "Torpedo missed Klingon at " + distance + " sectors..." + "
");
                } else {
                    damage = 800 + this.randomWithinLimitOf(50);
                    $("#dialogue").append("
" + "Photons hit Klingon at " + distance + " sectors with " + damage + " units" + "
");
                    if (damage < enemy.energy) {
                        enemy.energy = enemy.energy - damage;
                        $("#dialogue").append("
" + "Klingon has " + enemy.energy + " remaining" + "
");
                    } else {
                        $("#dialogue").append("
" + "Klingon destroyed!" + "
");
                        enemy.destroy();
                    }
                }
                this.t--;
            } else {
                $("#dialogue").append("
" + "No more photon torpedoes!" + "
");
            }
        }
    }
};<|endoftext|>


<commit_before>const HealthBarMap = {
  tasksUnknown: {
    className: 'unknown',
    label: 'Unknown'
  },
  tasksHealthy: {
    className: 'healthy',
    label: 'Healthy'
  },
  tasksUnhealthy: {
    className: 'unhealthy',
    label: 'Unhealthy'
  },
  tasksStaged: {
    className: 'staged',
    label: 'Staged'
  }
};

module.exports = HealthBarMap;
<commit_msg>Renaming health bar constants<commit_after>const HealthBarStates = {
  tasksUnknown: {
    className: 'unknown',
    label: 'Unknown'
  },
  tasksHealthy: {
    className: 'healthy',
    label: 'Healthy'
  },
  tasksUnhealthy: {
    className: 'unhealthy',
    label: 'Unhealthy'
  },
  tasksStaged: {
    className: 'staged',
    label: 'Staged'
  }
};

module.exports = HealthBarStates;
<|endoftext|>


<commit_before>'use strict';

/* global _, uuid, CartConst, CartUtility */
module.exports = function ($scope, $location, $window, $routeParams, $modal, $dataService, $accessService) {
    CartUtility.log('CartBlogListCtrl');

    $scope.utility = CartUtility;
    $scope.encodeURIComponent = encodeURIComponent;

    $scope.isMaster = $accessService.isMaster();

    // FIXME 数据加载机制需要整个重构
    // FIXME 页面上post列表的创建时间错误"46851- 04- 46851-04-26 17:14:51"，但是在tmp 列表上是对的，是否服务器回传的时间不正确，或者说服务器创建的timestamp不正确

    $scope.createNewPost = function() {
        if (!$scope.isMaster) {
            return;
        }
        // redirect to create post page
        $window.location.href = CartUtility.getPureRootUrlFromLocation($location) + 'edit/' + uuid.v4();
    };

    $scope.openTmpPostList = function() {
        if (!$scope.isMaster) {
            return;
        }
        $modal.open({
            templateUrl: 'CartBlogListModal.html',
            controller: 'CartBlogListModalCtrl',
            size: 'lg'
        });
    };

    $scope.fetchCategoryDisplayName = function(categoryUuid) {
        var name = '';
        var category = $dataService.categorySearchById(categoryUuid);
        if (!_.isNull(category)) {
            name = category.title;
        }
        return name;
    };

    $scope.fetchTagDisplayName = function(tagUuid) {
        var name = '';
        var tag = $dataService.tagSearchById(tagUuid);
        if (!_.isNull(tag)) {
            name = tag.title;
        }
        return name;
    };

    $scope.deletePost = function(uuid) {
        if (!window.confirm('Do you confirm the delete operation of the post: ' + uuid + '?\nThis action cannot be undo!')) {
            return;
        }
        var post = $dataService.postSearchById(uuid);
        if (_.isNull(post)) {
            CartUtility.notify('Error!', 'Target post to be deleted not found, uuid: ' + uuid, 'error');
            return;
        }
        $dataService.postRemove(uuid).then(function() {
            _.forEach(postRows, function(row, index) {
                if (row.uuid === uuid) {
                    postRows.splice(index, 1);
                }
            });
            $scope.loadPageData();
            CartUtility.notify('Done!', 'Post ' + uuid + ' deleted!');
        });
    };

    var postRows = [];

    // pagination
    $scope.postOnPage = []; // data used to be displayed on page
    $scope.paginationTotalItems = 0;
    $scope.paginationCurrentPage = 1;
    $scope.itemsPerPage = CartConst.PAGINATION_ITEMS_PER_PAGE;
    $scope.paginationMaxSize = 5;

    $scope.loadPageData = function() {
        var startPos = ($scope.paginationCurrentPage - 1) * $scope.itemsPerPage;
        var endPos = startPos + $scope.itemsPerPage;
        $scope.postOnPage = postRows.slice(startPos, endPos);
    };

    var displayPageItems = function() {
        var options = {};
        if ($routeParams.hasOwnProperty('category')) {
            options.category = $routeParams.category;
        }
        if ($routeParams.hasOwnProperty('tag')) {
            options.tags = [$routeParams.tag];
        }
        if ($location.url().indexOf('year') !== -1) {
            options.year = $routeParams.datetime;
        }
        if ($location.url().indexOf('month') !== -1) {
            options.month = $routeParams.datetime;
        }
        if ($location.url().indexOf('day') !== -1) {
            options.day = $routeParams.datetime;
        }
        postRows = $dataService.postSearch(options);
        postRows = _.sortBy(postRows, function(post) { return post.created; }).reverse(); // orderBy "created" DESC
        $scope.paginationTotalItems = postRows.length;
        $scope.paginationCurrentPage = 1;
        $scope.loadPageData();
    };
    displayPageItems();

    // FIXME 页脚的分页标签的位置最好紧贴页面的footer，现在是在内容展示的div下面
};<commit_msg>Fix post search logic on post list page.<commit_after>'use strict';

/* global _, uuid, CartConst, CartUtility */
module.exports = function ($scope, $location, $window, $routeParams, $modal, $dataService, $accessService) {
    CartUtility.log('CartBlogListCtrl');

    $scope.utility = CartUtility;
    $scope.encodeURIComponent = encodeURIComponent;

    $scope.isMaster = $accessService.isMaster();

    // FIXME 数据加载机制需要整个重构
    // FIXME 页面上post列表的创建时间错误"46851- 04- 46851-04-26 17:14:51"，但是在tmp 列表上是对的，是否服务器回传的时间不正确，或者说服务器创建的timestamp不正确

    $scope.createNewPost = function() {
        if (!$scope.isMaster) {
            return;
        }
        // redirect to create post page
        $window.location.href = CartUtility.getPureRootUrlFromLocation($location) + 'edit/' + uuid.v4();
    };

    $scope.openTmpPostList = function() {
        if (!$scope.isMaster) {
            return;
        }
        $modal.open({
            templateUrl: 'CartBlogListModal.html',
            controller: 'CartBlogListModalCtrl',
            size: 'lg'
        });
    };

    $scope.fetchCategoryDisplayName = function(categoryUuid) {
        var name = '';
        var category = $dataService.categorySearchById(categoryUuid);
        if (!_.isNull(category)) {
            name = category.title;
        }
        return name;
    };

    $scope.fetchTagDisplayName = function(tagUuid) {
        var name = '';
        var tag = $dataService.tagSearchById(tagUuid);
        if (!_.isNull(tag)) {
            name = tag.title;
        }
        return name;
    };

    $scope.deletePost = function(uuid) {
        if (!window.confirm('Do you confirm the delete operation of the post: ' + uuid + '?\nThis action cannot be undo!')) {
            return;
        }
        var post = $dataService.postSearchById(uuid);
        if (_.isNull(post)) {
            CartUtility.notify('Error!', 'Target post to be deleted not found, uuid: ' + uuid, 'error');
            return;
        }
        $dataService.postRemove(uuid).then(function() {
            _.forEach($scope.postOnPage, function(row, index) {
                if (row.uuid === uuid) {
                    $scope.postOnPage.splice(index, 1);
                }
            });
            $scope.loadPageData();
            CartUtility.notify('Done!', 'Post ' + uuid + ' deleted!');
        });
    };

    // pagination
    $scope.postOnPage = []; // data used to be displayed on page
    $scope.paginationTotalItems = 0;
    $scope.paginationCurrentPage = 1;
    $scope.itemsPerPage = CartConst.PAGINATION_ITEMS_PER_PAGE;
    $scope.paginationMaxSize = 5;

    $scope.loadPageData = function() {
        var options = {};
        if ($routeParams.hasOwnProperty('category')) {
            options.category = $routeParams.category;
        }
        if ($routeParams.hasOwnProperty('tag')) {
            options.tags = [$routeParams.tag];
        }
        if ($location.url().indexOf('year') !== -1) {
            options.year = $routeParams.datetime;
        }
        if ($location.url().indexOf('month') !== -1) {
            options.month = $routeParams.datetime;
        }
        if ($location.url().indexOf('day') !== -1) {
            options.day = $routeParams.datetime;
        }
        options.isUuidSearch = false;
        options.pageNumber = $scope.paginationCurrentPage;
        $dataService.postSearch(options).then(function(data) { // FIXME 修改postSearch接口，posts里带的categories和tags，都要附带下载
            var posts = data.posts;
            if (_.isObject(posts) && _.keys(posts).length > 0) {
                $scope.postOnPage = _.values(posts);
            }
            if (_.isNumber(data.total)) {
                $scope.paginationTotalItems = data.total;
            }
        });
    };

    $scope.loadPageData();

    // FIXME 页脚的分页标签的位置最好紧贴页面的footer，现在是在内容展示的div下面
};<|endoftext|>