<commit_before>Controllers.controller("LoginCtrl",
    ["$scope", "$http", "$rootScope", "$location", "$timeout", "Connection", "User", "Channel", "Parser",
    function ($scope, $http, $rootScope, $location, $timeout, Connection, User, Channel, Parser)
    {
        $scope.user = User.get("~");

        $http.jsonp("http://freegeoip.net/json/?callback=JSON_CALLBACK").success(function (data)
        {
            $scope.user.country = data.country_name;
            $scope.user.flag = data.country_code;
        });

        $scope.login = function ()
        {
            //var cs = Channel.register("#Coldstorm");
            //var two = Channel.register("#2");

            var test = Channel.register("#test");

            Connection.connect("ws://coldstorm.tk:81");

            Connection.onOpen(function ()
            {
                Connection.send("NICK " + $scope.user.nickName);
                Connection.send("USER " +
                    $scope.user.color.substring(1).toUpperCase() +
                    $scope.user.flag + " - - :New coldstormer");

                Connection.onWelcome(function ()
                {
                    test.join();

                    if ($scope.user.password)
                    {
                        Connection.send("PRIVMSG NickServ identify " +
                            $scope.user.password);
                    }
                });
            });

            Connection.onMessage(function (message)
            {
                Parser.parse(message);
            });

            Connection.onClose(function ()
            {
                console.log("Closed");
            });

            $location.path("/channels/#test");
        };
    }]);
<commit_msg>Strip hash on login<commit_after>Controllers.controller("LoginCtrl",
    ["$scope", "$http", "$rootScope", "$location", "$timeout", "Connection", "User", "Channel", "Parser",
    function ($scope, $http, $rootScope, $location, $timeout, Connection, User, Channel, Parser)
    {
        $scope.user = User.get("~");

        $location.hash("");

        $http.jsonp("http://freegeoip.net/json/?callback=JSON_CALLBACK").success(function (data)
        {
            $scope.user.country = data.country_name;
            $scope.user.flag = data.country_code;
        });

        $scope.login = function ()
        {
            //var cs = Channel.register("#Coldstorm");
            //var two = Channel.register("#2");

            var test = Channel.register("#test");

            Connection.connect("ws://coldstorm.tk:81");

            Connection.onOpen(function ()
            {
                Connection.send("NICK " + $scope.user.nickName);
                Connection.send("USER " +
                    $scope.user.color.substring(1).toUpperCase() +
                    $scope.user.flag + " - - :New coldstormer");

                Connection.onWelcome(function ()
                {
                    test.join();

                    if ($scope.user.password)
                    {
                        Connection.send("PRIVMSG NickServ identify " +
                            $scope.user.password);
                    }
                });
            });

            Connection.onMessage(function (message)
            {
                Parser.parse(message);
            });

            Connection.onClose(function ()
            {
                console.log("Closed");
            });

            $location.path("/channels/#test");
        };
    }]);
<|endoftext|>


<commit_before>'use strict';

describe ('Tournament Tests', function() {

    var $httpBackend;
    var customMatchers = {
        toEqualData: function () {
            return {
                compare: function (actual, expected) {
                    if (expected === undefined) {
                        expected = '';
                    }
                    return {pass:  angular.equals(actual, expected)};
                }
            };
        }
    };

    beforeEach(function () {
        module('stbgfc.tournament');
        jasmine.addMatchers(customMatchers);
    });

    describe('TournamentController', function () {
        var scope, Tournament;

        beforeEach(
            inject(function(_Tournament_, _$httpBackend_, $rootScope, $controller) {
                Tournament = _Tournament_;
                $httpBackend = _$httpBackend_;
                scope = $rootScope.$new();
                $controller('TournamentController', {$scope: scope});

                $httpBackend
                    .whenGET('api/tournaments').respond([tournamentData]);
                $httpBackend.flush();
            })
        );

        it('should attach the tournament to the scope', function () {
            expect(scope.tournament).toEqualData(tournamentData);
        });

        it('should attach one competition to the scope', function () {
            scope.createCompetition({name: 'U11', section: 'All', groups: 2});
            expect(scope.tournament.competitions.length).toBe(6);
            expect(scope.tournament.competitions[5].name).toBe('U11');
        });
    });

    describe('ResultsController', function () {
        var scope, rootScope, Result, stateParams;
        var qry = 'api/results?conditions=%7B%22competition.name%22:%22U8%22,%22competition.section%22:%22A%22%7D';

        beforeEach(
            inject(function(_Result_, _$httpBackend_, $rootScope, $controller) {
                Result = _Result_;
                $httpBackend = _$httpBackend_;
                scope = $rootScope.$new();
                scope.tournament = tournamentData;
                stateParams = {name:'U8', section:'A'};
                rootScope = $rootScope;
                $controller('ResultsController', {$scope: scope, $stateParams: stateParams, Result: Result});
            })
        );

        it('should setup a new result', function () {
            scope.createResult();
            expect(scope.newResult).toBeDefined();
            expect(scope.newResult.index).toBe(1000);
        });

        it('should save a new result in group 1', function() {
            $httpBackend
                .whenGET(qry)
                .respond([newResultData]);
            $httpBackend.whenPOST('/api/results').respond(newResultData);
            $httpBackend.flush();

            scope.newResult = newResultData;
            scope.saveResult(1);
            var gresults = scope.competition.groups[0].results;
            expect(gresults.length).toBe(1);
            expect(gresults[0].homeTeam).toEqual('Foo');
            expect(scope.newResult).toEqual({});
        });

        it('should populate groups and results for the competition in scope', function() {
            $httpBackend
                .whenGET(qry)
                .respond(u8GroupResults);
            $httpBackend.flush();
            var grps = scope.competition.groups;
            expect(grps.length).toBe(4);
            expect(grps[0].results.length).toBe(6);
            expect(grps[1].results[0].homeTeam).toEqual('Rotherham');
            expect(grps[0].table.length).toBe(4);
            expect(grps[0].table[0].name).toBe('Sheffield Wednesday');
            expect(grps[1].table.length).toBe(0);
        });

        it('should update the results and tables when a new result is received on the socket', function() {
            $httpBackend
                .whenGET(qry)
                .respond(u8GroupResults);
            $httpBackend.flush();
            var grps = scope.competition.groups;

            expect(grps[0].results.length).toBe(6);
            expect(grps[0].table.length).toBe(4);
            expect(grps[0].table[3].name).toBe('Brentford');

            rootScope.$broadcast('socket:result', {
                _id: '0987654321',
                tag: '1',
                homeTeam: 'Millwall', homeGoals: 10,
                awayTeam: 'Wolves', awayGoals: 0,
                competition: {name: 'U8', section: 'A', group: 1}
            });

            expect(grps[0].results.length).toBe(7);
            expect(grps[0].results[6].homeTeam).toBe('Millwall');
            expect(grps[0].results[6].awayTeam).toBe('Wolves');
            expect(grps[0].table.length).toBe(6);
            expect(grps[0].table[5].name).toBe('Wolves');
        });

    });

    describe('ResultEditController', function () {
        var scope, Result, state, stateParams;

        beforeEach(
            inject(function(_Result_, _$httpBackend_, $rootScope, $controller) {
                Result = _Result_;
                $httpBackend = _$httpBackend_;
                $httpBackend.whenGET('api/results/dead012345beef')
                    .respond(newResultData);
                scope = $rootScope.$new();
                scope.tournament = tournamentData;
                state = {
                    go: function(a, b) {
                        console.log('state.go called with ' + a + ' and ' + b);
                    }
                };
                spyOn(state, 'go').and.callThrough();
                stateParams = {id:'dead012345beef'};
                $controller('ResultEditController', {$scope: scope, $stateParams: stateParams, $state: state, Result: Result});
            })
        );

        it('should add or subtract goals from teams in a match', function() {
            $httpBackend.flush();
            expect(scope.result).toEqualData(newResultData);

            // add a home goal should also init away score to 0
            scope.addGoal(true, 1);
            expect(scope.result.homeGoals).toBe(1);
            expect(scope.result.awayGoals).toBe(0);

            scope.addGoal(true, -1);
            expect(scope.result.homeGoals).toBe(0);
            expect(scope.result.awayGoals).toBe(0);

            scope.addGoal(false, 1);
            scope.addGoal(false, 1);
            expect(scope.result.homeGoals).toBe(0);
            expect(scope.result.awayGoals).toBe(2);

            scope.addGoal(false, -1);
            expect(scope.result.homeGoals).toBe(0);
            expect(scope.result.awayGoals).toBe(1);
        });

        it('should add or subtract penalties in knockout games', function() {
            $httpBackend.flush();

            scope.goalEntry = false;
            expect(scope.result).toEqualData(newResultData);

            // add a home goal should also init away score to 0
            scope.addGoal(true, 1);
            expect(scope.result.homeGoals).toBe(0);
            expect(scope.result.awayGoals).toBe(0);
            expect(scope.result.homePens).toBe(1);
            expect(scope.result.awayPens).toBe(0);

            scope.addGoal(false, 2);
            expect(scope.result.homePens).toBe(1);
            expect(scope.result.awayPens).toBe(2);
        });

        it('should update an edited result', function() {
            $httpBackend.whenPUT('api/results/dead012345beef')
                    .respond({});
            $httpBackend.flush();

            scope.result._id = 'dead012345beef';
            scope.updateResult(scope.result);
            // TODO: expect(state.go).toHaveBeenCalledWith('resultsGroup', {name: 'U10', section: 'A', group: 1});
        });
    });

    describe('NewsListController', function () {
        var scope, News;

        beforeEach(
            inject(function(_News_, _$httpBackend_, $rootScope, $controller) {
                News = _News_;
                $httpBackend = _$httpBackend_;
                scope = $rootScope.$new();
                $controller('NewsListController', {$scope: scope});

                $httpBackend
                    .whenGET('api/news').respond(newsItemData);
                $httpBackend.flush();
            })
        );

        it('should attach a list of news items to the scope', function () {
            expect(scope.latestNews).toEqualData(newsItemData[newsItemData.length-1]);
            expect(scope.newsItems[0].title).toEqual('News1');
            expect(scope.newsItems[0].body).toEqual('This is the body of the news.  Please take careful note of it :)');
        });
    });

    // ============================================================================================
    // fixtures
    // ============================================================================================

    var tournamentData = {
        name: 'Karma Tournament',
        description: 'Welcome to our Karma Tournament',
        current: true,
        club: 'Jasmine',
        siteUrl: 'http://www.example.com',
        competitions: [
            {name: 'U8', section: 'A', groups: 4},
            {name: 'U8', section: 'B', groups: 4},
            {name: 'U9', section: 'A', groups: 4},
            {name: 'U9', section: 'Champions League', groups: 2},
            {name: 'U9', section: 'Europa League', groups: 2}
        ]
    };

    var newResultData = {
        index: 1000,
        homeTeam: 'Foo',
        awayTeam: 'Bar',
        tag: '1',
        competition: {
            name: 'U10',
            section: 'A',
            group: 1
        }
    };

    var u8GroupResults = [
        {'__v':0,'index':1,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'1', 'homeTeam':'Sheffield Wednesday', 'awayTeam':'Brentford', 'homeGoals':2, 'awayGoals':0},
        {'__v':0,'index':2,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'2', 'homeTeam':'Derby County', 'awayTeam':'Middlesbrough', 'homeGoals': 0, 'awayGoals': 0},
        {'__v':0,'index':3,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'3', 'homeTeam':'Derby County', 'awayTeam':'Sheffield Wednesday', 'homeGoals': 0, 'awayGoals': 3},
        {'__v':0,'index':4,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'4', 'homeTeam':'Brentford', 'awayTeam':'Middlesbrough'},
        {'__v':0,'index':5,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'5', 'homeTeam':'Middlesbrough', 'awayTeam':'Sheffield Wednesday'},
        {'__v':0,'index':6,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'6', 'homeTeam':'Brentford', 'awayTeam':'Derby County'},
        {'__v':0,'index':7,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'1', 'homeTeam':'Rotherham', 'awayTeam':'Cardiff'},
        {'__v':0,'index':8,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'2', 'homeTeam':'MK Dons', 'awayTeam':'Bristol City'},
        {'__v':0,'index':9,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'3', 'homeTeam':'MK Dons', 'awayTeam':'Rotherham'},
        {'__v':0,'index':10,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'4', 'homeTeam':'Cardiff', 'awayTeam':'Bristol City'},
        {'__v':0,'index':11,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'5', 'homeTeam':'Bristol City', 'awayTeam':'Rotherham'},
        {'__v':0,'index':12,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'6', 'homeTeam':'Cardiff', 'awayTeam':'MK Dons'},
        {'__v':0,'index':13,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'1', 'homeTeam':'Ipswich', 'awayTeam':'Preston North End'},
        {'__v':0,'index':14,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'2', 'homeTeam':'Hull City', 'awayTeam':'Reading'},
        {'__v':0,'index':15,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'3', 'homeTeam':'Hull City', 'awayTeam':'Ipswich'},
        {'__v':0,'index':16,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'4', 'homeTeam':'Preston North End', 'awayTeam':'Reading'},
        {'__v':0,'index':17,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'5', 'homeTeam':'Reading', 'awayTeam':'Ipswich'},
        {'__v':0,'index':18,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'6', 'homeTeam':'Preston North End', 'awayTeam':'Hull City'},
        {'__v':0,'index':19,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'1', 'homeTeam':'QPR', 'awayTeam':'Fulham FC'},
        {'__v':0,'index':20,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'2', 'homeTeam':'Birmingham', 'awayTeam':'Leeds'},
        {'__v':0,'index':21,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'3', 'homeTeam':'Birmingham', 'awayTeam':'QPR'},
        {'__v':0,'index':22,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'4', 'homeTeam':'Fulham FC', 'awayTeam':'Leeds'},
        {'__v':0,'index':23,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'5', 'homeTeam':'Leeds', 'awayTeam':'QPR'},
        {'__v':0,'index':24,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'6', 'homeTeam':'Fulham FC', 'awayTeam':'Birmingham'}
    ];

    var newsItemData = [
        {
            created: new Date('2015/5/12 12:26:32'),
            title: 'News1',
            body: 'This is the body of the news.  Please take careful note of it :)'
        },
        {
            created: new Date('2015/4/1 11:17:32'),
            title: 'News2',
            body: 'This is the body of the news.  Please take careful note of it s adfsgfsd fgdsf gs fg :)'
        },
        {
            created: new Date('2015/4/11 10:13:32'),
            title: 'News3',
            body: 'This is the body of the news.  Please take careful note of it :)'
        },
        {
            created: new Date('2015/4/9 17:47:32'),
            title: 'News4',
            body: '...'
        }
    ];
});
<commit_msg>Updated karma tests to include a socket event for deleting a result<commit_after>'use strict';

