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

  var app = angular.module('app');
  app.controller('appCtrl', function($scope, $http, localStorageService, $interval) {

    $scope.Math = window.Math;

    $scope.activeTournament = '';
    $scope.matches = '';
    $scope.match_ids = {};
    $scope.currentMatch = {};

    $scope.participants = {};
    $scope.stations = {};

    $scope.is_loading = false;
    $scope.ready = false;

    $scope.is_organizer = false;

    $scope.tournamentFilters = [{
      "name": "In Progress",
      "value": "in_progress"
    }, {
      "name": "Completed",
      "value": "ended"
    }, {
      "name": "Pending",
      "value": "ended"
    }, {
      "name": "All",
      "value": "all"
    }];

    $scope.credentials = {
      'organizer': {
        'tournament_filter': $scope.tournamentFilters[0]
      },
      'participant': {

      },
      'api_key': '',
      'subdomain': '',
      'hide_completed': localStorageService.get('hide_completed'),
      'hide_stations': localStorageService.get('hide_stations'),

    };

    $scope.getCredentials = function(clicked, type) {

      if(type == 'organizer') {
        $scope.credentials.organizer.api_key = localStorageService.get('api_key');
        $scope.credentials.organizer.subdomain = localStorageService.get('subdomain');
        if (!$scope.credentials.organizer.api_key) {
          $scope.ready = false;
        }
        else {
          $scope.ready = true;
          $scope.confirmed = clicked;
        }
      }
      else if (type == 'participant') {

        $scope.credentials.full_challonge_url = localStorageService.get('full_challonge_url');
        $scope.ready = true;
        $scope.confirmed = clicked;

        if( $scope.confirmed) {
          $scope.activateTournament();
        }
      }
    };

    $scope.setCredentials = function(type) {

      if(type == 'organizer') {
        $scope.is_organizer = true;
        localStorageService.set('api_key',   $scope.credentials.organizer.api_key);
        localStorageService.set('subdomain', $scope.credentials.organizer.subdomain);
        $scope.getCredentials(true, 'organizer');
        $scope.getActiveTournaments();
      }
      else if (type == 'participant') {
        $scope.is_organizer = false;

        localStorageService.set('full_challonge_url',  $scope.credentials.full_challonge_url);

        var n = $scope.credentials.full_challonge_url.search("://");
        if (n) {
          $scope.credentials.full_challonge_url = $scope.credentials.full_challonge_url.substring(n+3);
        }

        var split_slash = $scope.credentials.full_challonge_url.split('/');
        $scope.credentials.participant.tournament_url = split_slash[split_slash.length - 1];

        var split_dot = $scope.credentials.full_challonge_url.split('.');

        if (split_dot.length >2) {
          $scope.credentials.participant.subdomain = split_dot[0];
        }
        else {
          $scope.credentials.participant.subdomain = '';
        }

        $scope.getCredentials(true, 'participant');
      }
    };

    $scope.hideCompletedMatches = function() {
      localStorageService.set('hide_completed', $scope.credentials.hide_completed);
    };
    $scope.hideStations = function() {
      localStorageService.set('hide_stations', $scope.credentials.hide_stations);
    };

    $scope.getActiveTournaments = function(filter) {
      $scope.is_loading = true;

      var state = 'in_progress';

      if ($scope.credentials.organizer.tournament_filter && 'value' in $scope.credentials.organizer.tournament_filter) {
        state = $scope.credentials.organizer.tournament_filter.value;
      }

      $http.get("getTournaments/", {
        params: {
          "api_key" : $scope.credentials.organizer.api_key,
          "subdomain" : $scope.credentials.organizer.subdomain,
          "state" : state
        }
      })
      .then(
        function(data, status) {
          $scope.tournaments = data.data;
          $scope.is_loading = false;
        },
        function(data, status) {
          console.log(data);
      });
    };

    $scope.selectTournament = function(tournament) {
      $scope.activeTournament = tournament;
      $scope.activateTournament();
    };

    $scope.activateTournament = function() {
      if ($scope.is_organizer) {
        $scope.tournamentAttachments();
        $scope.getTournamentParticipants();
      }
      else {
        $scope.getTournamentParticipants();
        $interval(function () {
          $scope.getTournamentParticipants(false);
        }, 30000);
      }
    }

    $scope.tournamentAttachments = function() {
      $http.get("tournamentAttachments/", {
        params: {
          "api_key" : $scope.credentials.organizer.api_key,
          "subdomain" : $scope.credentials.subdomain,
          "tournament_url" : $scope.activeTournament.tournament.url
        }
      });
    };

    $scope.getTournamentParticipants = function(reload) {
      $scope.is_loading = reload;

      var api_key;
      var subdomain;
      var tournament_url;

      if( $scope.is_organizer ) {
        api_key        = $scope.credentials.organizer.api_key;
        subdomain      = $scope.credentials.organizer.subdomain;
        tournament_url = $scope.activeTournament.tournament.url;
      }
      else {
        subdomain      = $scope.credentials.participant.subdomain;
        tournament_url = $scope.credentials.participant.tournament_url;
      }
      $http.get("getTournamentParticipants/", {
        params: {
          "api_key"        : api_key,
          "subdomain"      : subdomain,
          "tournament_url" : tournament_url,
          "is_organizer"   : $scope.is_organizer
        }
      })
      .then(
        function(data, status) {
          var participants = data.data;

          for(var i = 0; i < participants.length; i++) {
            $scope.participants[participants[i].participant.id] = participants[i].participant.name;
          }

          $scope.getTournamentMatches(reload);
        },
        function(data, status) {
          console.log(data);
      });
    };

    $scope.getTournamentMatches = function(reload) {
      $scope.is_loading = reload;

      var api_key;
      var subdomain;
      var tournament_url;

      if( $scope.is_organizer ) {
        api_key        = $scope.credentials.organizer.api_key;
        subdomain      = $scope.credentials.organizer.subdomain;
        tournament_url = $scope.activeTournament.tournament.url;
      }
      else {
        subdomain      = $scope.credentials.participant.subdomain;
        tournament_url = $scope.credentials.participant.tournament_url;
      }

      $http.get("getMatches/", {
        params: {
          "api_key"        : api_key,
          "subdomain"      : subdomain,
          "tournament_url" : tournament_url,
          "is_organizer"   : $scope.is_organizer
        }
      })
      .then(
        function(data, status) {
          $scope.matches = data.data;
          $scope.match_ids = {};

          // store match ids to determine winner
          angular.forEach($scope.matches, function(value) {
            $scope.match_ids[value.match.id] = {
              'id': value.match.identifier,
              'round': value.match.round
            };

            if (value.match.attachment_count) {
             $scope.getMatchStation(value);
            }

            // sort matches
            value.match.order = $scope.matchOrder(value);
          });

          $scope.is_loading = false;

        },
        function(data, status) {
          console.log(data);

      });
    };

    $scope.editMatch = function(match) {
      // there really isn't anything you can do on a match that is pending, at least now
      if($scope.is_organizer && match.match.state != 'pending') {
        $scope.currentMatch = match;
        if($scope.currentMatch.match.scores_csv) {
          var scores = $scope.currentMatch.match.scores_csv.split('-');
          $scope.currentMatch.match.player1_score = parseInt(scores[0]) || 0;
          $scope.currentMatch.match.player2_score = parseInt(scores[1]) || 0;
        }
        $('#matchModal').modal();
      }
    };

    $scope.postMatchResults = function() {
      var p1_score = $scope.currentMatch.match.player1_score || 0;
      var p2_score = $scope.currentMatch.match.player2_score || 0;
      var score = '' + p1_score + '-' + p2_score;

      var match_station = $scope.currentMatch.match.station || '';

      $http.post("postMatchResults/", {
        data: {
          "api_key" : $scope.credentials.organizer.api_key,
          "subdomain" : $scope.credentials.organizer.subdomain,
          "tournament_url" : $scope.activeTournament.tournament.url,
          "match_id": $scope.currentMatch.match.id,
          "match_station": match_station,
          "score": score,
          'winner_id': $scope.currentMatch.match.winner_id
        }
      })
      .then(
        function(response) {
          $scope.getTournamentMatches(false);
          $('#matchModal').modal('hide');
        },
        function(response) {
          console.log(response);
      });
    };

    $scope.getMatchStation = function(match) {

      var api_key;
      var subdomain;
      var tournament_url;

      if( $scope.is_organizer ) {
        api_key        = $scope.credentials.organizer.api_key;
        subdomain      = $scope.credentials.organizer.subdomain;
        tournament_url = $scope.activeTournament.tournament.url;
      }
      else {
        subdomain      = $scope.credentials.participant.subdomain;
        tournament_url = $scope.credentials.participant.tournament_url;
      }

      $http.get("getMatchStation/", {
        params: {
          "api_key"        : api_key,
          "subdomain"      : subdomain,
          "tournament_url" : tournament_url,
          "match_id"       : match.match.id,
          "is_organizer"   : $scope.is_organizer
        }
      })
      .then(
        function(response) {
          if (!response.data.match) {
            return;
          }

          var match_data = response.data.match;

          var station = '';
          var id = '';

          for(var i = 0; i < match_data.attachment_count; ++i) {
            if(match_data.attachments[i].match_attachment.description.substring(0,8) == 'station ') {
              match.match.station = match_data.attachments[i].match_attachment.description.substring(8);
              match.match.station_id = match_data.attachments[i].match_attachment.id;
            }
          }
        },
        function(response) {
          console.log(response);
      });
    };

    $scope.updateMatchStation = function(match, station) {

      if ($scope.is_organizer) {
        var match_id = match.match.id;
        var station_id = '';
        var get_method = 'POST';

        if(match.match.station_id) {
          station_id = match.match.station_id;
          get_method = 'PUT';

          if(!station) {
            get_method = 'DELETE';
          }
        }

        $http.post("postMatchStation/", {
          data: {
            "api_key" : $scope.credentials.organizer.api_key,
            "subdomain" : $scope.credentials.organizer.subdomain,
            "tournament_url" : $scope.activeTournament.tournament.url,
            "match_id": match_id,
            "match_station": station,
            "station_id": station_id,
            "get_method": get_method
          }
        })
        .then(
          function(response) {
            $scope.getMatchStation(match);
          },
          function(response) {
            alert('Error, sorry. Working on it');
        });

      }
    };

    $scope.determineRound = function(round) {
      var place;
      if(round > 0) {
        place = 'WR ';
      }
      else {
        place = 'LR ';
      }
      round = Math.abs(round);
      return place + round;
    };

    // determine match order by state
    // 0: green  / success
    // 1: purple / info
    // 2: grey   / pending
    // 3: white  / none
    // 4: red    / error (not yet implemented)
    $scope.matchOrder = function(match) {
      if (match.match.state == 'complete') {
        return 0;

      }
      else if (match.match.state == 'open') {
        if (match.match.underway_at || match.match.scores_csv) {
          return 1;
        }
        else {
          return 2;
        }
      }
      else {
        return 3;
      }
    };

    // init
    $scope.getCredentials(false, 'organizer');
    $scope.getCredentials(false, 'participant');

  });
}());<commit_msg>show registered participants, fixes #3<commit_after>(function () {
  'use strict';

  var app = angular.module('app');
  app.controller('appCtrl', function($scope, $http, localStorageService, $interval) {

    $scope.Math = window.Math;

    $scope.activeTournament = '';
    $scope.matches = '';
    $scope.match_ids = {};
    $scope.currentMatch = {};

    $scope.participants = {};
    $scope.stations = {};

    $scope.is_loading = false;
    $scope.ready = false;

    $scope.is_organizer = false;

    $scope.tournamentFilters = [{
      "name": "In Progress",
      "value": "in_progress"
    }, {
      "name": "Completed",
      "value": "ended"
    }, {
      "name": "Pending",
      "value": "ended"
    }, {
      "name": "All",
      "value": "all"
    }];

    $scope.credentials = {
      'organizer': {
        'tournament_filter': $scope.tournamentFilters[0]
      },
      'participant': {

      },
      'api_key': '',
      'subdomain': '',
      'hide_completed': localStorageService.get('hide_completed'),
      'hide_stations': localStorageService.get('hide_stations'),

    };

    $scope.getCredentials = function(clicked, type) {

      if(type == 'organizer') {
        $scope.credentials.organizer.api_key = localStorageService.get('api_key');
        $scope.credentials.organizer.subdomain = localStorageService.get('subdomain');
        if (!$scope.credentials.organizer.api_key) {
          $scope.ready = false;
        }
        else {
          $scope.ready = true;
          $scope.confirmed = clicked;
        }
      }
      else if (type == 'participant') {

        $scope.credentials.full_challonge_url = localStorageService.get('full_challonge_url');
        $scope.ready = true;
        $scope.confirmed = clicked;

        if( $scope.confirmed) {
          $scope.activateTournament();
        }
      }
    };

    $scope.setCredentials = function(type) {

      if(type == 'organizer') {
        $scope.is_organizer = true;
        localStorageService.set('api_key',   $scope.credentials.organizer.api_key);
        localStorageService.set('subdomain', $scope.credentials.organizer.subdomain);
        $scope.getCredentials(true, 'organizer');
        $scope.getActiveTournaments();
      }
      else if (type == 'participant') {
        $scope.is_organizer = false;

        localStorageService.set('full_challonge_url',  $scope.credentials.full_challonge_url);

        var n = $scope.credentials.full_challonge_url.search("://");
        if (n) {
          $scope.credentials.full_challonge_url = $scope.credentials.full_challonge_url.substring(n+3);
        }

        var split_slash = $scope.credentials.full_challonge_url.split('/');
        $scope.credentials.participant.tournament_url = split_slash[split_slash.length - 1];

        var split_dot = $scope.credentials.full_challonge_url.split('.');

        if (split_dot.length >2) {
          $scope.credentials.participant.subdomain = split_dot[0];
        }
        else {
          $scope.credentials.participant.subdomain = '';
        }

        $scope.getCredentials(true, 'participant');
      }
    };

    $scope.hideCompletedMatches = function() {
      localStorageService.set('hide_completed', $scope.credentials.hide_completed);
    };
    $scope.hideStations = function() {
      localStorageService.set('hide_stations', $scope.credentials.hide_stations);
    };

    $scope.getActiveTournaments = function(filter) {
      $scope.is_loading = true;

      var state = 'in_progress';

      if ($scope.credentials.organizer.tournament_filter && 'value' in $scope.credentials.organizer.tournament_filter) {
        state = $scope.credentials.organizer.tournament_filter.value;
      }

      $http.get("getTournaments/", {
        params: {
          "api_key" : $scope.credentials.organizer.api_key,
          "subdomain" : $scope.credentials.organizer.subdomain,
          "state" : state
        }
      })
      .then(
        function(data, status) {
          $scope.tournaments = data.data;
          $scope.is_loading = false;
        },
        function(data, status) {
          console.log(data);
      });
    };

    $scope.selectTournament = function(tournament) {
      $scope.activeTournament = tournament;
      $scope.activateTournament();
    };

    $scope.activateTournament = function() {
      if ($scope.is_organizer) {
        $scope.tournamentAttachments();
        $scope.getTournamentParticipants();
      }
      else {
        $scope.getTournamentParticipants();
        $interval(function () {
          $scope.getTournamentParticipants(false);
        }, 30000);
      }
    }

    $scope.tournamentAttachments = function() {
      $http.get("tournamentAttachments/", {
        params: {
          "api_key" : $scope.credentials.organizer.api_key,
          "subdomain" : $scope.credentials.subdomain,
          "tournament_url" : $scope.activeTournament.tournament.url
        }
      });
    };

    $scope.getTournamentParticipants = function(reload) {
      $scope.is_loading = reload;

      var api_key;
      var subdomain;
      var tournament_url;

      if( $scope.is_organizer ) {
        api_key        = $scope.credentials.organizer.api_key;
        subdomain      = $scope.credentials.organizer.subdomain;
        tournament_url = $scope.activeTournament.tournament.url;
      }
      else {
        subdomain      = $scope.credentials.participant.subdomain;
        tournament_url = $scope.credentials.participant.tournament_url;
      }
      $http.get("getTournamentParticipants/", {
        params: {
          "api_key"        : api_key,
          "subdomain"      : subdomain,
          "tournament_url" : tournament_url,
          "is_organizer"   : $scope.is_organizer
        }
      })
      .then(
        function(data, status) {
          var participants = data.data;

          for(var i = 0; i < participants.length; i++) {
            $scope.participants[participants[i].participant.id] = participants[i].participant.name || participants[i].participant.username || participants[i].participant.display_name;
          }

          console.log($scope.participants);

          $scope.getTournamentMatches(reload);
        },
        function(data, status) {
          console.log(data);
      });
    };

    $scope.getTournamentMatches = function(reload) {
      $scope.is_loading = reload;

      var api_key;
      var subdomain;
      var tournament_url;

      if( $scope.is_organizer ) {
        api_key        = $scope.credentials.organizer.api_key;
        subdomain      = $scope.credentials.organizer.subdomain;
        tournament_url = $scope.activeTournament.tournament.url;
      }
      else {
        subdomain      = $scope.credentials.participant.subdomain;
        tournament_url = $scope.credentials.participant.tournament_url;
      }

      $http.get("getMatches/", {
        params: {
          "api_key"        : api_key,
          "subdomain"      : subdomain,
          "tournament_url" : tournament_url,
          "is_organizer"   : $scope.is_organizer
        }
      })
      .then(
        function(data, status) {
          $scope.matches = data.data;
          $scope.match_ids = {};

          // store match ids to determine winner
          angular.forEach($scope.matches, function(value) {
            $scope.match_ids[value.match.id] = {
              'id': value.match.identifier,
              'round': value.match.round
            };

            if (value.match.attachment_count) {
             $scope.getMatchStation(value);
            }

            // sort matches
            value.match.order = $scope.matchOrder(value);
          });

          $scope.is_loading = false;

        },
        function(data, status) {
          console.log(data);

      });
    };

    $scope.editMatch = function(match) {
      // there really isn't anything you can do on a match that is pending, at least now
      if($scope.is_organizer && match.match.state != 'pending') {
        $scope.currentMatch = match;
        if($scope.currentMatch.match.scores_csv) {
          var scores = $scope.currentMatch.match.scores_csv.split('-');
          $scope.currentMatch.match.player1_score = parseInt(scores[0]) || 0;
          $scope.currentMatch.match.player2_score = parseInt(scores[1]) || 0;
        }
        $('#matchModal').modal();
      }
    };

    $scope.postMatchResults = function() {
      var p1_score = $scope.currentMatch.match.player1_score || 0;
      var p2_score = $scope.currentMatch.match.player2_score || 0;
      var score = '' + p1_score + '-' + p2_score;

      var match_station = $scope.currentMatch.match.station || '';

      $http.post("postMatchResults/", {
        data: {
          "api_key" : $scope.credentials.organizer.api_key,
          "subdomain" : $scope.credentials.organizer.subdomain,
          "tournament_url" : $scope.activeTournament.tournament.url,
          "match_id": $scope.currentMatch.match.id,
          "match_station": match_station,
          "score": score,
          'winner_id': $scope.currentMatch.match.winner_id
        }
      })
      .then(
        function(response) {
          $scope.getTournamentMatches(false);
          $('#matchModal').modal('hide');
        },
        function(response) {
          console.log(response);
      });
    };

    $scope.getMatchStation = function(match) {

      var api_key;
      var subdomain;
      var tournament_url;

      if( $scope.is_organizer ) {
        api_key        = $scope.credentials.organizer.api_key;
        subdomain      = $scope.credentials.organizer.subdomain;
        tournament_url = $scope.activeTournament.tournament.url;
      }
      else {
        subdomain      = $scope.credentials.participant.subdomain;
        tournament_url = $scope.credentials.participant.tournament_url;
      }

      $http.get("getMatchStation/", {
        params: {
          "api_key"        : api_key,
          "subdomain"      : subdomain,
          "tournament_url" : tournament_url,
          "match_id"       : match.match.id,
          "is_organizer"   : $scope.is_organizer
        }
      })
      .then(
        function(response) {
          if (!response.data.match) {
            return;
          }

          var match_data = response.data.match;

          var station = '';
          var id = '';

          for(var i = 0; i < match_data.attachment_count; ++i) {
            if(match_data.attachments[i].match_attachment.description.substring(0,8) == 'station ') {
              match.match.station = match_data.attachments[i].match_attachment.description.substring(8);
              match.match.station_id = match_data.attachments[i].match_attachment.id;
            }
          }
        },
        function(response) {
          console.log(response);
      });
    };

    $scope.updateMatchStation = function(match, station) {

      if ($scope.is_organizer) {
        var match_id = match.match.id;
        var station_id = '';
        var get_method = 'POST';

        if(match.match.station_id) {
          station_id = match.match.station_id;
          get_method = 'PUT';

          if(!station) {
            get_method = 'DELETE';
          }
        }

        $http.post("postMatchStation/", {
          data: {
            "api_key" : $scope.credentials.organizer.api_key,
            "subdomain" : $scope.credentials.organizer.subdomain,
            "tournament_url" : $scope.activeTournament.tournament.url,
            "match_id": match_id,
            "match_station": station,
            "station_id": station_id,
            "get_method": get_method
          }
        })
        .then(
          function(response) {
            $scope.getMatchStation(match);
          },
          function(response) {
            alert('Error, sorry. Working on it');
        });

      }
    };

    $scope.determineRound = function(round) {
      var place;
      if(round > 0) {
        place = 'WR ';
      }
      else {
        place = 'LR ';
      }
      round = Math.abs(round);
      return place + round;
    };

    // determine match order by state
    // 0: green  / success
    // 1: purple / info
    // 2: grey   / pending
    // 3: white  / none
    // 4: red    / error (not yet implemented)
    $scope.matchOrder = function(match) {
      if (match.match.state == 'complete') {
        return 0;

      }
      else if (match.match.state == 'open') {
        if (match.match.underway_at || match.match.scores_csv) {
          return 1;
        }
        else {
          return 2;
        }
      }
      else {
        return 3;
      }
    };

    // init
    $scope.getCredentials(false, 'organizer');
    $scope.getCredentials(false, 'participant');

  });
}());<|endoftext|>


