<commit_before>/*!
 * @@name v@@version (JS part)
 * Author: @@author
 * Repo: @@homepage
 * Licensed under MIT (@@homepage/blob/master/LICENSE)
 */

if (canUseTransform() === false)
{
	var absalignPolyfill = new AbsalignPolyfill().init();
}

function canUseTransform()
{
    var prefixes =
	[
		'transform',
		'WebkitTransform',
		'MozTransform',
		'OTransform',
		'msTransform'
	];

	var prefixes_length = prefixes.length;

    for (var i = 0; i < prefixes_length; i++)
	{
        if (document.createElement('div').style[prefixes[i]] !== undefined)
		{
            return prefixes[i];
        }
    }

    return false;
}

function AbsalignPolyfill()
{
    var OBJ = this;

    var _classesCollection = [],
        _elements = [];

    _populateClassCollection();

    OBJ.init = function ()
    {
        _scan();

        return OBJ;
    };

    function _populateClassCollection()
    {
    /*// Declaring parts of classes names
        var positions =
        [
            'abs',
            'fix'
        ];

        var xAxes =
        [
            'left',
            'center',
            'right'
        ];

        var yAxes =
        [
            'top',
            'middle',
            'bottom'
        ];

        var pseudos =
        [
            false,
            'before',
            'after'
        ];

    // Declaring classes lists
    // Lists by position
        var absClasses = [];
        var fixClasses = [];

        var transformedClasses =
        [
            // '.absalign-animate'    // All absalign-animate classes are transformed
        ];

    // Axes lists
        var leftTopClasses = [];
        var leftMiddleClasses = [];
        var leftBottomClasses = [];

        var centerTopClasses = [];
        var centerMiddleClasses = [];
        var centerBottomClasses = [];

        var rightTopClasses = [];
        var rightMiddleClasses = [];
        var rightBottomClasses = [];

    // Mono-axis lists
        var leftClasses = [];
        var centerClasses = [];
        var rightClasses = [];

        var topClasses = [];
        var middleClasses = [];
        var bottomClasses = [];

    // Inanimate classes lists
        var leftBottomAnimateClasses = [];

        var centerBottomAnimateClasses = [];

        var rightTopAnimateClasses = [];
        var rightMiddleAnimateClasses = [];
        var rightBottomAnimateClasses = [];

        var rightAnimateClasses = [];
        var bottomAnimateClasses = [];

        var currentClass = '';
        var currentInanimateClass = '';

    // First loop creates the positions and axes lists
        positions.forEach(function (position)
        {
            xAxes.forEach(function (xAxis)
            {
                yAxes.forEach(function (yAxis)
                {
                    pseudos.forEach(function (pseudo)
                    {
                        is__inanimate = (xAxis === 'right' || yAxis === 'bottom');

                        if (position !== 'fix' || !pseudo)
                        {
                            currentClass = '.' + position + '-' + xAxis + '-' + yAxis;

        					if (pseudo)
        					{
        						currentClass = currentClass + '-' + pseudo;
        					}

        					if (is__inanimate)
                            {
                                currentInanimateClass = currentClass + '.absalign-animate';

                                if (pseudo)
                                {
                                    currentInanimateClass = currentInanimateClass + '-' + pseudo + ':' + pseudo;
                                }
                            }

                            if (pseudo)
                            {
                                currentClass = currentClass + ':' + pseudo;
                            }
                            else if (xAxis === 'center' || yAxis === 'middle')
                            {
                                transformedClasses.push(currentClass);
                            }

                            if (position === 'abs')
                            {
                                absClasses.push(currentClass);
                            }
                            else if (position === 'fix')
                            {
                                fixClasses.push(currentClass);
                            }

                            if (xAxis === 'left')
                            {
                                if (yAxis === 'top')
                                {
                                    leftTopClasses.push(currentClass);
                                }
                                if (yAxis === 'middle')
                                {
                                    leftMiddleClasses.push(currentClass);
                                }
                                if (yAxis === 'bottom')
                                {
                                    leftBottomClasses.push(currentClass);

                                    if (is__inanimate)
                                    {
                                        leftBottomAnimateClasses.push(currentInanimateClass);
                                    }
                                }
                            }

                            if (xAxis === 'center')
                            {
                                if (yAxis === 'top')
                                {
                                    centerTopClasses.push(currentClass);
                                }
                                if (yAxis === 'middle')
                                {
                                    centerMiddleClasses.push(currentClass);
                                }
                                if (yAxis === 'bottom')
                                {
                                    centerBottomClasses.push(currentClass);

                                    if (is__inanimate)
                                    {
                                        centerBottomAnimateClasses.push(currentInanimateClass);
                                    }
                                }
                            }

                            if (xAxis === 'right')
                            {
                                if (yAxis === 'top')
                                {
                                    rightTopClasses.push(currentClass);

                                    if (is__inanimate)
        							{
        								rightTopAnimateClasses.push(currentInanimateClass);
        							}
                                }
                                if (yAxis === 'middle')
                                {
                                    rightMiddleClasses.push(currentClass);

                                    if (is__inanimate)
        							{
        								rightMiddleAnimateClasses.push(currentInanimateClass);
        							}
                                }
                                if (yAxis === 'bottom')
                                {
                                    rightBottomClasses.push(currentClass);

                                    if (is__inanimate)
        							{
        								rightBottomAnimateClasses.push(currentInanimateClass);
        							}
                                }
                            }
                        }
                    });
                });
            });
        });

    // Second loop creates the mono-axis lists
        positions.forEach(function (position)
        {
            xAxes.forEach(function (xAxis)
            {
                pseudos.forEach(function (pseudo)
                {
                    is__inanimate = (xAxis === 'right');

                    if (position !== 'fix' || !pseudo)
                    {
                        currentClass = '.' + position + '-' + xAxis;

        				if (pseudo)
        				{
        					currentClass = currentClass + '-' + pseudo;
        				}

        				if (is__inanimate)
                        {
                            currentInanimateClass = currentClass + '.absalign-animate';

                            if (pseudo)
                            {
                                currentInanimateClass = currentInanimateClass + '-' + pseudo + ':' + pseudo;
                            }
                        }

                        if (pseudo)
                        {
                            currentClass = currentClass + ':' + pseudo;
                        }
                        else if (xAxis === 'center')
                        {
                            transformedClasses.push(currentClass);
                        }

                        if (position === 'abs')
                        {
                            absClasses.push(currentClass);
                        }
                        else if (position === 'fix')
                        {
                            fixClasses.push(currentClass);
                        }

                        if (xAxis === 'left')
                        {
                            leftClasses.push(currentClass);
                        }
                        if (xAxis === 'center')
                        {
                            centerClasses.push(currentClass);
                        }
                        if (xAxis === 'right')
                        {
                            rightClasses.push(currentClass);

                            if (is__inanimate)
                            {
                                rightAnimateClasses.push(currentInanimateClass);
                            }
                        }
                    }
                });
            });

            yAxes.forEach(function (yAxis)
            {
                pseudos.forEach(function (pseudo)
                {
                    is__inanimate = (yAxis === 'bottom');

                    if (position !== 'fix' || !pseudo)
                    {
                        currentClass = '.' + position + '-' + yAxis;

                        if (pseudo)
        				{
        					currentClass = currentClass + '-' + pseudo;
        				}

        				if (is__inanimate)
                        {
                            currentInanimateClass = currentClass + '.absalign-animate';

                            if (pseudo)
                            {
                                currentInanimateClass = currentInanimateClass + '-' + pseudo + ':' + pseudo;
                            }
                        }

                        if (pseudo)
                        {
                            currentClass = currentClass + ':' + pseudo;
                        }
                        else if (yAxis === 'middle')
                        {
                            transformedClasses.push(currentClass);
                        }

                        if (position === 'abs')
                        {
                            absClasses.push(currentClass);
                        }
                        else if (position === 'fix')
                        {
                            fixClasses.push(currentClass);
                        }

                        if (yAxis === 'top')
                        {
                            topClasses.push(currentClass);
                        }
                        if (yAxis === 'middle')
                        {
                            middleClasses.push(currentClass);
                        }
                        if (yAxis === 'bottom')
                        {
                            bottomClasses.push(currentClass);

                            if (is__inanimate)
                            {
                                bottomAnimateClasses.push(currentInanimateClass);
                            }
                        }
                    }
                });
            });
        });

        _classesCollection = transformedClasses;*/

        /* include _class-collection.js */
    }

    function _scan()
    {
        _classesCollection.forEach(function (className)
        {
            var elements = document.querySelectorAll(className);

            for (var i = 0; i < elements.length; i++)
            {
                _elements.push(new AbsalignElement(elements[i], className).init());
            }
        });
    }

    return OBJ;
}

function AbsalignElement(element, absalignClass)
{
    var OBJ = this;

    var _element = element,
        _xAxis,
        _yAxis;

    absalignClass = absalignClass.split('-');

    var nbAxes = absalignClass.length - 1;

    if (nbAxes === 1)
    {
        if (absalignUtilities().isXAxis(absalignClass[1]))
        {
            _xAxis = absalignClass[1];
        }

        if (absalignUtilities().isYAxis(absalignClass[1]))
        {
            _yAxis = absalignClass[1];
        }
    }

    if (nbAxes === 2)
    {
        _xAxis = absalignClass[1];
        _yAxis = absalignClass[2];
    }

    OBJ.init = function ()
    {
        _place();

        return OBJ;
    };

    function _place()
    {
        if (_xAxis === 'center')
        {
            var elementWidth = _getWidth();

            _element.style.marginLeft = -(elementWidth / 2) + 'px';
        }

        if (_yAxis === 'middle')
        {
            var elementHeight = _getHeight();

            _element.style.marginTop = -(elementHeight / 2) + 'px';
        }
    }

    function _getWidth()
    {
        return _element.offsetWidth;
    }

    function _getHeight()
    {
        return _element.offsetHeight;
    }

    return OBJ;
}

