<commit_before>function SupplyStatusController($scope, SupplyStatusReport, ReportSchedules, ReportPrograms , Periods , Products ,ReportFacilityTypes,GeographicZones, RequisitionGroups, $http, $routeParams,$location) {
    //to minimize and maximize the filter section
    var section = 1;

    $scope.section = function (id) {
        section = id;
    };

    $scope.show = function (id) {
        return section == id;
    };
    // lookups and references

    $scope.pagingOptions = {
        pageSizes: [ 20, 40, 50, 100],
        pageSize: 20,
        totalServerItems: 0,
        currentPage: 1
    };

    $scope.filterGrid = function (){
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
    };

    //filter form data section
    $scope.filterOptions = {
        period:$scope.period,
        filterText: "",
        useExternalFilter: false
    };

    //filter form data section
    $scope.filterObject =  {
        facilityTypeId : $scope.facilityType,
        facilityType : "",
        programId : $scope.program,
        periodId : $scope.period,
        zoneId : $scope.zone,
        productId : $scope.productId,
        scheduleId : $scope.schedule,
        rgroupId : $scope.rgroup,
        rgroup : "",
        facilityName : $scope.facilityNameFilter
    };

    ReportPrograms.get(function(data){
        $scope.programs = data.programs;
        $scope.programs.push({'name':'Select a Program'});
    });

    RequisitionGroups.get(function(data){
        $scope.requisitionGroups = data.requisitionGroupList;
        $scope.requisitionGroups.push({'name':'All Reporting Groups','id':'All'});
    });

    ReportFacilityTypes.get(function(data) {
        $scope.facilityTypes = data.facilityTypes;
        $scope.facilityTypes.push({'name': 'All Facility Types', 'id' : 'All'});
    });

    ReportSchedules.get(function(data){
        $scope.schedules = data.schedules;
        $scope.schedules.push({'name':'Select a Schedule', 'id':'All'});
    });

    Products.get(function(data){
        $scope.products = data.productList;
        $scope.products.push({'name': 'All Products','id':'All'});
    });

    $scope.ChangeSchedule = function(){
        Periods.get({ scheduleId : $scope.schedule },function(data) {
            $scope.periods = data.periods;
            $scope.periods.push({'name': 'Select Period', 'id':'All'});
        });
    }

    GeographicZones.get(function(data) {
        $scope.zones = data.zones;
        $scope.zones.push({'name': '- All Zones -', 'id' : 'All'});
    });

    $scope.$watch('facilityType', function(selection){
        if(selection == "All"){
            $scope.filterObject.facilityTypeId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.facilityTypeId =  selection;
            $.each( $scope.facilityTypes,function( item,idx){
                if(idx.id == selection){
                    $scope.filterObject.facilityType = idx.name;
                }
            });
        }else{
            $scope.filterObject.facilityTypeId =  0;
        }
        $scope.filterGrid();

    });

    $scope.$watch('facilityNameFilter', function(selection){
        if(selection != undefined || selection == ""){
            $scope.filterObject.facilityName =  selection;

        }else{
            $scope.filterObject.facilityName = "";
        }
        $scope.filterGrid();
    });

    $scope.$watch('product', function(selection){
        if(selection == "All"){
            $scope.filterObject.productId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.productId =  selection;
        }else{
            $scope.filterObject.productId =  0;
        }
        $scope.filterGrid();
    });

    $scope.$watch('rgroup', function(selection){
        if(selection == "All"){
            $scope.filterObject.rgroupId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.rgroupId =  selection;
            $.each( $scope.requisitionGroups,function( item,idx){
                if(idx.id == selection){
                    $scope.filterObject.rgroup = idx.name;
                }
            });
        }else{
            $scope.filterObject.rgroupId =  0;
        }
        $scope.filterGrid();
    });

    $scope.$watch('period', function(selection){
        if(selection == "All"){
            $scope.filterObject.periodId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.periodId =  selection;
        }else{
            $scope.filterObject.periodId =  0;
        }
        $scope.filterGrid();
    });

    $scope.$watch('program', function(selection){
        if(selection == "All"){
            $scope.filterObject.programId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.programId =  selection;
        }else{
            $scope.filterObject.programId =  0;
        }
        $scope.filterGrid();
    });

    $scope.$watch('schedule', function(selection){
        if(selection != undefined || selection == ""){
            $scope.filterObject.scheduleId =  selection;
        }else{
            $scope.filterObject.scheduleId =  0;
        }
        $scope.filterGrid();
    });

    $scope.$watch('zone', function(selection){
        if(selection == "All"){
            $scope.filterObject.zoneId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.zoneId =  selection;
        }else{
            $scope.filterObject.zoneId =  0;
        }
        $scope.filterGrid();
    });

    $scope.currentPage = ($routeParams.page) ? parseInt($routeParams.page) || 1 : 1;

    $scope.exportReport   = function (type){
        $scope.filterObject.pdformat =1;
        var params = jQuery.param($scope.filterObject);
        var url = '/reports/download/supply_status/' + type +'?' + params;
        window.open(url);

    }

    $scope.goToPage = function (page, event) {
        angular.element(event.target).parents(".dropdown").click();
        $location.search('page', page);
    };

    $scope.$watch("currentPage", function () {  //good watch no problem

        if($scope.currentPage != undefined && $scope.currentPage != 1){
            //when clicked using the links they have done updated the paging info no problem here
            //or using the url page param
            //$scope.pagingOptions.currentPage = $scope.currentPage;
            $location.search("page", $scope.currentPage);
        }
    });

    $scope.$on('$routeUpdate', function () {
        if (!utils.isValidPage($routeParams.page, $scope.numberOfPages)) {
            $location.search('page', 1);
            return;
        }
    });

    $scope.sortInfo = { fields:["code","facilityType"], directions: ["ASC"]};

    $scope.setPagingData = function(data, page, pageSize, total){
        $scope.myData = data;
        $scope.pagingOptions.totalServerItems = total;
        $scope.numberOfPages = ( Math.ceil( total / pageSize))  ? Math.ceil( total / pageSize) : 1 ;

    };

    $scope.getPagedDataAsync = function (pageSize, page) {
        var params  = {};
        if(pageSize != undefined && page != undefined ){
            var params =  {
                "max" : pageSize,
                "page" : page
            };
        }

        $.each($scope.filterObject, function(index, value) {
            //if(value != undefined)
            params[index] = value;
        });

        // put out the sort order
        $.each($scope.sortInfo.fields, function(index, value) {
            if(value != undefined) {
                params['sort-' + $scope.sortInfo.fields[index]] = $scope.sortInfo.directions[index];
            }
        });

        SupplyStatusReport.get(params, function(data) {
            $scope.setPagingData(data.pages.rows,page,pageSize,data.pages.total);
        });

    };

    $scope.$watch('pagingOptions.currentPage', function () {
        $scope.currentPage = $scope.pagingOptions.currentPage;
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
    }, true);

    $scope.$watch('pagingOptions.pageSize', function () {
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
    }, true);

    $scope.$watch('sortInfo', function () {
        $.each($scope.sortInfo.fields, function(index, value) {
            if(value != undefined)
                $scope.filterObject[$scope.sortInfo.fields[index]] = $scope.sortInfo.directions[index];
        });
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage, $scope.filterOptions.filterText);
    }, true);

    $scope.gridOptions = {
        data: 'myData',
        columnDefs:
            [
                { field: 'facility', displayName: 'Facility', width: "*", resizable: false},
                { field: 'code', displayName: 'Code', width: "*", resizable: false},
                { field: 'product', displayName: 'Product', width: "*" },
                { field: 'openingBalance', displayName: 'Opening Balance', width : "*"},
                { field: 'receipts', displayName: 'Receipts', width : "*"},
                { field: 'issues', displayName: 'Issues', width : "*"},
                { field: 'adjustments', displayName: 'Adjustments', width : "*"},
                { field: 'closingBalance', displayName: 'Closing Balance', width : "*"},
                { field: 'monthsOfStock', displayName: 'Months of Stock', width : "*"},
                { field: 'averageMonthlyConsumption', displayName: 'AMC', width : "*"},
                { field: 'maximumStock', displayName: 'Maximum Stock', width : "*"},
                { field: 'reorderAmount', displayName: 'Re-order Amount', width : "*"}

            ],
        enablePaging: true,
        enableSorting :true,
        showFooter: true,
        selectWithCheckboxOnly :false,
        pagingOptions: $scope.pagingOptions,
        filterOptions: $scope.filterOptions,
        useExternalSorting: true,
        sortInfo: $scope.sortInfo,
        showColumnMenu: true,
        enableRowReordering: true,
        showFilter: true,
        plugins: [new ngGridFlexibleHeightPlugin()]

    };

}
<commit_msg>ELMIS-181 : The number columns should be aligned to the right, and formatted<commit_after>function SupplyStatusController($scope, SupplyStatusReport, ReportSchedules, ReportPrograms , Periods , Products ,ReportFacilityTypes,GeographicZones, RequisitionGroups, $http, $routeParams,$location) {
    //to minimize and maximize the filter section
    var section = 1;

    $scope.section = function (id) {
        section = id;
    };

    $scope.show = function (id) {
        return section == id;
    };
    // lookups and references

    $scope.pagingOptions = {
        pageSizes: [ 20, 40, 50, 100],
        pageSize: 20,
        totalServerItems: 0,
        currentPage: 1
    };

    $scope.filterGrid = function (){
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
    };

    //filter form data section
    $scope.filterOptions = {
        period:$scope.period,
        filterText: "",
        useExternalFilter: false
    };

    //filter form data section
    $scope.filterObject =  {
        facilityTypeId : $scope.facilityType,
        facilityType : "",
        programId : $scope.program,
        periodId : $scope.period,
        period : "",
        zoneId : $scope.zone,
        productId : $scope.productId,
        scheduleId : $scope.schedule,
        rgroupId : $scope.rgroup,
        rgroup : "",
        facilityName : $scope.facilityNameFilter
    };

    ReportPrograms.get(function(data){
        $scope.programs = data.programs;
        $scope.programs.push({'name':'Select a Program'});
    });

    RequisitionGroups.get(function(data){
        $scope.requisitionGroups = data.requisitionGroupList;
        $scope.requisitionGroups.push({'name':'All Reporting Groups','id':'All'});
    });

    ReportFacilityTypes.get(function(data) {
        $scope.facilityTypes = data.facilityTypes;
        $scope.facilityTypes.push({'name': 'All Facility Types', 'id' : 'All'});
    });

    ReportSchedules.get(function(data){
        $scope.schedules = data.schedules;
        $scope.schedules.push({'name':'Select a Schedule', 'id':'All'});
    });

    Products.get(function(data){
        $scope.products = data.productList;
        $scope.products.push({'name': 'All Products','id':'All'});
    });

    $scope.ChangeSchedule = function(){
        Periods.get({ scheduleId : $scope.schedule },function(data) {
            $scope.periods = data.periods;
            $scope.periods.push({'name': 'Select Period', 'id':'All'});
        });
    }

    GeographicZones.get(function(data) {
        $scope.zones = data.zones;
        $scope.zones.push({'name': '- All Zones -', 'id' : 'All'});
    });

    $scope.$watch('facilityType', function(selection){
        if(selection == "All"){
            $scope.filterObject.facilityTypeId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.facilityTypeId =  selection;
            $.each( $scope.facilityTypes,function( item,idx){
                if(idx.id == selection){
                    $scope.filterObject.facilityType = idx.name;
                }
            });
        }else{
            $scope.filterObject.facilityTypeId =  0;
        }
        $scope.filterGrid();

    });

    $scope.$watch('facilityNameFilter', function(selection){
        if(selection != undefined || selection == ""){
            $scope.filterObject.facilityName =  selection;

        }else{
            $scope.filterObject.facilityName = "";
        }
        $scope.filterGrid();
    });

    $scope.$watch('product', function(selection){
        if(selection == "All"){
            $scope.filterObject.productId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.productId =  selection;
        }else{
            $scope.filterObject.productId =  0;
        }
        $scope.filterGrid();
    });

    $scope.$watch('rgroup', function(selection){
        if(selection == "All"){
            $scope.filterObject.rgroupId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.rgroupId =  selection;
            $.each( $scope.requisitionGroups,function( item,idx){
                if(idx.id == selection){
                    $scope.filterObject.rgroup = idx.name;
                }
            });
        }else{
            $scope.filterObject.rgroupId =  0;
        }
        $scope.filterGrid();
    });

    $scope.$watch('period', function(selection){
        if(selection == "All"){
            $scope.filterObject.periodId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.periodId =  selection;
            $.each( $scope.periods,function( item,idx){
                if(idx.id == selection){
                    $scope.filterObject.period = idx.name;
                }
            });

        }else{
            $scope.filterObject.periodId =  0;
        }
        $scope.filterGrid();
    });

    $scope.$watch('program', function(selection){
        if(selection == "All"){
            $scope.filterObject.programId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.programId =  selection;
        }else{
            $scope.filterObject.programId =  0;
        }
        $scope.filterGrid();
    });

    $scope.$watch('schedule', function(selection){
        if(selection != undefined || selection == ""){
            $scope.filterObject.scheduleId =  selection;
        }else{
            $scope.filterObject.scheduleId =  0;
        }
        $scope.filterGrid();
    });

    $scope.$watch('zone', function(selection){
        if(selection == "All"){
            $scope.filterObject.zoneId =  -1;
        }else if(selection != undefined || selection == ""){
            $scope.filterObject.zoneId =  selection;
        }else{
            $scope.filterObject.zoneId =  0;
        }
        $scope.filterGrid();
    });

    $scope.currentPage = ($routeParams.page) ? parseInt($routeParams.page) || 1 : 1;

    $scope.exportReport   = function (type){
        $scope.filterObject.pdformat =1;
        var params = jQuery.param($scope.filterObject);
        var url = '/reports/download/supply_status/' + type +'?' + params;
        window.open(url);

    }

    $scope.goToPage = function (page, event) {
        angular.element(event.target).parents(".dropdown").click();
        $location.search('page', page);
    };

    $scope.$watch("currentPage", function () {  //good watch no problem

        if($scope.currentPage != undefined && $scope.currentPage != 1){
            //when clicked using the links they have done updated the paging info no problem here
            //or using the url page param
            //$scope.pagingOptions.currentPage = $scope.currentPage;
            $location.search("page", $scope.currentPage);
        }
    });

    $scope.$on('$routeUpdate', function () {
        if (!utils.isValidPage($routeParams.page, $scope.numberOfPages)) {
            $location.search('page', 1);
            return;
        }
    });

    $scope.sortInfo = { fields:["code","facilityType"], directions: ["ASC"]};

    $scope.setPagingData = function(data, page, pageSize, total){
        $scope.myData = data;
        $scope.pagingOptions.totalServerItems = total;
        $scope.numberOfPages = ( Math.ceil( total / pageSize))  ? Math.ceil( total / pageSize) : 1 ;

    };

    $scope.getPagedDataAsync = function (pageSize, page) {
        var params  = {};
        if(pageSize != undefined && page != undefined ){
            var params =  {
                "max" : pageSize,
                "page" : page
            };
        }

        $.each($scope.filterObject, function(index, value) {
            //if(value != undefined)
            params[index] = value;
        });

        // put out the sort order
        $.each($scope.sortInfo.fields, function(index, value) {
            if(value != undefined) {
                params['sort-' + $scope.sortInfo.fields[index]] = $scope.sortInfo.directions[index];
            }
        });

        SupplyStatusReport.get(params, function(data) {
            $scope.setPagingData(data.pages.rows,page,pageSize,data.pages.total);
        });

    };

    $scope.$watch('pagingOptions.currentPage', function () {
        $scope.currentPage = $scope.pagingOptions.currentPage;
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
    }, true);

    $scope.$watch('pagingOptions.pageSize', function () {
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
    }, true);

    $scope.$watch('sortInfo', function () {
        $.each($scope.sortInfo.fields, function(index, value) {
            if(value != undefined)
                $scope.filterObject[$scope.sortInfo.fields[index]] = $scope.sortInfo.directions[index];
        });
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage, $scope.filterOptions.filterText);
    }, true);

    $scope.gridOptions = {
        data: 'myData',
        columnDefs:
            [
                { field: 'facility', displayName: 'Facility', width: "*", resizable: false},
                { field: 'code', displayName: 'Code', width: "*", resizable: false},
                { field: 'product', displayName: 'Product', width: "*" },
                { field: 'openingBalance', displayName: 'Opening Balance', width : "*", cellClass : 'numeric'},
                { field: 'receipts', displayName: 'Receipts', width : "*", cellClass : 'numeric'},
                { field: 'issues', displayName: 'Issues', width : "*", cellClass : 'numeric'},
                { field: 'adjustments', displayName: 'Adjustments', width : "*", cellClass : 'numeric'},
                { field: 'closingBalance', displayName: 'Closing Balance', width : "*", cellClass : 'numeric'},
                { field: 'monthsOfStock', displayName: 'Months of Stock', width : "*", cellClass : 'numeric'},
                { field: 'averageMonthlyConsumption', displayName: 'AMC', width : "*", cellClass : 'numeric'},
                { field: 'maximumStock', displayName: 'Maximum Stock', width : "*", cellClass : 'numeric'},
                { field: 'reorderAmount', displayName: 'Re-order Amount', width : "*", cellClass : 'numeric'}

            ],
        enablePaging: true,
        enableSorting :true,
        showFooter: true,
        selectWithCheckboxOnly :false,
        pagingOptions: $scope.pagingOptions,
        filterOptions: $scope.filterOptions,
        useExternalSorting: true,
        sortInfo: $scope.sortInfo,
        showColumnMenu: true,
        enableRowReordering: true,
        showFilter: true,
        plugins: [new ngGridFlexibleHeightPlugin()]

    };

}
<|endoftext|>