<commit_before>/**
 * Created by tusharmathur on 5/15/15.
 */
"use strict";
var fs = require('fs'),
    _ = require('lodash'),
    utils = require('./lib/Utility'),
    request = require('request'),
    rx = require('rx'),
    HttpRequest = require('./lib/HttpRequest'),
    co = require('co'),
    MAX_BUFFER = 512,
    MIN_WAIT = 1;

var defaultOptions = {
    headers: {},
    threadCount: 3
};
var fsTruncate = utils.promisify(fs.truncate),
    fsRename = utils.promisify(fs.rename),
    requestHead = HttpRequest.head,
    fsWrite = (fd, buffer, position) => utils.promisify(fs.write)(fd, buffer, 0, buffer.length, position),
    fsWriteObservable = rx.Observable.fromCallback(fs.write),
    fsTruncateObservable = rx.Observable.fromCallback(fs.truncate),
    fsRenameObservable = rx.Observable.fromCallback(fs.rename),
    fsOpen = (path) => utils.promisify(fs.open)(path, 'w+'),
    getLength = (res) => parseInt(res.headers['content-length'], 10),
    rangeHeader = (thread) => ({'range': `bytes=${thread.start}-${thread.end}`}),
    toBuffer = _.partialRight(utils.toBuffer, MAX_BUFFER),
    metaCreate = function (url, path, _ranges) {
        var positions = _.pluck(_ranges, 'start');
        return {url, path: path, nextByte: _.clone(positions), positions};
    };