function absalignUtilities()
{
    var OBJ = OBJ || { };

    var _xAxes = ['left', 'center', 'right'];
    var _yAxes = ['top', 'middle', 'bottom'];

    OBJ.isXAxis = function (axis)
    {
        return (_xAxes.indexOf(axis) !== -1);
    };

    OBJ.isYAxis = function (axis)
    {
        return (_yAxes.indexOf(axis) !== -1);
    };

    return OBJ;
}
<commit_msg>Removed the last forEach from polyfill. It now works with IE8!<commit_after>/*!
 * @@name v@@version (JS part)
 * Author: @@author
 * Repo: @@homepage
 * Licensed under MIT (@@homepage/blob/master/LICENSE)
 */

if (canUseTransform() === false)
{
	var absalignPolyfill = new AbsalignPolyfill().init();
}

function canUseTransform()
{
    var prefixes =
	[
		'transform',
		'WebkitTransform',
		'MozTransform',
		'OTransform',
		'msTransform'
	];

	var prefixes_length = prefixes.length;

    for (var i = 0; i < prefixes_length; i++)
	{
        if (document.createElement('div').style[prefixes[i]] !== undefined)
		{
            return prefixes[i];
        }
    }

    return false;
}

function AbsalignPolyfill()
{
    var OBJ = this;

    var _classesCollection = [],
        _elements = [];

    _populateClassCollection();

    OBJ.init = function ()
    {
        _scan();

        return OBJ;
    };

    function _populateClassCollection()
    {
    /*// Declaring parts of classes names
        var positions =
        [
            'abs',
            'fix'
        ];

        var xAxes =
        [
            'left',
            'center',
            'right'
        ];

        var yAxes =
        [
            'top',
            'middle',
            'bottom'
        ];

        var pseudos =
        [
            false,
            'before',
            'after'
        ];

    // Declaring classes lists
    // Lists by position
        var absClasses = [];
        var fixClasses = [];

        var transformedClasses =
        [
            // '.absalign-animate'    // All absalign-animate classes are transformed
        ];

    // Axes lists
        var leftTopClasses = [];
        var leftMiddleClasses = [];
        var leftBottomClasses = [];

        var centerTopClasses = [];
        var centerMiddleClasses = [];
        var centerBottomClasses = [];

        var rightTopClasses = [];
        var rightMiddleClasses = [];
        var rightBottomClasses = [];

    // Mono-axis lists
        var leftClasses = [];
        var centerClasses = [];
        var rightClasses = [];

        var topClasses = [];
        var middleClasses = [];
        var bottomClasses = [];

    // Inanimate classes lists
        var leftBottomAnimateClasses = [];

        var centerBottomAnimateClasses = [];

        var rightTopAnimateClasses = [];
        var rightMiddleAnimateClasses = [];
        var rightBottomAnimateClasses = [];

        var rightAnimateClasses = [];
        var bottomAnimateClasses = [];

        var currentClass = '';
        var currentInanimateClass = '';

    // First loop creates the positions and axes lists
        positions.forEach(function (position)
        {
            xAxes.forEach(function (xAxis)
            {
                yAxes.forEach(function (yAxis)
                {
                    pseudos.forEach(function (pseudo)
                    {
                        is__inanimate = (xAxis === 'right' || yAxis === 'bottom');

                        if (position !== 'fix' || !pseudo)
                        {
                            currentClass = '.' + position + '-' + xAxis + '-' + yAxis;

        					if (pseudo)
        					{
        						currentClass = currentClass + '-' + pseudo;
        					}

        					if (is__inanimate)
                            {
                                currentInanimateClass = currentClass + '.absalign-animate';

                                if (pseudo)
                                {
                                    currentInanimateClass = currentInanimateClass + '-' + pseudo + ':' + pseudo;
                                }
                            }

                            if (pseudo)
                            {
                                currentClass = currentClass + ':' + pseudo;
                            }
                            else if (xAxis === 'center' || yAxis === 'middle')
                            {
                                transformedClasses.push(currentClass);
                            }

                            if (position === 'abs')
                            {
                                absClasses.push(currentClass);
                            }
                            else if (position === 'fix')
                            {
                                fixClasses.push(currentClass);
                            }

                            if (xAxis === 'left')
                            {
                                if (yAxis === 'top')
                                {
                                    leftTopClasses.push(currentClass);
                                }
                                if (yAxis === 'middle')
                                {
                                    leftMiddleClasses.push(currentClass);
                                }
                                if (yAxis === 'bottom')
                                {
                                    leftBottomClasses.push(currentClass);

                                    if (is__inanimate)
                                    {
                                        leftBottomAnimateClasses.push(currentInanimateClass);
                                    }
                                }
                            }

                            if (xAxis === 'center')
                            {
                                if (yAxis === 'top')
                                {
                                    centerTopClasses.push(currentClass);
                                }
                                if (yAxis === 'middle')
                                {
                                    centerMiddleClasses.push(currentClass);
                                }
                                if (yAxis === 'bottom')
                                {
                                    centerBottomClasses.push(currentClass);

                                    if (is__inanimate)
                                    {
                                        centerBottomAnimateClasses.push(currentInanimateClass);
                                    }
                                }
                            }

                            if (xAxis === 'right')
                            {
                                if (yAxis === 'top')
                                {
                                    rightTopClasses.push(currentClass);

                                    if (is__inanimate)
        							{
        								rightTopAnimateClasses.push(currentInanimateClass);
        							}
                                }
                                if (yAxis === 'middle')
                                {
                                    rightMiddleClasses.push(currentClass);

                                    if (is__inanimate)
        							{
        								rightMiddleAnimateClasses.push(currentInanimateClass);
        							}
                                }
                                if (yAxis === 'bottom')
                                {
                                    rightBottomClasses.push(currentClass);

                                    if (is__inanimate)
        							{
        								rightBottomAnimateClasses.push(currentInanimateClass);
        							}
                                }
                            }
                        }
                    });
                });
            });
        });

    // Second loop creates the mono-axis lists
        positions.forEach(function (position)
        {
            xAxes.forEach(function (xAxis)
            {
                pseudos.forEach(function (pseudo)
                {
                    is__inanimate = (xAxis === 'right');

                    if (position !== 'fix' || !pseudo)
                    {
                        currentClass = '.' + position + '-' + xAxis;

        				if (pseudo)
        				{
        					currentClass = currentClass + '-' + pseudo;
        				}

        				if (is__inanimate)
                        {
                            currentInanimateClass = currentClass + '.absalign-animate';

                            if (pseudo)
                            {
                                currentInanimateClass = currentInanimateClass + '-' + pseudo + ':' + pseudo;
                            }
                        }

                        if (pseudo)
                        {
                            currentClass = currentClass + ':' + pseudo;
                        }
                        else if (xAxis === 'center')
                        {
                            transformedClasses.push(currentClass);
                        }

                        if (position === 'abs')
                        {
                            absClasses.push(currentClass);
                        }
                        else if (position === 'fix')
                        {
                            fixClasses.push(currentClass);
                        }

                        if (xAxis === 'left')
                        {
                            leftClasses.push(currentClass);
                        }
                        if (xAxis === 'center')
                        {
                            centerClasses.push(currentClass);
                        }
                        if (xAxis === 'right')
                        {
                            rightClasses.push(currentClass);

                            if (is__inanimate)
                            {
                                rightAnimateClasses.push(currentInanimateClass);
                            }
                        }
                    }
                });
            });

            yAxes.forEach(function (yAxis)
            {
                pseudos.forEach(function (pseudo)
                {
                    is__inanimate = (yAxis === 'bottom');

                    if (position !== 'fix' || !pseudo)
                    {
                        currentClass = '.' + position + '-' + yAxis;

                        if (pseudo)
        				{
        					currentClass = currentClass + '-' + pseudo;
        				}

        				if (is__inanimate)
                        {
                            currentInanimateClass = currentClass + '.absalign-animate';

                            if (pseudo)
                            {
                                currentInanimateClass = currentInanimateClass + '-' + pseudo + ':' + pseudo;
                            }
                        }

                        if (pseudo)
                        {
                            currentClass = currentClass + ':' + pseudo;
                        }
                        else if (yAxis === 'middle')
                        {
                            transformedClasses.push(currentClass);
                        }

                        if (position === 'abs')
                        {
                            absClasses.push(currentClass);
                        }
                        else if (position === 'fix')
                        {
                            fixClasses.push(currentClass);
                        }

                        if (yAxis === 'top')
                        {
                            topClasses.push(currentClass);
                        }
                        if (yAxis === 'middle')
                        {
                            middleClasses.push(currentClass);
                        }
                        if (yAxis === 'bottom')
                        {
                            bottomClasses.push(currentClass);

                            if (is__inanimate)
                            {
                                bottomAnimateClasses.push(currentInanimateClass);
                            }
                        }
                    }
                });
            });
        });

        _classesCollection = transformedClasses;*/

        /* include _class-collection.js */
    }

    function _scan()
    {
        for (var i = 0; i < _classesCollection.length; i++)
        {
            var className = _classesCollection[i];

            var elements = document.querySelectorAll(className);

            for (var j = 0; j < elements.length; j++)
            {
                _elements.push(new AbsalignElement(elements[j], className).init());
            }
        }
    }

    return OBJ;
}

function AbsalignElement(element, absalignClass)
{
    var OBJ = this;

    var _element = element,
        _xAxis,
        _yAxis;

    absalignClass = absalignClass.split('-');

    var nbAxes = absalignClass.length - 1;

    if (nbAxes === 1)
    {
        if (absalignUtilities().isXAxis(absalignClass[1]))
        {
            _xAxis = absalignClass[1];
        }

        if (absalignUtilities().isYAxis(absalignClass[1]))
        {
            _yAxis = absalignClass[1];
        }
    }

    if (nbAxes === 2)
    {
        _xAxis = absalignClass[1];
        _yAxis = absalignClass[2];
    }

    OBJ.init = function ()
    {
        _place();

        return OBJ;
    };

    function _place()
    {
        if (_xAxis === 'center')
        {
            var elementWidth = _getWidth();

            _element.style.marginLeft = -(elementWidth / 2) + 'px';
        }

        if (_yAxis === 'middle')
        {
            var elementHeight = _getHeight();

            _element.style.marginTop = -(elementHeight / 2) + 'px';
        }
    }

    function _getWidth()
    {
        return _element.offsetWidth;
    }

    function _getHeight()
    {
        return _element.offsetHeight;
    }

    return OBJ;
}