describe ('Tournament Tests', function() {

    var $httpBackend;
    var customMatchers = {
        toEqualData: function () {
            return {
                compare: function (actual, expected) {
                    if (expected === undefined) {
                        expected = '';
                    }
                    return {pass:  angular.equals(actual, expected)};
                }
            };
        }
    };

    beforeEach(function () {
        module('stbgfc.tournament');
        jasmine.addMatchers(customMatchers);
    });

    describe('TournamentController', function () {
        var scope, Tournament;

        beforeEach(
            inject(function(_Tournament_, _$httpBackend_, $rootScope, $controller) {
                Tournament = _Tournament_;
                $httpBackend = _$httpBackend_;
                scope = $rootScope.$new();
                $controller('TournamentController', {$scope: scope});

                $httpBackend
                    .whenGET('api/tournaments').respond([tournamentData]);
                $httpBackend.flush();
            })
        );

        it('should attach the tournament to the scope', function () {
            expect(scope.tournament).toEqualData(tournamentData);
        });

        it('should attach one competition to the scope', function () {
            scope.createCompetition({name: 'U11', section: 'All', groups: 2});
            expect(scope.tournament.competitions.length).toBe(6);
            expect(scope.tournament.competitions[5].name).toBe('U11');
        });
    });

    describe('ResultsController', function () {
        var scope, rootScope, Result, stateParams;
        var qry = 'api/results?conditions=%7B%22competition.name%22:%22U8%22,%22competition.section%22:%22A%22%7D';

        beforeEach(
            inject(function(_Result_, _$httpBackend_, $rootScope, $controller) {
                Result = _Result_;
                $httpBackend = _$httpBackend_;
                scope = $rootScope.$new();
                scope.tournament = tournamentData;
                stateParams = {name:'U8', section:'A'};
                rootScope = $rootScope;
                $controller('ResultsController', {$scope: scope, $stateParams: stateParams, Result: Result});
            })
        );

        it('should setup a new result', function () {
            scope.createResult();
            expect(scope.newResult).toBeDefined();
            expect(scope.newResult.index).toBe(1000);
        });

        it('should save a new result in group 1', function() {
            $httpBackend
                .whenGET(qry)
                .respond([newResultData]);
            $httpBackend.whenPOST('/api/results').respond(newResultData);
            $httpBackend.flush();

            scope.newResult = newResultData;
            scope.saveResult(1);
            var gresults = scope.competition.groups[0].results;
            expect(gresults.length).toBe(1);
            expect(gresults[0].homeTeam).toEqual('Foo');
            expect(scope.newResult).toEqual({});
        });

        it('should populate groups and results for the competition in scope', function() {
            $httpBackend
                .whenGET(qry)
                .respond(u8GroupResults);
            $httpBackend.flush();
            var grps = scope.competition.groups;
            expect(grps.length).toBe(4);
            expect(grps[0].results.length).toBe(6);
            expect(grps[1].results[0].homeTeam).toEqual('Rotherham');
            expect(grps[0].table.length).toBe(4);
            expect(grps[0].table[0].name).toBe('Sheffield Wednesday');
            expect(grps[1].table.length).toBe(0);
        });

        it('should update the results and tables when a new result is received on the socket', function() {
            $httpBackend
                .whenGET(qry)
                .respond(u8GroupResults);
            $httpBackend.flush();

            var addedRes = {
                _id: '0987654321',
                tag: '1',
                homeTeam: 'Millwall', homeGoals: 10,
                awayTeam: 'Wolves', awayGoals: 0,
                competition: {name: 'U8', section: 'A', group: 1}
            };
            var grps = scope.competition.groups;

            expect(grps[0].results.length).toBe(6);
            expect(grps[0].table.length).toBe(4);
            expect(grps[0].table[3].name).toBe('Brentford');

            rootScope.$broadcast('socket:result', addedRes);

            expect(grps[0].results.length).toBe(7);
            expect(grps[0].results[6].homeTeam).toBe('Millwall');
            expect(grps[0].results[6].awayTeam).toBe('Wolves');
            expect(grps[0].table.length).toBe(6);
            expect(grps[0].table[5].name).toBe('Wolves');

            // delete it
            rootScope.$broadcast('socket:remove', addedRes);
            expect(grps[0].results.length).toBe(6);
            expect(grps[0].table.length).toBe(4);
            for (var i = 0; i < grps[0].table.length; i++) {
                expect(grps[0].table[i].name).not.toBe('Millwall');
                expect(grps[0].table[i].name).not.toBe('Wolves');
            }
        });

    });

    describe('ResultEditController', function () {
        var scope, Result, state, stateParams;

        beforeEach(
            inject(function(_Result_, _$httpBackend_, $rootScope, $controller) {
                Result = _Result_;
                $httpBackend = _$httpBackend_;
                $httpBackend.whenGET('api/results/dead012345beef')
                    .respond(newResultData);
                scope = $rootScope.$new();
                scope.tournament = tournamentData;
                state = {
                    go: function(a, b) {
                        console.log('state.go called with ' + a + ' and ' + b);
                    }
                };
                spyOn(state, 'go').and.callThrough();
                stateParams = {id:'dead012345beef'};
                $controller('ResultEditController', {$scope: scope, $stateParams: stateParams, $state: state, Result: Result});
            })
        );

        it('should add or subtract goals from teams in a match', function() {
            $httpBackend.flush();
            expect(scope.result).toEqualData(newResultData);

            // add a home goal should also init away score to 0
            scope.addGoal(true, 1);
            expect(scope.result.homeGoals).toBe(1);
            expect(scope.result.awayGoals).toBe(0);

            scope.addGoal(true, -1);
            expect(scope.result.homeGoals).toBe(0);
            expect(scope.result.awayGoals).toBe(0);

            scope.addGoal(false, 1);
            scope.addGoal(false, 1);
            expect(scope.result.homeGoals).toBe(0);
            expect(scope.result.awayGoals).toBe(2);

            scope.addGoal(false, -1);
            expect(scope.result.homeGoals).toBe(0);
            expect(scope.result.awayGoals).toBe(1);
        });

        it('should add or subtract penalties in knockout games', function() {
            $httpBackend.flush();

            scope.goalEntry = false;
            expect(scope.result).toEqualData(newResultData);

            // add a home goal should also init away score to 0
            scope.addGoal(true, 1);
            expect(scope.result.homeGoals).toBe(0);
            expect(scope.result.awayGoals).toBe(0);
            expect(scope.result.homePens).toBe(1);
            expect(scope.result.awayPens).toBe(0);

            scope.addGoal(false, 2);
            expect(scope.result.homePens).toBe(1);
            expect(scope.result.awayPens).toBe(2);
        });

        it('should update an edited result', function() {
            $httpBackend.whenPUT('api/results/dead012345beef')
                    .respond({});
            $httpBackend.flush();

            scope.result._id = 'dead012345beef';
            scope.updateResult(scope.result);
            // TODO: expect(state.go).toHaveBeenCalledWith('resultsGroup', {name: 'U10', section: 'A', group: 1});
        });
    });

    describe('NewsListController', function () {
        var scope, News;

        beforeEach(
            inject(function(_News_, _$httpBackend_, $rootScope, $controller) {
                News = _News_;
                $httpBackend = _$httpBackend_;
                scope = $rootScope.$new();
                $controller('NewsListController', {$scope: scope});

                $httpBackend
                    .whenGET('api/news').respond(newsItemData);
                $httpBackend.flush();
            })
        );

        it('should attach a list of news items to the scope', function () {
            expect(scope.latestNews).toEqualData(newsItemData[newsItemData.length-1]);
            expect(scope.newsItems[0].title).toEqual('News1');
            expect(scope.newsItems[0].body).toEqual('This is the body of the news.  Please take careful note of it :)');
        });
    });

    // ============================================================================================
    // fixtures
    // ============================================================================================

    var tournamentData = {
        name: 'Karma Tournament',
        description: 'Welcome to our Karma Tournament',
        current: true,
        club: 'Jasmine',
        siteUrl: 'http://www.example.com',
        competitions: [
            {name: 'U8', section: 'A', groups: 4},
            {name: 'U8', section: 'B', groups: 4},
            {name: 'U9', section: 'A', groups: 4},
            {name: 'U9', section: 'Champions League', groups: 2},
            {name: 'U9', section: 'Europa League', groups: 2}
        ]
    };

    var newResultData = {
        index: 1000,
        homeTeam: 'Foo',
        awayTeam: 'Bar',
        tag: '1',
        competition: {
            name: 'U10',
            section: 'A',
            group: 1
        }
    };

    var u8GroupResults = [
        {'__v':0,'index':1,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'1', 'homeTeam':'Sheffield Wednesday', 'awayTeam':'Brentford', 'homeGoals':2, 'awayGoals':0},
        {'__v':0,'index':2,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'2', 'homeTeam':'Derby County', 'awayTeam':'Middlesbrough', 'homeGoals': 0, 'awayGoals': 0},
        {'__v':0,'index':3,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'3', 'homeTeam':'Derby County', 'awayTeam':'Sheffield Wednesday', 'homeGoals': 0, 'awayGoals': 3},
        {'__v':0,'index':4,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'4', 'homeTeam':'Brentford', 'awayTeam':'Middlesbrough'},
        {'__v':0,'index':5,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'5', 'homeTeam':'Middlesbrough', 'awayTeam':'Sheffield Wednesday'},
        {'__v':0,'index':6,'pitch':'5','competition':{'name':'U8', 'section':'A', 'group':'1'},'tag':'6', 'homeTeam':'Brentford', 'awayTeam':'Derby County'},
        {'__v':0,'index':7,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'1', 'homeTeam':'Rotherham', 'awayTeam':'Cardiff'},
        {'__v':0,'index':8,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'2', 'homeTeam':'MK Dons', 'awayTeam':'Bristol City'},
        {'__v':0,'index':9,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'3', 'homeTeam':'MK Dons', 'awayTeam':'Rotherham'},
        {'__v':0,'index':10,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'4', 'homeTeam':'Cardiff', 'awayTeam':'Bristol City'},
        {'__v':0,'index':11,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'5', 'homeTeam':'Bristol City', 'awayTeam':'Rotherham'},
        {'__v':0,'index':12,'pitch':'6','competition':{'name':'U8', 'section':'A', 'group':'2'},'tag':'6', 'homeTeam':'Cardiff', 'awayTeam':'MK Dons'},
        {'__v':0,'index':13,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'1', 'homeTeam':'Ipswich', 'awayTeam':'Preston North End'},
        {'__v':0,'index':14,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'2', 'homeTeam':'Hull City', 'awayTeam':'Reading'},
        {'__v':0,'index':15,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'3', 'homeTeam':'Hull City', 'awayTeam':'Ipswich'},
        {'__v':0,'index':16,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'4', 'homeTeam':'Preston North End', 'awayTeam':'Reading'},
        {'__v':0,'index':17,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'5', 'homeTeam':'Reading', 'awayTeam':'Ipswich'},
        {'__v':0,'index':18,'pitch':'7','competition':{'name':'U8', 'section':'A', 'group':'3'},'tag':'6', 'homeTeam':'Preston North End', 'awayTeam':'Hull City'},
        {'__v':0,'index':19,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'1', 'homeTeam':'QPR', 'awayTeam':'Fulham FC'},
        {'__v':0,'index':20,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'2', 'homeTeam':'Birmingham', 'awayTeam':'Leeds'},
        {'__v':0,'index':21,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'3', 'homeTeam':'Birmingham', 'awayTeam':'QPR'},
        {'__v':0,'index':22,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'4', 'homeTeam':'Fulham FC', 'awayTeam':'Leeds'},
        {'__v':0,'index':23,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'5', 'homeTeam':'Leeds', 'awayTeam':'QPR'},
        {'__v':0,'index':24,'pitch':'8','competition':{'name':'U8', 'section':'A', 'group':'4'},'tag':'6', 'homeTeam':'Fulham FC', 'awayTeam':'Birmingham'}
    ];

    var newsItemData = [
        {
            created: new Date('2015/5/12 12:26:32'),
            title: 'News1',
            body: 'This is the body of the news.  Please take careful note of it :)'
        },
        {
            created: new Date('2015/4/1 11:17:32'),
            title: 'News2',
            body: 'This is the body of the news.  Please take careful note of it s adfsgfsd fgdsf gs fg :)'
        },
        {
            created: new Date('2015/4/11 10:13:32'),
            title: 'News3',
            body: 'This is the body of the news.  Please take careful note of it :)'
        },
        {
            created: new Date('2015/4/9 17:47:32'),
            title: 'News4',
            body: '...'
        }
    ];
});
<|endoftext|>