function * download(options) {
    var url = options.url,
        threadCount = options.threadCount,
        path = options.path,
        size = getLength(yield requestHead(url)),
        fd = yield fsOpen(path),
        _fsTruncate = ()=> fsTruncateObservable(fd, size),
        _fsRename = function () {
            return fsRenameObservable(path, path.replace('.mtd', ''))
        },
        _httpRequest = _.partial(HttpRequest, url),
        _httpRequestRange = _.flowRight(_httpRequest, rangeHeader),
        _ranges = utils.sliceRange(threadCount, size),
        _meta = metaCreate(url, path, _ranges),
        _attachThread = _.curry(function (thread, buffer) {
            return {buffer, thread};
        }),
        _httpRequestThread = function (range, thread) {
            return _httpRequestRange(range).map(_attachThread(thread));
        },
        _attachPacketPosition = function (packet) {
            packet.position = _meta.nextByte[packet.thread];
            _updateNextByte(packet);
            return packet;
        },
        _updateNextByte = function (packet) {
            _meta.nextByte[packet.thread] += packet.buffer.length;
        },
        _updatePosition = function (packet) {
            _meta.positions[packet.thread] += packet.buffer.length;
        },
        _fsWrite = function (fd, buffer, position) {
            return fsWriteObservable(fd, buffer, 0, buffer.length, position);
        }
        ;
    var defer = Promise.defer();
    rx.Observable
        .from(_ranges)
        .selectMany(_httpRequestThread)
        .select(_attachPacketPosition)
        .selectMany(packet => _fsWrite(fd, packet.buffer, packet.position), _.identity)
        .select(_updatePosition)
        .selectMany(() => _fsWrite(fd, toBuffer(_meta), size))
        .last()
        .selectMany(_fsTruncate)
        .selectMany(_fsRename)
       .subscribe(defer.resolve, defer.reject);

    yield defer.promise;
    return _meta;
}

class Download {
    constructor(options) {
        this.options = _.assign(options, defaultOptions);
        this.options.path += '.mtd';
    }

    start() {
        return co.wrap(download)(this.options);
    }
}
module.exports = Download;<commit_msg>use to promise<commit_after>/**
 * Created by tusharmathur on 5/15/15.
 */
"use strict";
var fs = require('fs'),
    _ = require('lodash'),
    utils = require('./lib/Utility'),
    request = require('request'),
    rx = require('rx'),
    HttpRequest = require('./lib/HttpRequest'),
    co = require('co'),
    MAX_BUFFER = 512,
    MIN_WAIT = 1;

var defaultOptions = {
    headers: {},
    threadCount: 3
};
var fsTruncate = utils.promisify(fs.truncate),
    fsRename = utils.promisify(fs.rename),
    requestHead = HttpRequest.head,
    fsWrite = (fd, buffer, position) => utils.promisify(fs.write)(fd, buffer, 0, buffer.length, position),
    fsWriteObservable = rx.Observable.fromCallback(fs.write),
    fsTruncateObservable = rx.Observable.fromCallback(fs.truncate),
    fsRenameObservable = rx.Observable.fromCallback(fs.rename),
    fsOpen = (path) => utils.promisify(fs.open)(path, 'w+'),
    getLength = (res) => parseInt(res.headers['content-length'], 10),
    rangeHeader = (thread) => ({'range': `bytes=${thread.start}-${thread.end}`}),
    toBuffer = _.partialRight(utils.toBuffer, MAX_BUFFER),
    metaCreate = function (url, path, _ranges) {
        var positions = _.pluck(_ranges, 'start');
        return {url, path: path, nextByte: _.clone(positions), positions};
    };
function * download(options) {
    var url = options.url,
        threadCount = options.threadCount,
        path = options.path,
        size = getLength(yield requestHead(url)),
        fd = yield fsOpen(path),
        _fsTruncate = ()=> fsTruncateObservable(fd, size),
        _fsRename = function () {
            return fsRenameObservable(path, path.replace('.mtd', ''))
        },
        _httpRequest = _.partial(HttpRequest, url),
        _httpRequestRange = _.flowRight(_httpRequest, rangeHeader),
        _ranges = utils.sliceRange(threadCount, size),
        _meta = metaCreate(url, path, _ranges),
        _attachThread = _.curry(function (thread, buffer) {
            return {buffer, thread};
        }),
        _httpRequestThread = function (range, thread) {
            return _httpRequestRange(range).map(_attachThread(thread));
        },
        _attachPacketPosition = function (packet) {
            packet.position = _meta.nextByte[packet.thread];
            _updateNextByte(packet);
            return packet;
        },
        _updateNextByte = function (packet) {
            _meta.nextByte[packet.thread] += packet.buffer.length;
        },
        _updatePosition = function (packet) {
            _meta.positions[packet.thread] += packet.buffer.length;
        },
        _fsWrite = function (fd, buffer, position) {
            return fsWriteObservable(fd, buffer, 0, buffer.length, position);
        }
        ;

    yield rx.Observable
        .from(_ranges)
        .selectMany(_httpRequestThread)
        .select(_attachPacketPosition)
        .selectMany(packet => _fsWrite(fd, packet.buffer, packet.position), _.identity)
        .select(_updatePosition)
        .selectMany(() => _fsWrite(fd, toBuffer(_meta), size))
        .last()
        .selectMany(_fsTruncate)
        .selectMany(_fsRename)
        .toPromise();

    return _meta;
}