<commit_before><commit_msg>Added test<commit_after>// Creates an instace of invertedIndex
var indexObj = new InvertedIndex();
// Runs the createIndex before every spec.
beforeEach(function (done){
  indexObj.createIndex('books.json',done);
});

describe('Read book data', function () {

  it('Reads the JSON file and asserts that it is not empty.',function () {
    // This spec checks if the JSON object is empty.
    expect( Object.keys(indexObj.bookObject).length ).toBeGreaterThan(0);
  });

  it('verifies that the JSON file contains a JSON object', function() {
    // This spec checks if the JSON object is an object.
    expect(typeof indexObj.bookObject).toBe('object');
  });

  it('verifies that the title of the first object property in the array is of type string', function() {
    // This spec checks if the JSON object is an object.
    expect(typeof indexObj.bookObject[0].title).toBe('string');
  });
});

describe('Populate Index',function() {

  it('Verifies the index is created once the file is read', function () {
    // Checks if the index have been created
    expect(Object.keys(indexObj.getIndex(indexObj.bookObject)).length).toBeGreaterThan(0);
  });

  it('Verifies the index maps the string keys to the correct objects in the JSON array', function () {
    // Checks if the index key maps to the correct object and position in the JSON array
    expect(indexObj.dictionary.wonderland).toEqual([[0,'TL',9]]);
  });

  it('Verifies the index maps the string keys to the correct objects in the JSON array', function () {
    // Checks if the index key maps to the correct object and position in the JSON array
    expect(indexObj.dictionary.alice).toEqual([
      [0,'TL',0],
      [0,'TX',0]
      ]);
  });

  it('Verifies the index maps the string keys to the correct objects in the JSON array', function () {
    // Checks if the index key maps to the correct object and position in the JSON array
    expect(indexObj.dictionary.ring).toEqual([
      [1,'TL',16],
      [1,'TL',44],
      [1,'TX',82]
    ]);
  });
});