<commit_before>angularFiles = {
  'angularSrc': [
    'src/Angular.js',
    'src/loader.js',
    'src/AngularPublic.js',
    'src/jqLite.js',
    'src/apis.js',

    'src/auto/injector.js',

    'src/ng/anchorScroll.js',
    'src/ng/browser.js',
    'src/ng/cacheFactory.js',
    'src/ng/compile.js',
    'src/ng/controller.js',
    'src/ng/document.js',
    'src/ng/exceptionHandler.js',
    'src/ng/interpolate.js',
    'src/ng/location.js',
    'src/ng/log.js',
    'src/ng/parse.js',
    'src/ng/q.js',
    'src/ng/route.js',
    'src/ng/routeParams.js',
    'src/ng/rootScope.js',
    'src/ng/sniffer.js',
    'src/ng/window.js',
    'src/ng/http.js',
    'src/ng/httpBackend.js',
    'src/ng/locale.js',
    'src/ng/timeout.js',

    'src/ng/filter.js',
    'src/ng/filter/filter.js',
    'src/ng/filter/filters.js',
    'src/ng/filter/limitTo.js',
    'src/ng/filter/orderBy.js',

    'src/ng/directive/directives.js',
    'src/ng/directive/a.js',
    'src/ng/directive/booleanAttrs.js',
    'src/ng/directive/form.js',
    'src/ng/directive/input.js',
    'src/ng/directive/ngBind.js',
    'src/ng/directive/ngClass.js',
    'src/ng/directive/ngCloak.js',
    'src/ng/directive/ngController.js',
    'src/ng/directive/ngCsp.js',
    'src/ng/directive/ngEventDirs.js',
    'src/ng/directive/ngInclude.js',
    'src/ng/directive/ngInit.js',
    'src/ng/directive/ngNonBindable.js',
    'src/ng/directive/ngPluralize.js',
    'src/ng/directive/ngRepeat.js',
    'src/ng/directive/ngShowHide.js',
    'src/ng/directive/ngStyle.js',
    'src/ng/directive/ngSwitch.js',
    'src/ng/directive/ngTransclude.js',
    'src/ng/directive/ngView.js',
    'src/ng/directive/script.js',
    'src/ng/directive/select.js',
    'src/ng/directive/style.js'
  ],

  'angularSrcModules': [
    'src/ngCookies/cookies.js',
    'src/ngResource/resource.js',
    'src/ngSanitize/sanitize.js',
    'src/ngSanitize/directive/ngBindHtml.js',
    'src/ngSanitize/filter/linky.js',
    'src/ngMock/angular-mocks.js',

    'src/bootstrap/bootstrap.js'
  ],

  'angularScenario': [
    'src/ngScenario/Scenario.js',
    'src/ngScenario/Application.js',
    'src/ngScenario/Describe.js',
    'src/ngScenario/Future.js',
    'src/ngScenario/ObjectModel.js',
    'src/ngScenario/Describe.js',
    'src/ngScenario/Runner.js',
    'src/ngScenario/SpecRunner.js',
    'src/ngScenario/dsl.js',
    'src/ngScenario/matchers.js',
    'src/ngScenario/output/Html.js',
    'src/ngScenario/output/Json.js',
    'src/ngScenario/output/Xml.js',
    'src/ngScenario/output/Object.js'
  ],

  'angularTest': [
    'test/testabilityPatch.js',
    'test/matchers.js',
    'test/ngScenario/*.js',
    'test/ngScenario/output/*.js',
    'test/ngScenario/jstd-scenario-adapter/*.js',
    'test/*.js',
    'test/auto/*.js',
    'test/bootstrap/*.js',
    'test/ng/*.js',
    'test/ng/directive/*.js',
    'test/ng/filter/*.js',
    'test/ngCookies/*.js',
    'test/ngResource/*.js',
    'test/ngSanitize/*.js',
    'test/ngSanitize/directive/*.js',
    'test/ngSanitize/filter/*.js',
    'test/ngMock/*.js'
  ],

  'jstd': [
    'lib/jasmine/jasmine.js',
    'lib/jasmine-jstd-adapter/JasmineAdapter.js',
    'lib/jquery/jquery.js',
    'test/jquery_remove.js',
    '@angularSrc',
    'src/publishExternalApis.js',
    '@angularSrcModules',
    '@angularScenario',
    'src/ngScenario/jstd-scenario-adapter/Adapter.js',
    '@angularTest',
    'example/personalLog/*.js',
    'example/personalLog/test/*.js'
  ],

  'jstdExclude': [
    'test/jquery_alias.js',
    'src/angular-bootstrap.js',
    'src/ngScenario/angular-bootstrap.js'
  ],

  'jstdScenario': [
    'build/angular-scenario.js',
    'build/jstd-scenario-adapter-config.js',
    'build/jstd-scenario-adapter.js',
    'build/docs/docs-scenario.js'
  ],

  "jstdModules": [
    'lib/jasmine/jasmine.js',
    'lib/jasmine-jstd-adapter/JasmineAdapter.js',
    'build/angular.js',
    'src/ngMock/angular-mocks.js',
    'src/ngCookies/cookies.js',
    'src/ngResource/resource.js',
    'src/ngSanitize/sanitize.js',
    'src/ngSanitize/directive/ngBindHtml.js',
    'src/ngSanitize/filter/linky.js',
    'test/matchers.js',
    'test/ngMock/*.js',
    'test/ngCookies/*.js',
    'test/ngResource/*.js',
    'test/ngSanitize/*.js',
    'test/ngSanitize/directive/*.js',
    'test/ngSanitize/filter/*.js'
  ],

  'jstdPerf': [
   'lib/jasmine/jasmine.js',
   'lib/jasmine-jstd-adapter/JasmineAdapter.js',
   '@angularSrc',
   '@angularSrcModules',
   'src/ngMock/angular-mocks.js',
   'perf/data/*.js',
   'perf/testUtils.js',
   'perf/*.js'
  ],

  'jstdPerfExclude': [
    'src/ng/angular-bootstrap.js',
    'src/ngScenario/angular-bootstrap.js'
  ],

  'jstdJquery': [
    'lib/jasmine/jasmine.js',
    'lib/jasmine-jstd-adapter/JasmineAdapter.js',
    'lib/jquery/jquery.js',
    'test/jquery_alias.js',
    '@angularSrc',
    'src/publishExternalApis.js',
    '@angularSrcModules',
    '@angularScenario',
    'src/ngScenario/jstd-scenario-adapter/Adapter.js',
    '@angularTest',
    'example/personalLog/*.js',

    'example/personalLog/test/*.js'
  ],

  'jstdJqueryExclude': [
    'src/angular-bootstrap.js',
    'src/ngScenario/angular-bootstrap.js',
    'test/jquery_remove.js'
  ]
};