class Download {
    constructor(options) {
        this.options = _.assign(options, defaultOptions);
        this.options.path += '.mtd';
    }

    start() {
        return co.wrap(download)(this.options);
    }
}
module.exports = Download;<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict'

const fs = require('fs')

const templates = require('./templates.js');

const log = (...args) => {console.log(...args)}
const logError = (...args) => {console.error(...args)}

const handleFileWritingErr = (err) => {
	switch (err.code) {
		case 'EEXIST':
			logError(`A file named ${err.path} already exists!`)
			break
		default:
			logError(err)
	}
}

const main = (args) => {
	if (!args || args.length < 3) {
		return printUsage()
	}

	switch (args[2]) {
		case 'g': case 'generate':
			generate(args.slice(3))
			break
		default:
			if (args.length == 3) {
				generateComponents([args[2]]);
			} else {
				printUsage()
			}
	}
}

const printUsage = () => {
	log('I should explain usage here')
}

const generate = (args) => {
	if (!args || args.length < 2) {
		return printUsage()
	}

	switch(args[0]) {
		case 'component': case 'c':
			generateComponents(args.slice(1))
			break
		default:
			printUsage()
	}
}

const generateComponents = (components) => {
	components.forEach(c => {
		fs.writeFile(
			`${c.toLowerCase()}.component.jsx`,
			templates.component(c),
			{ flag: 'wx' },
			(err) => {
				if (err) {
					return handleFileWritingErr(err);
				}
				log(`Component ${c} created`);
			}
		)
	})
}

main(process.argv)
<commit_msg>syntaxic tweaking<commit_after>#!/usr/bin/env node
'use strict'

const fs = require('fs')

const templates = require('./templates.js')

const log = (...args) => { console.log(...args) }
const logError = (...args) => { console.error(...args) }

const handleFileWritingErr = (err) => {
	switch (err.code) {
		case 'EEXIST':
			logError(`A file named ${err.path} already exists!`)
			break
		default:
			logError(err)
	}
}

const main = (args) => {
	if (!args || args.length < 3) {
		return printUsage()
	}

	if (args.length == 3) {
		return generateComponents([args[2]])
	}

	switch (args[2]) {
		case 'g': case 'generate':
			generate(args.slice(3))
			break
		default:
			printUsage()
	}
}

const printUsage = () => {
	log('I should explain usage here')
}

const generate = (args) => {
	if (!args || args.length < 2) {
		return printUsage()
	}

	switch(args[0]) {
		case 'component': case 'c':
			generateComponents(args.slice(1))
			break
		default:
			printUsage()
	}
}

const generateComponents = (components) => {
	components.forEach(c => {
		fs.writeFile(
			`${c.toLowerCase()}.component.jsx`,
			templates.component(c),
			{ flag: 'wx' },
			(err) => {
				if (err) {
					return handleFileWritingErr(err)
				}
				log(`Component ${c} created`)
			}
		)
	})
}

main(process.argv)
<|endoftext|>


<commit_before>import * as LogManager from 'aurelia-logging';
import {Container} from 'aurelia-dependency-injection';
import {Loader} from 'aurelia-loader';
import {BindingLanguage,ResourceCoordinator, ViewSlot, ResourceRegistry} from 'aurelia-templating';
import {EventAggregator, includeEventsIn} from 'aurelia-event-aggregator';

var logger = LogManager.getLogger('aurelia');

function loadPlugins(loader, plugins){
  var toLoad = [], i, ii, current;

  for(i = 0, ii = plugins.length; i < ii; ++i){
    current = plugins[i];
    logger.debug(`Loading plugin ${current.moduleId}.`);
    toLoad.push(loader.loadModule(current.moduleId).then(exportedValue => {
      if('install' in exportedValue){
        return exportedValue.install(current.config || {}).then(() =>{
          logger.debug(`Installed plugin ${current.moduleId}.`);
        });
      }else{
        logger.debug(`Loaded plugin ${current.moduleId}.`);
      }
    }));
  }

  return Promise.all(toLoad);
}

export class Aurelia {
  constructor(loader, container, resources){
    this.loader = loader || Loader.createDefaultLoader();
    this.container = container || new Container();
    this.resources = resources || new ResourceRegistry();
    this.resourcesToLoad = [];
    this.plugins = [];

    this.withInstance(Aurelia, this);
    this.withInstance(Loader, this.loader);
    this.withInstance(ResourceRegistry, this.resources);
    this.withInstance(EventAggregator, includeEventsIn(this));
  }

  withInstance(type, instance){
    this.container.registerInstance(type, instance);
    return this;
  }

  withSingleton(type, implementation){
    this.container.registerSingleton(type, implementation);
    return this;
  }

  withBindingLanguage(languageType){
    this.container.registerSingleton(BindingLanguage, languageType);
    return this;
  }

  withPlugin(moduleId, config){
    this.plugins.push({moduleId:moduleId, config:config});
    return this;
  }

  withResources(resources){
    if(Array.isArray(resources)){
      this.resourcesToLoad = this.resourcesToLoad.concat(resources);
    }else{
      this.resourcesToLoad = this.resourcesToLoad.concat(Array.prototype.slice.call(arguments));
    }

    return this;
  }

  start(){
    if(this.started){
      return;
    }

    this.started = true;
    logger.info('Aurelia Starting');

    if(!this.container.hasHandler(BindingLanguage)){
      logger.error('You must configure Aurelia with a BindingLanguage implementation.');
    }

    return loadPlugins(this.loader, this.plugins).then(() => {
      return this.container.get(ResourceCoordinator)
        .importResources(this.resourcesToLoad).then(resources => {
          resources.forEach(x => x.register(this.resources));
          logger.info('Aurelia Started');
          return this;
        });
    });
  }

  setRoot(root, applicationHost){
    if (!applicationHost || typeof applicationHost == 'string') {
      this.host = document.getElementById(applicationHost || 'applicationHost') || document.body;
    } else {
      this.host = applicationHost;
    }

    this.host.aurelia = this;

    return this.container.get(ResourceCoordinator)
      .loadElement(root).then(type => {
        this.root = type.create(this.container);
        var slot = new ViewSlot(this.host, true);
        slot.swap(this.root.view);
        slot.attached();
        return this;
      });
  }
}<commit_msg>fix(aurelia): plugin loading module id fix<commit_after>import * as LogManager from 'aurelia-logging';
import {Container} from 'aurelia-dependency-injection';
import {Loader} from 'aurelia-loader';
import {BindingLanguage,ResourceCoordinator, ViewSlot, ResourceRegistry} from 'aurelia-templating';
import {EventAggregator, includeEventsIn} from 'aurelia-event-aggregator';

var logger = LogManager.getLogger('aurelia');

function loadPlugin(aurelia, loader, info){
  logger.debug(`Loading plugin ${info.moduleId}.`);

  return loader.loadModule(info.moduleId, '').then(exportedValue => {
    if('install' in exportedValue){
      var result = exportedValue.install(aurelia, info.config || {});

      if(result){
        return result.then(() =>{
          logger.debug(`Installed plugin ${info.moduleId}.`);
        });
      }else{
        logger.debug(`Installed plugin ${info.moduleId}.`);
      }
    }else{
      logger.debug(`Loaded plugin ${info.moduleId}.`);
    }
  });
}

function loadPlugins(aurelia){
  var toLoad = [],
      loader = aurelia.loader,
      plugins = aurelia.plugins,
      i, ii, current, result;

  for(i = 0, ii = plugins.length; i < ii; ++i){
    toLoad.push(loadPlugin(aurelia, loader, plugins[i]));
  }

  return Promise.all(toLoad);
}

export class Aurelia {
  constructor(loader, container, resources){
    this.loader = loader || Loader.createDefaultLoader();
    this.container = container || new Container();
    this.resources = resources || new ResourceRegistry();
    this.resourcesToLoad = [];
    this.plugins = [];

    this.withInstance(Aurelia, this);
    this.withInstance(Loader, this.loader);
    this.withInstance(ResourceRegistry, this.resources);
    this.withInstance(EventAggregator, includeEventsIn(this));
  }

  withInstance(type, instance){
    this.container.registerInstance(type, instance);
    return this;
  }

  withSingleton(type, implementation){
    this.container.registerSingleton(type, implementation);
    return this;
  }

  withBindingLanguage(languageType){
    this.container.registerSingleton(BindingLanguage, languageType);
    return this;
  }

  withPlugin(moduleId, config){
    this.plugins.push({moduleId:moduleId, config:config});
    return this;
  }

  withResources(resources){
    if(Array.isArray(resources)){
      this.resourcesToLoad = this.resourcesToLoad.concat(resources);
    }else{
      this.resourcesToLoad = this.resourcesToLoad.concat(Array.prototype.slice.call(arguments));
    }

    return this;
  }

  start(){
    if(this.started){
      return;
    }

    this.started = true;
    logger.info('Aurelia Starting');

    if(!this.container.hasHandler(BindingLanguage)){
      logger.error('You must configure Aurelia with a BindingLanguage implementation.');
    }

    return loadPlugins(this).then(() => {
      return this.container.get(ResourceCoordinator)
        .importResources(this.resourcesToLoad).then(resources => {
          resources.forEach(x => x.register(this.resources));
          logger.info('Aurelia Started');
          return this;
        });
    });
  }