function absalignUtilities()
{
    var OBJ = OBJ || { };

    var _xAxes = ['left', 'center', 'right'];
    var _yAxes = ['top', 'middle', 'bottom'];

    OBJ.isXAxis = function (axis)
    {
        return (_xAxes.indexOf(axis) !== -1);
    };

    OBJ.isYAxis = function (axis)
    {
        return (_yAxes.indexOf(axis) !== -1);
    };

    return OBJ;
}
<|endoftext|>


<commit_before>/**
 * Created by brian.hunter on 4/11/17.
 * Jest test file for testing creation, adjustment, and voiding of a transaction in the REST API
 */

/*Import sample data and expected responses*/
import Avatax from '../lib/AvaTaxClient';
import loadCreds from './helpers/load_creds';
import nock from 'nock';
import { account, licenseKey, companyCode } from './test_creds';
import transactionRequest from './fixtures/transaction_request';
import transactionResponse from './fixtures/transaction_response';
import adjustTransactionRequest from './fixtures/adjust_transaction_request';
import adjustTransactionResponse from './fixtures/adjust_transaction_response';
import voidTransactionRequest from './fixtures/void_transaction_request';
import voidTransactionResponse from './fixtures/void_transaction_response';

let transactionCode = transactionResponse.code;

console.log(transactionCode);

const baseUrl = 'https://sandbox-rest.avatax.com';

describe('Avatax Transactions', () => {
    const clientCreds = loadCreds();
    const client = new Avatax(clientCreds).withSecurity(clientCreds);

    describe('Creating new transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post('/api/v2/transactions/create', transactionRequest)
                .reply(201, transactionResponse);
        });

        it('should create a new transaction', () => {
            return client.createTransaction(transactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(transactionResponse);
                });
        });
    });

    /*Case for adjusting existing transaction
    *
    * Need to grab transactionCode from newly created transaction above
    * transactionCode = actualResponse.code;
    * EDIT - its hard coded in so we can cheat a little
    * */
    describe('Adjusting existing transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post(`/api/v2/companies/${companyCode}/transactions/${transactionCode}/adjust`, adjustTransactionRequest)
                .reply(200, adjustTransactionResponse);
        });

        it('should adjust an existing transaction', () => {
            return client.adjustTransaction(companyCode, transactionCode,adjustTransactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(adjustTransactionResponse);
                });
        });
    });

    /* Code for voiding an existing transaction
     *
     * Use same transactionCode from before
     * */
    describe('Voiding existing transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post(`/api/v2/companies/${companyCode}/transactions/${transactionCode}/void`, voidTransactionRequest)
                .reply(200, voidTransactionResponse);
        });

        it('should void an existing transaction', () => {
            return client.voidTransaction(companyCode, transactionCode, voidTransactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(voidTransactionResponse);
                });
        });
    });

});
<commit_msg>log transcode<commit_after>/**
 * Created by brian.hunter on 4/11/17.
 * Jest test file for testing creation, adjustment, and voiding of a transaction in the REST API
 */

/*Import sample data and expected responses*/
import Avatax from '../lib/AvaTaxClient';
import loadCreds from './helpers/load_creds';
import nock from 'nock';
import { account, licenseKey, companyCode } from './test_creds';
import transactionRequest from './fixtures/transaction_request';
import transactionResponse from './fixtures/transaction_response';
import adjustTransactionRequest from './fixtures/adjust_transaction_request';
import adjustTransactionResponse from './fixtures/adjust_transaction_response';
import voidTransactionRequest from './fixtures/void_transaction_request';
import voidTransactionResponse from './fixtures/void_transaction_response';

let transactionCode = transactionResponse.code;

console.log(transactionCode);

const baseUrl = 'https://sandbox-rest.avatax.com';

describe('Avatax Transactions', () => {
    const clientCreds = loadCreds();
    const client = new Avatax(clientCreds).withSecurity(clientCreds);

    describe('Creating new transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post('/api/v2/transactions/create', transactionRequest)
                .reply(201, transactionResponse);
        });

        it('should create a new transaction', () => {
            return client.createTransaction(transactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(transactionResponse);
                });
        });
    });

    /*Case for adjusting existing transaction
    *
    * Need to grab transactionCode from newly created transaction above
    * transactionCode = actualResponse.code;
    * EDIT - its hard coded in so we can cheat a little
    * */
    console.log(transactionCode);
    describe('Adjusting existing transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post(`/api/v2/companies/${companyCode}/transactions/${transactionCode}/adjust`, adjustTransactionRequest)
                .reply(200, adjustTransactionResponse);
        });

        it('should adjust an existing transaction', () => {
            return client.adjustTransaction(companyCode, transactionCode,adjustTransactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(adjustTransactionResponse);
                });
        });
    });

    /* Code for voiding an existing transaction
     *
     * Use same transactionCode from before
     * */
    describe('Voiding existing transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post(`/api/v2/companies/${companyCode}/transactions/${transactionCode}/void`, voidTransactionRequest)
                .reply(200, voidTransactionResponse);
        });

        it('should void an existing transaction', () => {
            return client.voidTransaction(companyCode, transactionCode, voidTransactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(voidTransactionResponse);
                });
        });
    });

});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import get from 'lodash.get';
import ChipInput from 'material-ui-chip-input';

import translate from '../../i18n/translate';
import FieldTitle from '../../util/FieldTitle';

const dataSourceConfig = { text: 'text', value: 'value' };

/**
 * An Input component for an array
 *
 * @example
 * <SelectArrayInput source="categories" />
 *
 * Pass possible options as an array of objects in the 'choices' attribute.
 *
 * By default, the options are built from:
 *  - the 'id' property as the option value,
 *  - the 'name' property an the option text
 * @example
 * const choices = [
 *    { id: '1', name: 'Book' },
 *    { id: '2', name: 'Video' },
 *    { id: '3', name: 'Audio' },
 * ];
 * <SelectArrayInput source="categories" choices={choices} />
 *
 * You can also customize the properties to use for the option name and value,
 * thanks to the 'optionText' and 'optionValue' attributes.
 * @example
 * const choices = [
 *    { _id: '1', name: 'Book', plural_name: 'Books' },
 *    { _id: '2', name: 'Video', plural_name: 'Videos' },
 *    { _id: '3', name: 'Audio', plural_name: 'Audios' },
 * ];
 * <SelectArrayInput source="categories" choices={choices} optionText="plural_name" optionValue="_id" />
 *
 * `optionText` also accepts a function, so you can shape the option text at will:
 * @example
 * const choices = [
 *    { id: '1', name: 'Book', quantity: 23 },
 *    { id: '2', name: 'Video', quantity: 56 },
 *    { id: '3', name: 'Audio', quantity: 12 },
 * ];
 * const optionRenderer = choice => `${choice.name} (${choice.quantity})`;
 * <SelectArrayInput source="categories" choices={choices} optionText={optionRenderer} />
 *
 * The object passed as `options` props is passed to the material-ui-chip-input component
 * @see https://github.com/TeamWertarbyte/material-ui-chip-input
 */
export class SelectArrayInput extends Component {
    state = {
        values: [],
    };

    componentWillMount = () => {
        this.setState({
            values: this.getChoicesForValues(
                this.props.input.value || [],
                this.props.choices
            ),
        });
    };

    componentWillReceiveProps = nextProps => {
        if (
            this.props.choices !== nextProps.choices ||
            this.props.input.value !== nextProps.input.value
        ) {
            this.setState({
                values: this.getChoicesForValues(
                    nextProps.input.value || [],
                    nextProps.choices
                ),
            });
        }
    };

    handleBlur = () => {};

    handleFocus = () => {
        const extracted = this.extractIds(this.state.values);
        this.props.onFocus(extracted);
        this.props.input.onFocus(extracted);
    };

    handleAdd = newValue => {
        const values = [...this.state.values, newValue];
        this.setState({ values }, this.handleChange(values));
    };

    handleDelete = newValue => {
        const values = this.state.values.filter(v => v.value !== newValue);
        this.setState({ values }, this.handleChange(values));
    };

    handleChange = eventOrValue => {
        const extracted = this.extractIds(eventOrValue);
        this.props.onChange(extracted);
        this.props.input.onChange(extracted);
    };

    extractIds = eventOrValue => {
        const value =
            eventOrValue.target && eventOrValue.target.value
                ? eventOrValue.target.value
                : eventOrValue;
        if (Array.isArray(value)) {
            return value.map(o => o.value);
        }
        return [value];
    };

    getChoicesForValues = (values, choices = []) => {
        const { optionValue, optionText } = this.props;
        if (!values || !Array.isArray(values)) {
            throw Error('Value of SelectArrayInput should be an array');
        }
        return values
            .map(
                value =>
                    choices.find(c => c[optionValue] === value) || {
                        [optionValue]: value,
                        [optionText]: value,
                    }
            )
            .map(this.formatChoice);
    };

    formatChoices = choices => choices.map(this.formatChoice);

    formatChoice = choice => {
        const {
            optionText,
            optionValue,
            translateChoice,
            translate,
        } = this.props;
        const choiceText =
            typeof optionText === 'function'
                ? optionText(choice)
                : get(choice, optionText);
        return {
            value: get(choice, optionValue),
            text: translateChoice
                ? translate(choiceText, { _: choiceText })
                : choiceText,
        };
    };