describe('Search index',function () {

  it('verifies that searching the index returns an array of the indices of the correct objects that contain the words in the search query',function () {
    expect(indexObj.searchIndex('alice')).toEqual([
        [
          [0,'TL', 0],
          [0,'TX', 0]
        ]
      ] );

  });

  it('verifies that searching the index returns an array empty array when searched with words not in the index',function () {
    // Verifies if searching the index returns an array of the indices of the correct objects that contain the words in the search query.
    expect( indexObj.searchIndex('checkpoint')).toEqual([[]]);

  });

  it('Ensure searchIndex can handle a varied number of search terms as arguments.',function () {
    // Checks if search can handle varying number of arguments
    expect(indexObj.searchIndex('segun','tobi','wonderland')).toEqual([
                [  ],
                [  ],
                [
                  [0,'TL',9]
                ]
               ]);

  });

  it('Ensure searchIndex can handle a more complex search terms as arguments.',function () {
    // Checks if search can handle more complex arguments.
    expect(indexObj.searchIndex(['Rings','Yemi',['in','fall']],'yemi','stephen')).toEqual([
        [
          [ 1, 'TL', 16 ],
          [ 1, 'TL', 44 ],
          [ 1, 'TX', 82 ]
        ],
        [  ],
        [ [ 0, 'TL', 6 ] ],
        [ [ 0, 'TX', 6 ] ],
        [  ],
        [  ]
      ] );

  });

  it('Ensure searchIndex can handle a sentence as arguments.',function () {
        // Checks if search can handle a sentences
    expect(indexObj.searchIndex( 'ALice in wonderland.','this is Home elf.' )).toEqual( [
        [
          [0,'TL',0],
          [0,'TX', 0]
        ],
        [ [0,'TL', 6] ],
        [ [0,'TL', 9] ],
        [  ],
        [  ],
        [  ],
        [ [1,'TX', 27] ]
      ]  );

  });

  var testArray = [ 'lord', 'wonderland', 'enters',
                    ['destroy', 'ring', 'seek', 'alliance',
                      ['alice', 'rings',
                        ['imagination', 'hole', 'rabbit',
                          ['world', 'elf', 'dwarf', 'hobbit']
                        ]
                      ]
                    ],
                  'wizard'];

  it('Ensures search does not take too long to execute ',function () {
        // Checks if search can handle a sentences
    var expectedResult = [
                            [ [ 1, 'TL', 4 ] ],
                            [ [ 0, 'TL', 9 ] ],
                            [ [ 0, 'TX', 35 ] ],
                            [ [ 1, 'TX', 63 ] ],
                            [
                              [ 1, 'TL', 16 ],
                              [ 1, 'TL', 44 ],
                              [ 1, 'TX', 82 ]
                            ],
                            [ [ 1, 'TX', 55 ] ],
                            [ [ 1, 'TX', 11 ] ],
                            [
                              [ 0, 'TL', 0 ],
                              [ 0, 'TX', 0 ]
                            ],
                            [
                              [ 1, 'TL', 16 ],
                              [ 1, 'TL', 44 ],
                              [ 1, 'TX', 82 ]
                            ],
                            [ [ 0, 'TX', 58 ] ],
                            [ [ 0, 'TX', 26 ] ],
                            [ [ 0, 'TX', 19 ] ],
                            [ [ 0, 'TX', 44 ] ],
                            [ [ 1, 'TX', 27 ] ],
                            [ [ 1, 'TX', 31 ] ],
                            [ [ 1, 'TX', 48 ] ],
                            [ [ 1, 'TX', 37 ] ]
                          ];
    expect(indexObj.searchIndex( testArray )).toEqual(expectedResult);

  });
});

<|endoftext|>


<commit_before>
import React, { Component, View, Animated, PanResponder } from 'react-native';

/**
 * OpenProgress:
 * - 0: only content is visible
 * - 0..1: left sidebar is visible, over 1 for bounce effects
 * - -1..0: right sidebar is visible, below -1 for bounce effects
 */
export default class SidebarView extends Component {
	constructor(props) {
		super(props);

		const open = props.open || false;

		this.openProgress = new Animated.Value(open === 'right' ? -1 : open ? 1 : 0);
		this.panResponder = PanResponder.create({
			onMoveShouldSetPanResponder: this._handleShouldMove.bind(this),
			onPanResponderMove: this._handleMove.bind(this),
			onPanResponderRelease: this._handleMoveEnd.bind(this),
			onPanResponderTerminate: this._handleMoveEnd.bind(this)
		});
		this.threshold = this.props.threshold || 50;

		this.contentWidth = new Animated.Value(320); // will be changed in onLayout automatically
		this.leftSidebarWidth = new Animated.Value(this.props.leftSidebarWidth || 150);
		this.rightSidebarWidth = new Animated.Value(this.props.rightSidebarWidth || 150);

		this.contentOffset = this.openProgress.interpolate({
			inputRange: [-1, 0, 1],
			outputRange: [-150, 0, 150]
		});
		this.leftSidebarOffset = this.openProgress.interpolate({
			inputRange: [0, 1],
			outputRange: [-50, 0]
		});
		this.rightSidebarOffset = this.openProgress.interpolate({
			inputRange: [-1, 0],
			outputRange: [0, -50]
		});
		this.leftSidebarOpacity = this.openProgress.interpolate({
			inputRange: [0, 1],
			outputRange: [0, 1]
		});
		this.rightSidebarOpacity = this.openProgress.interpolate({
			inputRange: [-1, 0],
			outputRange: [1, 0]
		});
	}

	open(side) {
		if (this.props.leftSidebar && side !== 'right') {
			Animated.spring(this.openProgress, { toValue: 1 }).start();
		} else if (this.props.rightSidebar && side !== 'right') {
			Animated.spring(this.openProgress, { toValue: -1 }).start();
		} else {
			this.close();
		}
	}

	close() {
		Animated.spring(this.openProgress, { toValue: 0 }).start();
	}

	toggle(side) {
		if (this.props.leftSidebar && this.openProgress._value !== 1 && side !== 'right') {
			this.open();
		} else if (this.props.rightSidebar && this.openProgress._value !== -1 && side === 'right') {
			this.open('right');
		} else {
			this.close();
		}
	}

	onLayout(event) {
		this.contentWidth.setValue(event.nativeEvent.layout.width);
	}

	_handleShouldMove(event, gestureState) {
		const locationX = event.nativeEvent.locationX;
		const contentWidth = this.contentWidth._value;

		this.progressOffset = this.openProgress._value;
		this.progressFactor = 1 / contentWidth;

		return this.openProgress._value !== 0 ||
				this.props.leftSidebar && locationX >= 0 && locationX <= this.threshold ||
				this.props.rightSidebar && locationX >= contentWidth - this.threshold && locationX <= contentWidth;
	}

	_handleMove(event, gestureState) {
		const currentProgress = this.progressOffset + gestureState.dx * this.progressFactor;

		this.openProgress.setValue(currentProgress);
	}

	_handleMoveEnd(event, gestureState) {
		const currentProgress = this.progressOffset + gestureState.dx * this.progressFactor;
		const velocity = gestureState.vx * this.progressFactor;

		let toValue = 0;
		if (this.props.leftSidebar && currentProgress + gestureState.vx >= 0.5) {
			toValue = 1;
		} else if (this.props.rightSidebar && currentProgress + gestureState.vx < -0.5) {
			toValue = -1;
		}

		Animated.sequence([
			Animated.decay(this.openProgress, { velocity }),
			Animated.spring(this.openProgress, { toValue })
		]).start();
	}

	_componentWillReceiveProps(nextProps) {
		if (this.openProgress._value === -1 || this.openProgress._value === 0 || this.openProgress._value === 1) {
			// FIXME use new open state!
		}
	}

	render() {
		const props = {
			onLayout: this.onLayout.bind(this),
			...this.panResponder.panHandlers,
			style: this.props.style
		};

		const contentStyle = {
			position: 'absolute',
			top: 0,
			bottom: 0,
			left: this.contentOffset,
			width: this.contentWidth
		};

		const leftSidebarStyle = {
			position: 'absolute',
			top: 0,
			bottom: 0,
			left: this.leftSidebarOffset,
			width: this.leftSidebarWidth,
			opacity: this.leftSidebarOpacity
		};

		const rightSidebarStyle = {
			position: 'absolute',
			top: 0,
			bottom: 0,
			right: this.rightSidebarOffset,
			width: this.rightSidebarWidth,
			opacity: this.rightSidebarOpacity
		};

		return (
			<View { ...props }>
				<Animated.View key='leftSidebar' style={ leftSidebarStyle }>
					{ this.props.leftSidebar }
				</Animated.View>
				<Animated.View key='rightSidebar' style={ rightSidebarStyle }>
					{ this.props.rightSidebar }
				</Animated.View>
				<Animated.View key='content' style={ contentStyle }>
					{ this.props.children }
				</Animated.View>
			</View>
		);
	}
}
<commit_msg>Test some API ideas<commit_after>
import React, { Component, View, Animated, PanResponder } from 'react-native';

/**
 * OpenProgress:
 * - 0: only content is visible
 * - 0..1: left sidebar is visible, over 1 for bounce effects
 * - -1..0: right sidebar is visible, below -1 for bounce effects
 */
export default class SidebarView extends Component {
	constructor(props) {
		super(props);

		const open = props.open || false;

		this.openProgress = new Animated.Value(open === 'right' ? -1 : open ? 1 : 0);
		this.panResponder = PanResponder.create({
			onMoveShouldSetPanResponder: this._handleShouldMove.bind(this),
			onPanResponderMove: this._handleMove.bind(this),
			onPanResponderRelease: this._handleMoveEnd.bind(this),
			onPanResponderTerminate: this._handleMoveEnd.bind(this)
		});
		this.threshold = this.props.threshold || 50;

		this.contentWidth = new Animated.Value(320); // will be changed in onLayout automatically
		this.leftSidebarWidth = new Animated.Value(this.props.leftSidebarWidth || 150);
		this.rightSidebarWidth = new Animated.Value(this.props.rightSidebarWidth || 150);

		this.contentOffset = this.openProgress.interpolate({
			inputRange: [-1, 0, 1],
			outputRange: [-150, 0, 150]
		});
		this.leftSidebarOffset = this.openProgress.interpolate({
			inputRange: [0, 1],
			outputRange: [-50, 0]
		});
		this.rightSidebarOffset = this.openProgress.interpolate({
			inputRange: [-1, 0],
			outputRange: [0, -50]
		});
		this.leftSidebarOpacity = this.openProgress.interpolate({
			inputRange: [0, 1],
			outputRange: [0, 1]
		});
		this.rightSidebarOpacity = this.openProgress.interpolate({
			inputRange: [-1, 0],
			outputRange: [1, 0]
		});
	}

// API test / prototyping... Some methods will be removed later again.

	showLeftSidebar() {
		if (this.props.leftSidebar) {
			Animated.spring(this.openProgress, { toValue: 1 }).start();
		}
	}

	showRightSidebar() {
		if (this.props.rightSidebar) {
			Animated.spring(this.openProgress, { toValue: -1 }).start();
		}
	}

	toggleLeftSidebar() {
		// ...
	}

	toggleRightSidebar() {
		// ...
	}

	closeSidebars() {
		Animated.spring(this.openProgress, { toValue: 0 }).start();
	}

	open(side) {
		if (this.props.leftSidebar && side !== 'right') {
			Animated.spring(this.openProgress, { toValue: 1 }).start();
		} else if (this.props.rightSidebar && side !== 'right') {
			Animated.spring(this.openProgress, { toValue: -1 }).start();
		} else {
			this.close();
		}
	}

	close() {
		Animated.spring(this.openProgress, { toValue: 0 }).start();
	}

	toggle(side) {
		if (this.props.leftSidebar && this.openProgress._value !== 1 && side !== 'right') {
			this.open();
		} else if (this.props.rightSidebar && this.openProgress._value !== -1 && side === 'right') {
			this.open('right');
		} else {
			this.close();
		}
	}