  setRoot(root, applicationHost){
    if (!applicationHost || typeof applicationHost == 'string') {
      this.host = document.getElementById(applicationHost || 'applicationHost') || document.body;
    } else {
      this.host = applicationHost;
    }

    this.host.aurelia = this;

    return this.container.get(ResourceCoordinator)
      .loadElement(root).then(type => {
        this.root = type.create(this.container);
        var slot = new ViewSlot(this.host, true);
        slot.swap(this.root.view);
        slot.attached();
        return this;
      });
  }
}<|endoftext|>


<commit_before>var fs = require('fs');
var repeat = require('repeat');
var config = require('./config.json');
var canvas = require('./services/canvas');
var repo = require('./services/repo');

var getLetterArray = function(letter) {
    switch(letter) {
        case ' ':
            return [
                0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,
                0,0,0,0,0,0,0
            ];
            break;
        case 'a':
            return [
                0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,
                0,4,4,4,4,0,0,
                4,1,0,0,4,0,0,
                4,1,0,0,4,0,0,
                0,4,4,4,4,4,0,
                0,0,0,0,0,0,0
            ];
            break;
        case 'b':
            return [
                4,0,0,0,0,0,0,
                4,0,0,0,0,0,0,
                4,4,4,3,0,0,0,
                4,0,1,0,4,0,0,
                4,0,0,1,4,0,0,
                4,4,4,3,0,0,0,
                0,0,0,0,0,0,0
            ];
            break;
        case 'c':
            return [
                0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,
                0,3,4,4,0,0,0,
                4,1,0,1,2,0,0,
                4,0,0,0,0,0,0,
                0,3,4,4,3,0,0,
                0,0,0,0,0,0,0
            ];
            break;
        case 'd':
            return [
                0,0,0,0,4,0,0,
                0,0,0,0,4,0,0,
                0,3,4,4,4,0,0,
                4,0,0,0,4,0,0,
                4,0,0,0,4,0,0,
                0,3,4,4,4,0,0,
                0,0,0,0,0,0,0
            ];
            break;
        case 'e':
            return [
                0,0,0,0,0,0,0,
                0,3,4,4,0,0,0,
                4,0,0,0,4,0,0,
                4,4,4,4,3,0,0,
                4,0,0,0,0,0,0,
                0,3,4,4,3,0,0,
                0,0,0,0,0,0,0
            ];
            break;
        case 'f':
            return [
                0,0,4,0,0,0,0,
                0,4,0,3,0,0,0,
                0,4,0,0,0,0,0,
                4,4,4,3,0,0,0,
                0,4,0,0,0,0,0,
                0,4,0,0,0,0,0,
                0,0,0,0,0,0,0
            ];
            break;
        case 'g':
            return [
                0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,
                0,4,4,4,1,0,0,
                3,0,0,4,0,0,0,
                1,4,4,4,0,0,0,
                0,0,0,4,0,0,0,
                0,4,4,0,0,0,0
            ];
            break;
        case 'h':
            return [
                4,0,0,0,0,0,0,
                4,0,0,0,0,0,0,
                4,2,4,3,1,0,0,
                4,1,0,0,4,0,0,
                4,0,0,0,4,0,0,
                4,0,0,0,4,0,0,
                0,0,0,0,0,0,0
            ];
            break;
        case 'i':
            return [
                0,0,0,0,0,0,0,
                4,0,0,0,0,0,0,
                0,0,0,0,0,0,0,
                4,0,0,0,0,0,0,
                4,0,0,0,0,0,0,
                4,0,0,0,0,0,0,
                0,0,0,0,0,0,0
            ];
            break;
        case 'j':
            return [
                0,0,0,0,0,0,0,
                0,0,4,0,0,0,0,
                0,0,0,0,0,0,0,
                0,3,4,0,0,0,0,
                0,0,4,0,0,0,0,
                0,0,3,0,0,0,0,
                3,4,1,0,0,0,0
            ];
            break;
        default:
            throw new Error('Unsupported character, ' + letter);
    }
};

var getJulian = function(date) {
    var onejan = new Date(date.getFullYear(),0,1);
    return Math.ceil((date - onejan) / 86400000);
}

var getRequiredCommits = function(){
    var canvas = canvas.getCanvas(config.input);
    var julian =  getJulian(new Date());

    if(canvas.length > julian)
        return canvas[julian];
    else
        return 0;
}

var appendFile = function() {
    fs.appendFile(config.file, new Date(), [], function (error) {
        if(error) throw error;
    });
}

var updateCanvas = function() {
    console.log('updating canvas at ' + new Date())
    try
    {
        var requiredCommits = getRequiredCommits();
        for(var i = 0; i < requiredCommits; i++) {
            appendFile();
            repo.addCommit();
        }
        repo.pushCommits();
    }
    catch(error){
        console.log("Error: " + error)
    }
}

repeat(updateCanvas).every(24, 'h').start.now()
<commit_msg>Removed canvas letter templates.<commit_after>var fs = require('fs');
var repeat = require('repeat');
var config = require('./config.json');
var canvas = require('./services/canvas');
var repo = require('./services/repo');

var getJulian = function(date) {
    var onejan = new Date(date.getFullYear(),0,1);
    return Math.ceil((date - onejan) / 86400000);
}

var getRequiredCommits = function(){
    var canvas = canvas.getCanvas(config.input);
    var julian =  getJulian(new Date());

    if(canvas.length > julian)
        return canvas[julian];
    else
        return 0;
}

var appendFile = function() {
    fs.appendFile(config.file, new Date(), [], function (error) {
        if(error) throw error;
    });
}

var updateCanvas = function() {
    console.log('updating canvas at ' + new Date())
    try
    {
        var requiredCommits = getRequiredCommits();
        for(var i = 0; i < requiredCommits; i++) {
            appendFile();
            repo.addCommit();
        }
        repo.pushCommits();
    }
    catch(error){
        console.log("Error: " + error)
    }
}

repeat(updateCanvas).every(24, 'h').start.now()
<|endoftext|>