    render() {
        const {
            elStyle,
            input,
            isRequired,
            choices,
            label,
            meta,
            options,
            resource,
            source,
            setFilter,
        } = this.props;
        if (typeof meta === 'undefined') {
            throw new Error(
                "The SelectArrayInput component wasn't called within a redux-form <Field>. Did you decorate it and forget to add the addField prop to your component? See https://marmelab.com/admin-on-rest/Inputs.html#writing-your-own-input-component for details."
            );
        }
        const { touched, error } = meta;

        return (
            <ChipInput
                {...input}
                value={this.state.values}
                // Override onBlur so that redux-form does not try to handle it and miss
                // updates from onRequestAdd
                onBlur={this.handleBlur}
                onFocus={this.handleFocus}
                onClick={this.handleFocus}
                onRequestAdd={this.handleAdd}
                onRequestDelete={this.handleDelete}
                onUpdateInput={setFilter}
                floatingLabelText={
                    <FieldTitle
                        label={label}
                        source={source}
                        resource={resource}
                        isRequired={isRequired}
                    />
                }
                errorText={touched && error}
                style={elStyle}
                dataSource={this.formatChoices(choices)}
                dataSourceConfig={dataSourceConfig}
                openOnFocus
                {...options}
            />
        );
    }
}

SelectArrayInput.propTypes = {
    addField: PropTypes.bool.isRequired,
    elStyle: PropTypes.object,
    choices: PropTypes.arrayOf(PropTypes.object),
    input: PropTypes.object,
    isRequired: PropTypes.bool,
    label: PropTypes.string,
    meta: PropTypes.object,
    name: PropTypes.string,
    onBlur: PropTypes.func,
    onChange: PropTypes.func,
    onFocus: PropTypes.func,
    setFilter: PropTypes.func,
    options: PropTypes.object,
    optionText: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
        .isRequired,
    optionValue: PropTypes.string.isRequired,
    resource: PropTypes.string,
    source: PropTypes.string,
    translate: PropTypes.func.isRequired,
    translateChoice: PropTypes.bool.isRequired,
};

SelectArrayInput.defaultProps = {
    addField: true,
    choices: [],
    onBlur: () => true,
    onChange: () => true,
    onFocus: () => true,
    options: {},
    optionText: 'name',
    optionValue: 'id',
    translateChoice: true,
};

export default translate(SelectArrayInput);
<commit_msg>fix setState typo in #1427<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import get from 'lodash.get';
import ChipInput from 'material-ui-chip-input';

import translate from '../../i18n/translate';
import FieldTitle from '../../util/FieldTitle';

const dataSourceConfig = { text: 'text', value: 'value' };

/**
 * An Input component for an array
 *
 * @example
 * <SelectArrayInput source="categories" />
 *
 * Pass possible options as an array of objects in the 'choices' attribute.
 *
 * By default, the options are built from:
 *  - the 'id' property as the option value,
 *  - the 'name' property an the option text
 * @example
 * const choices = [
 *    { id: '1', name: 'Book' },
 *    { id: '2', name: 'Video' },
 *    { id: '3', name: 'Audio' },
 * ];
 * <SelectArrayInput source="categories" choices={choices} />
 *
 * You can also customize the properties to use for the option name and value,
 * thanks to the 'optionText' and 'optionValue' attributes.
 * @example
 * const choices = [
 *    { _id: '1', name: 'Book', plural_name: 'Books' },
 *    { _id: '2', name: 'Video', plural_name: 'Videos' },
 *    { _id: '3', name: 'Audio', plural_name: 'Audios' },
 * ];
 * <SelectArrayInput source="categories" choices={choices} optionText="plural_name" optionValue="_id" />
 *
 * `optionText` also accepts a function, so you can shape the option text at will:
 * @example
 * const choices = [
 *    { id: '1', name: 'Book', quantity: 23 },
 *    { id: '2', name: 'Video', quantity: 56 },
 *    { id: '3', name: 'Audio', quantity: 12 },
 * ];
 * const optionRenderer = choice => `${choice.name} (${choice.quantity})`;
 * <SelectArrayInput source="categories" choices={choices} optionText={optionRenderer} />
 *
 * The object passed as `options` props is passed to the material-ui-chip-input component
 * @see https://github.com/TeamWertarbyte/material-ui-chip-input
 */
export class SelectArrayInput extends Component {
    state = {
        values: [],
    };

    componentWillMount = () => {
        this.setState({
            values: this.getChoicesForValues(
                this.props.input.value || [],
                this.props.choices
            ),
        });
    };

    componentWillReceiveProps = nextProps => {
        if (
            this.props.choices !== nextProps.choices ||
            this.props.input.value !== nextProps.input.value
        ) {
            this.setState({
                values: this.getChoicesForValues(
                    nextProps.input.value || [],
                    nextProps.choices
                ),
            });
        }
    };

    handleBlur = () => {};

    handleFocus = () => {
        const extracted = this.extractIds(this.state.values);
        this.props.onFocus(extracted);
        this.props.input.onFocus(extracted);
    };

    handleAdd = newValue => {
        const values = [...this.state.values, newValue];
        this.setState({ values }, () => this.handleChange(this.state.values));
    };

    handleDelete = newValue => {
        const values = this.state.values.filter(v => v.value !== newValue);
        this.setState({ values }, () => this.handleChange(this.state.values));
    };

    handleChange = eventOrValue => {
        const extracted = this.extractIds(eventOrValue);
        this.props.onChange(extracted);
        this.props.input.onChange(extracted);
    };

    extractIds = eventOrValue => {
        const value =
            eventOrValue.target && eventOrValue.target.value
                ? eventOrValue.target.value
                : eventOrValue;
        if (Array.isArray(value)) {
            return value.map(o => o.value);
        }
        return [value];
    };

    getChoicesForValues = (values, choices = []) => {
        const { optionValue, optionText } = this.props;
        if (!values || !Array.isArray(values)) {
            throw Error('Value of SelectArrayInput should be an array');
        }
        return values
            .map(
                value =>
                    choices.find(c => c[optionValue] === value) || {
                        [optionValue]: value,
                        [optionText]: value,
                    }
            )
            .map(this.formatChoice);
    };

    formatChoices = choices => choices.map(this.formatChoice);

    formatChoice = choice => {
        const {
            optionText,
            optionValue,
            translateChoice,
            translate,
        } = this.props;
        const choiceText =
            typeof optionText === 'function'
                ? optionText(choice)
                : get(choice, optionText);
        return {
            value: get(choice, optionValue),
            text: translateChoice
                ? translate(choiceText, { _: choiceText })
                : choiceText,
        };
    };

    render() {
        const {
            elStyle,
            input,
            isRequired,
            choices,
            label,
            meta,
            options,
            resource,
            source,
            setFilter,
        } = this.props;
        if (typeof meta === 'undefined') {
            throw new Error(
                "The SelectArrayInput component wasn't called within a redux-form <Field>. Did you decorate it and forget to add the addField prop to your component? See https://marmelab.com/admin-on-rest/Inputs.html#writing-your-own-input-component for details."
            );
        }
        const { touched, error } = meta;

        return (
            <ChipInput
                {...input}
                value={this.state.values}
                // Override onBlur so that redux-form does not try to handle it and miss
                // updates from onRequestAdd
                onBlur={this.handleBlur}
                onFocus={this.handleFocus}
                onClick={this.handleFocus}
                onRequestAdd={this.handleAdd}
                onRequestDelete={this.handleDelete}
                onUpdateInput={setFilter}
                floatingLabelText={
                    <FieldTitle
                        label={label}
                        source={source}
                        resource={resource}
                        isRequired={isRequired}
                    />
                }
                errorText={touched && error}
                style={elStyle}
                dataSource={this.formatChoices(choices)}
                dataSourceConfig={dataSourceConfig}
                openOnFocus
                {...options}
            />
        );
    }
}

SelectArrayInput.propTypes = {
    addField: PropTypes.bool.isRequired,
    elStyle: PropTypes.object,
    choices: PropTypes.arrayOf(PropTypes.object),
    input: PropTypes.object,
    isRequired: PropTypes.bool,
    label: PropTypes.string,
    meta: PropTypes.object,
    name: PropTypes.string,
    onBlur: PropTypes.func,
    onChange: PropTypes.func,
    onFocus: PropTypes.func,
    setFilter: PropTypes.func,
    options: PropTypes.object,
    optionText: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
        .isRequired,
    optionValue: PropTypes.string.isRequired,
    resource: PropTypes.string,
    source: PropTypes.string,
    translate: PropTypes.func.isRequired,
    translateChoice: PropTypes.bool.isRequired,
};

SelectArrayInput.defaultProps = {
    addField: true,
    choices: [],
    onBlur: () => true,
    onChange: () => true,
    onFocus: () => true,
    options: {},
    optionText: 'name',
    optionValue: 'id',
    translateChoice: true,
};

export default translate(SelectArrayInput);
<|endoftext|>


<commit_before>import superagent from 'superagent';
import config from '../config';
import { setUser, clearToken } from 'redux/modules/auth';
import { show as showToast } from 'redux/modules/toast';

const methods = ['get', 'post', 'put', 'patch', 'del'];

function formatUrl(path) {
  const adjustedPath = path[0] !== '/' ? '/' + path : path;
  if (__SERVER__) {
    // Prepend host and port of the API server to the path.
    return 'http://' + config.apiHost + ':' + config.apiPort + '/api' + adjustedPath;
  }
  // Prepend `/api` to relative URL, to proxy to API server.
  return '/api' + adjustedPath;
}

/*
 * This silly underscore is here to avoid a mysterious "ReferenceError: ApiClient is not defined" error.
 * See Issue #14. https://github.com/erikras/react-redux-universal-hot-example/issues/14
 *
 * Remove it at your own risk.
 */
class _ApiClient {
  constructor(req) {
    methods.forEach((method) =>
      this[method] = (path, { params, data, attach } = {}) => new Promise((resolve, reject) => {
        const request = superagent[method](formatUrl(path));

        if (params) {
          request.query(params);
        }

        if (attach) {
          for (const [fieldName, file] of Object.entries(attach)) {
            request.attach(fieldName, file);
          }
        }

        if (__SERVER__ && req.get('cookie')) {
          request.set('cookie', req.get('cookie'));
        }

        if (data) {
          request.send(data);
        }

        request.end((err, { body, headers } = {}) => {
          if (headers && headers['x-remove-user-token'] === 'yes') {
            const { dispatch } = this.store;
            dispatch(clearToken());
            dispatch(setUser());
            dispatch(showToast('Время сессии истекло - необходимо войти снова', 'cancel', 'error'));
          }
          return err ? reject(body || err) : resolve(body);
        });
      }));
  }