	onLayout(event) {
		this.contentWidth.setValue(event.nativeEvent.layout.width);
	}

	_handleShouldMove(event, gestureState) {
		const locationX = event.nativeEvent.locationX;
		const contentWidth = this.contentWidth._value;

		this.progressOffset = this.openProgress._value;
		this.progressFactor = 1 / contentWidth;

		return this.openProgress._value !== 0 ||
				this.props.leftSidebar && locationX >= 0 && locationX <= this.threshold ||
				this.props.rightSidebar && locationX >= contentWidth - this.threshold && locationX <= contentWidth;
	}

	_handleMove(event, gestureState) {
		const currentProgress = this.progressOffset + gestureState.dx * this.progressFactor;

		this.openProgress.setValue(currentProgress);
	}

	_handleMoveEnd(event, gestureState) {
		const currentProgress = this.progressOffset + gestureState.dx * this.progressFactor;
		const velocity = gestureState.vx * this.progressFactor;

		let toValue = 0;
		if (this.props.leftSidebar && currentProgress + gestureState.vx >= 0.5) {
			toValue = 1;
		} else if (this.props.rightSidebar && currentProgress + gestureState.vx < -0.5) {
			toValue = -1;
		}

		Animated.sequence([
			Animated.decay(this.openProgress, { velocity }),
			Animated.spring(this.openProgress, { toValue })
		]).start();
	}

	_componentWillReceiveProps(nextProps) {
		if (this.openProgress._value === -1 || this.openProgress._value === 0 || this.openProgress._value === 1) {
			// FIXME use new open state!
		}
	}

	render() {
		const props = {
			onLayout: this.onLayout.bind(this),
			...this.panResponder.panHandlers,
			style: this.props.style
		};

		const contentStyle = {
			position: 'absolute',
			top: 0,
			bottom: 0,
			left: this.contentOffset,
			width: this.contentWidth
		};

		const leftSidebarStyle = {
			position: 'absolute',
			top: 0,
			bottom: 0,
			left: this.leftSidebarOffset,
			width: this.leftSidebarWidth,
			opacity: this.leftSidebarOpacity
		};

		const rightSidebarStyle = {
			position: 'absolute',
			top: 0,
			bottom: 0,
			right: this.rightSidebarOffset,
			width: this.rightSidebarWidth,
			opacity: this.rightSidebarOpacity
		};

		return (
			<View { ...props }>
				<Animated.View key='leftSidebar' style={ leftSidebarStyle }>
					{ this.props.leftSidebar }
				</Animated.View>
				<Animated.View key='rightSidebar' style={ rightSidebarStyle }>
					{ this.props.rightSidebar }
				</Animated.View>
				<Animated.View key='content' style={ contentStyle }>
					{ this.props.children }
				</Animated.View>
			</View>
		);
	}
}
<|endoftext|>


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

// sample-metadata:
//   title: Create Job
//   description: Create a job that posts to /log_payload on an App Engine service.
//   usage: node createJob.js [project-id] [location-id] [app-engine-service-id]

/**
 * Create a job with an App Engine target via the Cloud Scheduler API
 */
async function createJob(projectId, locationId, serviceId) {
  // [START cloud_scheduler_create_job]
  const scheduler = require('@google-cloud/scheduler');

  // Create a client.
  const client = new scheduler.CloudSchedulerClient();

  // TODO(developer): Uncomment and set the following variables
  // const projectId = "PROJECT_ID"
  // const locationId = "LOCATION_ID"
  // const serviceId = "my-serivce"

  // Construct the fully qualified location path.
  const parent = client.locationPath(projectId, locationId);

  // Construct the request body.
  const job = {
    appEngineHttpTarget: {
      appEngineRouting: {
        service: serviceId,
      },
      relativeUri: '/log_payload',
      httpMethod: 'POST',
      body: Buffer.from('Hello World'), //.toString("base64"),
    },
    schedule: '* * * * *',
    timeZone: 'America/Los_Angeles',
  };

  const request = {
    parent: parent,
    job: job,
  };

  // Use the client to send the job creation request.
  const [response] = await client.createJob(request);
  console.log(`Created job: ${response.name}`);
  // [END cloud_scheduler_create_job]
}

const args = process.argv.slice(2);
createJob(...args).catch(err => {
  console.error(err.message);
  process.exitCode = 1;
});
<commit_msg>fix(samples): delete stale comment from sample (#182)<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// sample-metadata:
//   title: Create Job
//   description: Create a job that posts to /log_payload on an App Engine service.
//   usage: node createJob.js [project-id] [location-id] [app-engine-service-id]

/**
 * Create a job with an App Engine target via the Cloud Scheduler API
 */
async function createJob(projectId, locationId, serviceId) {
  // [START cloud_scheduler_create_job]
  const scheduler = require('@google-cloud/scheduler');

  // Create a client.
  const client = new scheduler.CloudSchedulerClient();

  // TODO(developer): Uncomment and set the following variables
  // const projectId = "PROJECT_ID"
  // const locationId = "LOCATION_ID"
  // const serviceId = "my-serivce"

  // Construct the fully qualified location path.
  const parent = client.locationPath(projectId, locationId);

  // Construct the request body.
  const job = {
    appEngineHttpTarget: {
      appEngineRouting: {
        service: serviceId,
      },
      relativeUri: '/log_payload',
      httpMethod: 'POST',
      body: Buffer.from('Hello World'),
    },
    schedule: '* * * * *',
    timeZone: 'America/Los_Angeles',
  };

  const request = {
    parent: parent,
    job: job,
  };

  // Use the client to send the job creation request.
  const [response] = await client.createJob(request);
  console.log(`Created job: ${response.name}`);
  // [END cloud_scheduler_create_job]
}

const args = process.argv.slice(2);
createJob(...args).catch(err => {
  console.error(err.message);
  process.exitCode = 1;
});
<|endoftext|>


<commit_before>"use strict";

var env = require('../lib/env');
var Spec = require('../lib/Spec');
var Host = require('../lib/Host');
var Model = require('../lib/Model');
var SyncSet = require('../lib/Set');
var Storage = require('../lib/Storage');

env.multihost = true;
env.debug = console.log;

MetricLengthField.metricRe = /(\d+)(mm|cm|m|km)?/g;  // "1m and 10cm"
MetricLengthField.scale = { m:1, cm:0.01, mm:0.001, km:1000 };
MetricLengthField.scaleArray = ['km','m','cm','mm'];

function MetricLengthField (value) {
    // convert mm cm m km
    if (typeof(value)==='number') {
        this.meters = value;
    } else {
        value = value.toString();
        this.meters=0;
        var m=[], scale=MetricLengthField.scale;
        MetricLengthField.metricRe.lastIndex = 0;
        while (m=MetricLengthField.metricRe.exec(value)) {
            var unit = m[2] ? scale[m[2]] : 1;
            this.meters += parseInt(m[1]) * unit;
        }
    }
}
MetricLengthField.prototype.add = function () {

};
// .pojo() invokes (entry.toJSON&&entry.toJSON()) || entry.toString()
MetricLengthField.prototype.toString = function () {
    var m = this.meters, ret='', scar = MetricLengthField.scaleArray;
    for(var i=0; i<scar.length; i++) {
        var unit = scar[i],
            scale= MetricLengthField.scale[unit];
        var wholeUnits = Math.floor(m/scale);
        if (wholeUnits>=1) {
            ret += wholeUnits + unit;
        }
        m -= wholeUnits*scale;
    }
    return ret;
};
MetricLengthField.prototype.toPojo = MetricLengthField.prototype.toString;

// Duck is our core testing class :)
var Duck = Model.extend('Duck',{
    defaults: {
        age: 0,
        height: {type:MetricLengthField,value:'3cm'},
        mood: 'neutral'
    },
    // Simply a regular convenience method
    canDrink: function () {
        return this.age >= 18; // Russia
    },
    validate: function (spec,val) {
        return ''; // :|
        //return spec.op()!=='set' || !('height' in val);
        //throw new Error("can't set height, may only grow");
    }
    /*$$grow: function (spec,by,src) {
        this.height = this.height.add(by);
    }*/
});

var Nest = SyncSet.extend('Nest',{
    entryType: Duck
});

var storage2 = new Storage(false);
var host2 = env.localhost= new Host('gritzko',0,storage2);
host2.availableUplinks = function () {return [storage2]; };

asyncTest('2.a basic listener func', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    expect(5);
    // construct an object with an id provided; it will try to fetch
    // previously saved state for the id (which is none)
    var huey = host2.get('/Duck#hueyA');
    //ok(!huey._version); //storage is a?sync
    // listen to a field
    huey.on('age',function lsfn2a (spec,val){  // FIXME: filtered .set listener!!!
        equal(val.age,1);
        equal(spec.op(),'set');
        equal(spec.toString(),'/Duck#hueyA!'+spec.version()+'.set');
        var version = spec.token('!');
        equal(version.ext,'gritzko');
        huey.off('age',lsfn2a);
        equal(huey._lstn.length,2); // only the uplink remains (and the comma)
        start();
    });
    huey.on('.init', function init2a () {
        huey.set({age:1});
    });
});

test('2.b create-by-id', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    // there is 1:1 spec-to-object correspondence;
    // an attempt of creating a second copy of a model object
    // will throw an exception
    var dewey1 = new Duck('dewey');
    // that's we resort to descendant() doing find-or-create
    var dewey2 = host2.get('/Duck#dewey');
    // must be the same object
    strictEqual(dewey1,dewey2);
    equal(dewey1.spec().type(),'Duck');
});

test('2.c version ids', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var louie = new Duck('louie');
    var ts1 = host2.time();
    louie.set({age:3});
    var ts2 = host2.time();
    ok(ts2>ts1);
    var vid = louie._version.substr(1);
    ok(ts1<vid);
    ok(ts2>vid);
    console.log(ts1,vid,ts2);
});

test('2.d pojos',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var dewey = new Duck({age:0});
    var json = dewey.pojo();
    var duckJSON = {
        mood: "neutral",
        age: 0,
        height: '3cm'
    };
    deepEqual(json,duckJSON);
});

asyncTest('2.e reactions',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var huey = host2.get('/Duck#huey');
    expect(2);
    var handle = Duck.addReaction('age', function reactionFn(spec,val) {
        console.log('yupee im growing');
        equal(val.age,1);
        start();
    });
    //var version = host2.time(), sp = '!'+version+'.set';
    huey.deliver(huey.newEventSpec('set'), {age:1});
    Duck.removeReaction(handle);
    equal(Duck.prototype._reactions['set'].length,0); // no house cleaning :)
});