<commit_before>(function($) {

/**
 * Base class for all backends
 */
var _ = Mavo.Backend = $.Class({
	constructor: function(url, o = {}) {
		this.source = url;
		this.url = new URL(this.source, Mavo.base);
		this.mavo = o.mavo;
		this.format = Mavo.Formats.create(o.format, this);

		// Permissions of this particular backend.
		this.permissions = new Mavo.Permissions();
	},

	get: function(url = new URL(this.url)) {
		url.searchParams.set("timestamp", Date.now()); // ensure fresh copy

		return $.fetch(url.href).then(xhr => Promise.resolve(xhr.responseText), () => Promise.resolve(null));
	},

	load: function() {
		return this.ready
			.then(() => this.get())
			.then(response => {
			if (typeof response != "string") {
				// Backend did the parsing, we're done here
				return response;
			}

			response = response.replace(/^\ufeff/, ""); // Remove Unicode BOM

			return this.format.parse(response);
		});
	},

	store: function(data, {path, format = this.format} = {}) {
		return this.ready.then(() => {
			var serialize = typeof data === "string"? Promise.resolve(data) : format.stringify(data);

			return serialize.then(serialized => this.put(serialized, path).then(() => {
				return {data, serialized};
			}));
		});
	},

	// To be be overriden by subclasses
	ready: Promise.resolve(),
	login: () => Promise.resolve(),
	logout: () => Promise.resolve(),

	isAuthenticated: function() {
		return !!this.accessToken;
	},

	// Any extra params to be passed to the oAuth URL.
	oAuthParams: () => "",

	toString: function() {
		return `${this.id} (${this.url})`;
	},

	equals: function(backend) {
		return backend === this || (backend && this.id == backend.id && this.source == backend.source);
	},

	/**
	 * Helper for making OAuth requests with JSON-based APIs.
	 */
	request: function(call, data, method = "GET", req = {}) {
		req.method = req.method || method;
		req.responseType = req.responseType || "json";
		req.headers = req.headers || {};
		req.headers["Content-Type"] = req.headers["Content-Type"] || "application/json; charset=utf-8";
		req.data = data;

		if (this.isAuthenticated()) {
			req.headers["Authorization"] = req.headers["Authorization"] || `Bearer ${this.accessToken}`;
		}

		if ($.type(req.data) === "object") {
			if (req.method == "GET") {
				req.data = Object.keys(req.data).map(p => p + "=" + encodeURIComponent(req.data[p])).join("&");
			}
			else {
				req.data = JSON.stringify(req.data);
			}
		}

		call = new URL(call, this.constructor.apiDomain);

		return $.fetch(call, req)
			.catch(err => {
				if (err && err.xhr) {
					return Promise.reject(err.xhr);
				}
				else {
					this.mavo.error("Something went wrong while connecting to " + this.id, err);
				}
			})
			.then(xhr => req.method == "HEAD"? xhr : xhr.response);
	},

	/**
	 * Helper method for authenticating in OAuth APIs
	 */
	oAuthenticate: function(passive) {
		return this.ready.then(() => {
			if (this.isAuthenticated()) {
				return Promise.resolve();
			}

			return new Promise((resolve, reject) => {
				var id = this.id.toLowerCase();

				if (passive) {
					this.accessToken = localStorage[`mavo:${id}token`];

					if (this.accessToken) {
						resolve(this.accessToken);
					}
				}
				else {
					// Show window
					var popup = {
						width: Math.min(1000, innerWidth - 100),
						height: Math.min(800, innerHeight - 100)
					};

					popup.top = (innerHeight - popup.height)/2 + (screen.top || screenTop);
					popup.left = (innerWidth - popup.width)/2 + (screen.left || screenLeft);

					var state = {
						url: location.href,
						backend: this.id
					};

					this.authPopup = open(`${this.constructor.oAuth}?client_id=${this.key}&state=${encodeURIComponent(JSON.stringify(state))}` + this.oAuthParams(),
						"popup", `width=${popup.width},height=${popup.height},left=${popup.left},top=${popup.top}`);

					addEventListener("message", evt => {
						if (evt.source === this.authPopup) {
							if (evt.data.backend == this.id) {
								this.accessToken = localStorage[`mavo:${id}token`] = evt.data.token;
							}

							if (!this.accessToken) {
								reject(Error("Authentication error"));
							}

							resolve(this.accessToken);
						}
					});
				}
			});
		});
	},

	/**
	 * oAuth logout helper
	 */
	oAuthLogout: function() {
		if (this.isAuthenticated()) {
			var id = this.id.toLowerCase();

			localStorage.removeItem(`mavo:${id}token`);
			delete this.accessToken;

			this.permissions.off(["edit", "add", "delete", "save"]).on("login");

			this.mavo.element._.fire("mavo:logout", {backend: this});
		}

		return Promise.resolve();
	},

	static: {
		// Return the appropriate backend(s) for this url
		create: function(url, o) {
			if (url) {
				var Backend = _.types.filter(Backend => Backend.test(url))[0] || _.Remote;

				return new Backend(url, o);
			}

			return null;
		},

		types: [],

		register: function(Class) {
			_[Class.prototype.id] = Class;
			_.types.push(Class);
			return Class;
		}
	}
});

/**
 * Save in an HTML element
 */
_.register($.Class({
	id: "Element",
	extends: _,
	constructor: function () {
		this.permissions.on(["read", "edit", "save"]);

		this.element = $(this.source) || $.create("script", {
			type: "application/json",
			id: this.source.slice(1),
			inside: document.body
		});
	},

	get: function() {
		return Promise.resolve(this.element.textContent);
	},

	put: function(serialized) {
		return Promise.resolve(this.element.textContent = serialized);
	},

	static: {
		test: url => url.indexOf("#") === 0
	}
}));

// Load from a remote URL, no save
_.register($.Class({
	id: "Remote",
	extends: _,
	constructor: function() {
		this.permissions.on("read");
	},

	static: {
		test: url => false
	}
}));

// Save in localStorage
_.register($.Class({
	extends: _,
	id: "Local",
	constructor: function() {
		this.permissions.on(["read", "edit", "save"]);
		this.key = this.mavo.id;
	},

	get: function() {
		return Promise[this.key in localStorage? "resolve" : "reject"](localStorage[this.key]);
	},

	put: function(serialized) {
		if (!serialized) {
			delete localStorage[this.key];
		}
		else {
			localStorage[this.key] = serialized;
		}

		return Promise.resolve(serialized);
	},

	static: {
		test: value => value == "local"
	}
}));

})(Bliss);
<commit_msg>Fix Firefox login bug, reported by @corwin-of-amber<commit_after>(function($) {

/**
 * Base class for all backends
 */
var _ = Mavo.Backend = $.Class({
	constructor: function(url, o = {}) {
		this.source = url;
		this.url = new URL(this.source, Mavo.base);
		this.mavo = o.mavo;
		this.format = Mavo.Formats.create(o.format, this);

		// Permissions of this particular backend.
		this.permissions = new Mavo.Permissions();
	},

	get: function(url = new URL(this.url)) {
		url.searchParams.set("timestamp", Date.now()); // ensure fresh copy

		return $.fetch(url.href).then(xhr => Promise.resolve(xhr.responseText), () => Promise.resolve(null));
	},

	load: function() {
		return this.ready
			.then(() => this.get())
			.then(response => {
			if (typeof response != "string") {
				// Backend did the parsing, we're done here
				return response;
			}

			response = response.replace(/^\ufeff/, ""); // Remove Unicode BOM

			return this.format.parse(response);
		});
	},

	store: function(data, {path, format = this.format} = {}) {
		return this.ready.then(() => {
			var serialize = typeof data === "string"? Promise.resolve(data) : format.stringify(data);

			return serialize.then(serialized => this.put(serialized, path).then(() => {
				return {data, serialized};
			}));
		});
	},

	// To be be overriden by subclasses
	ready: Promise.resolve(),
	login: () => Promise.resolve(),
	logout: () => Promise.resolve(),

	isAuthenticated: function() {
		return !!this.accessToken;
	},

	// Any extra params to be passed to the oAuth URL.
	oAuthParams: () => "",

	toString: function() {
		return `${this.id} (${this.url})`;
	},

	equals: function(backend) {
		return backend === this || (backend && this.id == backend.id && this.source == backend.source);
	},

	/**
	 * Helper for making OAuth requests with JSON-based APIs.
	 */
	request: function(call, data, method = "GET", req = {}) {
		req.method = req.method || method;
		req.responseType = req.responseType || "json";
		req.headers = req.headers || {};
		req.headers["Content-Type"] = req.headers["Content-Type"] || "application/json; charset=utf-8";
		req.data = data;

		if (this.isAuthenticated()) {
			req.headers["Authorization"] = req.headers["Authorization"] || `Bearer ${this.accessToken}`;
		}

		if ($.type(req.data) === "object") {
			if (req.method == "GET") {
				req.data = Object.keys(req.data).map(p => p + "=" + encodeURIComponent(req.data[p])).join("&");
			}
			else {
				req.data = JSON.stringify(req.data);
			}
		}

		call = new URL(call, this.constructor.apiDomain);

		return $.fetch(call, req)
			.catch(err => {
				if (err && err.xhr) {
					return Promise.reject(err.xhr);
				}
				else {
					this.mavo.error("Something went wrong while connecting to " + this.id, err);
				}
			})
			.then(xhr => req.method == "HEAD"? xhr : xhr.response);
	},

	/**
	 * Helper method for authenticating in OAuth APIs
	 */
	oAuthenticate: function(passive) {
		return this.ready.then(() => {
			if (this.isAuthenticated()) {
				return Promise.resolve();
			}

			return new Promise((resolve, reject) => {
				var id = this.id.toLowerCase();

				if (passive) {
					this.accessToken = localStorage[`mavo:${id}token`];

					if (this.accessToken) {
						resolve(this.accessToken);
					}
				}
				else {
					// Show window
					var popup = {
						width: Math.min(1000, innerWidth - 100),
						height: Math.min(800, innerHeight - 100)
					};

					popup.top = (screen.height - popup.height)/2;
					popup.left = (screen.width - popup.width)/2;

					var state = {
						url: location.href,
						backend: this.id
					};

					this.authPopup = open(`${this.constructor.oAuth}?client_id=${this.key}&state=${encodeURIComponent(JSON.stringify(state))}` + this.oAuthParams(),
						"popup", `width=${popup.width},height=${popup.height},left=${popup.left},top=${popup.top}`);

					addEventListener("message", evt => {
						if (evt.source === this.authPopup) {
							if (evt.data.backend == this.id) {
								this.accessToken = localStorage[`mavo:${id}token`] = evt.data.token;
							}

							if (!this.accessToken) {
								reject(Error("Authentication error"));
							}

							resolve(this.accessToken);
						}
					});
				}
			});
		});
	},

	/**
	 * oAuth logout helper
	 */
	oAuthLogout: function() {
		if (this.isAuthenticated()) {
			var id = this.id.toLowerCase();

			localStorage.removeItem(`mavo:${id}token`);
			delete this.accessToken;

			this.permissions.off(["edit", "add", "delete", "save"]).on("login");

			this.mavo.element._.fire("mavo:logout", {backend: this});
		}

		return Promise.resolve();
	},

	static: {
		// Return the appropriate backend(s) for this url
		create: function(url, o) {
			if (url) {
				var Backend = _.types.filter(Backend => Backend.test(url))[0] || _.Remote;

				return new Backend(url, o);
			}

			return null;
		},

		types: [],

		register: function(Class) {
			_[Class.prototype.id] = Class;
			_.types.push(Class);
			return Class;
		}
	}
});

/**
 * Save in an HTML element
 */
_.register($.Class({
	id: "Element",
	extends: _,
	constructor: function () {
		this.permissions.on(["read", "edit", "save"]);

		this.element = $(this.source) || $.create("script", {
			type: "application/json",
			id: this.source.slice(1),
			inside: document.body
		});
	},

	get: function() {
		return Promise.resolve(this.element.textContent);
	},

	put: function(serialized) {
		return Promise.resolve(this.element.textContent = serialized);
	},

	static: {
		test: url => url.indexOf("#") === 0
	}
}));

// Load from a remote URL, no save
_.register($.Class({
	id: "Remote",
	extends: _,
	constructor: function() {
		this.permissions.on("read");
	},

	static: {
		test: url => false
	}
}));

// Save in localStorage
_.register($.Class({
	extends: _,
	id: "Local",
	constructor: function() {
		this.permissions.on(["read", "edit", "save"]);
		this.key = this.mavo.id;
	},

	get: function() {
		return Promise[this.key in localStorage? "resolve" : "reject"](localStorage[this.key]);
	},

	put: function(serialized) {
		if (!serialized) {
			delete localStorage[this.key];
		}
		else {
			localStorage[this.key] = serialized;
		}

		return Promise.resolve(serialized);
	},

	static: {
		test: value => value == "local"
	}
}));

})(Bliss);
<|endoftext|>


<commit_before>
function showContact() {
  event.preventDefault();
  $('#contact').slideToggle('fast');
}