  setStore(store) {
    this.store = store;
  }
}

const ApiClient = _ApiClient;

export default ApiClient;
<commit_msg>hot fix x-remove-user-token<commit_after>import superagent from 'superagent';
import config from '../config';
import { setUser, clearToken } from 'redux/modules/auth';
import { show as showToast } from 'redux/modules/toast';

const methods = ['get', 'post', 'put', 'patch', 'del'];

function formatUrl(path) {
  const adjustedPath = path[0] !== '/' ? '/' + path : path;
  if (__SERVER__) {
    // Prepend host and port of the API server to the path.
    return 'http://' + config.apiHost + ':' + config.apiPort + '/api' + adjustedPath;
  }
  // Prepend `/api` to relative URL, to proxy to API server.
  return '/api' + adjustedPath;
}

/*
 * This silly underscore is here to avoid a mysterious "ReferenceError: ApiClient is not defined" error.
 * See Issue #14. https://github.com/erikras/react-redux-universal-hot-example/issues/14
 *
 * Remove it at your own risk.
 */
class _ApiClient {
  constructor(req) {
    methods.forEach((method) =>
      this[method] = (path, { params, data, attach } = {}) => new Promise((resolve, reject) => {
        const request = superagent[method](formatUrl(path));

        if (params) {
          request.query(params);
        }

        if (attach) {
          for (const [fieldName, file] of Object.entries(attach)) {
            request.attach(fieldName, file);
          }
        }

        if (__SERVER__ && req.get('cookie')) {
          request.set('cookie', req.get('cookie'));
        }

        if (data) {
          request.send(data);
        }

        request.end((err, { body, headers } = {}) => {
          if ((headers && headers['x-remove-user-token']) === 'yes') {
            const { dispatch } = this.store;
            dispatch(clearToken());
            dispatch(setUser());
            dispatch(showToast('Время сессии истекло - необходимо войти снова', 'cancel', 'error'));
          }
          return err ? reject(body || err) : resolve(body);
        });
      }));
  }

  setStore(store) {
    this.store = store;
  }
}

const ApiClient = _ApiClient;

export default ApiClient;
<|endoftext|>


<commit_before>import querystring from 'querystring';
import _ from 'lodash';
import { format as formatDate, subDays, isWithinRange } from 'date-fns';
import config from 'configs';
import { setPackages } from '../packages/packages.js';
import processPackagesStats from 'frontend/src/utils/processPackagesStats';
import getPackagesDownloads from 'utils/stats/getPackagesDownloads';
import isPackageName from 'utils/isPackageName';
import fetchReposCommitsStats from 'frontend/src/home/fetchReposCommitStats';
import withRender from './home.html';
import { downloadCsv } from './downloadCsv';

const palette = config.palette;
const presetPackages = _.shuffle(config.presetPackages);

const maxRequestPeriod = 365; // ~1 year

const {
  default: packageInput,
  emitter: packageEvents,
  packages,
} = require('../packages/packages');

const getPackagesDownloadDataByNames = async (names, start, end) => {
  setTimeout(() => ga('send', 'pageview'));

  // set notify to false to prevent triggering route change
  setPackages(names, false);

  const operation = _.every(names, isPackageName)
    ? // names are npm packages
      getPackagesDownloadsOverPeriod(names, start, end).then(
        processPackagesStats,
      )
    : // names are github repo names
      fetchReposCommitsStats(names);

  return operation;
};

const getPackagesReleaseDataByNames = async (
  packageNames,
  startDaysOffset,
  endDaysOffset,
) => {
  const startDate = subDays(Date.now(), startDaysOffset);
  const endDate = subDays(Date.now(), endDaysOffset);
  const packageReleaseResponses = await Promise.all(
    packageNames.map(packageName =>
      fetch(`/api/npm-registry/${packageName}`)
        .then(response => response.json())
        .then(versionDateMap => [
          packageName,
          _.invertBy(
            _.omitBy(versionDateMap, (datePublished, versionName) => {
              if (['created', 'modified'].includes(versionName)) return true;
              if (!isWithinRange(datePublished, startDate, endDate))
                return true;
              if (versionName.includes('-')) return true;
            }),
            datePublished =>
              formatDate(datePublished, 'YYYY-MM-DD', null, 'UTC'),
          ),
        ]),
    ),
  );
  return Object.fromEntries(packageReleaseResponses);
};

/**
 * Merge 2 statistic periods
 * @param period0 Period before period1
 * @param period1 Period after period0
 * @returns The merged period
 */
function mergePeriods(period0, period1) {
  const sumPackages = [];

  for (let p = 0; p < period0.length; ++p) {
    sumPackages.push({
      downloads: period0[p].entries.concat(period1[p].entries),
      package: period0[p].package,
      start: period0[p].start,
      end: period1[p].end,
    });
  }

  return sumPackages;
}

function maxDate(a, b) {
  return new Date(Math.max(a.getTime(), b.getTime()));
}

/**
 * @param names    {string} Package names
 * @param startDay {number} Start of period, 1 is yesterday
 * @param endDay   {number} End of period 0 is today
 * @returns {Promise<any>}
 */
function getPackagesDownloadsOverPeriod(names, startDay, endDay) {
  const requestPeriod = Math.min(maxRequestPeriod, startDay - endDay);
  const requestEndDay = startDay - requestPeriod;

  const startStats = new Date(Date.UTC(2015, 1, 10));

  let startDate = maxDate(startStats, subDays(new Date(), startDay));
  let endDate = maxDate(startStats, subDays(new Date(), requestEndDay));

  startDate = formatDate(startDate, 'YYYY-MM-DD', null, 'UTC');
  endDate = formatDate(endDate, 'YYYY-MM-DD', null, 'UTC');

  const period1 = getPackagesDownloads(names, { startDate, endDate });

  if (requestEndDay > 0) {
    const period2 = getPackagesDownloadsOverPeriod(
      names,
      startDay - requestPeriod - 1,
      endDay,
    );
    return Promise.all([period1, period2]).then(res =>
      mergePeriods(res[0], res[1]),
    );
  }
  return period1;
}

export default withRender({
  created() {
    this.isLoading = true;

    Promise.allSettled([
      getPackagesDownloadDataByNames(
        this.packageNames,
        this.$route.query.start ? this.$route.query.start : 365,
        this.$route.query.end ? this.$route.query.end : 0,
      ),
      this.shouldShowVersionDates &&
        getPackagesReleaseDataByNames(
          this.packageNames,
          this.$route.query.start ? this.$route.query.start : 365,
          this.$route.query.end ? this.$route.query.end : 0,
        ),
    ]).then(([packagesDownloadStatsResponse, packageVersionDatesResponse]) => {
      if (
        this.shouldShowVersionDates &&
        packageVersionDatesResponse.status === 'fulfilled'
      ) {
        const packageVersionDates = packageVersionDatesResponse.value;
        const packagesDownloadStats = packagesDownloadStatsResponse.value;
        this.packageDownloadStats = packagesDownloadStats.map(
          ({ name, downloads }) => ({
            name,
            entries: downloads.map(({ day, count }) => ({
              day,
              count,
              releases:
                packageVersionDates[name][
                  formatDate(day, 'YYYY-MM-DD', null, 'UTC')
                ] || [],
            })),
          }),
        );
      } else {
        this.packageDownloadStats = packagesDownloadStatsResponse.value;
      }

      this.isLoading = false;
    });
  },
  render: withRender.default,
  data() {
    return {
      presetPackages,
      samplePreset: [],
      packageDownloadStats: null,
      isLoading: true,
      shouldShowVersionDates: true,
      palette,
      hoverCount: 0,
      twitterIcon: require('../assets/images/icon-twitter.svg'),
      shouldShowComments:
        window.innerWidth >= 1000 &&
        !JSON.parse(!!window.localStorage.getItem('shouldShowComments')),
    };
  },
  computed: {
    shareUrl() {
      return (
        this.packageNames &&
        `http://npmcharts.com/compare/${this.packageNames.join(',')}`
      );
    },
    twitterShareUrl() {
      return (
        this.shareUrl &&
        `https://twitter.com/intent/tweet?url=${window.encodeURIComponent(
          this.shareUrl,
        )}`
      );
    },
    isEmbedded() {
      return this.isMinimalMode;
    },
    queryString() {
      return querystring.stringify(this.$route.query);
    },
    interval() {
      return Number(
        this.$route.query.interval || this.$route.query.periodLength || 7,
      );
    },
    isUsingPresetPackages() {
      return !this.$route.params.packages;
    },
    packageNames() {
      const packageNames = this.isUsingPresetPackages
        ? _.sample(presetPackages)
        : this.$route.params.packages
            .split(',')
            .map(packageName => window.decodeURIComponent(packageName));
      return packageNames;
    },
    isMinimalMode() {
      return this.$route.query.minimal === 'true';
    },
  },
  watch: {
    shouldShowComments() {
      this.$refs.graph.render();
    },
    isMinimalMode(isMinimalMode, prevIsMinimalMode) {
      console.log('watch isMinimalMode');
      if (isMinimalMode) {
        document.body.classList.add('minimal');
      } else {
        document.body.classList.remove('minimal');
      }
    },
  },
  mounted() {
    if (this.isMinimalMode) {
      document.body.classList.add('minimal');
    } else {
      document.body.classList.remove('minimal');
    }
    packageEvents.on('change', this.handlePackagesChange);
    // expose router so puppeteer can trigger route changes
    window.router = this.$router;
  },
  beforeDestroy() {
    packageEvents.removeListener('change', this.handlePackagesChange);
  },
  methods: {
    track(eventName, value) {
      ga('send', 'event', eventName, value);
    },
    getMergedQueryParams(params) {
      const merged = { ...this.$route.query, ...params };
      delete merged.periodLength;
      return merged;
    },
    handlePackagesChange() {
      const nextRouteSansQuery = `/compare/${packages.join(',')}`;
      if (this.$router.app.$route.path !== nextRouteSansQuery) {
        this.$router.push(`${nextRouteSansQuery}?${this.queryString}`);
      }
    },
    addPackage(packageName) {
      ga(
        'send',
        'event',
        'packageInput',
        'add',
        `${packageName} existing:${this.packageNames}`,
      );

      this.$router.push({
        path: `/compare/${
          this.$route.params && this.$route.params.packages
            ? this.$route.params.packages + ',' + packageName
            : packageName
        }`,
        query: this.$route.query,
      });
    },
    clearPackages() {
      this.$router.push('/compare');
    },
    handleClickTwitter() {
      ga('send', 'event', 'share', 'twitter', this.twitterShareUrl);
      window.open(this.twitterShareUrl);
    },
    handleHoverTwitter() {
      this.hoverCount++;
      ga(
        'send',
        'event',
        'hoverShare',
        'twitter',
        this.twitterShareUrl,
        this.hoverCount,
      );
    },
    handleMouseEnterTwitter() {
      this.twitterEventTimeout = setTimeout(this.handleHoverTwitter, 500);
    },
    handleMouseLeaveTwitter() {
      clearTimeout(this.twitterEventTimeout);
    },
    handleDownloadCsv(e) {
      e.preventDefault();
      const packageNames = this.packageDownloadStats.map(x => x.name);
      const moduleWithLongestHistory = _.maxBy(
        this.packageDownloadStats,
        x => x.entries.length,
      );
      var csv = [['Date', ...packageNames]]
        .concat(
          moduleWithLongestHistory.entries.map(({ day, downloads }) => {
            return [day.toLocaleDateString()].concat(
              this.packageDownloadStats
                .map(
                  packageDownloadStats =>
                    packageDownloadStats.entries.find(
                      x => x.day.toISOString() === day.toISOString(),
                    ).count || '',
                )
                .join(','),
            );
          }),
        )
        .join('\n');
      this.track('download csv', packageNames);
      downloadCsv(csv, `${packageNames}.csv`);
    },
    shuffle: _.shuffle,
  },
  components: {
    'package-input': packageInput,
    graph: require('../graph/graph').default,
  },
});
<commit_msg>fix: when falling back, downloads is now entries<commit_after>import querystring from 'querystring';
import _ from 'lodash';
import { format as formatDate, subDays, isWithinRange } from 'date-fns';
import config from 'configs';
import { setPackages } from '../packages/packages.js';
import processPackagesStats from 'frontend/src/utils/processPackagesStats';
import getPackagesDownloads from 'utils/stats/getPackagesDownloads';
import isPackageName from 'utils/isPackageName';
import fetchReposCommitsStats from 'frontend/src/home/fetchReposCommitStats';
import withRender from './home.html';
import { downloadCsv } from './downloadCsv';