// TODO $$event listener/reaction (Model.on: 'key' > .set && key check)

test('2.f once',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var huey = host2.get('/Duck#huey');
    expect(1);
    huey.once('age',function onceAgeCb(spec,value){
        equal(value.age,4);
    });
    huey.set({age:4});
    huey.set({age:5});
});

test('2.g custom field type',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var huey = host2.get('/Duck#huey');
    huey.set({height:'32cm'});
    ok(Math.abs(huey.height.meters-0.32)<0.0001);
    var vid = host2.time();
    host2.deliver(new Spec('/Duck#huey!'+vid+'.set'),{height:'35cm'});
    ok(Math.abs(huey.height.meters-0.35)<0.0001);
});

test('2.h state init',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var factoryBorn = new Duck({age:0,height:'4cm'});
    ok(Math.abs(factoryBorn.height.meters-0.04)<0.0001);
    equal(factoryBorn.age,0);
});

test('2.i batched set',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var nameless = new Duck();
    nameless.set({
        age:1,
        height: '60cm'
    });
    ok(Math.abs(nameless.height.meters-0.6)<0.0001);
    equal(nameless.age,1);
    ok(!nameless.canDrink());

});

// FIXME:  spec - to - (order)
test('2.j basic Set functions (string index)',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var hueyClone = new Duck({age:2});
    var deweyClone = new Duck({age:1});
    var louieClone = new Duck({age:3});
    var clones = new Nest();
    clones.addObject(louieClone);
    clones.addObject(hueyClone);
    clones.addObject(deweyClone);
    var sibs = clones.list(function(a,b){return a.age - b.age;});
    strictEqual(sibs[0],deweyClone);
    strictEqual(sibs[1],hueyClone);
    strictEqual(sibs[2],louieClone);
    var change = {};
    change[hueyClone.spec()] = 0;
    clones.change(change);
    var sibs2 = clones.list(function(a,b){return a.age - b.age;});
    equal(sibs2.length,2);
    strictEqual(sibs2[0],deweyClone);
    strictEqual(sibs2[1],louieClone);
});

test('2.k distilled log', function (test) {
    function logSize(obj) {
        var log = obj._oplog, cnt=0;
        for(var key in log) { // jshint ignore:line
            cnt++;
        }
        return cnt;
    }
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var duckling1 = host2.get(Duck);
    duckling1.set({age:1});
    duckling1.set({age:2});
    duckling1.distillLog();
    equal(logSize(duckling1),1);
    duckling1.set({height:'30cm',age:3});
    duckling1.set({height:'40cm',age:4});
    duckling1.distillLog();
    equal(logSize(duckling1),1);
    duckling1.set({age:5});
    duckling1.distillLog();
    equal(logSize(duckling1),2);
});

test('2.l partial order', function (test) {
    env.localhost= host2;
    var duckling = new Duck();
    duckling.deliver(new Spec(duckling.spec()+'!time+user2.set'),{height:'2cm'});
    duckling.deliver(new Spec(duckling.spec()+'!time+user1.set'),{height:'1cm'});
    equal(duckling.height.toString(), '2cm');
});

asyncTest('2.m init push', function (test) {
    env.localhost= host2;
    var scrooge = new Duck({age:105});
    scrooge.on('.init', function check() {
        var tail = storage2.tails[scrooge.spec()];
        // FIXME equal(scrooge._version.substr(1), scrooge._id);
        var op = tail && tail[scrooge._version+'.set'];
        ok(tail) && ok(op) && equal(op.age,105);
        start();
    });
});

test('2.n local listeners for on/off', function () {
    console.warn(QUnit.config.current.testName);
    expect(5);
    env.localhost= host2;
    var duck = new Duck();
    duck.on('.on', function (spec, val) {
        console.log('triggered by itself, on(init) and host2.on below');
        equal(spec.op(), 'on');
    });
    duck.on('.init',function gotit(){
        console.log('inevitable');
        ok(duck._version);
    });
    duck.on('.reon', function (spec, val) {
        console.log("must NOT get triggered if the storage is sync");
        equal(spec.op(), 'reon');
    });
    host2.on('/Host#gritzko.on', function (spec, val) {
        console.log('this listener is triggered by itself');
        equal(spec.op(), 'on');
    });
});

/*  TODO
 * test('2.m on/off sub', function (test) {
    env.localhost= host2
    var duckling = new Duck();

    expect(2);
    duckling.on('on',function(spec){
        ok(spec.op(),'on');
    });
    duckling.on('set',function(spec){
        equal(spec.op(),'set');
    });
    duckling.set({age:1});

});*/
<commit_msg>one more event relay test<commit_after>"use strict";

var env = require('../lib/env');
var Spec = require('../lib/Spec');
var Host = require('../lib/Host');
var Model = require('../lib/Model');
var SyncSet = require('../lib/Set');
var Storage = require('../lib/Storage');

env.multihost = true;
env.debug = console.log;

MetricLengthField.metricRe = /(\d+)(mm|cm|m|km)?/g;  // "1m and 10cm"
MetricLengthField.scale = { m:1, cm:0.01, mm:0.001, km:1000 };
MetricLengthField.scaleArray = ['km','m','cm','mm'];

function MetricLengthField (value) {
    // convert mm cm m km
    if (typeof(value)==='number') {
        this.meters = value;
    } else {
        value = value.toString();
        this.meters=0;
        var m=[], scale=MetricLengthField.scale;
        MetricLengthField.metricRe.lastIndex = 0;
        while (m=MetricLengthField.metricRe.exec(value)) {
            var unit = m[2] ? scale[m[2]] : 1;
            this.meters += parseInt(m[1]) * unit;
        }
    }
}
MetricLengthField.prototype.add = function () {

};
// .pojo() invokes (entry.toJSON&&entry.toJSON()) || entry.toString()
MetricLengthField.prototype.toString = function () {
    var m = this.meters, ret='', scar = MetricLengthField.scaleArray;
    for(var i=0; i<scar.length; i++) {
        var unit = scar[i],
            scale= MetricLengthField.scale[unit];
        var wholeUnits = Math.floor(m/scale);
        if (wholeUnits>=1) {
            ret += wholeUnits + unit;
        }
        m -= wholeUnits*scale;
    }
    return ret;
};
MetricLengthField.prototype.toPojo = MetricLengthField.prototype.toString;

// Duck is our core testing class :)
var Duck = Model.extend('Duck',{
    defaults: {
        age: 0,
        height: {type:MetricLengthField,value:'3cm'},
        mood: 'neutral'
    },
    // Simply a regular convenience method
    canDrink: function () {
        return this.age >= 18; // Russia
    },
    validate: function (spec,val) {
        return ''; // :|
        //return spec.op()!=='set' || !('height' in val);
        //throw new Error("can't set height, may only grow");
    }
    /*$$grow: function (spec,by,src) {
        this.height = this.height.add(by);
    }*/
});

var Nest = SyncSet.extend('Nest',{
    entryType: Duck
});

var storage2 = new Storage(false);
var host2 = env.localhost= new Host('gritzko',0,storage2);
host2.availableUplinks = function () {return [storage2]; };

asyncTest('2.a basic listener func', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    expect(5);
    // construct an object with an id provided; it will try to fetch
    // previously saved state for the id (which is none)
    var huey = host2.get('/Duck#hueyA');
    //ok(!huey._version); //storage is a?sync
    // listen to a field
    huey.on('age',function lsfn2a (spec,val){  // FIXME: filtered .set listener!!!
        equal(val.age,1);
        equal(spec.op(),'set');
        equal(spec.toString(),'/Duck#hueyA!'+spec.version()+'.set');
        var version = spec.token('!');
        equal(version.ext,'gritzko');
        huey.off('age',lsfn2a);
        equal(huey._lstn.length,2); // only the uplink remains (and the comma)
        start();
    });
    huey.on('.init', function init2a () {
        huey.set({age:1});
    });
});

test('2.b create-by-id', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    // there is 1:1 spec-to-object correspondence;
    // an attempt of creating a second copy of a model object
    // will throw an exception
    var dewey1 = new Duck('dewey');
    // that's we resort to descendant() doing find-or-create
    var dewey2 = host2.get('/Duck#dewey');
    // must be the same object
    strictEqual(dewey1,dewey2);
    equal(dewey1.spec().type(),'Duck');
});

test('2.c version ids', function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var louie = new Duck('louie');
    var ts1 = host2.time();
    louie.set({age:3});
    var ts2 = host2.time();
    ok(ts2>ts1);
    var vid = louie._version.substr(1);
    ok(ts1<vid);
    ok(ts2>vid);
    console.log(ts1,vid,ts2);
});

test('2.d pojos',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var dewey = new Duck({age:0});
    var json = dewey.pojo();
    var duckJSON = {
        mood: "neutral",
        age: 0,
        height: '3cm'
    };
    deepEqual(json,duckJSON);
});

asyncTest('2.e reactions',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var huey = host2.get('/Duck#huey');
    expect(2);
    var handle = Duck.addReaction('age', function reactionFn(spec,val) {
        console.log('yupee im growing');
        equal(val.age,1);
        start();
    });
    //var version = host2.time(), sp = '!'+version+'.set';
    huey.deliver(huey.newEventSpec('set'), {age:1});
    Duck.removeReaction(handle);
    equal(Duck.prototype._reactions['set'].length,0); // no house cleaning :)
});

// TODO $$event listener/reaction (Model.on: 'key' > .set && key check)

test('2.f once',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var huey = host2.get('/Duck#huey');
    expect(1);
    huey.once('age',function onceAgeCb(spec,value){
        equal(value.age,4);
    });
    huey.set({age:4});
    huey.set({age:5});
});

test('2.g custom field type',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var huey = host2.get('/Duck#huey');
    huey.set({height:'32cm'});
    ok(Math.abs(huey.height.meters-0.32)<0.0001);
    var vid = host2.time();
    host2.deliver(new Spec('/Duck#huey!'+vid+'.set'),{height:'35cm'});
    ok(Math.abs(huey.height.meters-0.35)<0.0001);
});

test('2.h state init',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var factoryBorn = new Duck({age:0,height:'4cm'});
    ok(Math.abs(factoryBorn.height.meters-0.04)<0.0001);
    equal(factoryBorn.age,0);
});

test('2.i batched set',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var nameless = new Duck();
    nameless.set({
        age:1,
        height: '60cm'
    });
    ok(Math.abs(nameless.height.meters-0.6)<0.0001);
    equal(nameless.age,1);
    ok(!nameless.canDrink());

});