$("*").each( function () {
    var $this = $(this);
    if (parseInt($this.css("fontSize")) < 12) {
        $this.css({ "font-size": "12px" });
    }
});

setInterval( ()=> {
  $(window).scroll( () => {
    if($(window).scrollTop() < 100){
      $('.navbar-top').removeClass('navbar-scrolled');
      $('.navbar-top').addClass('navbar');
    } else {
      $('.navbar-top').removeClass('navbar');
      $('.navbar-top').addClass('navbar-scrolled');
    }
  })
}, 300)

const fade = (function(){
  var icon, text;
    $('.list-group-item').hover(() => {
      icon = $(event.target).find('.list-group-item-icon')
      text = $(event.target).find('.about')
      text.fadeIn(400)
      icon.fadeOut(300)
    }, ()=>{
      text.fadeOut(300)
      icon.fadeIn(400)
      icon = '';
      text = '';
    })
})();

$('.project-img').hover(function(){
  // debugger;
  let id = event.target.id
  $('.project-ul #' + id).toggle(100)
}, function(){
  let id = event.target.id
  $('.project-ul #' + id).toggle(100)
})

<commit_msg>Add slidetoggle.<commit_after>
function showContact() {
  event.preventDefault();
  $('#contact').slideToggle('fast');
}

$("*").each( function () {
    var $this = $(this);
    if (parseInt($this.css("fontSize")) < 12) {
        $this.css({ "font-size": "12px" });
    }
});

setInterval( ()=> {
  $(window).scroll( () => {
    if($(window).scrollTop() < 100){
      $('.navbar-top').removeClass('navbar-scrolled');
      $('.navbar-top').addClass('navbar');
    } else {
      $('.navbar-top').removeClass('navbar');
      $('.navbar-top').addClass('navbar-scrolled');
    }
  })
}, 300)

const fade = (function(){
  var icon, text;
    $('.list-group-item').hover(() => {
      icon = $(event.target).find('.list-group-item-icon')
      text = $(event.target).find('.about')
      text.fadeIn(400)
      icon.fadeOut(300)
    }, ()=>{
      text.fadeOut(300)
      icon.fadeIn(400)
      icon = '';
      text = '';
    })
})();

$('.project-img').hover(function(){
  // debugger;
  let id = event.target.id
  $('.project-ul #' + id).slideToggle(100)
}, function(){
  let id = event.target.id
  $('.project-ul #' + id).slideToggle(100)
})

<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const path = require('path');

/**
 * Формирует параметры сборки тестовых бандлов
 */
class TestBundler {

    /**
     * @param {Object} config - Настройки плаигна
     * @param {String} config.targetJsonPath - Путь для сохранения результата в JSON
     * @param {String} config.baseBundlePath - Папка, в которой нужно собирать бандлы
     * @param {Array} [config.devEntities=[]] - Дополнительные БЭМ-сущности, которые нужно добавить в декларацию каждого бандла
     * @param {Object} config.defaultBundleConfig - Содержимое по умолчанию
     * @param {String} [config.testTechnology=test.js] - Технология для файлов с тестами
     */
    constructor(config = {}) {
        this.config = config;
    }

    /**
     * Формирует результат для отдельного блока
     * @param {Object} blockData - Информация о блоке
     * @param {Object} blockData.techs - Технологии, в которых реализован блок (ключ - технология, значение - массив путей к файлам)
     * @param {Object} blockData.entities - БЭМ-сущности блока (ключ - ID БЭМ-сущности, значение - объект, аналогичный полю "techs", но для конкретной БЭМ-сущности)
     * @param {String} blockName - Название блока
     * @return {*}
     */
    eachBlock(blockData, blockName) {
        return Object.assign({}, this.config.defaultBundleConfig, {
            block: blockName,
            path: path.join(this.config.baseBundlePath, blockName),
            entities: [].concat(this.config.devEntities || []).concat(Object.keys(blockData.entities)),
            hasTests: !!blockData.techs[this.config.testTechnology || 'test.js']
        });
    }

    /**
     * Формирует общий результат для всех блоков
     * @param {Object[]} data - Массив объектов, полученных из метода "eachBlock"
     */
    allBlocks(data) {
        fs.writeFile(
            this.config.resultPath,
            JSON.stringify(data, null, 4),
            err => { err && console.log(err) }
        );
    }
}

module.exports = TestBundler;
<commit_msg>fix test-bundler params<commit_after>'use strict';

const fs = require('fs');
const path = require('path');

/**
 * Формирует параметры сборки тестовых бандлов
 */
class TestBundler {

    /**
     * @param {Object} config - Настройки плаигна
     * @param {String} config.targetJsonPath - Путь для сохранения результата в JSON
     * @param {String} config.baseBundlePath - Папка, в которой нужно собирать бандлы
     * @param {Array} [config.devEntities=[]] - Дополнительные БЭМ-сущности, которые нужно добавить в декларацию каждого бандла
     * @param {Object} config.defaultBundleConfig - Содержимое по умолчанию
     * @param {String} [config.testTechnology=test.js] - Технология для файлов с тестами
     */
    constructor(config = {}) {
        config.testTechnology = config.testTechnology || 'test.js';
        config.devEntities = [].concat(config.devEntities || []);

        this.config = config;
    }

    /**
     * Формирует результат для отдельного блока
     * @param {Object} blockData - Информация о блоке
     * @param {Object} blockData.techs - Технологии, в которых реализован блок (ключ - технология, значение - массив путей к файлам)
     * @param {Object} blockData.entities - БЭМ-сущности блока (ключ - ID БЭМ-сущности, значение - объект, аналогичный полю "techs", но для конкретной БЭМ-сущности)
     * @param {String} blockName - Название блока
     * @return {*}
     */
    eachBlock(blockData, blockName) {
        return Object.assign({}, this.config.defaultBundleConfig, {
            block: blockName,
            path: path.join(this.config.baseBundlePath, blockName),
            entities: this.config.devEntities.concat(Object.keys(blockData.entities)),
            hasTests: !!blockData.techs[this.config.testTechnology]
        });
    }

    /**
     * Формирует общий результат для всех блоков
     * @param {Object[]} data - Массив объектов, полученных из метода "eachBlock"
     */
    allBlocks(data) {
        fs.writeFile(
            this.config.resultPath,
            JSON.stringify(data, null, 4),
            err => { err && console.log(err) }
        );
    }
}

module.exports = TestBundler;
<|endoftext|>


<commit_before>import React from 'react';
import styled from 'styled-components';
import closeIcon from 'ui/assets/images/close@2x.png';
import settingsIcon from 'ui/assets/images/settings.svg';
import halfScreenIcon from 'ui/assets/images/half-screen.svg';
import fullScreenIcon from 'ui/assets/images/full-screen.svg';
import proIcon from 'ui/assets/images/pro@2x.png';
import helpIcon from 'ui/assets/images/help@2x.png';
import mockedIcon from 'ui/assets/images/mocked@2x.png';
import unmockedIcon from 'ui/assets/images/unmocked@2x.png';
import API from 'api';
import UIState, { UIStateListener } from 'ui/UIState';

const Icon = styled.img`
  height: 16px;
  user-select: none;
`;

const MainActions = styled.div`
  display: flex;
  flex-grow: 1;
  justify-content: flex-end;
  align-items: center;
`;

const TeamSync = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
`;

const Action = styled.div`
  margin-right: 10px;
  cursor: pointer;
`;

const toggleMimic = () => {
  if (API.enabled) {
    API.turnOff();
  } else {
    API.turnOn();
  }

  UIState.update({ mimicEnabled: API.enabled });
};

export const MainControls = ({ closeFullEditor }) => (
  <MainActions>
    <Action>
      <TeamSync>
        Team Sync <Icon src={ proIcon }/>
      </TeamSync>
    </Action>

    <Action>
      Import & Export
    </Action>

    <Action>
      <Icon
        src={ helpIcon }
        alt="Help"/>
    </Action>

    <Action onClick={ toggleMimic }>
      <Icon
        src={ UIState.mimicEnabled ? mockedIcon : unmockedIcon }
        alt={ `Mimic is ${UIState.mimicEnabled ? 'on' : 'off'}` }/>

      Mimic — { UIState.mimicEnabled ? 'On' : 'Off' }
    </Action>

    {
      API.mode !== 'remote' &&
      <Action>
        <Icon
          disabled={ UIState.editorHeight === 'half' }
          src={ halfScreenIcon }
          alt="Half Screen"
          onClick={ () => UIState.update({ editorHeight: 'half' }) }/>
      </Action>
    }

    {
      API.mode !== 'remote' &&
      <Action>
        <Icon
          disabled={ UIState.editorHeight === 'full' }
          src={ fullScreenIcon }
          alt="Full Screen"
          onClick={ () => UIState.update({ editorHeight: 'full' }) }/>
      </Action>
    }

    <Action>
      <Icon src={ settingsIcon } alt="Settings"/>
    </Action>

    <Action>
      <Icon src={ closeIcon } onClick={ () => UIState.update({ viewMode: 'closed' }) }/>
    </Action>
  </MainActions>
);

export default UIStateListener(MainControls);
<commit_msg>help icon opens a link to mimic website<commit_after>import React from 'react';
import styled from 'styled-components';
import closeIcon from 'ui/assets/images/close@2x.png';
import settingsIcon from 'ui/assets/images/settings.svg';
import halfScreenIcon from 'ui/assets/images/half-screen.svg';
import fullScreenIcon from 'ui/assets/images/full-screen.svg';
import proIcon from 'ui/assets/images/pro@2x.png';
import helpIcon from 'ui/assets/images/help@2x.png';
import mockedIcon from 'ui/assets/images/mocked@2x.png';
import unmockedIcon from 'ui/assets/images/unmocked@2x.png';
import API from 'api';
import UIState, { UIStateListener } from 'ui/UIState';

const Icon = styled.img`
  height: 16px;
  user-select: none;