const palette = config.palette;
const presetPackages = _.shuffle(config.presetPackages);

const maxRequestPeriod = 365; // ~1 year

const {
  default: packageInput,
  emitter: packageEvents,
  packages,
} = require('../packages/packages');

const getPackagesDownloadDataByNames = async (names, start, end) => {
  setTimeout(() => ga('send', 'pageview'));

  // set notify to false to prevent triggering route change
  setPackages(names, false);

  const operation = _.every(names, isPackageName)
    ? // names are npm packages
      getPackagesDownloadsOverPeriod(names, start, end).then(
        processPackagesStats,
      )
    : // names are github repo names
      fetchReposCommitsStats(names);

  return operation;
};

const getPackagesReleaseDataByNames = async (
  packageNames,
  startDaysOffset,
  endDaysOffset,
) => {
  const startDate = subDays(Date.now(), startDaysOffset);
  const endDate = subDays(Date.now(), endDaysOffset);
  const packageReleaseResponses = await Promise.all(
    packageNames.map(packageName =>
      fetch(`/api/npm-registry/${packageName}`)
        .then(response => response.json())
        .then(versionDateMap => [
          packageName,
          _.invertBy(
            _.omitBy(versionDateMap, (datePublished, versionName) => {
              if (['created', 'modified'].includes(versionName)) return true;
              if (!isWithinRange(datePublished, startDate, endDate))
                return true;
              if (versionName.includes('-')) return true;
            }),
            datePublished =>
              formatDate(datePublished, 'YYYY-MM-DD', null, 'UTC'),
          ),
        ]),
    ),
  );
  return Object.fromEntries(packageReleaseResponses);
};

/**
 * Merge 2 statistic periods
 * @param period0 Period before period1
 * @param period1 Period after period0
 * @returns The merged period
 */
function mergePeriods(period0, period1) {
  const sumPackages = [];

  for (let p = 0; p < period0.length; ++p) {
    sumPackages.push({
      downloads: period0[p].entries.concat(period1[p].entries),
      package: period0[p].package,
      start: period0[p].start,
      end: period1[p].end,
    });
  }

  return sumPackages;
}

function maxDate(a, b) {
  return new Date(Math.max(a.getTime(), b.getTime()));
}

/**
 * @param names    {string} Package names
 * @param startDay {number} Start of period, 1 is yesterday
 * @param endDay   {number} End of period 0 is today
 * @returns {Promise<any>}
 */
function getPackagesDownloadsOverPeriod(names, startDay, endDay) {
  const requestPeriod = Math.min(maxRequestPeriod, startDay - endDay);
  const requestEndDay = startDay - requestPeriod;

  const startStats = new Date(Date.UTC(2015, 1, 10));

  let startDate = maxDate(startStats, subDays(new Date(), startDay));
  let endDate = maxDate(startStats, subDays(new Date(), requestEndDay));

  startDate = formatDate(startDate, 'YYYY-MM-DD', null, 'UTC');
  endDate = formatDate(endDate, 'YYYY-MM-DD', null, 'UTC');

  const period1 = getPackagesDownloads(names, { startDate, endDate });

  if (requestEndDay > 0) {
    const period2 = getPackagesDownloadsOverPeriod(
      names,
      startDay - requestPeriod - 1,
      endDay,
    );
    return Promise.all([period1, period2]).then(res =>
      mergePeriods(res[0], res[1]),
    );
  }
  return period1;
}

export default withRender({
  created() {
    this.isLoading = true;

    Promise.allSettled([
      getPackagesDownloadDataByNames(
        this.packageNames,
        this.$route.query.start ? this.$route.query.start : 365,
        this.$route.query.end ? this.$route.query.end : 0,
      ),
      this.shouldShowVersionDates &&
        getPackagesReleaseDataByNames(
          this.packageNames,
          this.$route.query.start ? this.$route.query.start : 365,
          this.$route.query.end ? this.$route.query.end : 0,
        ),
    ]).then(([packagesDownloadStatsResponse, packageVersionDatesResponse]) => {
      if (
        this.shouldShowVersionDates &&
        packageVersionDatesResponse.status === 'fulfilled'
      ) {
        const packageVersionDates = packageVersionDatesResponse.value;
        const packagesDownloadStats = packagesDownloadStatsResponse.value;
        this.packageDownloadStats = packagesDownloadStats.map(
          ({ name, downloads }) => ({
            name,
            entries: downloads.map(({ day, count }) => ({
              day,
              count,
              releases:
                packageVersionDates[name][
                  formatDate(day, 'YYYY-MM-DD', null, 'UTC')
                ] || [],
            })),
          }),
        );
      } else {
        this.packageDownloadStats = packagesDownloadStatsResponse.value.map(
          ({ name, downloads }) => ({
            name,
            entries: downloads,
          }),
        );
      }

      this.isLoading = false;
    });
  },
  render: withRender.default,
  data() {
    return {
      presetPackages,
      samplePreset: [],
      packageDownloadStats: null,
      isLoading: true,
      shouldShowVersionDates: true,
      palette,
      hoverCount: 0,
      twitterIcon: require('../assets/images/icon-twitter.svg'),
      shouldShowComments:
        window.innerWidth >= 1000 &&
        !JSON.parse(!!window.localStorage.getItem('shouldShowComments')),
    };
  },
  computed: {
    shareUrl() {
      return (
        this.packageNames &&
        `http://npmcharts.com/compare/${this.packageNames.join(',')}`
      );
    },
    twitterShareUrl() {
      return (
        this.shareUrl &&
        `https://twitter.com/intent/tweet?url=${window.encodeURIComponent(
          this.shareUrl,
        )}`
      );
    },
    isEmbedded() {
      return this.isMinimalMode;
    },
    queryString() {
      return querystring.stringify(this.$route.query);
    },
    interval() {
      return Number(
        this.$route.query.interval || this.$route.query.periodLength || 7,
      );
    },
    isUsingPresetPackages() {
      return !this.$route.params.packages;
    },
    packageNames() {
      const packageNames = this.isUsingPresetPackages
        ? _.sample(presetPackages)
        : this.$route.params.packages
            .split(',')
            .map(packageName => window.decodeURIComponent(packageName));
      return packageNames;
    },
    isMinimalMode() {
      return this.$route.query.minimal === 'true';
    },
  },
  watch: {
    shouldShowComments() {
      this.$refs.graph.render();
    },
    isMinimalMode(isMinimalMode, prevIsMinimalMode) {
      console.log('watch isMinimalMode');
      if (isMinimalMode) {
        document.body.classList.add('minimal');
      } else {
        document.body.classList.remove('minimal');
      }
    },
  },
  mounted() {
    if (this.isMinimalMode) {
      document.body.classList.add('minimal');
    } else {
      document.body.classList.remove('minimal');
    }
    packageEvents.on('change', this.handlePackagesChange);
    // expose router so puppeteer can trigger route changes
    window.router = this.$router;
  },
  beforeDestroy() {
    packageEvents.removeListener('change', this.handlePackagesChange);
  },
  methods: {
    track(eventName, value) {
      ga('send', 'event', eventName, value);
    },
    getMergedQueryParams(params) {
      const merged = { ...this.$route.query, ...params };
      delete merged.periodLength;
      return merged;
    },
    handlePackagesChange() {
      const nextRouteSansQuery = `/compare/${packages.join(',')}`;
      if (this.$router.app.$route.path !== nextRouteSansQuery) {
        this.$router.push(`${nextRouteSansQuery}?${this.queryString}`);
      }
    },
    addPackage(packageName) {
      ga(
        'send',
        'event',
        'packageInput',
        'add',
        `${packageName} existing:${this.packageNames}`,
      );

      this.$router.push({
        path: `/compare/${
          this.$route.params && this.$route.params.packages
            ? this.$route.params.packages + ',' + packageName
            : packageName
        }`,
        query: this.$route.query,
      });
    },
    clearPackages() {
      this.$router.push('/compare');
    },
    handleClickTwitter() {
      ga('send', 'event', 'share', 'twitter', this.twitterShareUrl);
      window.open(this.twitterShareUrl);
    },
    handleHoverTwitter() {
      this.hoverCount++;
      ga(
        'send',
        'event',
        'hoverShare',
        'twitter',
        this.twitterShareUrl,
        this.hoverCount,
      );
    },
    handleMouseEnterTwitter() {
      this.twitterEventTimeout = setTimeout(this.handleHoverTwitter, 500);
    },
    handleMouseLeaveTwitter() {
      clearTimeout(this.twitterEventTimeout);
    },
    handleDownloadCsv(e) {
      e.preventDefault();
      const packageNames = this.packageDownloadStats.map(x => x.name);
      const moduleWithLongestHistory = _.maxBy(
        this.packageDownloadStats,
        x => x.entries.length,
      );
      var csv = [['Date', ...packageNames]]
        .concat(
          moduleWithLongestHistory.entries.map(({ day, downloads }) => {
            return [day.toLocaleDateString()].concat(
              this.packageDownloadStats
                .map(
                  packageDownloadStats =>
                    packageDownloadStats.entries.find(
                      x => x.day.toISOString() === day.toISOString(),
                    ).count || '',
                )
                .join(','),
            );
          }),
        )
        .join('\n');
      this.track('download csv', packageNames);
      downloadCsv(csv, `${packageNames}.csv`);
    },
    shuffle: _.shuffle,
  },
  components: {
    'package-input': packageInput,
    graph: require('../graph/graph').default,
  },
});
<|endoftext|>