if (exports) {
  exports.files = angularFiles
  exports.mergeFiles = function mergeFiles() {
    var files = [];

    [].splice.call(arguments, 0).forEach(function(file) {
      if (file.match(/testacular/)) {
        files.push(file);
      } else {
        angularFiles[file].forEach(function(f) {
          // replace @ref
          var match = f.match(/^\@(.*)/);
          if (match) {
            var deps = angularFiles[match[1]];
            files = files.concat(deps);
          } else {
            if (!/jstd|jasmine/.test(f)) { //TODO(i): remove once we don't have jstd/jasmine in repo
              files.push(f);
            }
          }
        });
      }
    });

    return files;
  }
}
<commit_msg>chore(Rakefile): remove a duplicate file in angularFiles.js<commit_after>angularFiles = {
  'angularSrc': [
    'src/Angular.js',
    'src/loader.js',
    'src/AngularPublic.js',
    'src/jqLite.js',
    'src/apis.js',

    'src/auto/injector.js',

    'src/ng/anchorScroll.js',
    'src/ng/browser.js',
    'src/ng/cacheFactory.js',
    'src/ng/compile.js',
    'src/ng/controller.js',
    'src/ng/document.js',
    'src/ng/exceptionHandler.js',
    'src/ng/interpolate.js',
    'src/ng/location.js',
    'src/ng/log.js',
    'src/ng/parse.js',
    'src/ng/q.js',
    'src/ng/route.js',
    'src/ng/routeParams.js',
    'src/ng/rootScope.js',
    'src/ng/sniffer.js',
    'src/ng/window.js',
    'src/ng/http.js',
    'src/ng/httpBackend.js',
    'src/ng/locale.js',
    'src/ng/timeout.js',

    'src/ng/filter.js',
    'src/ng/filter/filter.js',
    'src/ng/filter/filters.js',
    'src/ng/filter/limitTo.js',
    'src/ng/filter/orderBy.js',

    'src/ng/directive/directives.js',
    'src/ng/directive/a.js',
    'src/ng/directive/booleanAttrs.js',
    'src/ng/directive/form.js',
    'src/ng/directive/input.js',
    'src/ng/directive/ngBind.js',
    'src/ng/directive/ngClass.js',
    'src/ng/directive/ngCloak.js',
    'src/ng/directive/ngController.js',
    'src/ng/directive/ngCsp.js',
    'src/ng/directive/ngEventDirs.js',
    'src/ng/directive/ngInclude.js',
    'src/ng/directive/ngInit.js',
    'src/ng/directive/ngNonBindable.js',
    'src/ng/directive/ngPluralize.js',
    'src/ng/directive/ngRepeat.js',
    'src/ng/directive/ngShowHide.js',
    'src/ng/directive/ngStyle.js',
    'src/ng/directive/ngSwitch.js',
    'src/ng/directive/ngTransclude.js',
    'src/ng/directive/ngView.js',
    'src/ng/directive/script.js',
    'src/ng/directive/select.js',
    'src/ng/directive/style.js'
  ],

  'angularSrcModules': [
    'src/ngCookies/cookies.js',
    'src/ngResource/resource.js',
    'src/ngSanitize/sanitize.js',
    'src/ngSanitize/directive/ngBindHtml.js',
    'src/ngSanitize/filter/linky.js',
    'src/ngMock/angular-mocks.js',

    'src/bootstrap/bootstrap.js'
  ],

  'angularScenario': [
    'src/ngScenario/Scenario.js',
    'src/ngScenario/Application.js',
    'src/ngScenario/Describe.js',
    'src/ngScenario/Future.js',
    'src/ngScenario/ObjectModel.js',
    'src/ngScenario/Runner.js',
    'src/ngScenario/SpecRunner.js',
    'src/ngScenario/dsl.js',
    'src/ngScenario/matchers.js',
    'src/ngScenario/output/Html.js',
    'src/ngScenario/output/Json.js',
    'src/ngScenario/output/Xml.js',
    'src/ngScenario/output/Object.js'
  ],

  'angularTest': [
    'test/testabilityPatch.js',
    'test/matchers.js',
    'test/ngScenario/*.js',
    'test/ngScenario/output/*.js',
    'test/ngScenario/jstd-scenario-adapter/*.js',
    'test/*.js',
    'test/auto/*.js',
    'test/bootstrap/*.js',
    'test/ng/*.js',
    'test/ng/directive/*.js',
    'test/ng/filter/*.js',
    'test/ngCookies/*.js',
    'test/ngResource/*.js',
    'test/ngSanitize/*.js',
    'test/ngSanitize/directive/*.js',
    'test/ngSanitize/filter/*.js',
    'test/ngMock/*.js'
  ],

  'jstd': [
    'lib/jasmine/jasmine.js',
    'lib/jasmine-jstd-adapter/JasmineAdapter.js',
    'lib/jquery/jquery.js',
    'test/jquery_remove.js',
    '@angularSrc',
    'src/publishExternalApis.js',
    '@angularSrcModules',
    '@angularScenario',
    'src/ngScenario/jstd-scenario-adapter/Adapter.js',
    '@angularTest',
    'example/personalLog/*.js',
    'example/personalLog/test/*.js'
  ],

  'jstdExclude': [
    'test/jquery_alias.js',
    'src/angular-bootstrap.js',
    'src/ngScenario/angular-bootstrap.js'
  ],

  'jstdScenario': [
    'build/angular-scenario.js',
    'build/jstd-scenario-adapter-config.js',
    'build/jstd-scenario-adapter.js',
    'build/docs/docs-scenario.js'
  ],

  "jstdModules": [
    'lib/jasmine/jasmine.js',
    'lib/jasmine-jstd-adapter/JasmineAdapter.js',
    'build/angular.js',
    'src/ngMock/angular-mocks.js',
    'src/ngCookies/cookies.js',
    'src/ngResource/resource.js',
    'src/ngSanitize/sanitize.js',
    'src/ngSanitize/directive/ngBindHtml.js',
    'src/ngSanitize/filter/linky.js',
    'test/matchers.js',
    'test/ngMock/*.js',
    'test/ngCookies/*.js',
    'test/ngResource/*.js',
    'test/ngSanitize/*.js',
    'test/ngSanitize/directive/*.js',
    'test/ngSanitize/filter/*.js'
  ],

  'jstdPerf': [
   'lib/jasmine/jasmine.js',
   'lib/jasmine-jstd-adapter/JasmineAdapter.js',
   '@angularSrc',
   '@angularSrcModules',
   'src/ngMock/angular-mocks.js',
   'perf/data/*.js',
   'perf/testUtils.js',
   'perf/*.js'
  ],

  'jstdPerfExclude': [
    'src/ng/angular-bootstrap.js',
    'src/ngScenario/angular-bootstrap.js'
  ],

  'jstdJquery': [
    'lib/jasmine/jasmine.js',
    'lib/jasmine-jstd-adapter/JasmineAdapter.js',
    'lib/jquery/jquery.js',
    'test/jquery_alias.js',
    '@angularSrc',
    'src/publishExternalApis.js',
    '@angularSrcModules',
    '@angularScenario',
    'src/ngScenario/jstd-scenario-adapter/Adapter.js',
    '@angularTest',
    'example/personalLog/*.js',

    'example/personalLog/test/*.js'
  ],

  'jstdJqueryExclude': [
    'src/angular-bootstrap.js',
    'src/ngScenario/angular-bootstrap.js',
    'test/jquery_remove.js'
  ]
};

if (exports) {
  exports.files = angularFiles
  exports.mergeFiles = function mergeFiles() {
    var files = [];

    [].splice.call(arguments, 0).forEach(function(file) {
      if (file.match(/testacular/)) {
        files.push(file);
      } else {
        angularFiles[file].forEach(function(f) {
          // replace @ref
          var match = f.match(/^\@(.*)/);
          if (match) {
            var deps = angularFiles[match[1]];
            files = files.concat(deps);
          } else {
            if (!/jstd|jasmine/.test(f)) { //TODO(i): remove once we don't have jstd/jasmine in repo
              files.push(f);
            }
          }
        });
      }
    });

    return files;
  }
}
<|endoftext|>