// FIXME:  spec - to - (order)
test('2.j basic Set functions (string index)',function (test) {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var hueyClone = new Duck({age:2});
    var deweyClone = new Duck({age:1});
    var louieClone = new Duck({age:3});
    var clones = new Nest();
    clones.addObject(louieClone);
    clones.addObject(hueyClone);
    clones.addObject(deweyClone);
    var sibs = clones.list(function(a,b){return a.age - b.age;});
    strictEqual(sibs[0],deweyClone);
    strictEqual(sibs[1],hueyClone);
    strictEqual(sibs[2],louieClone);
    var change = {};
    change[hueyClone.spec()] = 0;
    clones.change(change);
    var sibs2 = clones.list(function(a,b){return a.age - b.age;});
    equal(sibs2.length,2);
    strictEqual(sibs2[0],deweyClone);
    strictEqual(sibs2[1],louieClone);
});

test('2.k distilled log', function (test) {
    function logSize(obj) {
        var log = obj._oplog, cnt=0;
        for(var key in log) { // jshint ignore:line
            cnt++;
        }
        return cnt;
    }
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var duckling1 = host2.get(Duck);
    duckling1.set({age:1});
    duckling1.set({age:2});
    duckling1.distillLog();
    equal(logSize(duckling1),1);
    duckling1.set({height:'30cm',age:3});
    duckling1.set({height:'40cm',age:4});
    duckling1.distillLog();
    equal(logSize(duckling1),1);
    duckling1.set({age:5});
    duckling1.distillLog();
    equal(logSize(duckling1),2);
});

test('2.l partial order', function (test) {
    env.localhost= host2;
    var duckling = new Duck();
    duckling.deliver(new Spec(duckling.spec()+'!time+user2.set'),{height:'2cm'});
    duckling.deliver(new Spec(duckling.spec()+'!time+user1.set'),{height:'1cm'});
    equal(duckling.height.toString(), '2cm');
});

asyncTest('2.m init push', function (test) {
    env.localhost= host2;
    var scrooge = new Duck({age:105});
    scrooge.on('.init', function check() {
        var tail = storage2.tails[scrooge.spec()];
        // FIXME equal(scrooge._version.substr(1), scrooge._id);
        var op = tail && tail[scrooge._version+'.set'];
        ok(tail) && ok(op) && equal(op.age,105);
        start();
    });
});

test('2.n local listeners for on/off', function () {
    console.warn(QUnit.config.current.testName);
    expect(5);
    env.localhost= host2;
    var duck = new Duck();
    duck.on('.on', function (spec, val) {
        console.log('triggered by itself, on(init) and host2.on below');
        equal(spec.op(), 'on');
    });
    duck.on('.init',function gotit(){
        console.log('inevitable');
        ok(duck._version);
    });
    duck.on('.reon', function (spec, val) {
        console.log("must NOT get triggered if the storage is sync");
        equal(spec.op(), 'reon');
    });
    host2.on('/Host#gritzko.on', function (spec, val) {
        console.log('this listener is triggered by itself');
        equal(spec.op(), 'on');
    });
});

test('2.o event relay', function () {
    console.warn(QUnit.config.current.testName);
    env.localhost= host2;
    var hueyClone = new Duck({age:2});
    var deweyClone = new Duck({age:1});
    var louieClone = new Duck({age:3});
    var clones = new Nest();
    clones.addObject(louieClone);
    clones.addObject(hueyClone);
    clones.onObjectEvent(function(spec,val){
        ok('age' in val);
    });
    expect(3);
    hueyClone.set({age:3});
    louieClone.set({age:4});
    clones.addObject(deweyClone);
    deweyClone.set({age:2});
});

/*  TODO
 * test('2.m on/off sub', function (test) {
    env.localhost= host2
    var duckling = new Duck();

    expect(2);
    duckling.on('on',function(spec){
        ok(spec.op(),'on');
    });
    duckling.on('set',function(spec){
        equal(spec.op(),'set');
    });
    duckling.set({age:1});

});*/
<|endoftext|>


<commit_before>const DescriptorStorage = require('./DescriptorStorage');
const Generator = require('@jymfony/compiler/src/SourceMap/Generator');
const ManagedProxy = require('./Proxy/ManagedProxy');
const StackHandler = require('@jymfony/compiler/src/SourceMap/StackHandler');
const CircularDependencyException = require('./Exception/CircularDependencyException');

let Compiler;
let Parser;
let AST;

const isNyc = !! global.__coverage__;
const { normalize } = require('path');

const Storage = function () {};
Storage.prototype = {};

let codeCache = new Storage();
let _cache = new Storage();

const { resolve } = require;

/**
 * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
 * because the buffer-to-string conversion in `fs.readFileSync()`
 * translates it to FEFF, the UTF-16 BOM.
 */
const stripBOM = (content) => 0xFEFF === content.charCodeAt(0) ? content.slice(1) : content;

// From node source:/lib/internal/modules/cjs/helpers.js
const builtinLibs = [
    'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'crypto',
    'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'http2', 'https', 'net',
    'os', 'path', 'perf_hooks', 'punycode', 'querystring', 'readline', 'repl',
    'stream', 'string_decoder', 'tls', 'trace_events', 'tty', 'url', 'util',
    'v8', 'vm', 'worker_threads', 'zlib',
];

/**
 * Patching-replacement for "require" function in Autoloader component.
 *
 * @internal
 * @memberOf Jymfony.Component.Autoloader
 */
class ClassLoader {
    /**
     * Constructor
     *
     * @param {Jymfony.Component.Autoloader.Finder} finder
     * @param {path} path
     * @param {vm} vm
     */
    constructor(finder, path, vm) {
        /**
         * @type {Jymfony.Component.Autoloader.Finder}
         *
         * @private
         */
        this._finder = finder;

        /**
         * @type {path}
         *
         * @private
         */
        this._path = path;

        /**
         * @type {vm}
         *
         * @private
         */
        this._vm = vm;

        /**
         * @type {Jymfony.Component.Autoloader.DescriptorStorage}
         *
         * @private
         */
        this._descriptorStorage = new DescriptorStorage(this);

        /**
         * @type {string[]}
         *
         * @private
         */
        this._compilerIgnorelist = (process.env.JYMFONY_COMPILER_IGNORE || '')
            .split(',')
            .map(__jymfony.trim)
            .map(v => v.startsWith('.') ? path.resolve(process.cwd(), v) : v)
        ;

        if (undefined === Compiler) {
            ClassLoader.compiler = require('@jymfony/compiler');
        }
    }

    /**
     * Sets the compiler class components.
     */
    static set compiler({ Compiler: compilerClass, Parser: parserClass, AST: astBase }) {
        Compiler = compilerClass;
        Parser = parserClass;
        AST = astBase;
    }

    /**
     * Clears the code/compiler cache.
     */
    static clearCache(prefix = null) {
        if (null === prefix) {
            codeCache = new Storage();
            _cache = new Storage();
        } else {
            prefix = new RegExp('^' + __jymfony.regex_quote(normalize(prefix)));
            for (const fn of Object.keys(_cache)) {
                if (! fn.match(prefix)) {
                    continue;
                }

                delete _cache[fn];
                delete codeCache[fn];
            }
        }
    }

    /**
     * Loads a class.
     *
     * @param {string} fn
     * @param {*} self
     *
     * @returns {*}
     */
    loadClass(fn, self) {
        const exports = this.loadFile(fn, self);

        return exports.__esModule ? exports.default : exports;
    }

    /**
     * Loads a file and returns the file exports.
     *
     * @param {string} fn
     * @param {*} self
     * @param {*} exports
     *
     * @returns {*}
     */
    loadFile(fn, self, exports = {}) {
        fn = this._path.resolve(fn);
        if (_cache[fn]) {
            return _cache[fn];
        }

        return _cache[fn] = this._doLoadFile(fn, self, exports);
    }

    /**
     * Gets a file code.
     *
     * @param {string} fn
     *
     * @returns {{code: string, program: Program}}
     */
    getCode(fn) {
        if (codeCache[fn]) {
            const cached = codeCache[fn];
            Object.assign(this._descriptorStorage._storage, cached.decorators);

            return cached;
        }

        let code = stripBOM(this._finder.load(fn)), program = null;
        const sourceMapGenerator = new Generator({ file: fn });
        const descriptorStorage = this._descriptorStorage;
        const decorators = {};

        try {
            this._descriptorStorage = this._descriptorStorage.setFile(fn);
            const parser = new Parser(this._descriptorStorage);
            const compiler = new Compiler(sourceMapGenerator);

            program = parser.parse(code);
            program.prepare();

            const p = new AST.Program(program.location);
            p.add(new AST.ParenthesizedExpression(null,
                new AST.FunctionExpression(null, new AST.BlockStatement(null, [
                    new AST.StringLiteral(null, '\'use strict\''),
                    ...program.body,
                ]), null, [
                    new AST.Identifier(null, 'exports'),
                    new AST.Identifier(null, 'require'),
                    new AST.Identifier(null, 'module'),
                    new AST.Identifier(null, '__filename'),
                    new AST.Identifier(null, '__dirname'),
                    new AST.Identifier(null, '__self'),
                ])
            ));

            code = compiler.compile(p);
            StackHandler.registerSourceMap(fn, sourceMapGenerator.toJSON().mappings);
        } catch (err) {
            // Compiler have failed. Code is unpatched, but can be included.

            if (! (err instanceof SyntaxError)) {
                throw err;
            } else {
                console.warn('Syntax error while parsing ' + fn + ': ' + err.message);
            }
        } finally {
            Object.assign(decorators, this._descriptorStorage._storage);
            this._descriptorStorage = descriptorStorage;
        }

        return codeCache[fn] = {
            code,
            program,
            decorators,
        };
    }