<commit_before><commit_msg>remove old gif<commit_after><|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import {
  cloneIfElement,
  requestTimeout,
  clearRequestTimeout,
  throttle,
  callIfExists
} from '../utils'
import {childIsFunctionInvariant} from '../invariants'

/**
const MousePositionButton = props => (
  <MousePosition propName='isOver' enterDelay={500} leaveDelay={200}>
    {
      ({
        mousePositionRef,
        clientX,
        clientY,
        elementX,
        elementY,
        isOver
      }) => (
        <button
          ref={mousePositionRef}
          className={`
            btn
            ${isOver ? 'btn--m' : 'btn--s'}
          `}
        >
          Element position X: {elementX}
          Element position Y: {elementY}
        </button>
      )
    }
  </MousePosition>
)
*/

export const canMove = !("ontouchstart" in window)

export class MousePosition extends React.PureComponent {
  static propTypes = {
    propName: PropTypes.string.isRequired,
    enterDelay: PropTypes.number,
    leaveDelay: PropTypes.number,
    onMove: PropTypes.func,
    onLeave: PropTypes.func
  }

  static defaultProps = {propName: 'isOver'}
  element = null
  timeout = null
  entered = false

  constructor (props) {
    super(props)
    const {propName} = props
    this.state = {
      clientX: null,
      clientY: null,
      elementX: null,
      elementY: null,
      [propName]: false
    }
  }

  mousePositionRef = e => {
    if (this.element !== null) {
      this.removeListeners(this.element)
    }

    if (e !== null) {
      this.element = e
      this.addListeners(this.element)
    }
  }

  delay = (onOrOff, delay) => {
    return e => {
      if (!canMove) {
        return
      }

      const {propName} = this.props

      if (this.timeout) {
        clearRequestTimeout(this.timeout)
      }

      if (delay) {
        this.timeout = requestTimeout(() => onOrOff(e), delay)
      } else {
        onOrOff(e)
      }
    }
  }

  get events () {
    const {enterDelay, leaveDelay} = this.props

    return {
      mouseenter: this.delay(this.onEnter, enterDelay),
      mousemove: this.onMove,
      mouseleave: this.delay(this.onLeave, leaveDelay)
    }
  }

  addListeners (e) {
    if (e === null) return;
    for (let name in this.events) {
      e.addEventListener(name, this.events[name])
    }
  }

  removeListeners (e) {
    if (e === null) return;
    for (let name in this.events) {
      e.removeEventListener(name, this.events[name])
    }
  }

  componentWillUnmount () {
    this.removeListeners(this.element)
  }

  onMove = throttle(
    e => {
      if (canMove === false || this.entered === false) return;
      const {propName} = this.props
      const {clientX, clientY, screenX, screenY, pageX, pageY} = e
      const elementX = pageX - this.element.offsetLeft
      const elementY = pageY - this.element.offsetTop
      this.setState(
        {
          pageX,
          pageY,
          clientX,
          clientY,
          screenX,
          screenY,
          elementX,
          elementY,
          elementWidth: this.element.offsetWidth,
          elementHeight: this.element.offsetHeight,
          [propName]: true
        },
        () => callIfExists(this.props.onMove, this.state, e)
      )
    }
  )

  onEnter = e => this.entered = true

  onLeave = e => {
    if (canMove === false) return;
    const {propName} = this.props
    this.entered = false

    this.setState(
      {
        pageX: null,
        pageY: null,
        clientX: null,
        clientY: null,
        screenX: null,
        screenY: null,
        elementX: null,
        elementY: null,
        [propName]: false
      },
      () => callIfExists(this.props.onLeave, this.state, e)
    )
  }

  render () {
    const {children, propName, ...props} = this.props
    const {mousePositionRef} = this

    return cloneIfElement(
      children,
      {
        mousePositionRef,
        ...this.state,
        ...props
      }
    )
  }
}

export default MousePosition
<commit_msg>Fixes delay issue in MousePosition<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import {
  cloneIfElement,
  requestTimeout,
  clearRequestTimeout,
  throttle,
  callIfExists
} from '../utils'
import {childIsFunctionInvariant} from '../invariants'

/**
const MousePositionButton = props => (
  <MousePosition propName='isOver' enterDelay={500} leaveDelay={200}>
    {
      ({
        mousePositionRef,
        clientX,
        clientY,
        elementX,
        elementY,
        isOver
      }) => (
        <button
          ref={mousePositionRef}
          className={`
            btn
            ${isOver ? 'btn--m' : 'btn--s'}
          `}
        >
          Element position X: {elementX}
          Element position Y: {elementY}
        </button>
      )
    }
  </MousePosition>
)
*/

export const canMove = !("ontouchstart" in window)

export class MousePosition extends React.PureComponent {
  static propTypes = {
    propName: PropTypes.string.isRequired,
    enterDelay: PropTypes.number,
    leaveDelay: PropTypes.number,
    onMove: PropTypes.func,
    onLeave: PropTypes.func
  }

  static defaultProps = {propName: 'isOver'}
  element = null
  timeout = null
  entered = false

  constructor (props) {
    super(props)
    const {propName} = props
    this.state = {
      clientX: null,
      clientY: null,
      elementX: null,
      elementY: null,
      [propName]: false
    }
  }

  mousePositionRef = e => {
    if (this.element !== null) {
      this.removeListeners(this.element)
    }

    if (e !== null) {
      this.element = e
      this.addListeners(this.element)
    }
  }

  delay = (onOrOff, delay) => {
    return e => {
      if (!canMove) {
        return
      }

      const {propName} = this.props

      if (this.timeout) {
        clearRequestTimeout(this.timeout)
      }

      if (delay) {
        this.timeout = requestTimeout(() => onOrOff(e), delay)
      } else {
        onOrOff(e)
      }
    }
  }

  get events () {
    const {enterDelay, leaveDelay} = this.props

    return {
      mouseenter: this.delay(this.onEnter, enterDelay),
      mousemove: this.onMove,
      mouseleave: this.delay(this.onLeave, leaveDelay)
    }
  }

  addListeners (e) {
    if (e === null) return;
    for (let name in this.events) {
      e.addEventListener(name, this.events[name])
    }
  }

  removeListeners (e) {
    if (e === null) return;
    for (let name in this.events) {
      e.removeEventListener(name, this.events[name])
    }
  }

  componentWillUnmount () {
    this.removeListeners(this.element)
  }

  onMove = throttle(
    e => {
      if (canMove === false || this.entered === false) return;
      const {propName} = this.props
      const {clientX, clientY, screenX, screenY, pageX, pageY} = e
      const elementX = pageX - this.element.offsetLeft
      const elementY = pageY - this.element.offsetTop
      this.setState(
        {
          pageX,
          pageY,
          clientX,
          clientY,
          screenX,
          screenY,
          elementX,
          elementY,
          elementWidth: this.element.offsetWidth,
          elementHeight: this.element.offsetHeight,
          [propName]: true
        },
        () => callIfExists(this.props.onMove, this.state, e)
      )
    }
  )

  onEnter = e => {
    this.entered = true
    this.onMove(e)
  }

  onLeave = e => {
    if (canMove === false) return;
    const {propName} = this.props
    this.entered = false

    this.setState(
      {
        pageX: null,
        pageY: null,
        clientX: null,
        clientY: null,
        screenX: null,
        screenY: null,
        elementX: null,
        elementY: null,
        [propName]: false
      },
      () => callIfExists(this.props.onLeave, this.state, e)
    )
  }

  render () {
    const {children, propName, ...props} = this.props
    const {mousePositionRef} = this

    return cloneIfElement(
      children,
      {
        mousePositionRef,
        ...this.state,
        ...props
      }
    )
  }
}

export default MousePosition
<|endoftext|>


<commit_before>'use strict';

// Include Gulp & Tools We'll Use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var pagespeed = require('psi');
var app = require('./server');

var AUTOPREFIXER_BROWSERS = [
  'ie >= 10',
  'ie_mob >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
  'ios >= 7',
  'android >= 4.4',
  'bb >= 10'
];