`;

const MainActions = styled.div`
  display: flex;
  flex-grow: 1;
  justify-content: flex-end;
  align-items: center;
`;

const TeamSync = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
`;

const Action = styled.div`
  margin-right: 10px;
  cursor: pointer;
`;

const toggleMimic = () => {
  if (API.enabled) {
    API.turnOff();
  } else {
    API.turnOn();
  }

  UIState.update({ mimicEnabled: API.enabled });
};

export const MainControls = ({ closeFullEditor }) => (
  <MainActions>
    <Action>
      <TeamSync>
        Team Sync <Icon src={ proIcon }/>
      </TeamSync>
    </Action>

    <Action>
      Import & Export
    </Action>

    <Action onClick={ () => window.open('https://mimic.js.org') }>
      <Icon
        src={ helpIcon }
        alt="Help"/>
    </Action>

    <Action onClick={ toggleMimic }>
      <Icon
        src={ UIState.mimicEnabled ? mockedIcon : unmockedIcon }
        alt={ `Mimic is ${UIState.mimicEnabled ? 'on' : 'off'}` }/>

      Mimic — { UIState.mimicEnabled ? 'On' : 'Off' }
    </Action>

    {
      API.mode !== 'remote' &&
      <Action>
        <Icon
          disabled={ UIState.editorHeight === 'half' }
          src={ halfScreenIcon }
          alt="Half Screen"
          onClick={ () => UIState.update({ editorHeight: 'half' }) }/>
      </Action>
    }

    {
      API.mode !== 'remote' &&
      <Action>
        <Icon
          disabled={ UIState.editorHeight === 'full' }
          src={ fullScreenIcon }
          alt="Full Screen"
          onClick={ () => UIState.update({ editorHeight: 'full' }) }/>
      </Action>
    }

    <Action>
      <Icon src={ settingsIcon } alt="Settings"/>
    </Action>

    <Action>
      <Icon src={ closeIcon } onClick={ () => UIState.update({ viewMode: 'closed' }) }/>
    </Action>
  </MainActions>
);

export default UIStateListener(MainControls);
<|endoftext|>


<commit_before><commit_msg>[T] add config for jest for pass test<commit_after>/* global jest fetch */

jest.mock('Linking', () =>
  ({
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    openURL: jest.fn(),
    canOpenURL: jest.fn(),
    getInitialURL: jest.fn(),
  }),
);
<|endoftext|>


<commit_before>var gulp      = require('gulp');
var $         = require('./$');

// shared streams to gulp tasks
var streams = $.streams = {};

//--

var outputCssDir = (
  $.is.release ?
    $.config.paths.dist :
    $.config.paths.build
);

//---

streams.autoprefix = function() {
  return $.autoprefixer( $.config.autoprefixer );
};

//---

streams.less = function() {

  return gulp
    .src( $.config.styles.less.main )
    .pipe( $.if( $.is.debug, $.debug() ) )
    .pipe( $.plumber() )
    .pipe( $.less() )
    .pipe( autoprefix() )
    .pipe( $.insert.prepend( $.config.banner ) )
    .pipe( $.if( $.is.release, $.minifyCss() ) )
    .pipe( gulp.dest( outputCssDir ) )
    .on( 'error', $.onError );

};

streams.sass = function() {

  return gulp
    .src( $.config.styles.sass.main )
    .pipe( $.if( $.is.debug, $.debug() ) )
    .pipe( $.plumber() )
    .pipe( $.sass() )
    .pipe( autoprefix() )
    .pipe( $.insert.prepend( $.config.banner ) )
    .pipe( $.if( $.is.release, $.minifyCss() ) )
    .pipe( gulp.dest( outputCssDir ) )
    .on( 'error', $.onError );

};
<commit_msg>#35 tools shared streams updated<commit_after>var gulp      = require('gulp');
var $         = require('./$');

// shared streams to gulp tasks
var streams = $.streams = {};

//--

var outputCssDir = (
  $.is.release ?
    $.config.paths.dist :
    $.config.paths.build
);

//---

streams.autoprefix = function() {
  return $.autoprefixer( $.config.autoprefixer );
};

//---

streams.less = function() {

  return gulp
    .src( $.config.styles.less.main )
    .pipe( $.if( $.is.debug, $.debug() ) )
    .pipe( $.plumber() )
    .pipe( $.less({ paths: [ $.path.join( $.rootPath, 'src' ) ] }) )
    .pipe( streams.autoprefix() )
    .pipe( $.insert.prepend( $.config.banner ) )
    .pipe( $.if( $.is.release, $.minifyCss() ) )
    .pipe( gulp.dest( $.config.paths.outputDir ) )
    .on( 'error', $.onError );

};

streams.sass = function() {

  return gulp
    .src( $.config.styles.sass.main )
    .pipe( $.if( $.is.debug, $.debug() ) )
    .pipe( $.plumber() )
    .pipe( $.sass() ) // TODO: review
    .pipe( streams.autoprefix() )
    .pipe( $.insert.prepend( $.config.banner ) )
    .pipe( $.if( $.is.release, $.minifyCss() ) )
    .pipe( gulp.dest( $.config.paths.outputDir ) )
    .on( 'error', $.onError );

};
<|endoftext|>


<commit_before>// Inspired from https://github.com/zgreen/lighthouse-circleci-example/blob/master/lighthouse.test.js
const lighthouse = require('lighthouse')
const chromeLauncher = require('chrome-launcher')

const TIME_FOR_LIGHTHOUSE_FULL_TEST = 60000
jest.setTimeout(TIME_FOR_LIGHTHOUSE_FULL_TEST)

const launchChromeAndRunLighthouse = async url => {
  const chrome = await chromeLauncher.launch({ chromeFlags: [] })
  const opts = { chromeFlags: [], port: chrome.port }
  const configJSON = null
  const results = await lighthouse(url, opts, configJSON)
  await chrome.kill()
  return results
}

const buildLighthouseReport = results => {
  const { categories } = results.lhr
  let rows = ''
  const scores = Object.values(categories).map(({ score }) => score * 100)
  const lighthouseScore = scores.reduce((a, b) => a + b, 0) / scores.length

  Object.values(categories).forEach(cat => {
    rows += `| ${cat.title} | ${cat.score * 100} |\n`
  })
  console.log('Total Lighthouse score is : ', lighthouseScore)
  console.log(rows)

  return { lighthouseScore, categories }
}

test('Meaningful first paint score', () =>
  launchChromeAndRunLighthouse('https://recontact-branch.herokuapp.com/')
    .then(buildLighthouseReport)
    .then(report => {
      const { categories, lighthouseScore } = report

      expect(lighthouseScore).toBeGreaterThanOrEqual(75) // 78, 73, 78, 77, 65, 63.8, 61.8, 55.6, 53.4
      expect(categories.performance.score * 100).toBeGreaterThanOrEqual(70) // 72 ,49, 74, 69, 45, 55, 43, 40, 30, 28.99, 26, 25, 15, 14 <=
      expect(categories.pwa.score * 100).toBeGreaterThanOrEqual(52) // 52, 46, 19
      expect(categories.accessibility.score * 100).toBeGreaterThanOrEqual(95) // 95, 73
      expect(categories['best-practices'].score * 100).toBeGreaterThanOrEqual(79) // 80, 79
      expect(categories.seo.score * 100).toBeGreaterThanOrEqual(92) // 92, 82, 80, 80
    }))
<commit_msg>fix(lighthouse): update threshold<commit_after>// Inspired from https://github.com/zgreen/lighthouse-circleci-example/blob/master/lighthouse.test.js
const lighthouse = require('lighthouse')
const chromeLauncher = require('chrome-launcher')

const TIME_FOR_LIGHTHOUSE_FULL_TEST = 60000
jest.setTimeout(TIME_FOR_LIGHTHOUSE_FULL_TEST)

const launchChromeAndRunLighthouse = async url => {
  const chrome = await chromeLauncher.launch({ chromeFlags: [] })
  const opts = { chromeFlags: [], port: chrome.port }
  const configJSON = null
  const results = await lighthouse(url, opts, configJSON)
  await chrome.kill()
  return results
}

const buildLighthouseReport = results => {
  const { categories } = results.lhr
  let rows = ''
  const scores = Object.values(categories).map(({ score }) => score * 100)
  const lighthouseScore = scores.reduce((a, b) => a + b, 0) / scores.length

  Object.values(categories).forEach(cat => {
    rows += `| ${cat.title} | ${cat.score * 100} |\n`
  })
  console.log('Total Lighthouse score is : ', lighthouseScore)
  console.log(rows)

  return { lighthouseScore, categories }
}

test('Meaningful first paint score', () =>
  launchChromeAndRunLighthouse('https://recontact-branch.herokuapp.com/')
    .then(buildLighthouseReport)
    .then(report => {
      const { categories, lighthouseScore } = report

      expect(lighthouseScore).toBeGreaterThanOrEqual(75) // 75 - 78,
      expect(categories.performance.score * 100).toBeGreaterThanOrEqual(70) // 55 - 72
      expect(categories.pwa.score * 100).toBeGreaterThanOrEqual(52) // 52
      expect(categories.accessibility.score * 100).toBeGreaterThanOrEqual(95) // 95
      expect(categories['best-practices'].score * 100).toBeGreaterThanOrEqual(79) // 79
      expect(categories.seo.score * 100).toBeGreaterThanOrEqual(92) // 92
    }))
<|endoftext|>