    /**
     * Internal file loader.
     *
     * @param {string} fn
     * @param {*} self
     * @param {*} exports
     *
     * @returns {*}
     *
     * @private
     */
    _doLoadFile(fn, self, exports) {
        const module = this._getModuleObject(fn, exports);
        const dirname = module.paths[0];
        const opts = isNyc ? fn : {
            filename: fn,
            produceCachedData: false,
        };

        const req = id => {
            if (builtinLibs.includes(id) || this._compilerIgnorelist.includes(id)) {
                return require(id);
            }

            if (id.startsWith('.')) {
                id = this._path.resolve(dirname, id);
            }

            id = resolve(id, { paths: [ dirname ] });
            if (! id.endsWith('.js')) {
                return require(id);
            }

            return this.loadFile(id, null);
        };

        req.nocompile = id => require(id);

        _cache[fn] = new __jymfony.ManagedProxy(function () { }, () => {
            throw new CircularDependencyException(fn);
        });

        req.proxy = id => {
            if (builtinLibs.includes(id)) {
                return require(id);
            }

            id = resolve(id, { paths: [ dirname ] });
            if (_cache[id]) {
                return _cache[id];
            }

            const code = this.getCode(id);
            const exports = function () {};

            return _cache[id] = new ManagedProxy(exports, proxy => {
                proxy.initializer = null;
                proxy.target = exports;

                const module = this._getModuleObject(id, exports);
                const dirname = module.paths[0];

                this._vm.runInThisContext(code.code, opts)(module.exports, req, module, id, dirname, null);
                _cache[id] = proxy.target = module.exports;

                return null;
            });
        };

        req.optional = (id, asObject = false) => {
            try {
                return req(id);
            } catch (e) {
                return asObject ? {} : undefined;
            }
        };

        req.resolve = (id, options = {}) => {
            return resolve(id, { paths: [ dirname ], ...options });
        };

        let _pending;
        try {
            this._vm.runInThisContext(this.getCode(fn).code, opts)(module.exports, req, module, fn, dirname, self);
        } catch (e) {
            if (e instanceof CircularDependencyException) {
                if (e.requiring === undefined) {
                    e.requiring = fn;
                }

                if (e.required === fn) {
                    delete _cache[e.requiring];
                    _pending = _cache[e.requiring] = req.proxy(e.requiring);
                    this._vm.runInThisContext(this.getCode(fn).code, opts)(module.exports, req, module, fn, dirname, self);

                    require.cache[fn] = module;
                    return _cache[fn] = module.exports;
                }
            }

            throw e;
        } finally {
            if (_pending) {
                Object.isExtensible(_pending); // Use isExtensible to initialize object
            }
        }

        require.cache[fn] = module;

        return _cache[fn] = module.exports;
    }

    _getModuleObject(fn, exports) {
        return {
            children: [],
            exports,
            filename: fn,
            id: fn,
            loaded: false,
            parent: module,
            paths: [ this._path.dirname(fn) ],
            require: require,
        };
    }
}

module.exports = ClassLoader;
<commit_msg>[Autoloader] restore workaround for require.resolve bug on node < 12<commit_after>const DescriptorStorage = require('./DescriptorStorage');
const Generator = require('@jymfony/compiler/src/SourceMap/Generator');
const ManagedProxy = require('./Proxy/ManagedProxy');
const StackHandler = require('@jymfony/compiler/src/SourceMap/StackHandler');
const CircularDependencyException = require('./Exception/CircularDependencyException');

let Compiler;
let Parser;
let AST;

const isNyc = !! global.__coverage__;
const { normalize } = require('path');

const Storage = function () {};
Storage.prototype = {};

let codeCache = new Storage();
let _cache = new Storage();

let { resolve } = require;
if (__jymfony.version_compare(process.versions.v8, '12.0.0', '<')) {
    resolve = (id, { paths }) => {
        if (id.startsWith('.')) {
            return require.resolve(id, { paths });
        }

        return require.resolve(id, { paths: [ paths[0] + '/node_modules' ] });
    };
}

/**
 * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
 * because the buffer-to-string conversion in `fs.readFileSync()`
 * translates it to FEFF, the UTF-16 BOM.
 */
const stripBOM = (content) => 0xFEFF === content.charCodeAt(0) ? content.slice(1) : content;

// From node source:/lib/internal/modules/cjs/helpers.js
const builtinLibs = [
    'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'crypto',
    'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'http2', 'https', 'net',
    'os', 'path', 'perf_hooks', 'punycode', 'querystring', 'readline', 'repl',
    'stream', 'string_decoder', 'tls', 'trace_events', 'tty', 'url', 'util',
    'v8', 'vm', 'worker_threads', 'zlib',
];

/**
 * Patching-replacement for "require" function in Autoloader component.
 *
 * @internal
 * @memberOf Jymfony.Component.Autoloader
 */
class ClassLoader {
    /**
     * Constructor
     *
     * @param {Jymfony.Component.Autoloader.Finder} finder
     * @param {path} path
     * @param {vm} vm
     */
    constructor(finder, path, vm) {
        /**
         * @type {Jymfony.Component.Autoloader.Finder}
         *
         * @private
         */
        this._finder = finder;

        /**
         * @type {path}
         *
         * @private
         */
        this._path = path;

        /**
         * @type {vm}
         *
         * @private
         */
        this._vm = vm;

        /**
         * @type {Jymfony.Component.Autoloader.DescriptorStorage}
         *
         * @private
         */
        this._descriptorStorage = new DescriptorStorage(this);

        /**
         * @type {string[]}
         *
         * @private
         */
        this._compilerIgnorelist = (process.env.JYMFONY_COMPILER_IGNORE || '')
            .split(',')
            .map(__jymfony.trim)
            .map(v => v.startsWith('.') ? path.resolve(process.cwd(), v) : v)
        ;

        if (undefined === Compiler) {
            ClassLoader.compiler = require('@jymfony/compiler');
        }
    }

    /**
     * Sets the compiler class components.
     */
    static set compiler({ Compiler: compilerClass, Parser: parserClass, AST: astBase }) {
        Compiler = compilerClass;
        Parser = parserClass;
        AST = astBase;
    }

    /**
     * Clears the code/compiler cache.
     */
    static clearCache(prefix = null) {
        if (null === prefix) {
            codeCache = new Storage();
            _cache = new Storage();
        } else {
            prefix = new RegExp('^' + __jymfony.regex_quote(normalize(prefix)));
            for (const fn of Object.keys(_cache)) {
                if (! fn.match(prefix)) {
                    continue;
                }

                delete _cache[fn];
                delete codeCache[fn];
            }
        }
    }

    /**
     * Loads a class.
     *
     * @param {string} fn
     * @param {*} self
     *
     * @returns {*}
     */
    loadClass(fn, self) {
        const exports = this.loadFile(fn, self);

        return exports.__esModule ? exports.default : exports;
    }

    /**
     * Loads a file and returns the file exports.
     *
     * @param {string} fn
     * @param {*} self
     * @param {*} exports
     *
     * @returns {*}
     */
    loadFile(fn, self, exports = {}) {
        fn = this._path.resolve(fn);
        if (_cache[fn]) {
            return _cache[fn];
        }

        return _cache[fn] = this._doLoadFile(fn, self, exports);
    }

    /**
     * Gets a file code.
     *
     * @param {string} fn
     *
     * @returns {{code: string, program: Program}}
     */
    getCode(fn) {
        if (codeCache[fn]) {
            const cached = codeCache[fn];
            Object.assign(this._descriptorStorage._storage, cached.decorators);

            return cached;
        }

        let code = stripBOM(this._finder.load(fn)), program = null;
        const sourceMapGenerator = new Generator({ file: fn });
        const descriptorStorage = this._descriptorStorage;
        const decorators = {};

        try {
            this._descriptorStorage = this._descriptorStorage.setFile(fn);
            const parser = new Parser(this._descriptorStorage);
            const compiler = new Compiler(sourceMapGenerator);

            program = parser.parse(code);
            program.prepare();

            const p = new AST.Program(program.location);
            p.add(new AST.ParenthesizedExpression(null,
                new AST.FunctionExpression(null, new AST.BlockStatement(null, [
                    new AST.StringLiteral(null, '\'use strict\''),
                    ...program.body,
                ]), null, [
                    new AST.Identifier(null, 'exports'),
                    new AST.Identifier(null, 'require'),
                    new AST.Identifier(null, 'module'),
                    new AST.Identifier(null, '__filename'),
                    new AST.Identifier(null, '__dirname'),
                    new AST.Identifier(null, '__self'),
                ])
            ));

            code = compiler.compile(p);
            StackHandler.registerSourceMap(fn, sourceMapGenerator.toJSON().mappings);
        } catch (err) {
            // Compiler have failed. Code is unpatched, but can be included.

            if (! (err instanceof SyntaxError)) {
                throw err;
            } else {
                console.warn('Syntax error while parsing ' + fn + ': ' + err.message);
            }
        } finally {
            Object.assign(decorators, this._descriptorStorage._storage);
            this._descriptorStorage = descriptorStorage;
        }

        return codeCache[fn] = {
            code,
            program,
            decorators,
        };
    }

    /**
     * Internal file loader.
     *
     * @param {string} fn
     * @param {*} self
     * @param {*} exports
     *
     * @returns {*}
     *
     * @private
     */
    _doLoadFile(fn, self, exports) {
        const module = this._getModuleObject(fn, exports);
        const dirname = module.paths[0];
        const opts = isNyc ? fn : {
            filename: fn,
            produceCachedData: false,
        };

        const req = id => {
            if (builtinLibs.includes(id) || this._compilerIgnorelist.includes(id)) {
                return require(id);
            }

            if (id.startsWith('.')) {
                id = this._path.resolve(dirname, id);
            }

            id = resolve(id, { paths: [ dirname ] });
            if (! id.endsWith('.js')) {
                return require(id);
            }

            return this.loadFile(id, null);
        };

        req.nocompile = id => require(id);

        _cache[fn] = new __jymfony.ManagedProxy(function () { }, () => {
            throw new CircularDependencyException(fn);
        });

        req.proxy = id => {
            if (builtinLibs.includes(id)) {
                return require(id);
            }

            id = resolve(id, { paths: [ dirname ] });
            if (_cache[id]) {
                return _cache[id];
            }

            const code = this.getCode(id);
            const exports = function () {};

            return _cache[id] = new ManagedProxy(exports, proxy => {
                proxy.initializer = null;
                proxy.target = exports;

                const module = this._getModuleObject(id, exports);
                const dirname = module.paths[0];

                this._vm.runInThisContext(code.code, opts)(module.exports, req, module, id, dirname, null);
                _cache[id] = proxy.target = module.exports;

                return null;
            });
        };

        req.optional = (id, asObject = false) => {
            try {
                return req(id);
            } catch (e) {
                return asObject ? {} : undefined;
            }
        };

        req.resolve = (id, options = {}) => {
            return resolve(id, { paths: [ dirname ], ...options });
        };

        let _pending;
        try {
            this._vm.runInThisContext(this.getCode(fn).code, opts)(module.exports, req, module, fn, dirname, self);
        } catch (e) {
            if (e instanceof CircularDependencyException) {
                if (e.requiring === undefined) {
                    e.requiring = fn;
                }

                if (e.required === fn) {
                    delete _cache[e.requiring];
                    _pending = _cache[e.requiring] = req.proxy(e.requiring);
                    this._vm.runInThisContext(this.getCode(fn).code, opts)(module.exports, req, module, fn, dirname, self);

                    require.cache[fn] = module;
                    return _cache[fn] = module.exports;
                }
            }

            throw e;
        } finally {
            if (_pending) {
                Object.isExtensible(_pending); // Use isExtensible to initialize object
            }
        }

        require.cache[fn] = module;

        return _cache[fn] = module.exports;
    }