<commit_before>import { BufferGeometryAnalyzer, ConnectedSTL, STLLoader, STLBinaryExporter } from '..';
import { STLExporter } from '../src/exporters/STLExporter';
import { expect } from 'chai';
import fs from 'fs';
import * as THREE from 'three';

// Tests of ConnectedSTL.  To run:
// npm test
// To run with large tests and also write outputs:
// env INCLUDE_LARGE_TESTS=1 WRITE_TEST_OUTPUTS=1 npm test
// To run just the cubes tests:
// npm test -- --grep "cubes"
// To run just the Big test with chome://inspect debugger:
// env INCLUDE_LARGE_TESTS=1 npm test -- "--grep" "Big" --inspect --debug-brk

const equalNormals = function (v0, v1) {
    return v0.angleTo(v1) < Math.PI/180*0.0001;
};
describe("ConnectedSTL", function() {
    describe("isolatedBufferGeometries", function() {
        let testFile = function (filename, expectedGeometriesCount, writeShapes = process.env.WRITE_TEST_OUTPUTS) {
            // Test that the number of shapes is as expected.
            let stl = fs.readFileSync("test/" + filename + ".stl", {encoding: "binary"});
            let geometry = new STLLoader().parse(stl);
            let connectedSTL = new ConnectedSTL().fromBufferGeometry(geometry);
            let newGeometries = Array.from(connectedSTL.isolate()).map((x) => x.bufferGeometry());
            expect(newGeometries.length).to.equal(expectedGeometriesCount);
            if (writeShapes) {
                for (let i = 0; i < newGeometries.length; i++) {
                    let mesh = new THREE.Mesh(newGeometries[i]);
                    let obj = new THREE.Object3D();
                    obj.add(mesh);
                    fs.writeFileSync(filename + "_old" + i + ".stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
                }
            }

            // Split the faces in the shape and check that the
            // neighbors array is maintained correctly.
            geometry.computeBoundingBox();
            let boundingBox = geometry.boundingBox;
            let oldFaceCount = connectedSTL.positions.length/9;
            let splits = connectedSTL.splitFaces(new THREE.Plane(
                new THREE.Vector3(1,0,0), -((boundingBox.max.x*2 + boundingBox.min.x)/3)));

            if (writeShapes) {
                let mesh = new THREE.Mesh(connectedSTL.bufferGeometry());
                let obj = new THREE.Object3D();
                obj.add(mesh);
                fs.writeFileSync(filename + "_split.stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
            }
            expect(splits.size).to.be.greaterThan(0);
            let newFaceCount = connectedSTL.positions.length/9;
            // Splitting an edge affects two faces.
            expect(newFaceCount).to.be.greaterThan(oldFaceCount);
            let oldNeighbors = connectedSTL.neighbors.slice(0);
            connectedSTL.neighbors = [];
            connectedSTL.reverseIslands = [];
            expect(connectedSTL.findNeighbors()).to.be.true;
            let newNeighbors = connectedSTL.neighbors.slice(0);
            // neighbors array should have be updated correctly during split.
            expect(newNeighbors).to.have.ordered.members(oldNeighbors);

            // Spliting should not affect the number of shapes.
            newGeometries = Array.from(connectedSTL.isolate()).map((x) => x.bufferGeometry());
            if (writeShapes) {
                for (let i = 0; i < newGeometries.length; i++) {
                    let mesh = new THREE.Mesh(newGeometries[i]);
                    let obj = new THREE.Object3D();
                    obj.add(mesh);
                    fs.writeFileSync(filename + "_new" + i + ".stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
                }
            }
            expect(newGeometries.length).to.equal(expectedGeometriesCount);

            // Merging faces should not affect the number of shapes.
            connectedSTL.mergeFaces(equalNormals);
            if (writeShapes) {
                let mesh = new THREE.Mesh(connectedSTL.bufferGeometry());
                let obj = new THREE.Object3D();
                obj.add(mesh);
                fs.writeFileSync(filename + "_merged.stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
            }

            expect(newGeometries.length).to.equal(expectedGeometriesCount);

            let newConnectedSTLs = connectedSTL.chop(new THREE.Plane(
                new THREE.Vector3(1,0,0), -((boundingBox.max.x + boundingBox.min.x*3)/4)));
            for (let i = 0; i < newConnectedSTLs.length; i++) {
                let newConnectedSTL = newConnectedSTLs[i];
                //newConnectedSTL.mergeFaces(equalNormals);
                //newConnectedSTL.retriangle(Array.from(new Array(newConnectedSTL.positions.length/9).keys()), equalNormals);
                if (writeShapes) {
                    let mesh = new THREE.Mesh(newConnectedSTL.bufferGeometry());
                    let obj = new THREE.Object3D();
                    obj.add(mesh);
                    fs.writeFileSync(filename + "_chop" + i + ".stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
                    newGeometries = Array.from(connectedSTL.isolate()).map((x) => x.bufferGeometry());
                    for (let j = 0; j < newGeometries.length; j++) {
                        let mesh = new THREE.Mesh(newGeometries[j]);
                        let obj = new THREE.Object3D();
                        obj.add(mesh);
                        fs.writeFileSync(filename + "_new" + i + "_" + j + ".stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
                    }
                }
            }
        }

        it("Plus", function() {
            testFile("plus", 1);
        });

        it("Hollow Cube", function() {
            // We'd prefer this to be just 1 object.
            testFile("hollow_cube", 2);
        });

        it("Cup", function() {
            testFile("cup", 1);
        });

        it("Stairs", function() {
            testFile("stairs", 1);
        });

        it("Crescent", function() {
            testFile("crescent", 1);
        });

        it("Simple tetrahedron", function() {
            testFile("tetrahedron", 1);
        });

        it("Split ruler with degenerate facets", function() {
            testFile("lungo", 2);
        });

        it("2 tetrahedrons that share a face", function() {
            testFile("face_connected_tetrahedrons", 2);
        });

        it("2 tetrahedrons that share an edge", function() {
            testFile("edge_connected_tetrahedrons", 2);
        });

        it("27 cubes in 3 by 3 by 3 formation", function() {
            testFile("rubix", 27);
        });

        it("27 cubes in 3 by 3 by 3 formation on an angle", function() {
            testFile("twisted_rubix", 27);
        });

        it("27 cubes in 3 by 3 by 3 formation with facets in lightly shuffled order", function() {
            testFile("shuffled_rubix", 27);
        });

        it("egg shape with lots of faces", function() {
            this.timeout(0);
            testFile("egg", 1);
        });

        it("non-manifold egg with a side sliced off and a hole", function() {
            this.timeout(0);
            testFile("egg_chopped", 1);
        });

        it("Big object: Dinosaur Jump", function() {
            if (!process.env.INCLUDE_LARGE_TESTS) {
                this.skip();
            }
            this.timeout(0);
            testFile("DINOSAUR_JUMP", 1);
        });

        it("Non-manifold egg just fixHoles", function () {
            if (!process.env.INCLUDE_LARGE_TESTS) {
                this.skip();
            }
            this.timeout(0);
            let stl = fs.readFileSync("test/egg_with_holes.stl", {encoding: "binary"});
            let geometry = new STLLoader().parse(stl);
            let connectedSTL = new ConnectedSTL().fromBufferGeometry(geometry);
            connectedSTL.fixHoles();
            let mesh = new THREE.Mesh(connectedSTL.bufferGeometry());
            let obj = new THREE.Object3D();
            obj.add(mesh);
            fs.writeFileSync("egg_with_holes_repaired.stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
        });

        it("dino jump just merge", function () {
            if (!process.env.INCLUDE_LARGE_TESTS) {
                this.skip();
            }
            this.timeout(30000);
            let stl = fs.readFileSync("test/DINOSAUR_JUMP.stl", {encoding: "binary"});
            let geometry = new STLLoader().parse(stl);
            let connectedSTL = new ConnectedSTL().fromBufferGeometry(geometry);
            connectedSTL.mergeFaces(function (v0, v1) {
                return v0.angleTo(v1) < Math.PI/180*2;
            });
            let mesh = new THREE.Mesh(connectedSTL.bufferGeometry());
            let obj = new THREE.Object3D();
            obj.add(mesh);
            fs.writeFileSync("DINOSAUR_JUMP_merged.stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
        });

        it("dino jump just retriangle", function () {
            if (!process.env.INCLUDE_LARGE_TESTS) {
                this.skip();
            }
            this.timeout(30000);
            let stl = fs.readFileSync("test/DINOSAUR_JUMP.stl", {encoding: "binary"});
            let geometry = new STLLoader().parse(stl);
            let connectedSTL = new ConnectedSTL().fromBufferGeometry(geometry);
            connectedSTL.retriangle(
                Array.from(new Array(connectedSTL.positions.length/9).keys()));
            let mesh = new THREE.Mesh(connectedSTL.bufferGeometry());
            let obj = new THREE.Object3D();
            obj.add(mesh);
            fs.writeFileSync("DINOSAUR_JUMP_retriangle.stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
        });

        it("dino jump just chop", function () {
            if (!process.env.INCLUDE_LARGE_TESTS) {
                this.skip();
            }
            this.timeout(0);
            let stl = fs.readFileSync("test/DINOSAUR_JUMP.stl", {encoding: "binary"});
            let geometry = new STLLoader().parse(stl);
            geometry.computeBoundingBox();
            let boundingBox = geometry.boundingBox;
            let connectedSTL = new ConnectedSTL().fromBufferGeometry(geometry);
            let newConnectedSTLs = connectedSTL.chop(new THREE.Plane(
                new THREE.Vector3(1,0,0), -((boundingBox.max.x + boundingBox.min.x*3)/4)));
        });
    });
});
<commit_msg>uncomment merge and retriangle<commit_after>import { BufferGeometryAnalyzer, ConnectedSTL, STLLoader, STLBinaryExporter } from '..';
import { STLExporter } from '../src/exporters/STLExporter';
import { expect } from 'chai';
import fs from 'fs';
import * as THREE from 'three';

// Tests of ConnectedSTL.  To run:
// npm test
// To run with large tests and also write outputs:
// env INCLUDE_LARGE_TESTS=1 WRITE_TEST_OUTPUTS=1 npm test
// To run just the cubes tests:
// npm test -- --grep "cubes"
// To run just the Big test with chome://inspect debugger:
// env INCLUDE_LARGE_TESTS=1 npm test -- "--grep" "Big" --inspect --debug-brk

const equalNormals = function (v0, v1) {
    return v0.angleTo(v1) < Math.PI/180*0.0001;
};
describe("ConnectedSTL", function() {
    describe("isolatedBufferGeometries", function() {
        let testFile = function (filename, expectedGeometriesCount, writeShapes = process.env.WRITE_TEST_OUTPUTS) {
            // Test that the number of shapes is as expected.
            let stl = fs.readFileSync("test/" + filename + ".stl", {encoding: "binary"});
            let geometry = new STLLoader().parse(stl);
            let connectedSTL = new ConnectedSTL().fromBufferGeometry(geometry);
            let newGeometries = Array.from(connectedSTL.isolate()).map((x) => x.bufferGeometry());
            expect(newGeometries.length).to.equal(expectedGeometriesCount);
            if (writeShapes) {
                for (let i = 0; i < newGeometries.length; i++) {
                    let mesh = new THREE.Mesh(newGeometries[i]);
                    let obj = new THREE.Object3D();
                    obj.add(mesh);
                    fs.writeFileSync(filename + "_old" + i + ".stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
                }
            }

            // Split the faces in the shape and check that the
            // neighbors array is maintained correctly.
            geometry.computeBoundingBox();
            let boundingBox = geometry.boundingBox;
            let oldFaceCount = connectedSTL.positions.length/9;
            let splits = connectedSTL.splitFaces(new THREE.Plane(
                new THREE.Vector3(1,0,0), -((boundingBox.max.x*2 + boundingBox.min.x)/3)));

            if (writeShapes) {
                let mesh = new THREE.Mesh(connectedSTL.bufferGeometry());
                let obj = new THREE.Object3D();
                obj.add(mesh);
                fs.writeFileSync(filename + "_split.stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
            }
            expect(splits.size).to.be.greaterThan(0);
            let newFaceCount = connectedSTL.positions.length/9;
            // Splitting an edge affects two faces.
            expect(newFaceCount).to.be.greaterThan(oldFaceCount);
            let oldNeighbors = connectedSTL.neighbors.slice(0);
            connectedSTL.neighbors = [];
            connectedSTL.reverseIslands = [];
            expect(connectedSTL.findNeighbors()).to.be.true;
            let newNeighbors = connectedSTL.neighbors.slice(0);
            // neighbors array should have be updated correctly during split.
            expect(newNeighbors).to.have.ordered.members(oldNeighbors);

            // Spliting should not affect the number of shapes.
            newGeometries = Array.from(connectedSTL.isolate()).map((x) => x.bufferGeometry());
            if (writeShapes) {
                for (let i = 0; i < newGeometries.length; i++) {
                    let mesh = new THREE.Mesh(newGeometries[i]);
                    let obj = new THREE.Object3D();
                    obj.add(mesh);
                    fs.writeFileSync(filename + "_new" + i + ".stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
                }
            }
            expect(newGeometries.length).to.equal(expectedGeometriesCount);

            // Merging faces should not affect the number of shapes.
            connectedSTL.mergeFaces(equalNormals);
            if (writeShapes) {
                let mesh = new THREE.Mesh(connectedSTL.bufferGeometry());
                let obj = new THREE.Object3D();
                obj.add(mesh);
                fs.writeFileSync(filename + "_merged.stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
            }

            expect(newGeometries.length).to.equal(expectedGeometriesCount);

            let newConnectedSTLs = connectedSTL.chop(new THREE.Plane(
                new THREE.Vector3(1,0,0), -((boundingBox.max.x + boundingBox.min.x*3)/4)));
            for (let i = 0; i < newConnectedSTLs.length; i++) {
                let newConnectedSTL = newConnectedSTLs[i];
                newConnectedSTL.mergeFaces(equalNormals);
                newConnectedSTL.retriangle(Array.from(new Array(newConnectedSTL.positions.length/9).keys()), equalNormals);
                if (writeShapes) {
                    let mesh = new THREE.Mesh(newConnectedSTL.bufferGeometry());
                    let obj = new THREE.Object3D();
                    obj.add(mesh);
                    fs.writeFileSync(filename + "_chop" + i + ".stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
                    newGeometries = Array.from(connectedSTL.isolate()).map((x) => x.bufferGeometry());
                    for (let j = 0; j < newGeometries.length; j++) {
                        let mesh = new THREE.Mesh(newGeometries[j]);
                        let obj = new THREE.Object3D();
                        obj.add(mesh);
                        fs.writeFileSync(filename + "_new" + i + "_" + j + ".stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
                    }
                }
            }
        }

        it("Plus", function() {
            testFile("plus", 1);
        });

        it("Hollow Cube", function() {
            // We'd prefer this to be just 1 object.
            testFile("hollow_cube", 2);
        });

        it("Cup", function() {
            testFile("cup", 1);
        });

        it("Stairs", function() {
            testFile("stairs", 1);
        });

        it("Crescent", function() {
            testFile("crescent", 1);
        });

        it("Simple tetrahedron", function() {
            testFile("tetrahedron", 1);
        });

        it("Split ruler with degenerate facets", function() {
            testFile("lungo", 2);
        });

        it("2 tetrahedrons that share a face", function() {
            testFile("face_connected_tetrahedrons", 2);
        });

        it("2 tetrahedrons that share an edge", function() {
            testFile("edge_connected_tetrahedrons", 2);
        });

        it("27 cubes in 3 by 3 by 3 formation", function() {
            testFile("rubix", 27);
        });

        it("27 cubes in 3 by 3 by 3 formation on an angle", function() {
            testFile("twisted_rubix", 27);
        });

        it("27 cubes in 3 by 3 by 3 formation with facets in lightly shuffled order", function() {
            testFile("shuffled_rubix", 27);
        });

        it("egg shape with lots of faces", function() {
            this.timeout(0);
            testFile("egg", 1);
        });

        it("non-manifold egg with a side sliced off and a hole", function() {
            this.timeout(0);
            testFile("egg_chopped", 1);
        });

        it("Big object: Dinosaur Jump", function() {
            if (!process.env.INCLUDE_LARGE_TESTS) {
                this.skip();
            }
            this.timeout(0);
            testFile("DINOSAUR_JUMP", 1);
        });

        it("Non-manifold egg just fixHoles", function () {
            if (!process.env.INCLUDE_LARGE_TESTS) {
                this.skip();
            }
            this.timeout(0);
            let stl = fs.readFileSync("test/egg_with_holes.stl", {encoding: "binary"});
            let geometry = new STLLoader().parse(stl);
            let connectedSTL = new ConnectedSTL().fromBufferGeometry(geometry);
            connectedSTL.fixHoles();
            let mesh = new THREE.Mesh(connectedSTL.bufferGeometry());
            let obj = new THREE.Object3D();
            obj.add(mesh);
            fs.writeFileSync("egg_with_holes_repaired.stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
        });

        it("dino jump just merge", function () {
            if (!process.env.INCLUDE_LARGE_TESTS) {
                this.skip();
            }
            this.timeout(30000);
            let stl = fs.readFileSync("test/DINOSAUR_JUMP.stl", {encoding: "binary"});
            let geometry = new STLLoader().parse(stl);
            let connectedSTL = new ConnectedSTL().fromBufferGeometry(geometry);
            connectedSTL.mergeFaces(function (v0, v1) {
                return v0.angleTo(v1) < Math.PI/180*2;
            });
            let mesh = new THREE.Mesh(connectedSTL.bufferGeometry());
            let obj = new THREE.Object3D();
            obj.add(mesh);
            fs.writeFileSync("DINOSAUR_JUMP_merged.stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
        });

        it("dino jump just retriangle", function () {
            if (!process.env.INCLUDE_LARGE_TESTS) {
                this.skip();
            }
            this.timeout(30000);
            let stl = fs.readFileSync("test/DINOSAUR_JUMP.stl", {encoding: "binary"});
            let geometry = new STLLoader().parse(stl);
            let connectedSTL = new ConnectedSTL().fromBufferGeometry(geometry);
            connectedSTL.retriangle(
                Array.from(new Array(connectedSTL.positions.length/9).keys()));
            let mesh = new THREE.Mesh(connectedSTL.bufferGeometry());
            let obj = new THREE.Object3D();
            obj.add(mesh);
            fs.writeFileSync("DINOSAUR_JUMP_retriangle.stl", new Buffer(new STLExporter().parse(obj)), 'ascii');
        });

        it("dino jump just chop", function () {
            if (!process.env.INCLUDE_LARGE_TESTS) {
                this.skip();
            }
            this.timeout(0);
            let stl = fs.readFileSync("test/DINOSAUR_JUMP.stl", {encoding: "binary"});
            let geometry = new STLLoader().parse(stl);
            geometry.computeBoundingBox();
            let boundingBox = geometry.boundingBox;
            let connectedSTL = new ConnectedSTL().fromBufferGeometry(geometry);
            let newConnectedSTLs = connectedSTL.chop(new THREE.Plane(
                new THREE.Vector3(1,0,0), -((boundingBox.max.x + boundingBox.min.x*3)/4)));
        });
    });
});
<|endoftext|>


<commit_before>'use strict';

var includeTagForWidgets = require.resolve('../include-tag');

module.exports = function(includeNode) {
    var builder = this.builder;
    var context = this.context;

    if (!this.hasBoundWidgetForTemplate()) {
        return;
    }

    var parentNode = includeNode.parentNode;
    parentNode._normalizeChildTextNodes(context, true /* force trim */);

    if (parentNode.childCount === 1) {
        if (includeNode.hasAttribute('ref')) {
            this.assignWidgetId();
        }

        let parentTransformHelper = this.getTransformHelper(parentNode);

        if (includeNode.data.bodySlot) {
            parentTransformHelper.assignWidgetId(false /* not repeated */);
            var widgetProps = this.getWidgetProps();
            widgetProps.body = parentTransformHelper.getNestedIdExpression();
        } else {
            let widgetIdInfo = parentTransformHelper.assignWidgetId(true /* repeated */);
            if (!widgetIdInfo.idVarNode) {
                let idVarNode = widgetIdInfo.createIdVarNode();
                parentNode.onBeforeGenerateCode((event) => {
                    event.insertCode(idVarNode);
                });
            }
        }

        includeNode.setRendererPath(includeTagForWidgets);

        includeNode.onBeforeGenerateCode(function() {
            includeNode.addProp('_elId', parentTransformHelper.getIdExpression());
            includeNode.addProp('_arg', builder.identifier('widget'));
        });
    }

    // includeNode.generateCodeForDynamicInclude = (options, codegen) => {
    //     var target = options.target;
    //     var data = options.data;
    //
    //     if (!data) {
    //         data = builder.literal(null);
    //     }
    //
    //     let includeVar = context.importModule('marko_widget_include', this.getMarkoWidgetsRequirePath('marko/widgets/taglib/helpers/include'));
    //
    //     let includeArgs = [
    //         target,
    //         builder.identifierOut(),
    //         data
    //     ];
    //
    //     if (parentTransformHelper) {
    //         includeArgs = includeArgs.concat([
    //             parentTransformHelper.getIdExpression(),
    //
    //         ]);
    //     }
    //
    //     return builder.functionCall(includeVar, includeArgs);
    // };
};
<commit_msg>Avoid widget include check if not nested within a custom tag or an HTML tag<commit_after>'use strict';

var includeTagForWidgets = require.resolve('../include-tag');

module.exports = function(includeNode) {
    var builder = this.builder;
    var context = this.context;

    if (!this.hasBoundWidgetForTemplate()) {
        return;
    }

    var parentNode = includeNode.parentNode;

    if (!parentNode.hasAttribute) {
        return;
    }

    parentNode._normalizeChildTextNodes(context, true /* force trim */);

    if (parentNode.childCount === 1) {
        if (includeNode.hasAttribute('ref')) {
            this.assignWidgetId();
        }

        let parentTransformHelper = this.getTransformHelper(parentNode);

        if (includeNode.data.bodySlot) {
            parentTransformHelper.assignWidgetId(false /* not repeated */);
            var widgetProps = this.getWidgetProps();
            widgetProps.body = parentTransformHelper.getNestedIdExpression();
        } else {
            let widgetIdInfo = parentTransformHelper.assignWidgetId(true /* repeated */);
            if (!widgetIdInfo.idVarNode) {
                let idVarNode = widgetIdInfo.createIdVarNode();
                parentNode.onBeforeGenerateCode((event) => {
                    event.insertCode(idVarNode);
                });
            }
        }

        includeNode.setRendererPath(includeTagForWidgets);

        includeNode.onBeforeGenerateCode(function() {
            includeNode.addProp('_elId', parentTransformHelper.getIdExpression());
            includeNode.addProp('_arg', builder.identifier('widget'));
        });
    }

    // includeNode.generateCodeForDynamicInclude = (options, codegen) => {
    //     var target = options.target;
    //     var data = options.data;
    //
    //     if (!data) {
    //         data = builder.literal(null);
    //     }
    //
    //     let includeVar = context.importModule('marko_widget_include', this.getMarkoWidgetsRequirePath('marko/widgets/taglib/helpers/include'));
    //
    //     let includeArgs = [
    //         target,
    //         builder.identifierOut(),
    //         data
    //     ];
    //
    //     if (parentTransformHelper) {
    //         includeArgs = includeArgs.concat([
    //             parentTransformHelper.getIdExpression(),
    //
    //         ]);
    //     }
    //
    //     return builder.functionCall(includeVar, includeArgs);
    // };
};
<|endoftext|>


<commit_before>/* jspsych-palmer
 * a jspsych plugin for presenting and querying about stimuli modeled after
 *
 * Palmer, S. (1977). Hierarchical Structure in Perceptual Representation. Cognitive Psychology, 9, 441.
 *
 * and
 *
 * Goldstone, R. L., Rogosky, B. J., Pevtzow, R., & Blair, M. (2005). Perceptual and semantic reorganization during category learning.
 * In H. Cohen & C. Lefebvre (Eds.) Handbook of Categorization in Cognitive Science. (pp. 651-678). Amsterdam: Elsevier.
 *
 * Josh de Leeuw (October 2013)
 *
 * NOTE: This plugin requires the Raphaeljs library for manipulating vector graphics (SVG). Download at http://www.raphaeljs.com
 *
 */

(function($) {
    jsPsych.palmer = (function() {

        var plugin = {};

        plugin.create = function(params) {
            var trials = [];
            for (var i = 0; i < params.configurations.length; i++) {
                var trial = {
                    type: "palmer",
                    configurations: params.configurations[i],
                    editable: params.editable,
                    show_feedback: (typeof params.show_feedback === 'undefined') ? false : params.show_feedback,
                    grid_spacing: params.grid_spacing || 75,
                    square_size: params.square_size || 3,
                    circle_radius: params.circle_radius || 20,
                    timing_item: params.timing_item || 1000,
                    timing_post_trial: params.timing_post_trial || 1000,
                    timing_feedback: params.timing_feedback || 1000,
                    prompt: (typeof params.prompt === 'undefined') ? "" : params.prompt,
                    data: (typeof params.data === 'undefined') ? {} : params.data[i]
                };

                trials.push(trial);
            }
            return trials;
        };

        plugin.trial = function(display_element, block, trial, part) {

            // variables to keep track of user interaction
            var start_circle = -1;
            var end_circle = -1;
            var line_started = false;

            var size = trial.grid_spacing * (trial.square_size + 1);

            display_element.append($("
", {
                css: {
                    width: size + "px",
                    height: size + "px"
                }
            }));

            var paper = Raphael("raphaelCanvas", size, size);

            // create the circles at the vertices.
            var circles = [];
            var node_idx = 0;
            for (var i = 1; i <= trial.square_size; i++) {
                for (var j = 1; j <= trial.square_size; j++) {
                    var circle = paper.circle(trial.grid_spacing * j, trial.grid_spacing * i, trial.circle_radius);
                    circle.attr("fill", "#000").attr("stroke-width", "0").attr("stroke", "#000").data("node", node_idx);

                    if (trial.editable) {
                        circle.hover(

                        function() {
                            this.attr("stroke-width", "2");
                            //this.attr("stroke", "#000");
                        },

                        function() {
                            this.attr("stroke-width", "0");
                            //this.attr("stroke", "#fff")
                        }).click(

                        function() {
                            if (!line_started) {
                                line_started = true;
                                start_circle = this.data("node");
                                this.attr("fill", "#777").attr("stroke", "#777");
                            }
                            else {
                                end_circle = this.data("node");
                                draw_connection(start_circle, end_circle);
                            }
                        });
                    }
                    node_idx++;
                    circles.push(circle);
                }
            }

            function draw_connection(start_circle, end_circle) {
                var the_line = getLineIndex(start_circle, end_circle);
                if (the_line > -1) {
                    toggle_line(the_line);
                }
                // reset highlighting on circles
                for (var i = 0; i < circles.length; i++) {
                    circles[i].attr("fill", "#000").attr("stroke", "#000");
                }
                // cleanup the variables
                line_started = false;
                start_circle = -1;
                end_circle = -1;
            }

            // create all possible lines that connect circles
            var horizontal_lines = [];
            var vertical_lines = [];
            var backslash_lines = [];
            var forwardslash_lines = [];

            for (var i = 0; i < trial.square_size; i++) {
                for (var j = 0; j < trial.square_size; j++) {
                    var current_item = (i * trial.square_size) + j;
                    // add horizontal connections
                    if (j < (trial.square_size - 1)) {
                        horizontal_lines.push([current_item, current_item + 1]);
                    }
                    // add vertical connections
                    if (i < (trial.square_size - 1)) {
                        vertical_lines.push([current_item, current_item + trial.square_size]);
                    }
                    // add diagonal backslash connections
                    if (i < (trial.square_size - 1) && j < (trial.square_size - 1)) {
                        backslash_lines.push([current_item, current_item + trial.square_size + 1]);
                    }
                    // add diagonal forwardslash connections
                    if (i < (trial.square_size - 1) && j > 0) {
                        forwardslash_lines.push([current_item, current_item + trial.square_size - 1]);
                    }
                }
            }

            var lines = horizontal_lines.concat(vertical_lines).concat(backslash_lines).concat(forwardslash_lines);

            // actually draw the lines
            var lineIsVisible = [];
            var lineElements = [];

            for (var i = 0; i < lines.length; i++) {
                var line = paper.path("M" + circles[lines[i][0]].attr("cx") + " " + circles[lines[i][0]].attr("cy") + "L" + circles[lines[i][1]].attr("cx") + " " + circles[lines[i][1]].attr("cy")).attr("stroke-width", "8").attr("stroke", "#000");
                line.hide();
                lineElements.push(line);
                lineIsVisible.push(0);
            }

            // define some helper functions to toggle lines on and off

            // this function gets the index of a line based on the two circles it connects
            function getLineIndex(start_circle, end_circle) {
                var the_line = -1;
                for (var i = 0; i < lines.length; i++) {
                    if ((start_circle == lines[i][0] && end_circle == lines[i][1]) || (start_circle == lines[i][1] && end_circle == lines[i][0])) {
                        the_line = i;
                        break;
                    }
                }
                return the_line;
            }

            // this function turns a line on/off based on the index (the_line)
            function toggle_line(the_line) {
                if (the_line > -1) {
                    if (lineIsVisible[the_line] === 0) {
                        lineElements[the_line].show();
                        lineElements[the_line].toBack();
                        lineIsVisible[the_line] = 1;
                    }
                    else {
                        lineElements[the_line].hide();
                        lineElements[the_line].toBack();
                        lineIsVisible[the_line] = 0;
                    }
                }
            }

            // this function takes an array of length = num lines, and displays the line whereever there
            // is a 1 in the array.
            function showConfiguration(configuration) {
                for (var i = 0; i < configuration.length; i++) {
                    if (configuration[i] != lineIsVisible[i]) {
                        toggle_line(i);
                    }
                }
            }

            // highlight a line
            function highlightLine(line) {
                lineElements[line].attr("stroke", "#f00");
            }

            // start recording the time
            var startTime = (new Date()).getTime();

            // what kind of trial are we doing?
            // if trial.editable is true, then we will let the user interact with the stimulus to create
            // something, e.g. for a reconstruction probe.
            // need a way for the user to submit when they are done in that case...
            if (trial.editable) {
                display_element.append($('<button id="submitButton" type="button">Submit Answer</button>'));
                $('#submitButton').click(function() {
                    save_data();
                });
            }

            // if trial.editable is false, then we are just showing a pre-determined configuration.
            // for now, the only option will be to display for a fixed amount of time.
            // future ideas: allow for key response, to enable things like n-back, same/different, etc..
            if (!trial.editable) {
                showConfiguration(trial.configurations);

                setTimeout(function() {
                    save_data();
                }, trial.timing_item);
            }

            if (trial.prompt !== "") {
                display_element.append($('
'));
                $("#palmer_prompt").html(trial.prompt);
            }

            function arrayDifferences(arr1, arr2) {
                var n_diff = 0;
                for (var i = 0; i < arr1.length; i++) {
                    if (arr1[i] != arr2[i]) {
                        n_diff++;
                    }
                }
                return n_diff;
            }

            // save data
            function save_data() {

                // measure RT
                var endTime = (new Date()).getTime();
                var response_time = endTime - startTime;

                // check if configuration is correct
                // this is meaningless for trials where the user can't edit
                var n_diff = arrayDifferences(trial.configurations, lineIsVisible);
                var correct = (n_diff === 0);

                block.data[block.trial_idx] = $.extend({}, {
                    "trial_type": "palmer",
                    "trial_index": block.trial_idx,
                    "configuration": lineIsVisible,
                    "rt": response_time,
                    "correct": correct,
                    "num_wrong": n_diff,
                }, trial.data);

                if (trial.editable && trial.show_feedback) {
                    // hide the button
                    $('#submitButton').hide();
                    $('#palmer_prompt').hide();

                    showConfiguration(trial.configurations);
                    var feedback = "";
                    if (correct) {
                        feedback = "Correct!";
                    }
                    else {
                        if (n_diff > 1) {
                            feedback = "You missed " + n_diff + " lines. The correct symbol is shown above.";
                        }
                        else {
                            feedback = "You missed 1 line. The correct symbol is shown above.";
                        }
                    }
                    display_element.append($.parseHTML("
" + feedback + "
"));

                    setTimeout(function() {
                        next_trial();
                    }, trial.timing_feedback);

                }
                else {
                    next_trial();
                }
            }

            function next_trial() {

                display_element.html('');

                // next trial
                setTimeout(function() {
                    block.next();
                }, trial.timing_post_trial);

            }

        };

        return plugin;
    })();
})(jQuery);<commit_msg>bug fix palmer<commit_after>/* jspsych-palmer
 * a jspsych plugin for presenting and querying about stimuli modeled after
 *
 * Palmer, S. (1977). Hierarchical Structure in Perceptual Representation. Cognitive Psychology, 9, 441.
 *
 * and
 *
 * Goldstone, R. L., Rogosky, B. J., Pevtzow, R., & Blair, M. (2005). Perceptual and semantic reorganization during category learning.
 * In H. Cohen & C. Lefebvre (Eds.) Handbook of Categorization in Cognitive Science. (pp. 651-678). Amsterdam: Elsevier.
 *
 * Josh de Leeuw (October 2013)
 *
 * NOTE: This plugin requires the Raphaeljs library for manipulating vector graphics (SVG). Download at http://www.raphaeljs.com
 *
 */

(function($) {
    jsPsych.palmer = (function() {

        var plugin = {};

        plugin.create = function(params) {
            var trials = [];
            for (var i = 0; i < params.configurations.length; i++) {
                var trial = {
                    type: "palmer",
                    configurations: params.configurations[i],
                    editable: params.editable,
                    show_feedback: (typeof params.show_feedback === 'undefined') ? false : params.show_feedback,
                    grid_spacing: params.grid_spacing || 75,
                    square_size: params.square_size || 3,
                    circle_radius: params.circle_radius || 20,
                    timing_item: params.timing_item || 1000,
                    timing_post_trial: params.timing_post_trial || 1000,
                    timing_feedback: params.timing_feedback || 1000,
                    prompt: (typeof params.prompt === 'undefined') ? "" : params.prompt,
                    data: (typeof params.data === 'undefined') ? {} : params.data[i]
                };

                trials.push(trial);
            }
            return trials;
        };

        plugin.trial = function(display_element, block, trial, part) {

            // variables to keep track of user interaction
            var start_circle = -1;
            var end_circle = -1;
            var line_started = false;

            var size = trial.grid_spacing * (trial.square_size + 1);

            display_element.append($("
", {
                css: {
                    width: size + "px",
                    height: size + "px"
                }
            }));

            var paper = Raphael("raphaelCanvas", size, size);

            // create the circles at the vertices.
            var circles = [];
            var node_idx = 0;
            for (var i = 1; i <= trial.square_size; i++) {
                for (var j = 1; j <= trial.square_size; j++) {
                    var circle = paper.circle(trial.grid_spacing * j, trial.grid_spacing * i, trial.circle_radius);
                    circle.attr("fill", "#000").attr("stroke-width", "0").attr("stroke", "#000").data("node", node_idx);

                    if (trial.editable) {
                        circle.hover(

                        function() {
                            this.attr("stroke-width", "2");
                            //this.attr("stroke", "#000");
                        },

                        function() {
                            this.attr("stroke-width", "0");
                            //this.attr("stroke", "#fff")
                        }).click(

                        function() {
                            if (!line_started) {
                                line_started = true;
                                start_circle = this.data("node");
                                this.attr("fill", "#777").attr("stroke", "#777");
                            }
                            else {
                                end_circle = this.data("node");
                                draw_connection(start_circle, end_circle);
                            }
                        });
                    }
                    node_idx++;
                    circles.push(circle);
                }
            }

            function draw_connection(start_circle, end_circle) {
                var the_line = getLineIndex(start_circle, end_circle);
                if (the_line > -1) {
                    toggle_line(the_line);
                }
                // reset highlighting on circles
                for (var i = 0; i < circles.length; i++) {
                    circles[i].attr("fill", "#000").attr("stroke", "#000");
                }
                // cleanup the variables
                line_started = false;
                start_circle = -1;
                end_circle = -1;
            }

            // create all possible lines that connect circles
            var horizontal_lines = [];
            var vertical_lines = [];
            var backslash_lines = [];
            var forwardslash_lines = [];

            for (var i = 0; i < trial.square_size; i++) {
                for (var j = 0; j < trial.square_size; j++) {
                    var current_item = (i * trial.square_size) + j;
                    // add horizontal connections
                    if (j < (trial.square_size - 1)) {
                        horizontal_lines.push([current_item, current_item + 1]);
                    }
                    // add vertical connections
                    if (i < (trial.square_size - 1)) {
                        vertical_lines.push([current_item, current_item + trial.square_size]);
                    }
                    // add diagonal backslash connections
                    if (i < (trial.square_size - 1) && j < (trial.square_size - 1)) {
                        backslash_lines.push([current_item, current_item + trial.square_size + 1]);
                    }
                    // add diagonal forwardslash connections
                    if (i < (trial.square_size - 1) && j > 0) {
                        forwardslash_lines.push([current_item, current_item + trial.square_size - 1]);
                    }
                }
            }

            var lines = horizontal_lines.concat(vertical_lines).concat(backslash_lines).concat(forwardslash_lines);

            // actually draw the lines
            var lineIsVisible = [];
            var lineElements = [];

            for (var i = 0; i < lines.length; i++) {
                var line = paper.path("M" + circles[lines[i][0]].attr("cx") + " " + circles[lines[i][0]].attr("cy") + "L" + circles[lines[i][1]].attr("cx") + " " + circles[lines[i][1]].attr("cy")).attr("stroke-width", "8").attr("stroke", "#000");
                line.hide();
                lineElements.push(line);
                lineIsVisible.push(0);
            }

            // define some helper functions to toggle lines on and off

            // this function gets the index of a line based on the two circles it connects
            function getLineIndex(start_circle, end_circle) {
                var the_line = -1;
                for (var i = 0; i < lines.length; i++) {
                    if ((start_circle == lines[i][0] && end_circle == lines[i][1]) || (start_circle == lines[i][1] && end_circle == lines[i][0])) {
                        the_line = i;
                        break;
                    }
                }
                return the_line;
            }

            // this function turns a line on/off based on the index (the_line)
            function toggle_line(the_line) {
                if (the_line > -1) {
                    if (lineIsVisible[the_line] === 0) {
                        lineElements[the_line].show();
                        lineElements[the_line].toBack();
                        lineIsVisible[the_line] = 1;
                    }
                    else {
                        lineElements[the_line].hide();
                        lineElements[the_line].toBack();
                        lineIsVisible[the_line] = 0;
                    }
                }
            }

            // this function takes an array of length = num lines, and displays the line whereever there
            // is a 1 in the array.
            function showConfiguration(configuration) {
                for (var i = 0; i < configuration.length; i++) {
                    if (configuration[i] != lineIsVisible[i]) {
                        toggle_line(i);
                    }
                }
            }

            // highlight a line
            function highlightLine(line) {
                lineElements[line].attr("stroke", "#f00");
            }

            // start recording the time
            var startTime = (new Date()).getTime();

            // what kind of trial are we doing?
            // if trial.editable is true, then we will let the user interact with the stimulus to create
            // something, e.g. for a reconstruction probe.
            // need a way for the user to submit when they are done in that case...
            if (trial.editable) {
                display_element.append($('<button id="submitButton" type="button">Submit Answer</button>'));
                $('#submitButton').click(function() {
                    save_data();
                });
            }

            // if trial.editable is false, then we are just showing a pre-determined configuration.
            // for now, the only option will be to display for a fixed amount of time.
            // future ideas: allow for key response, to enable things like n-back, same/different, etc..
            if (!trial.editable) {
                showConfiguration(trial.configurations);

                setTimeout(function() {
                    save_data();
                }, trial.timing_item);
            }

            if (trial.prompt !== "") {
                display_element.append($('
'));
                $("#palmer_prompt").html(trial.prompt);
            }

            function arrayDifferences(arr1, arr2) {
                var n_diff = 0;
                for (var i = 0; i < arr1.length; i++) {
                    if (arr1[i] != arr2[i]) {
                        n_diff++;
                    }
                }
                return n_diff;
            }

            // save data
            function save_data() {

                // measure RT
                var endTime = (new Date()).getTime();
                var response_time = endTime - startTime;

                // check if configuration is correct
                // this is meaningless for trials where the user can't edit
                var n_diff = arrayDifferences(trial.configurations, lineIsVisible);
                var correct = (n_diff === 0);

                block.data[block.trial_idx] = $.extend({}, {
                    "trial_type": "palmer",
                    "trial_index": block.trial_idx,
                    "configuration": lineIsVisible,
                    "target_configuration": trial.configurations,
                    "rt": response_time,
                    "correct": correct,
                    "num_wrong": n_diff,
                }, trial.data);

                if (trial.editable && trial.show_feedback) {
                    // hide the button
                    $('#submitButton').hide();
                    $('#palmer_prompt').hide();

                    showConfiguration(trial.configurations);
                    var feedback = "";
                    if (correct) {
                        feedback = "Correct!";
                    }
                    else {
                        if (n_diff > 1) {
                            feedback = "You missed " + n_diff + " lines. The correct symbol is shown above.";
                        }
                        else {
                            feedback = "You missed 1 line. The correct symbol is shown above.";
                        }
                    }
                    display_element.append($.parseHTML("
" + feedback + "
"));

                    setTimeout(function() {
                        next_trial();
                    }, trial.timing_feedback);

                }
                else {
                    next_trial();
                }
            }

            function next_trial() {

                display_element.html('');

                // next trial
                setTimeout(function() {
                    block.next();
                }, trial.timing_post_trial);

            }

        };

        return plugin;
    })();
})(jQuery);<|endoftext|>