// Lint JavaScript
gulp.task('jshint', function () {
  return gulp.src('site-assets/*.js')
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'));
});

// Optimize Images
gulp.task('images', function () {
  return gulp.src('site-assets/*.{png,jpg,svg}')
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('dist/site-assets'))
    .pipe($.size({title: 'images'}));
});

// Copy All Files At The Root Level (app)
gulp.task('copy', function () {
  return gulp.src([
    'examples/**',
    'bower_components/**',
    'learn.json',
    'CNAME',
    '.nojekyll',
    'site-assets/favicon.ico'
  ], {
    dot: true,
    base: './'
  }).pipe(gulp.dest('dist'))
    .pipe($.size({title: 'copy'}));
});

// Compile and Automatically Prefix Stylesheets
gulp.task('styles', function () {
  // For best performance, don't add Sass partials to `gulp.src`
  return gulp.src([
      'site-assets/*.css',
    ])
    .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
    .pipe(gulp.dest('dist/site-assets'))
    .pipe($.size({title: 'styles'}))
    .pipe(gulp.dest('.tmp/site-assets'));
});

// Scan Your HTML For Assets & Optimize Them
gulp.task('html', function () {
  var assets = $.useref.assets({searchPath: '{.tmp,.}'});

  return gulp.src('index.html')
    .pipe(assets)
    // Concatenate And Minify JavaScript
    .pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
    // Concatenate And Minify Styles
    .pipe($.if('*.css', $.csso()))
    .pipe(assets.restore())
    .pipe($.useref())
    // Output Files
    .pipe(gulp.dest('dist'))
    // Running vulcanize over the written output
    // because it requires access to the written
    // CSS and JS.
    .pipe($.vulcanize({ dest: 'dist', strip: true }))
    .pipe($.size({title: 'html'}));
});

// Clean Output Directory
gulp.task('clean', del.bind(null, ['.tmp', 'dist']));

// Build Production Files, the Default Task
gulp.task('default', ['clean'], function (cb) {
  runSequence(['styles', 'copy'], ['jshint', 'html', 'images'], cb);
});

// Run PageSpeed Insights
// Update `url` below to the public URL for your site
gulp.task('pagespeed', pagespeed.bind(null, {
  // By default, we use the PageSpeed Insights
  // free (no API key) tier. You can use a Google
  // Developer API key if you have one. See
  // http://goo.gl/RkN0vE for info key: 'YOUR_API_KEY'
  url: 'https://todomvc.com',
  strategy: 'mobile'
}));

gulp.task('serve', function (cb) {
  app.listen(8080, cb);
});
<commit_msg>Fix code style in `gulpfile.js`<commit_after>'use strict';

// Include Gulp & Tools We'll Use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var pagespeed = require('psi');
var app = require('./server');

var AUTOPREFIXER_BROWSERS = [
	'ie >= 10',
	'ie_mob >= 10',
	'ff >= 30',
	'chrome >= 34',
	'safari >= 7',
	'opera >= 23',
	'ios >= 7',
	'android >= 4.4',
	'bb >= 10'
];

// Lint JavaScript
gulp.task('jshint', function () {
	return gulp.src('site-assets/*.js')
		.pipe($.jshint())
		.pipe($.jshint.reporter('jshint-stylish'));
});

// Optimize Images
gulp.task('images', function () {
	return gulp.src('site-assets/*.{png,jpg,svg}')
		.pipe($.cache($.imagemin({
			progressive: true,
			interlaced: true
		})))
		.pipe(gulp.dest('dist/site-assets'))
		.pipe($.size({title: 'images'}));
});

// Copy All Files At The Root Level (app)
gulp.task('copy', function () {
	return gulp.src([
		'examples/**',
		'bower_components/**',
		'learn.json',
		'CNAME',
		'.nojekyll',
		'site-assets/favicon.ico'
	], {
		dot: true,
		base: './'
	}).pipe(gulp.dest('dist'))
	.pipe($.size({title: 'copy'}));
});

// Compile and Automatically Prefix Stylesheets
gulp.task('styles', function () {
	// For best performance, don't add Sass partials to `gulp.src`
	return gulp.src([
		'site-assets/*.css'
	])
	.pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
	.pipe(gulp.dest('dist/site-assets'))
	.pipe($.size({title: 'styles'}))
	.pipe(gulp.dest('.tmp/site-assets'));
});

// Scan Your HTML For Assets & Optimize Them
gulp.task('html', function () {
	var assets = $.useref.assets({searchPath: '{.tmp,.}'});

	return gulp.src('index.html')
		.pipe(assets)
		// Concatenate And Minify JavaScript
		.pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
		// Concatenate And Minify Styles
		.pipe($.if('*.css', $.csso()))
		.pipe(assets.restore())
		.pipe($.useref())
		// Output Files
		.pipe(gulp.dest('dist'))
		// Running vulcanize over the written output
		// because it requires access to the written
		// CSS and JS.
		.pipe($.vulcanize({ dest: 'dist', strip: true }))
		.pipe($.size({title: 'html'}));
});

// Clean Output Directory
gulp.task('clean', del.bind(null, ['.tmp', 'dist']));

// Build Production Files, the Default Task
gulp.task('default', ['clean'], function (cb) {
	runSequence(['styles', 'copy'], ['jshint', 'html', 'images'], cb);
});

// Run PageSpeed Insights
// Update `url` below to the public URL for your site
gulp.task('pagespeed', pagespeed.bind(null, {
	// By default, we use the PageSpeed Insights
	// free (no API key) tier. You can use a Google
	// Developer API key if you have one. See
	// http://goo.gl/RkN0vE for info key: 'YOUR_API_KEY'
	url: 'https://todomvc.com',
	strategy: 'mobile'
}));

gulp.task('serve', function (cb) {
	app.listen(8080, cb);
});
<|endoftext|>


<commit_before>define([
    'jquery',
    'underscore',
    'backbone',
    'app',
    'models/project/ProjectModel'
], function($, _, Backbone, app, ProjectModel){
    var ProjectsCollection = Backbone.Collection.extend({
        model: ProjectModel,
        models: [],

        initialize: function(options){
            _.bindAll(this, 'setPage', 'url', 'fetch', 'parse', 'position');
            this.page = 0;
            this.perPage = 0;
            this.currentPage = 0;
            this.lastPage = 0;
            this.nextPageUrl = '';
            this.previousPageUrl = '';
            this.from = 0;
            this.to = 0;
        },

        setPage: function(page) {
            this.page = page;
        },

        url: function() {
            return 'api/projects/?page=' + this.page;
        },

        fetchError: function(collection, response) {
            throw new Error("Projects fetch error");
        },

        parse: function(response) {
            this.perPage = response.per_page;
            this.currentPage = response.current_page;
            this.lastPage = response.last_page;
            this.nextPageUrl = response.next_page_url;
            this.previousPageUrl = response.previous_page_url;
            this.from = response.from;
            this.to = response.to;
            return response ? response.data : [];
        },

        position: function(projectId, reload) {
            projectId = parseInt(projectId);
            var url = 'api/projects/' + projectId + '/position';
            $.ajax({
                url: url,
                contentType: 'application/json',
                dataType: 'json',
                type: 'GET',
                beforeSend: function(xhr) {
                    // Set the CSRF Token in the header for security
                    var token = $('meta[name="csrf-token"]').attr('content');
                    if (token) xhr.setRequestHeader('X-CSRF-Token', token);

                    // Set the API version
                    // TODO: get api tree and sub application name from config
                    xhr.setRequestHeader('Accept', 'application/vnd.nestorqa.v1+json');
                },
                success: function(data, textStatus, request) {
                    console.log('Positioned project ' + projectId);
                    Backbone.trigger('project:position', [data.project, reload]);
                },
                error: function(data, textStatus, request) {
                    app.showAlert('Error positioning project', request, 'error');
                }
            });
        }

    });

    return ProjectsCollection;
});
<commit_msg>Remove models as it's there by default<commit_after>define([
    'jquery',
    'underscore',
    'backbone',
    'app',
    'models/project/ProjectModel'
], function($, _, Backbone, app, ProjectModel){
    var ProjectsCollection = Backbone.Collection.extend({
        model: ProjectModel,

        initialize: function(options){
            _.bindAll(this, 'setPage', 'url', 'fetch', 'parse', 'position');
            this.page = 0;
            this.perPage = 0;
            this.currentPage = 0;
            this.lastPage = 0;
            this.nextPageUrl = '';
            this.previousPageUrl = '';
            this.from = 0;
            this.to = 0;
        },

        setPage: function(page) {
            this.page = page;
        },

        url: function() {
            return 'api/projects/?page=' + this.page;
        },

        fetchError: function(collection, response) {
            throw new Error("Projects fetch error");
        },

        parse: function(response) {
            this.perPage = response.per_page;
            this.currentPage = response.current_page;
            this.lastPage = response.last_page;
            this.nextPageUrl = response.next_page_url;
            this.previousPageUrl = response.previous_page_url;
            this.from = response.from;
            this.to = response.to;
            return response ? response.data : [];
        },

        position: function(projectId, reload) {
            projectId = parseInt(projectId);
            var url = 'api/projects/' + projectId + '/position';
            $.ajax({
                url: url,
                contentType: 'application/json',
                dataType: 'json',
                type: 'GET',
                beforeSend: function(xhr) {
                    // Set the CSRF Token in the header for security
                    var token = $('meta[name="csrf-token"]').attr('content');
                    if (token) xhr.setRequestHeader('X-CSRF-Token', token);

                    // Set the API version
                    // TODO: get api tree and sub application name from config
                    xhr.setRequestHeader('Accept', 'application/vnd.nestorqa.v1+json');
                },
                success: function(data, textStatus, request) {
                    console.log('Positioned project ' + projectId);
                    Backbone.trigger('project:position', [data.project, reload]);
                },
                error: function(data, textStatus, request) {
                    app.showAlert('Error positioning project', request, 'error');
                }
            });
        }

    });

    return ProjectsCollection;
});
<|endoftext|>