    _getModuleObject(fn, exports) {
        return {
            children: [],
            exports,
            filename: fn,
            id: fn,
            loaded: false,
            parent: module,
            paths: [ this._path.dirname(fn) ],
            require: require,
        };
    }
}

module.exports = ClassLoader;
<|endoftext|>


<commit_before>// Dependencies
// =============================================================================
const fs          = require('fs');
const getRepoInfo = require('git-repo-info');
const pkg         = JSON.parse(fs.readFileSync('./package.json', 'utf8'));

// Variables
// =============================================================================
const files = {
    fixtures: './tests/fixtures/**/*',
    test    : './tests/**/*.test.js'
};
const gitInfo = getRepoInfo();

// Settings
// =============================================================================
const settings = {
    files: [
        files.test,
        // Served only (Access in tests by prepending /base/ to path)
        { pattern: files.fixtures, included: false, served: true, watched: true }
    ],
    preprocessors: {
        [files.fixtures]: ['file-fixtures'],
        [files.test]    : ['eslint', 'webpack', 'sourcemap']
    },
    frameworks: ['mocha', 'chai'],
    reporters : ['mocha', 'coverage-istanbul'],
    fileFixtures: {
        stripPrefix: 'tests/fixtures/'
    },
    webpack: {
        mode  : 'development',
        module: {
            rules: [
                {
                    test   : /\.js$/,
                    exclude: [/node_modules/],
                    use    : [
                        {
                            loader : 'babel-loader',
                            options: {
                                // See .babelrc
                                plugins: [
                                    ['istanbul', { include: 'src/*' }]
                                ]
                            },
                        }
                    ]
                }
            ]
        }
    },
    webpackMiddleware: {
        // https://webpack.js.org/configuration/stats/
        stats: 'minimal'
    },
    // Code coverage
    // https://github.com/mattlewis92/karma-coverage-istanbul-reporter
    coverageIstanbulReporter: {
        reports                : ['lcovonly', 'text-summary'],
        combineBrowserReports  : true,
        fixWebpackSourcePaths  : true,
        skipFilesWithNoCoverage: true
    },
    mochaReporter: {
        // https://www.npmjs.com/package/karma-mocha-reporter
        output: 'autowatch'
    },
    autoWatch  : false,
    colors     : true,
    concurrency: Infinity,
    port       : 9876,
    singleRun  : true,
    // browserDisconnectTimeout  : 1000*10, // default 2000
    // browserDisconnectTolerance: 1,       // default 0
    // browserNoActivityTimeout  : 1000*30, // default 10000
    // captureTimeout            : 1000*60, // default 60000
    client: {
        // Prevent browser messages from appearing in terminal
        captureConsole: false,
        mocha: {
            timeout: 1000*5 // default 2000
        }
    }
};

// Export
// =============================================================================
module.exports = function(config) {
    const isDebug  = Boolean(process.argv.indexOf('--debug') > -1);
    const isRemote = Boolean(process.argv.indexOf('--remote') > -1);

    // Remote test
    if (isRemote) {
        // Browsers
        // https://www.browserstack.com/automate/capabilities
        settings.customLaunchers = {
            bs_chrome_latest: {
                base           : 'BrowserStack',
                browser        : 'Chrome',
                os             : 'Windows',
                os_version     : '10'
            },
            bs_chrome: {
                base           : 'BrowserStack',
                browser        : 'Chrome',
                browser_version: '48.0',
                os             : 'Windows',
                os_version     : '10'
            },
            bs_ie_11: {
                base           : 'BrowserStack',
                browser        : 'IE',
                browser_version: '11.0',
                os             : 'Windows',
                os_version     : '10'
            }
        };
        settings.browsers = Object.keys(settings.customLaunchers);
        settings.reporters.push('BrowserStack');
        settings.browserStack = {
            username : process.env.BROWSERSTACK_USERNAME,
            accessKey: process.env.BROWSERSTACK_ACCESS_KEY,
            build    : `${process.env.TRAVIS_BRANCH || gitInfo.branch}: ${process.env.TRAVIS_COMMIT_MESSAGE || gitInfo.commitMessage}`,
            name     : (process.env.TRAVIS_BUILD_NUMBER ? `Travis ${process.env.TRAVIS_BUILD_NUMBER}` : 'Local') + ` @ ${new Date().toLocaleString('en-US', { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', hour: 'numeric', minute: 'numeric', timeZoneName: 'short', hour12: true })}`,
            project  : pkg.name,
            video    : false
        };
    }
    // Local
    else {
        settings.customLaunchers = {
            ChromeHeadlessDebug: {
                base : 'ChromeHeadless',
                flags: [
                    '--disable-extensions',
                    '--remote-debugging-port=9333'
                ]
            },
        };
        settings.browsers = [].concat(
            Object.keys(settings.customLaunchers)
            // 'jsdom' // SSR Testing
        );
        settings.webpack.devtool = 'inline-source-map';
        settings.coverageIstanbulReporter.reports.push('html');

        if (isDebug) {
            // Prevent disconnect during VSCode debugging
            settings.browserDisconnectTimeout = 1000*6000; // default 2000
        }

        // eslint-disable-next-line
        console.log([
            '============================================================\n',
            `KARMA: localhost:${settings.port}/debug.html\n`,
            '============================================================\n'
        ].join(''));
    }

    // Logging: LOG_DISABLE, LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG
    settings.logLevel = config.LOG_INFO;
    config.set(settings);
};
<commit_msg>Remove Travis & update Browserstack config<commit_after>// Dependencies
// =============================================================================
const fs          = require('fs');
const getRepoInfo = require('git-repo-info');
const pkg         = JSON.parse(fs.readFileSync('./package.json', 'utf8'));

// Variables
// =============================================================================
const files = {
    fixtures: './tests/fixtures/**/*',
    test    : './tests/**/*.test.js'
};
const gitInfo = getRepoInfo();

// Settings
// =============================================================================
const settings = {
    files: [
        files.test,
        // Served only (Access in tests by prepending /base/ to path)
        { pattern: files.fixtures, included: false, served: true, watched: true }
    ],
    preprocessors: {
        [files.fixtures]: ['file-fixtures'],
        [files.test]    : ['eslint', 'webpack', 'sourcemap']
    },
    frameworks: ['mocha', 'chai'],
    reporters : ['mocha', 'coverage-istanbul', 'BrowserStack'],
    fileFixtures: {
        stripPrefix: 'tests/fixtures/'
    },
    webpack: {
        mode  : 'development',
        module: {
            rules: [
                {
                    test   : /\.js$/,
                    exclude: [/node_modules/],
                    use    : [
                        {
                            loader : 'babel-loader',
                            options: {
                                // See .babelrc
                                plugins: [
                                    ['istanbul', { include: 'src/*' }]
                                ]
                            },
                        }
                    ]
                }
            ]
        }
    },
    webpackMiddleware: {
        // https://webpack.js.org/configuration/stats/
        stats: 'minimal'
    },
    // Code coverage
    // https://github.com/mattlewis92/karma-coverage-istanbul-reporter
    coverageIstanbulReporter: {
        reports                : ['lcovonly', 'text-summary'],
        combineBrowserReports  : true,
        fixWebpackSourcePaths  : true,
        skipFilesWithNoCoverage: true
    },
    mochaReporter: {
        // https://www.npmjs.com/package/karma-mocha-reporter
        output: 'autowatch'
    },
    autoWatch  : false,
    colors     : true,
    concurrency: Infinity,
    port       : 9876,
    singleRun  : true,
    // browserDisconnectTimeout  : 1000*10, // default 2000
    // browserDisconnectTolerance: 1,       // default 0
    // browserNoActivityTimeout  : 1000*30, // default 10000
    // captureTimeout            : 1000*60, // default 60000
    client: {
        // Prevent browser messages from appearing in terminal
        captureConsole: false,
        mocha: {
            timeout: 1000*5 // default 2000
        }
    }
};

// Export
// =============================================================================
module.exports = function(config) {
    const isDebug  = Boolean(process.argv.indexOf('--debug') > -1);
    const isRemote = Boolean(process.argv.indexOf('--remote') > -1);

    // Remote test
    if (isRemote) {
        // Browsers
        // https://www.browserstack.com/automate/capabilities
        settings.customLaunchers = {
            bs_chrome_latest: {
                base           : 'BrowserStack',
                browser        : 'Chrome',
                os             : 'Windows',
                os_version     : '10'
            },
            bs_chrome: {
                base           : 'BrowserStack',
                browser        : 'Chrome',
                browser_version: '48.0',
                os             : 'Windows',
                os_version     : '10'
            },
            bs_ie_11: {
                base           : 'BrowserStack',
                browser        : 'IE',
                browser_version: '11.0',
                os             : 'Windows',
                os_version     : '10'
            }
        };
        settings.browsers = Object.keys(settings.customLaunchers);
        settings.reporters.push('BrowserStack');
        settings.browserStack = {
            username : process.env.BROWSERSTACK_USERNAME,
            accessKey: process.env.BROWSERSTACK_ACCESS_KEY,
            build    : [
                `${gitInfo.branch}:` ,
                gitInfo.commitMessage,
                '@',
                new Date().toLocaleString('en-US', { month: 'numeric', day: 'numeric', year: 'numeric', hour: 'numeric', minute: 'numeric', timeZoneName: 'short', hour12: true }),
                '-',
                process.env.GITHUB_RUN_ID ? 'GitHub' : 'Local'
            ].join(' '),
            project  : pkg.name,
            video    : false
        };
    }
    // Local
    else {
        settings.customLaunchers = {
            ChromeHeadlessDebug: {
                base : 'ChromeHeadless',
                flags: [
                    '--disable-extensions',
                    '--remote-debugging-port=9333'
                ]
            },
        };
        settings.browsers = [].concat(
            Object.keys(settings.customLaunchers)
            // 'jsdom' // SSR Testing
        );
        settings.webpack.devtool = 'inline-source-map';
        settings.coverageIstanbulReporter.reports.push('html');

        if (isDebug) {
            // Prevent disconnect during VSCode debugging
            settings.browserDisconnectTimeout = 1000*6000; // default 2000
        }

        // eslint-disable-next-line
        console.log([
            '============================================================\n',
            `KARMA: localhost:${settings.port}/debug.html\n`,
            '============================================================\n'
        ].join(''));
    }

    // Logging: LOG_DISABLE, LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG
    settings.logLevel = config.LOG_INFO;
    config.set(settings);
};
<|endoftext|>