<commit_before>'use strict';

var commitStreamAdminControllers = angular.module('commitStreamAdminControllers', []);

var isInstanceMode = function(config) {
  if (!config.configMode) return true;
  return config.configMode.type === 'instance';
};

var isDigestMode = function(config) {
  return config.configMode && config.configMode.type === 'digest';
};

var isDigestConfigured = function(config) {
  return config.configMode.configured;
};

commitStreamAdminControllers.controller('InstancesController', [
  '$rootScope',
  '$scope',
  '$http',
  '$q',
  '$location',
  'CommitStreamApi',
  'serviceUrl',
  'configGetUrl',
  'configSaveUrl',
  'persistentOptions',
  function($rootScope, $scope, $http, $q, $location, CommitStreamApi, serviceUrl, configGetUrl, configSaveUrl, persistentOptions) {
    var config;

    $scope.loaderUrl = serviceUrl + '/ajax-loader.gif';

    var loading = true;

    $scope.loading = function() {
      return loading;
    };

    var errorHandler = function(error) {
      loading = false;
      if (error.data && error.data.errors && error.data.errors.length) {
        $scope.error.value = error.data.errors[0];
      } else {
        $scope.error.value = 'There was an unexpected error when processing your request.';
      }
    };

    $scope.error = {
      value: ''
    };

    $scope.errorActive = function() {
      return $scope.error.value !== '';
    };

    CommitStreamApi
      .load()
      .then(function(resources) {
        $rootScope.resources = resources;
        if (!configGetUrl) return {
          data: {
            configMode: {
              type: 'instance',
              digestId: '',
              configured: false,
              enabled: false,
              useGlobalDigestId: false
            },
            serviceUrl: serviceUrl,
            instanceId: '',
            apiKey: '',
            globalDigestId: '',
            configured: false,
            enabled: false
          }
        }
        return $http.get(configGetUrl);
      })
      .then(function(configRes) {
        // TODO handle null case?
        config = configRes.data;
        $rootScope.config = config;

        if (config.configured) {
          persistentOptions.headers.Bearer = config.apiKey;
          return $rootScope.resources.$get('instance', {
            instanceId: config.instanceId
          });
        } else {
          // return $rootScope.resources.$post('instances');
          return false;
        }
      })
      .then(function(instance) {
        if (instance) {
          persistentOptions.headers.Bearer = instance.apiKey; // Ensure apiKey for NEW instance
          $rootScope.instance = instance;

          if (isInstanceMode(config)) {
            if (config.configured) {
              return $rootScope.resources.$get('digest', {
                instanceId: config.instanceId,
                digestId: config.globalDigestId
              });
            } else {
              return instance.$post('digest-create', {}, {
                description: 'Global Repositories List'
              });
            }
          } else if (isDigestMode(config)) {
            if (isDigestConfigured(config)) {
              // return $rootScope.resources.$get('digest', {
              //   instanceId: config.instanceId,
              //   digestId: config.configMode.digestId
              // });
            } else {
              // return instance.$post('digest-create', {}, {
              //   description: 'Repositories List'
              // });
            }
          } else {
            // Don't know what state it's in here, but probably didn't get here naturally, so just return false
            return false;
          }
        }
      })
      .then(function(digest) {
        if (digest) {
          $rootScope.digest = digest;
          // Check if we are in digestMode and need to save
          if (isDigestMode(config) && !isDigestConfigured(config)) {
            //   config.configMode.digestId = digest.digestId;
            //   configDigestModeSave(config.configMode)
            //     .then(function(configModeSaveResult) {
            //       $location.path('/inboxes');
            //     })
            //     .catch(errorHandler);
          } else {
            $location.path('/inboxes');
          }
        } else {
          $location.path('/inboxes');
        }
      })
      .catch(errorHandler);
  }
]);

commitStreamAdminControllers.controller('InboxesController', [
  '$rootScope',
  '$scope',
  '$timeout',
  'serviceUrl',
  'configSaveUrl',
  '$http',
  '$q',
  'prompt',
  '$location',
  'persistentOptions',
  function($rootScope, $scope, $timeout, serviceUrl,
    configSaveUrl, $http, $q, prompt, $location, persistentOptions) {

    $scope.inboxesVisible = function() {
      // Only display when we actually have the config in $scope!
      return $rootScope.config;
    };

    var isCustomDigest = function() {
      return $scope.digestConfig.selection === 'useCustomDigest';
    };

    var createDigest = function() {
      return $rootScope.instance.$post('digest-create', {}, {
        description: 'Repositories List'
      });
    }

    var getDigest = function() {
      return $rootScope.resources.$get('digest', {
        instanceId: $rootScope.config.instanceId,
        digestId: $rootScope.config.configMode.digestId
      });
    }

    // For teamroom settings:
    var configDigestModeSave = function(configMode) {
      if (!configMode.configured) {
        if (configSaveUrl) return $http.post(configSaveUrl, configMode);
        return $q.when(true);
      }
      // TODO: do we even need this below?
      return $q.when(true);
    };

    $scope.magicWorks = function(value) {
      // 'disabled'
      // 'useGlobalDigest'
      // 'useCustomDigest'
      //alert(value);
      if (isCustomDigest()) {
        if (!isDigestConfigured($rootScope.config)) {
          createDigest().then(function(digest) {
            $rootScope.digest = digest;
            $rootScope.config.configMode.digestId = digest.digestId;
            configDigestModeSave($rootScope.config.configMode);
          });
        } else {
          getDigest().then(function(digest) {
            $rootScope.digest = digest;
            inboxesUpdate($rootScope.config.enabled);
          });
          console.log("MEffel configurado!!!!")
        }
      }

    }

    $scope.inboxesVisible2 = function() {
      return $scope.config.configMode.type === 'instance' || $scope.digestConfig.selection !== 'disabled';
    };

    $scope.editAllowed = function() {
      return $scope.config.configMode.type === 'instance' || $scope.digestConfig.selection === 'useCustomDigest';
    };

    $scope.getHeading = function() {
      if ($scope.isInstanceMode()) return 'Setup Global Repositories';
      if ($scope.isDigestMode()) return isCustomDigest() ? 'Setup TeamRoom Repositories' : 'Active Global Repositories';
    };

    if (!$rootScope.config) {
      $location.path('/');
      return;
    }

    $scope.newInbox = {
      url: '',
      name: '',
      family: 'GitHub' // Until we support other systems, hard-code this.
    };

    $scope.serviceUrl = serviceUrl;
    $scope.inboxes = [];

    $scope.enabledState = {
      enabled: $rootScope.config.enabled,
      applying: false,
      onText: 'Enabled',
      offText: 'Disabled'
    };

    $scope.message = {
      value: ''
    };

    $scope.messageActive = function() {
      return $scope.message.value !== '';
    };

    $scope.error = {
      value: ''
    };

    $scope.errorActive = function() {
      return $scope.error.value !== '';
    };

    // NOTE: this is a bit of a hack to remove errors upon network request to clear
    // out the UI prompts
    persistentOptions.transformUrl = function(url) {
      $scope.error.value = '';
      return url;
    };

    $scope.urlPattern = /^https?\:\/\/.{1,}\/.{1,}$/;

    $scope.digestConfig = {
      selection: 'disabled'
    };

    $scope.inboxName = function() {
      if (!$scope.newInbox.url || $scope.newInbox.url.length < 1) return '...';
      var index = $scope.newInbox.url.lastIndexOf('/');
      if (index < 0) return '...';
      if (index === $scope.newInbox.url.length - 1) return '...';
      return $scope.newInbox.url.substr(index + 1);
    };

    var errorHandler = function(error) {
      if (error.data && error.data.errors && error.data.errors.length) {
        $scope.error.value = error.data.errors[0];
      } else {
        $scope.error.value = 'There was an unexpected error when processing your request.';
      }
    };

    var configSave = function(enabled) {
      $rootScope.config.enabled = enabled;

      if (!$rootScope.config.configured) {
        return $rootScope.resources.$post('instances')
          .then(function(instance) {
            persistentOptions.headers.Bearer = instance.apiKey; // Ensure apiKey for NEW instance
            $rootScope.instance = instance;
            return instance.$post('digest-create', {}, {
              description: 'Global Repositories List'
            });
          })
          .then(function(digest) {
            $rootScope.digest = digest;
            $rootScope.config.instanceId = $rootScope.instance.instanceId;
            $rootScope.config.globalDigestId = digest.digestId;
            $rootScope.config.apiKey = $rootScope.instance.apiKey;
            $rootScope.config.configured = true;
            if (configSaveUrl) return $http.post(configSaveUrl, $rootScope.config);
            return $q.when(true);
          });
      } else {
        if (configSaveUrl) return $http.post(configSaveUrl, $rootScope.config);
        return $q.when(true);
      }
    };

    var inboxConfigure = function(inbox) {
      var links = inbox.$links();
      inbox.addCommit = links['add-commit'].href + '?apiKey=' + persistentOptions.headers.Bearer;
      inbox.removeHref = links['self'].href + '?apiKey=' + persistentOptions.headers.Bearer;
    };

    var inboxesGet = function() {
      if ($rootScope.digest) {
        $rootScope.digest.$get('inboxes')
          .then(function(inboxesRes) {
            return inboxesRes.$get('inboxes');
          }).then(function(inboxes) {
            $scope.inboxes.length = 0;
            inboxes.forEach(function(inbox) {
              inboxConfigure(inbox);
              $scope.inboxes.unshift(inbox);
            });
          })
          .catch(errorHandler);
      }
    };

    var inboxesUpdate = function(enabled) {
      if (enabled) {
        $timeout(function() {
          $('.inbox-url').select().focus();
        });
      }
      inboxesGet();
    }

    inboxesUpdate($rootScope.config.enabled);

    $scope.isInstanceMode = function() {
      return isInstanceMode($rootScope.config);
    };

    $scope.isDigestMode = function() {
      return isDigestMode($rootScope.config);
    };

    $scope.enabledChanged = function() {
      $scope.newInbox.url = '';

      var toggle = $('.commitstream-admin .enabled');

      var enabled = toggle.prop('checked');

      $scope.enabledState.applying = true;
      toggle.bootstrapToggle('disable');

      configSave(enabled).then(function(configSaveResult) {
        // TODO need to handle configSaveResult?
        inboxesUpdate(enabled);
      })
        .catch(errorHandler)
        .finally(function() {
          $scope.enabledState.applying = false;
          toggle.bootstrapToggle('enable');
        });
    };

    $scope.applying = function() {
      return $scope.enabledState.applying;
    };

    $scope.overlayVisible = function() {
      return $scope.enabledState.applying || !$rootScope.config.enabled;
    };

    $scope.adjustOverlay = function() {
      var repolistWidth = $('.repos-list').width();
      var repolistHeight = $('.repos-list').height();
      $('.repos-section .overlay').height(repolistHeight);
      $('.repos-section .overlay').width(repolistWidth);
    };

    // A jQuery based way of handling resizing of the window to adjust the overlay
    // when CS is disabled.
    // $(window).resize(function(){
    //   $scope.adjustOverlay();
    // });

    $scope.inboxCreating = false;

    $scope.inboxCreate = function() {
      //TODO: put the first 3 lines after the try in a promise
      try {
        $scope.inboxCreating = true;
        var index = $scope.newInbox.url.lastIndexOf('/');
        $scope.newInbox.name = $scope.newInbox.url.substr(index + 1);

        $rootScope.digest.$post('inbox-create', {}, $scope.newInbox)
          .then(function(inbox) {
            inboxConfigure(inbox);
            $scope.inboxes.unshift(inbox);
            $scope.newInbox.url = '';
            $scope.inboxHighlightTop(inbox.removeHref);
          })
          .catch(errorHandler)
          .finally(function() {
            $scope.inboxCreating = false;
          });
      } catch (e) {
        $scope.inboxCreating = false;
      }
    };

    $scope.inboxRemove = function(inbox) {
      prompt({
        title: 'Remove Repository?',
        message: 'Are you sure you want to remove the repository ' + inbox.name + '?',
        buttons: [{
          label: 'Remove',
          primary: true,
          class: 'action-remove'
        }, {
          label: 'Cancel',
          cancel: true,
          class: 'action-cancel'
        }]
      }).then(function() {
        inbox.$del('self').then(function(result) {
          $scope.message.value = 'Successfully removed repository';
          var index = $scope.inboxes.indexOf(inbox);
          $scope.inboxes.splice(index, 1);
          $timeout(function() {
            $('.commitstream-admin .message').fadeOut('slow', function() {
              $scope.message.value = '';
            });
          }, 4000);
        })
          .catch(errorHandler);
      });
    };

    var inboxHighlight = function(el) {
      if ($rootScope.config.enabled) {
        el.focus();
        el.select();
      }
    };

    $scope.inboxHighlight = function(evt) {
      inboxHighlight(evt.currentTarget);
    };

    $scope.inboxHighlightTop = function() {
      $timeout(function() {
        var el = $($('.commitstream-admin .inbox')[0]);
        inboxHighlight(el);
      }, 0);
    };

  }
]);<commit_msg>S-52697<commit_after>'use strict';

var commitStreamAdminControllers = angular.module('commitStreamAdminControllers', []);

var isInstanceMode = function(config) {
  if (!config.configMode) return true;
  return config.configMode.type === 'instance';
};

var isDigestMode = function(config) {
  return config.configMode && config.configMode.type === 'digest';
};

var isDigestConfigured = function(config) {
  return config.configMode.configured;
};

commitStreamAdminControllers.controller('InstancesController', [
  '$rootScope',
  '$scope',
  '$http',
  '$q',
  '$location',
  'CommitStreamApi',
  'serviceUrl',
  'configGetUrl',
  'configSaveUrl',
  'persistentOptions',
  function($rootScope, $scope, $http, $q, $location, CommitStreamApi, serviceUrl, configGetUrl, configSaveUrl, persistentOptions) {
    var config;

    $scope.loaderUrl = serviceUrl + '/ajax-loader.gif';

    var loading = true;

    $scope.loading = function() {
      return loading;
    };

    var errorHandler = function(error) {
      loading = false;
      if (error.data && error.data.errors && error.data.errors.length) {
        $scope.error.value = error.data.errors[0];
      } else {
        $scope.error.value = 'There was an unexpected error when processing your request.';
      }
    };

    $scope.error = {
      value: ''
    };

    $scope.errorActive = function() {
      return $scope.error.value !== '';
    };

    CommitStreamApi
      .load()
      .then(function(resources) {
        $rootScope.resources = resources;
        if (!configGetUrl) return {
          data: {
            configMode: {
              type: 'instance',
              digestId: '',
              configured: false,
              enabled: false,
              useGlobalDigestId: false
            },
            serviceUrl: serviceUrl,
            instanceId: '',
            apiKey: '',
            globalDigestId: '',
            configured: false,
            enabled: false
          }
        }
        return $http.get(configGetUrl);
      })
      .then(function(configRes) {
        // TODO handle null case?
        config = configRes.data;
        $rootScope.config = config;

        if (config.configured) {
          persistentOptions.headers.Bearer = config.apiKey;
          return $rootScope.resources.$get('instance', {
            instanceId: config.instanceId
          });
        } else {
          // return $rootScope.resources.$post('instances');
          return false;
        }
      })
      .then(function(instance) {
        if (instance) {
          persistentOptions.headers.Bearer = instance.apiKey; // Ensure apiKey for NEW instance
          $rootScope.instance = instance;

          if (isInstanceMode(config)) {
            if (config.configured) {
              return $rootScope.resources.$get('digest', {
                instanceId: config.instanceId,
                digestId: config.globalDigestId
              });
            } else {
              return instance.$post('digest-create', {}, {
                description: 'Global Repositories List'
              });
            }
          } else if (isDigestMode(config)) {
            if (isDigestConfigured(config)) {
              // return $rootScope.resources.$get('digest', {
              //   instanceId: config.instanceId,
              //   digestId: config.configMode.digestId
              // });
            } else {
              // return instance.$post('digest-create', {}, {
              //   description: 'Repositories List'
              // });
            }
          } else {
            // Don't know what state it's in here, but probably didn't get here naturally, so just return false
            return false;
          }
        }
      })
      .then(function(digest) {
        if (digest) {
          $rootScope.digest = digest;
          // Check if we are in digestMode and need to save
          if (isDigestMode(config) && !isDigestConfigured(config)) {
            //   config.configMode.digestId = digest.digestId;
            //   configDigestModeSave(config.configMode)
            //     .then(function(configModeSaveResult) {
            //       $location.path('/inboxes');
            //     })
            //     .catch(errorHandler);
          } else {
            $location.path('/inboxes');
          }
        } else {
          $location.path('/inboxes');
        }
      })
      .catch(errorHandler);
  }
]);

commitStreamAdminControllers.controller('InboxesController', [
  '$rootScope',
  '$scope',
  '$timeout',
  'serviceUrl',
  'configSaveUrl',
  '$http',
  '$q',
  'prompt',
  '$location',
  'persistentOptions',
  function($rootScope, $scope, $timeout, serviceUrl,
    configSaveUrl, $http, $q, prompt, $location, persistentOptions) {

    $scope.inboxesVisible = function() {
      // Only display when we actually have the config in $scope!
      return $rootScope.config;
    };

    var isCustomDigest = function() {
      return $scope.digestConfig.selection === 'useCustomDigest';
    };

    var getDigest = function(config) {
      if (!isDigestConfigured(config)) {
        return $rootScope.instance.$post('digest-create', {}, {
          description: 'Repositories List'
        }).then(function(digest) {
          return {
            digest: digest,
            created: true
          }
        });
      } else {
        return $rootScope.resources.$get('digest', {
          instanceId: $rootScope.config.instanceId,
          digestId: $rootScope.config.configMode.digestId
        }).then(function(digest) {
          return {
            digest: digest,
            created: false
          }
        });
      }
    }

    // For teamroom settings:
    var configDigestModeSave = function(configMode) {

      if (configSaveUrl) return $http.post(configSaveUrl, configMode);
      return $q.when(true);

    };

    $scope.magicWorks = function(value) {
      // 'disabled'
      // 'useGlobalDigest'
      // 'useCustomDigest'
      //alert(value);
      if (isCustomDigest()) {
        getDigest($rootScope.config).then(function(digestResponse) {
          $rootScope.digest = digestResponse.digest;
          $rootScope.config.configMode.digestId = digestResponse.digest.digestId;
          $rootScope.config.configMode.useGlobalDigestId = false;
          $rootScope.config.configMode.enabled = true;
          configDigestModeSave($rootScope.config.configMode);
          if (!digestResponse.created) inboxesUpdate($rootScope.config.enabled);
        });
      }

    }

    $scope.inboxesVisible2 = function() {
      return $scope.config.configMode.type === 'instance' || $scope.digestConfig.selection !== 'disabled';
    };

    $scope.editAllowed = function() {
      return $scope.config.configMode.type === 'instance' || $scope.digestConfig.selection === 'useCustomDigest';
    };

    $scope.getHeading = function() {
      if ($scope.isInstanceMode()) return 'Setup Global Repositories';
      if ($scope.isDigestMode()) return isCustomDigest() ? 'Setup TeamRoom Repositories' : 'Active Global Repositories';
    };

    if (!$rootScope.config) {
      $location.path('/');
      return;
    }

    $scope.newInbox = {
      url: '',
      name: '',
      family: 'GitHub' // Until we support other systems, hard-code this.
    };

    $scope.serviceUrl = serviceUrl;
    $scope.inboxes = [];

    $scope.enabledState = {
      enabled: $rootScope.config.enabled,
      applying: false,
      onText: 'Enabled',
      offText: 'Disabled'
    };

    $scope.message = {
      value: ''
    };

    $scope.messageActive = function() {
      return $scope.message.value !== '';
    };

    $scope.error = {
      value: ''
    };

    $scope.errorActive = function() {
      return $scope.error.value !== '';
    };

    // NOTE: this is a bit of a hack to remove errors upon network request to clear
    // out the UI prompts
    persistentOptions.transformUrl = function(url) {
      $scope.error.value = '';
      return url;
    };

    $scope.urlPattern = /^https?\:\/\/.{1,}\/.{1,}$/;

    $scope.digestConfig = {
      selection: 'disabled'
    };

    $scope.inboxName = function() {
      if (!$scope.newInbox.url || $scope.newInbox.url.length < 1) return '...';
      var index = $scope.newInbox.url.lastIndexOf('/');
      if (index < 0) return '...';
      if (index === $scope.newInbox.url.length - 1) return '...';
      return $scope.newInbox.url.substr(index + 1);
    };

    var errorHandler = function(error) {
      if (error.data && error.data.errors && error.data.errors.length) {
        $scope.error.value = error.data.errors[0];
      } else {
        $scope.error.value = 'There was an unexpected error when processing your request.';
      }
    };

    var configSave = function(enabled) {
      $rootScope.config.enabled = enabled;

      if (!$rootScope.config.configured) {
        return $rootScope.resources.$post('instances')
          .then(function(instance) {
            persistentOptions.headers.Bearer = instance.apiKey; // Ensure apiKey for NEW instance
            $rootScope.instance = instance;
            return instance.$post('digest-create', {}, {
              description: 'Global Repositories List'
            });
          })
          .then(function(digest) {
            $rootScope.digest = digest;
            $rootScope.config.instanceId = $rootScope.instance.instanceId;
            $rootScope.config.globalDigestId = digest.digestId;
            $rootScope.config.apiKey = $rootScope.instance.apiKey;
            $rootScope.config.configured = true;
            if (configSaveUrl) return $http.post(configSaveUrl, $rootScope.config);
            return $q.when(true);
          });
      } else {
        if (configSaveUrl) return $http.post(configSaveUrl, $rootScope.config);
        return $q.when(true);
      }
    };

    var inboxConfigure = function(inbox) {
      var links = inbox.$links();
      inbox.addCommit = links['add-commit'].href + '?apiKey=' + persistentOptions.headers.Bearer;
      inbox.removeHref = links['self'].href + '?apiKey=' + persistentOptions.headers.Bearer;
    };

    var inboxesGet = function() {
      if ($rootScope.digest) {
        $rootScope.digest.$get('inboxes')
          .then(function(inboxesRes) {
            return inboxesRes.$get('inboxes');
          }).then(function(inboxes) {
            $scope.inboxes.length = 0;
            inboxes.forEach(function(inbox) {
              inboxConfigure(inbox);
              $scope.inboxes.unshift(inbox);
            });
          })
          .catch(errorHandler);
      }
    };

    var inboxesUpdate = function(enabled) {
      if (enabled) {
        $timeout(function() {
          $('.inbox-url').select().focus();
        });
      }
      inboxesGet();
    }

    inboxesUpdate($rootScope.config.enabled);

    $scope.isInstanceMode = function() {
      return isInstanceMode($rootScope.config);
    };

    $scope.isDigestMode = function() {
      return isDigestMode($rootScope.config);
    };

    $scope.enabledChanged = function() {
      $scope.newInbox.url = '';

      var toggle = $('.commitstream-admin .enabled');

      var enabled = toggle.prop('checked');

      $scope.enabledState.applying = true;
      toggle.bootstrapToggle('disable');

      configSave(enabled).then(function(configSaveResult) {
        // TODO need to handle configSaveResult?
        inboxesUpdate(enabled);
      })
        .catch(errorHandler)
        .finally(function() {
          $scope.enabledState.applying = false;
          toggle.bootstrapToggle('enable');
        });
    };

    $scope.applying = function() {
      return $scope.enabledState.applying;
    };

    $scope.overlayVisible = function() {
      return $scope.enabledState.applying || !$rootScope.config.enabled;
    };

    $scope.adjustOverlay = function() {
      var repolistWidth = $('.repos-list').width();
      var repolistHeight = $('.repos-list').height();
      $('.repos-section .overlay').height(repolistHeight);
      $('.repos-section .overlay').width(repolistWidth);
    };

    // A jQuery based way of handling resizing of the window to adjust the overlay
    // when CS is disabled.
    // $(window).resize(function(){
    //   $scope.adjustOverlay();
    // });

    $scope.inboxCreating = false;

    $scope.inboxCreate = function() {
      //TODO: put the first 3 lines after the try in a promise
      try {
        $scope.inboxCreating = true;
        var index = $scope.newInbox.url.lastIndexOf('/');
        $scope.newInbox.name = $scope.newInbox.url.substr(index + 1);

        $rootScope.digest.$post('inbox-create', {}, $scope.newInbox)
          .then(function(inbox) {
            inboxConfigure(inbox);
            $scope.inboxes.unshift(inbox);
            $scope.newInbox.url = '';
            $scope.inboxHighlightTop(inbox.removeHref);
          })
          .catch(errorHandler)
          .finally(function() {
            $scope.inboxCreating = false;
          });
      } catch (e) {
        $scope.inboxCreating = false;
      }
    };

    $scope.inboxRemove = function(inbox) {
      prompt({
        title: 'Remove Repository?',
        message: 'Are you sure you want to remove the repository ' + inbox.name + '?',
        buttons: [{
          label: 'Remove',
          primary: true,
          class: 'action-remove'
        }, {
          label: 'Cancel',
          cancel: true,
          class: 'action-cancel'
        }]
      }).then(function() {
        inbox.$del('self').then(function(result) {
          $scope.message.value = 'Successfully removed repository';
          var index = $scope.inboxes.indexOf(inbox);
          $scope.inboxes.splice(index, 1);
          $timeout(function() {
            $('.commitstream-admin .message').fadeOut('slow', function() {
              $scope.message.value = '';
            });
          }, 4000);
        })
          .catch(errorHandler);
      });
    };

    var inboxHighlight = function(el) {
      if ($rootScope.config.enabled) {
        el.focus();
        el.select();
      }
    };

    $scope.inboxHighlight = function(evt) {
      inboxHighlight(evt.currentTarget);
    };

    $scope.inboxHighlightTop = function() {
      $timeout(function() {
        var el = $($('.commitstream-admin .inbox')[0]);
        inboxHighlight(el);
      }, 0);
    };

  }
]);<|endoftext|>


<commit_before>import _ from 'lodash';
import events from 'events';
import {
    GRBL_MODAL_GROUPS
} from '../../constants';

class GrblLineParser {
    parse(line) {
        const parsers = [
            GrblLineParserResultStatus,
            GrblLineParserResultOk,
            GrblLineParserResultError,
            GrblLineParserResultAlarm,
            GrblLineParserResultParserState,
            GrblLineParserResultParameters,
            GrblLineParserResultFeedback,
            GrblLineParserResultSettings,
            GrblLineParserResultStartup
        ];

        for (let parser of parsers) {
            const result = parser.parse(line);
            if (result) {
                _.set(result, 'payload.raw', line);
                return result;
            }
        }

        return {
            type: null,
            payload: {
                raw: line
            }
        };
    }
}

//https://github.com/grbl/grbl/blob/master/grbl/report.c
class GrblLineParserResultStatus {
    // <Idle>
    // <Idle,MPos:5.529,0.560,7.000,WPos:1.529,-5.440,-0.000>
    // <Idle,MPos:5.529,0.560,7.000,0.000,WPos:1.529,-5.440,-0.000,0.000>
    // <Idle,MPos:0.000,0.000,0.000,WPos:0.000,0.000,0.000,Buf:0,RX:0,Lim:000>
    // <Idle,MPos:0.000,0.000,0.000,WPos:0.000,0.000,0.000,Buf:0,RX:0,Ln:0,F:0.>
    static parse(line) {
        const r = line.match(/^<(.+)>$/);
        if (!r) {
            return null;
        }

        const payload = {};
        const pattern = /[a-zA-Z]+(:[0-9\.\-]+(,[0-9\.\-]+){0,5})?/g;
        let params = r[1].match(pattern);
        let result = {};

        // Active State
        payload.activeState = params.shift();

        for (let param of params) {
            const nv = param.match(/^(.+):(.+)/);
            if (nv) {
                let type = nv[1];
                let value = nv[2].split(',');
                result[type] = value;
            }
        }

        { // Machine Position
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const mPos = _.get(result, 'MPos') || ['0.000', '0.000', '0.000']; // Defaults to [x, y, z]
            payload.machinePosition = {};
            for (let i = 0; i < mPos.length; ++i) {
                payload.machinePosition[axes[i]] = mPos[i];
            }
        }

        { // Work Position
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const wPos = _.get(result, 'WPos') || ['0.000', '0.000', '0.000']; // Defaults to [x, y, z]
            payload.workPosition = {};
            for (let i = 0; i < wPos.length; ++i) {
                payload.workPosition[axes[i]] = wPos[i];
            }
        }

        { // Planner Buffer
            if (result.hasOwnProperty('Buf')) {
                payload.plannerBuffer = _.get(result, 'Buf[0]');
            }
        }

        { // RX Buffer
            if (result.hasOwnProperty('RX')) {
                payload.rxBuffer = _.get(result, 'RX[0]');
            }
        }

        { // Line Number
            if (result.hasOwnProperty('Ln')) {
                payload.lineNumber = _.get(result, 'Ln[0]');
            }
        }

        { // Realtime Rate
            if (result.hasOwnProperty('F')) {
                payload.realtimeRate = _.get(result, 'F[0]');
            }
        }

        { // Limit Pins
            if (result.hasOwnProperty('Lim')) {
                payload.limitPins = _.get(result, 'Lim[0]');
            }
        }

        return {
            type: GrblLineParserResultStatus,
            payload: payload
        };
    }
}

class GrblLineParserResultOk {
    static parse(line) {
        const r = line.match(/^ok$/);
        if (!r) {
            return null;
        }

        const payload = {};

        return {
            type: GrblLineParserResultOk,
            payload: payload
        };
    }
}

// https://github.com/grbl/grbl/wiki/Interfacing-with-Grbl#grbl-response-meanings
class GrblLineParserResultError {
    static parse(line) {
        const r = line.match(/^error:\s*(.+)$/);
        if (!r) {
            return null;
        }

        const payload = {
            message: r[1]
        };

        return {
            type: GrblLineParserResultError,
            payload: payload
        };
    }
}

// https://github.com/grbl/grbl/wiki/Interfacing-with-Grbl#alarms
class GrblLineParserResultAlarm {
    static parse(line) {
        const r = line.match(/^ALARM:\s*(.+)$/);
        if (!r) {
            return null;
        }

        const payload = {
            message: r[1]
        };

        return {
            type: GrblLineParserResultAlarm,
            payload: payload
        };
    }
}

class GrblLineParserResultParserState {
    static parse(line) {
        // [G38.2 G54 G17 G21 G91 G94 M0 M5 M9 T0 F20. S0.]
        const r = line.match(/^\[((?:[a-zA-Z][0-9]+(?:\.[0-9]*)?\s*)+)\]$/);
        if (!r) {
            return null;
        }

        const payload = {};
        const words = _(r[1].split(' '))
            .compact()
            .map((word) => {
                return _.trim(word);
            })
            .value();

        words.forEach((word) => {
            // Gx, Mx
            if (word.indexOf('G') === 0 || word.indexOf('M') === 0) {
                let r = _.find(GRBL_MODAL_GROUPS, (group) => {
                    return _.includes(group.modes, word);
                });

                if (r) {
                    _.set(payload, 'modal.' + r.group, word);
                }
            }

            // T: tool number
            if (word.indexOf('T') === 0) {
                _.set(payload, 'tool', word.substring(1));
            }

            // F: feed rate
            if (word.indexOf('F') === 0) {
                _.set(payload, 'feedrate', word.substring(1));
            }

            // S: spindle speed
            if (word.indexOf('S') === 0) {
                _.set(payload, 'spindle', word.substring(1));
            }
        });

        return {
            type: GrblLineParserResultParserState,
            payload: payload
        };
    }
}

class GrblLineParserResultParameters {
    static parse(line) {
        const r = line.match(/^\[(G54|G55|G56|G57|G58|G59|G28|G30|G92|TLO|PRB):(.+)\]$/);
        if (!r) {
            return null;
        }

        const name = r[1];
        const value = r[2];
        const payload = {
            name: name,
            value: ''
        };

        if (_.includes(['G54', 'G55', 'G56', 'G57', 'G58', 'G59', 'G28', 'G30', 'G92'], name)) {
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const list = value.split(',');
            payload.value = {};
            for (let i = 0; i < list.length; ++i) {
                payload.value[axes[i]] = list[i];
            }
        }

        // [TLO:0.000]
        if (name === 'TLO') {
            payload.value = value;
        }

        // [PRB:0.000,0.000,1.492:1]
        if (name === 'PRB') {
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const [str, result] = value.split(':');
            const list = str.split(',');
            payload.value = {};
            payload.value.result = Number(result);
            for (let i = 0; i < list.length; ++i) {
                payload.value[axes[i]] = list[i];
            }
        }

        return {
            type: GrblLineParserResultParameters,
            payload: payload
        };
    }
}

// https://github.com/grbl/grbl/wiki/Interfacing-with-Grbl#feedback-messages
class GrblLineParserResultFeedback {
    static parse(line) {
        const r = line.match(/^\[(.+)\]$/);
        if (!r) {
            return null;
        }

        const payload = {
            message: r[1]
        };

        return {
            type: GrblLineParserResultFeedback,
            payload: payload
        };
    }
}

class GrblLineParserResultSettings {
    static parse(line) {
        const r = line.match(/^(\$[^=]+)=([^ ]*)\s*(.*)/);
        if (!r) {
            return null;
        }

        const payload = {
            name: r[1],
            value: r[2],
            message: _.trim(r[3], '()')
        };

        return {
            type: GrblLineParserResultSettings,
            payload: payload
        };
    }
}

class GrblLineParserResultStartup {
    // Grbl 0.9j ['$' for help]
    static parse(line) {
        const r = line.match(/^Grbl\s*(\d+\.\d+[a-zA-Z]?)/);
        if (!r) {
            return null;
        }

        const payload = {
            version: r[1]
        };

        return {
            type: GrblLineParserResultStartup,
            payload: payload
        };
    }
}

class Grbl extends events.EventEmitter {
    state = {
        status: {
            activeState: '',
            machinePosition: {
                x: '0.000',
                y: '0.000',
                z: '0.000'
            },
            workPosition: {
                x: '0.000',
                y: '0.000',
                z: '0.000'
            }
        },
        parserstate: {
            modal: {
                motion: 'G0', // G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
                coordinate: 'G54', // G54, G55, G56, G57, G58, G59
                plane: 'G17', // G17: xy-plane, G18: xz-plane, G19: yz-plane
                units: 'G21', // G20: Inches, G21: Millimeters
                distance: 'G90', // G90: Absolute, G91: Relative
                feedrate: 'G94', // G93: Inverse Time Mode, G94: Units Per Minutes
                program: 'M0',
                spindle: 'M5',
                coolant: 'M9'
            },
            tool: '',
            feedrate: '',
            spindle: ''
        },
        parameters: {
        },
        settings: {
        }
    };
    parser = new GrblLineParser();

    parse(data) {
        data = ('' + data).replace(/\s+$/, '');
        if (!data) {
            return;
        }

        this.emit('raw', { raw: data });

        const result = this.parser.parse(data) || {};
        const { type, payload } = result;

        if (type === GrblLineParserResultStatus) {
            if (!_.isEqual(this.state.status, payload)) {
                this.state = { // enforce state change
                    ...this.state,
                    status: {
                        ...this.state.status,
                        ...payload
                    }
                };
            }
            this.emit('status', payload);
            return;
        }
        if (type === GrblLineParserResultOk) {
            this.emit('ok', payload);
            return;
        }
        if (type === GrblLineParserResultError) {
            this.emit('error', payload);
            return;
        }
        if (type === GrblLineParserResultAlarm) {
            this.emit('alarm', payload);
            return;
        }
        if (type === GrblLineParserResultParserState) {
            if (!_.isEqual(this.state.parserstate, payload)) {
                this.state = { // enforce state change
                    ...this.state,
                    parserstate: {
                        ...this.state.parserstate,
                        ...payload
                    }
                };
            }
            this.emit('parserstate', payload);
            return;
        }
        if (type === GrblLineParserResultParameters) {
            this.emit('parameters', payload);
            const { name, value } = payload;
            const { parameters } = this.state;
            parameters[name] = value;
            this.state = { // enforce state change
                ...this.state,
                parameters: parameters
            };
            return;
        }
        if (type === GrblLineParserResultFeedback) {
            this.emit('feedback', payload);
            return;
        }
        if (type === GrblLineParserResultSettings) {
            this.emit('settings', payload);
            const { name, value } = payload;
            const { settings } = this.state;
            settings[name] = value;
            this.state = { // enforce state change
                ...this.state,
                settings: settings
            };
            return;
        }
        if (type === GrblLineParserResultStartup) {
            this.emit('startup', payload);
            return;
        }
        if (data.length > 0) {
            this.emit('others', payload);
            return;
        }
    }
}

export {
    GrblLineParser,
    GrblLineParserResultStatus,
    GrblLineParserResultOk,
    GrblLineParserResultError,
    GrblLineParserResultAlarm,
    GrblLineParserResultParserState,
    GrblLineParserResultParameters,
    GrblLineParserResultFeedback,
    GrblLineParserResultSettings,
    GrblLineParserResultStartup
};
export default Grbl;
<commit_msg>Update Grbl.js<commit_after>import _ from 'lodash';
import events from 'events';
import {
    GRBL_MODAL_GROUPS
} from './constants';

class GrblLineParser {
    parse(line) {
        const parsers = [
            GrblLineParserResultStatus,
            GrblLineParserResultOk,
            GrblLineParserResultError,
            GrblLineParserResultAlarm,
            GrblLineParserResultParserState,
            GrblLineParserResultParameters,
            GrblLineParserResultFeedback,
            GrblLineParserResultSettings,
            GrblLineParserResultStartup
        ];

        for (let parser of parsers) {
            const result = parser.parse(line);
            if (result) {
                _.set(result, 'payload.raw', line);
                return result;
            }
        }

        return {
            type: null,
            payload: {
                raw: line
            }
        };
    }
}

//https://github.com/grbl/grbl/blob/master/grbl/report.c
class GrblLineParserResultStatus {
    // <Idle>
    // <Idle,MPos:5.529,0.560,7.000,WPos:1.529,-5.440,-0.000>
    // <Idle,MPos:5.529,0.560,7.000,0.000,WPos:1.529,-5.440,-0.000,0.000>
    // <Idle,MPos:0.000,0.000,0.000,WPos:0.000,0.000,0.000,Buf:0,RX:0,Lim:000>
    // <Idle,MPos:0.000,0.000,0.000,WPos:0.000,0.000,0.000,Buf:0,RX:0,Ln:0,F:0.>
    static parse(line) {
        const r = line.match(/^<(.+)>$/);
        if (!r) {
            return null;
        }

        const payload = {};
        const pattern = /[a-zA-Z]+(:[0-9\.\-]+(,[0-9\.\-]+){0,5})?/g;
        let params = r[1].match(pattern);
        let result = {};

        // Active State
        payload.activeState = params.shift();

        for (let param of params) {
            const nv = param.match(/^(.+):(.+)/);
            if (nv) {
                let type = nv[1];
                let value = nv[2].split(',');
                result[type] = value;
            }
        }

        { // Machine Position
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const mPos = _.get(result, 'MPos') || ['0.000', '0.000', '0.000']; // Defaults to [x, y, z]
            payload.machinePosition = {};
            for (let i = 0; i < mPos.length; ++i) {
                payload.machinePosition[axes[i]] = mPos[i];
            }
        }

        { // Work Position
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const wPos = _.get(result, 'WPos') || ['0.000', '0.000', '0.000']; // Defaults to [x, y, z]
            payload.workPosition = {};
            for (let i = 0; i < wPos.length; ++i) {
                payload.workPosition[axes[i]] = wPos[i];
            }
        }

        { // Planner Buffer
            if (result.hasOwnProperty('Buf')) {
                payload.plannerBuffer = _.get(result, 'Buf[0]');
            }
        }

        { // RX Buffer
            if (result.hasOwnProperty('RX')) {
                payload.rxBuffer = _.get(result, 'RX[0]');
            }
        }

        { // Line Number
            if (result.hasOwnProperty('Ln')) {
                payload.lineNumber = _.get(result, 'Ln[0]');
            }
        }

        { // Realtime Rate
            if (result.hasOwnProperty('F')) {
                payload.realtimeRate = _.get(result, 'F[0]');
            }
        }

        { // Limit Pins
            if (result.hasOwnProperty('Lim')) {
                payload.limitPins = _.get(result, 'Lim[0]');
            }
        }

        return {
            type: GrblLineParserResultStatus,
            payload: payload
        };
    }
}

class GrblLineParserResultOk {
    static parse(line) {
        const r = line.match(/^ok$/);
        if (!r) {
            return null;
        }

        const payload = {};

        return {
            type: GrblLineParserResultOk,
            payload: payload
        };
    }
}

// https://github.com/grbl/grbl/wiki/Interfacing-with-Grbl#grbl-response-meanings
class GrblLineParserResultError {
    static parse(line) {
        const r = line.match(/^error:\s*(.+)$/);
        if (!r) {
            return null;
        }

        const payload = {
            message: r[1]
        };

        return {
            type: GrblLineParserResultError,
            payload: payload
        };
    }
}

// https://github.com/grbl/grbl/wiki/Interfacing-with-Grbl#alarms
class GrblLineParserResultAlarm {
    static parse(line) {
        const r = line.match(/^ALARM:\s*(.+)$/);
        if (!r) {
            return null;
        }

        const payload = {
            message: r[1]
        };

        return {
            type: GrblLineParserResultAlarm,
            payload: payload
        };
    }
}

class GrblLineParserResultParserState {
    static parse(line) {
        // [G38.2 G54 G17 G21 G91 G94 M0 M5 M9 T0 F20. S0.]
        const r = line.match(/^\[((?:[a-zA-Z][0-9]+(?:\.[0-9]*)?\s*)+)\]$/);
        if (!r) {
            return null;
        }

        const payload = {};
        const words = _(r[1].split(' '))
            .compact()
            .map((word) => {
                return _.trim(word);
            })
            .value();

        words.forEach((word) => {
            // Gx, Mx
            if (word.indexOf('G') === 0 || word.indexOf('M') === 0) {
                let r = _.find(GRBL_MODAL_GROUPS, (group) => {
                    return _.includes(group.modes, word);
                });

                if (r) {
                    _.set(payload, 'modal.' + r.group, word);
                }
            }

            // T: tool number
            if (word.indexOf('T') === 0) {
                _.set(payload, 'tool', word.substring(1));
            }

            // F: feed rate
            if (word.indexOf('F') === 0) {
                _.set(payload, 'feedrate', word.substring(1));
            }

            // S: spindle speed
            if (word.indexOf('S') === 0) {
                _.set(payload, 'spindle', word.substring(1));
            }
        });

        return {
            type: GrblLineParserResultParserState,
            payload: payload
        };
    }
}

class GrblLineParserResultParameters {
    static parse(line) {
        const r = line.match(/^\[(G54|G55|G56|G57|G58|G59|G28|G30|G92|TLO|PRB):(.+)\]$/);
        if (!r) {
            return null;
        }

        const name = r[1];
        const value = r[2];
        const payload = {
            name: name,
            value: ''
        };

        if (_.includes(['G54', 'G55', 'G56', 'G57', 'G58', 'G59', 'G28', 'G30', 'G92'], name)) {
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const list = value.split(',');
            payload.value = {};
            for (let i = 0; i < list.length; ++i) {
                payload.value[axes[i]] = list[i];
            }
        }

        // [TLO:0.000]
        if (name === 'TLO') {
            payload.value = value;
        }

        // [PRB:0.000,0.000,1.492:1]
        if (name === 'PRB') {
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const [str, result] = value.split(':');
            const list = str.split(',');
            payload.value = {};
            payload.value.result = Number(result);
            for (let i = 0; i < list.length; ++i) {
                payload.value[axes[i]] = list[i];
            }
        }

        return {
            type: GrblLineParserResultParameters,
            payload: payload
        };
    }
}

// https://github.com/grbl/grbl/wiki/Interfacing-with-Grbl#feedback-messages
class GrblLineParserResultFeedback {
    static parse(line) {
        const r = line.match(/^\[(.+)\]$/);
        if (!r) {
            return null;
        }

        const payload = {
            message: r[1]
        };

        return {
            type: GrblLineParserResultFeedback,
            payload: payload
        };
    }
}

class GrblLineParserResultSettings {
    static parse(line) {
        const r = line.match(/^(\$[^=]+)=([^ ]*)\s*(.*)/);
        if (!r) {
            return null;
        }

        const payload = {
            name: r[1],
            value: r[2],
            message: _.trim(r[3], '()')
        };

        return {
            type: GrblLineParserResultSettings,
            payload: payload
        };
    }
}

class GrblLineParserResultStartup {
    // Grbl 0.9j ['$' for help]
    static parse(line) {
        const r = line.match(/^Grbl\s*(\d+\.\d+[a-zA-Z]?)/);
        if (!r) {
            return null;
        }

        const payload = {
            version: r[1]
        };

        return {
            type: GrblLineParserResultStartup,
            payload: payload
        };
    }
}

class Grbl extends events.EventEmitter {
    state = {
        status: {
            activeState: '',
            machinePosition: {
                x: '0.000',
                y: '0.000',
                z: '0.000'
            },
            workPosition: {
                x: '0.000',
                y: '0.000',
                z: '0.000'
            }
        },
        parserstate: {
            modal: {
                motion: 'G0', // G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
                coordinate: 'G54', // G54, G55, G56, G57, G58, G59
                plane: 'G17', // G17: xy-plane, G18: xz-plane, G19: yz-plane
                units: 'G21', // G20: Inches, G21: Millimeters
                distance: 'G90', // G90: Absolute, G91: Relative
                feedrate: 'G94', // G93: Inverse Time Mode, G94: Units Per Minutes
                program: 'M0',
                spindle: 'M5',
                coolant: 'M9'
            },
            tool: '',
            feedrate: '',
            spindle: ''
        },
        parameters: {
        },
        settings: {
        }
    };
    parser = new GrblLineParser();

    parse(data) {
        data = ('' + data).replace(/\s+$/, '');
        if (!data) {
            return;
        }

        this.emit('raw', { raw: data });

        const result = this.parser.parse(data) || {};
        const { type, payload } = result;

        if (type === GrblLineParserResultStatus) {
            if (!_.isEqual(this.state.status, payload)) {
                this.state = { // enforce state change
                    ...this.state,
                    status: {
                        ...this.state.status,
                        ...payload
                    }
                };
            }
            this.emit('status', payload);
            return;
        }
        if (type === GrblLineParserResultOk) {
            this.emit('ok', payload);
            return;
        }
        if (type === GrblLineParserResultError) {
            this.emit('error', payload);
            return;
        }
        if (type === GrblLineParserResultAlarm) {
            this.emit('alarm', payload);
            return;
        }
        if (type === GrblLineParserResultParserState) {
            if (!_.isEqual(this.state.parserstate, payload)) {
                this.state = { // enforce state change
                    ...this.state,
                    parserstate: {
                        ...this.state.parserstate,
                        ...payload
                    }
                };
            }
            this.emit('parserstate', payload);
            return;
        }
        if (type === GrblLineParserResultParameters) {
            this.emit('parameters', payload);
            const { name, value } = payload;
            const { parameters } = this.state;
            parameters[name] = value;
            this.state = { // enforce state change
                ...this.state,
                parameters: parameters
            };
            return;
        }
        if (type === GrblLineParserResultFeedback) {
            this.emit('feedback', payload);
            return;
        }
        if (type === GrblLineParserResultSettings) {
            this.emit('settings', payload);
            const { name, value } = payload;
            const { settings } = this.state;
            settings[name] = value;
            this.state = { // enforce state change
                ...this.state,
                settings: settings
            };
            return;
        }
        if (type === GrblLineParserResultStartup) {
            this.emit('startup', payload);
            return;
        }
        if (data.length > 0) {
            this.emit('others', payload);
            return;
        }
    }
}

export {
    GrblLineParser,
    GrblLineParserResultStatus,
    GrblLineParserResultOk,
    GrblLineParserResultError,
    GrblLineParserResultAlarm,
    GrblLineParserResultParserState,
    GrblLineParserResultParameters,
    GrblLineParserResultFeedback,
    GrblLineParserResultSettings,
    GrblLineParserResultStartup
};
export default Grbl;
<|endoftext|>


<commit_before>import _ from 'lodash';
import events from 'events';
import settings from '../../config/settings';
import {
    GRBL_ACTIVE_STATES,
    GRBL_MODAL_GROUPS
} from './constants';

class GrblLineParser {
    parse(line) {
        const parsers = [
            GrblLineParserResultStatus,
            GrblLineParserResultOk,
            GrblLineParserResultError,
            GrblLineParserResultGCodeModes,
            GrblLineParserResultStartup
        ];

        for (let parser of parsers) {
            const result = parser.parse(line);
            if (result) {
                return result;
            }
        }

        return null;
    }
}

class GrblLineParserResult {
    raw = '';

    constructor(raw) {
        this.raw = raw;
    }
    toObject() {
        const ret = { ...this };
        return ret;
    }
}

class GrblLineParserResultStatus extends GrblLineParserResult {
    // <Idle>
    // <Idle,MPos:5.529,0.560,7.000,WPos:1.529,-5.440,-0.000>
    // <Idle,MPos:5.529,0.560,7.000,0.000,WPos:1.529,-5.440,-0.000,0.000>
    // <Idle,MPos:0.000,0.000,0.000,WPos:0.000,0.000,0.000,Buf:0,RX:0,Lim:000>
    // <Idle,MPos:0.000,0.000,0.000,WPos:0.000,0.000,0.000,Buf:0,RX:0,Ln:0,F:0.>
    static parse(line) {
        const r = line.match(/^<(.+)>$/);
        if (!r) {
            return null;
        }

        // See https://github.com/grbl/grbl/blob/master/grbl/report.c
        const ret = new GrblLineParserResultStatus(line);
        const pattern = /[a-zA-Z]+(:([0-9\.\-]+(,[0-9\.\-]+){1,5})|:([0-9\.\-]+))?/g;
        let params = r[1].match(pattern);
        let result = {};

        // Active State
        ret.activeState = params.shift();

        for (let param of params) {
            const nv = param.match(/^(.+):(.+)/);
            if (nv) {
                let type = nv[1];
                let value = nv[2].split(',');
                result[type] = value;
            }
        }

        { // Machine Position
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const mPos = _.get(result, 'MPos') || ['0.000', '0.000', '0.000']; // Defaults to [x, y, z]
            ret.machinePosition = {};
            for (let i = 0; i < mPos.length; ++i) {
                ret.machinePosition[axes[i]] = mPos[i];
            }
        }

        { // Work Position
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const wPos = _.get(result, 'WPos') || ['0.000', '0.000', '0.000']; // Defaults to [x, y, z]
            ret.workPosition = {};
            for (let i = 0; i < wPos.length; ++i) {
                ret.workPosition[axes[i]] = wPos[i];
            }
        }

        { // Planner Buffer
            if (result.hasOwnProperty('Buf')) {
                ret.plannerBuffer = _.get(result, 'Buf[0]');
            }
        }

        { // RX Buffer
            if (result.hasOwnProperty('RX')) {
                ret.rxBuffer = _.get(result, 'RX[0]');
            }
        }

        { // Line Number
            if (result.hasOwnProperty('Ln')) {
                ret.lineNumber = _.get(result, 'Ln[0]');
            }
        }

        { // Realtime Rate
            if (result.hasOwnProperty('F')) {
                ret.realtimeRate = _.get(result, 'F[0]');
            }
        }

        { // Limit Pins
            if (result.hasOwnProperty('Lim')) {
                ret.limitPins = _.get(result, 'Lim[0]');
            }
        }

        return ret;
    }
}

class GrblLineParserResultOk extends GrblLineParserResult {
    static parse(line) {
        const r = line.match(/^ok$/);
        if (!r) {
            return null;
        }

        const ret = new GrblLineParserResultOk(line);
        return ret;
    }
}

class GrblLineParserResultError extends GrblLineParserResult {
    static parse(line) {
        const r = line.match(/^error:\s*(.+)$/);
        if (!r) {
            return null;
        }

        const ret = new GrblLineParserResultError(line);
        ret.message = r[1];
        return ret;
    }
}

class GrblLineParserResultGCodeModes extends GrblLineParserResult {
    static parse(line) {
        const r = line.match(/^\[(.+)\]$/);
        if (!r) {
            return null;
        }

        const ret = new GrblLineParserResultGCodeModes(line);
        const words = _(r[1].split(' '))
            .compact()
            .map((word) => {
                return _.trim(word);
            })
            .value();

        words.forEach((word) => {
            // Gx, Mx
            if (word.indexOf('G') === 0 || word.indexOf('M') === 0) {
                let r = _.find(GRBL_MODAL_GROUPS, (group) => {
                    return _.includes(group.modes, word);
                });

                if (r) {
                    _.set(ret, 'modal.' + r.group, word);
                }
            }

            // T: tool number
            if (word.indexOf('T') === 0) {
                _.set(ret, 'tool', word.substring(1));
            }

            // F: feed rate
            if (word.indexOf('F') === 0) {
                _.set(ret, 'feedrate', word.substring(1));
            }

            // S: spindle speed
            if (word.indexOf('S') === 0) {
                _.set(ret, 'spindle', word.substring(1));
            }
        });

        return ret;
    }
}

class GrblLineParserResultStartup extends GrblLineParserResult {
    // Grbl 0.9j ['$' for help]
    static parse(line) {
        const r = line.match(/^Grbl\s*(\d+\.\d+[a-zA-Z]?)/);
        if (!r) {
            return null;
        }

        const ret = new GrblLineParserResultStartup(line);
        ret.version = r[1];
        return ret;
    }
}

class Grbl extends events.EventEmitter {
    status = {};
    parserstate = {
        modal: {
            motion: 'G0', // G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
            coordinate: 'G54', // G54, G55, G56, G57, G58, G59
            plane: 'G17', // G17: xy-plane, G18: xz-plane, G19: yz-plane
            units: 'G21', // G20: Inches, G21: Millimeters
            distance: 'G90', // G90: Absolute, G91: Relative
            feedrate: 'G94', // G93: Inverse Time Mode, G94: Units Per Minutes
            program: 'M0',
            spindle: 'M5',
            coolant: 'M9'
        },
        tool: '',
        feedrate: '',
        spindle: ''
    };
    parser = new GrblLineParser();

    getActiveState() {
        const { activeState } = this.status;

        // Idle, Run, Hold, Door, Home, Alarm, Check
        console.assert(_.includes(GRBL_ACTIVE_STATES, activeState), activeState);

        return activeState;
    }
    parse(data) {
        data = ('' + data).replace(/\s+$/, '');
        if (settings.debug) {
            // console.log('<<', data);
        }
        if (!data) {
            return;
        }

        this.emit('raw', data);

        const result = this.parser.parse(data);

        if (result instanceof GrblLineParserResultStatus) {
            if (!_.isEqual(this.status, result)) {
                this.emit('statuschange', result);
            }
            this.status = result;
            this.emit('status', result);
            return;
        }
        if (result instanceof GrblLineParserResultOk) {
            this.emit('ok', result);
            return;
        }
        if (result instanceof GrblLineParserResultError) {
            this.emit('error', result);
            return;
        }
        if (result instanceof GrblLineParserResultGCodeModes) {
            if (!_.isEqual(this.parserstate, result)) {
                this.emit('parserstatechange', result);
            }
            this.parserstate = result;
            this.emit('parserstate', result);
            return;
        }
        if (result instanceof GrblLineParserResultStartup) {
            this.emit('startup', result);
            return;
        }
        if (data.length > 0) {
            this.emit('others', { raw: data });
            return;
        }
    }
}

export {
    Grbl,
    GrblLineParser,
    GrblLineParserResult,
    GrblLineParserResultStartup
};
<commit_msg>Refactor Grbl controller (#50)<commit_after>import _ from 'lodash';
import events from 'events';
import settings from '../../config/settings';
import {
    GRBL_ACTIVE_STATES,
    GRBL_MODAL_GROUPS
} from './constants';

class GrblLineParser {
    parse(line) {
        const parsers = [
            GrblLineParserResultStatus,
            GrblLineParserResultOk,
            GrblLineParserResultError,
            GrblLineParserResultGCodeModes,
            GrblLineParserResultStartup
        ];

        for (let parser of parsers) {
            const result = parser.parse(line);
            if (result) {
                _.set(result, 'payload.raw', line);
                return result;
            }
        }

        return {
            type: null,
            payload: {
                raw: line
            }
        };
    }
}

//https://github.com/grbl/grbl/blob/master/grbl/report.c
class GrblLineParserResultStatus {
    // <Idle>
    // <Idle,MPos:5.529,0.560,7.000,WPos:1.529,-5.440,-0.000>
    // <Idle,MPos:5.529,0.560,7.000,0.000,WPos:1.529,-5.440,-0.000,0.000>
    // <Idle,MPos:0.000,0.000,0.000,WPos:0.000,0.000,0.000,Buf:0,RX:0,Lim:000>
    // <Idle,MPos:0.000,0.000,0.000,WPos:0.000,0.000,0.000,Buf:0,RX:0,Ln:0,F:0.>
    static parse(line) {
        const r = line.match(/^<(.+)>$/);
        if (!r) {
            return null;
        }

        const payload = {};
        const pattern = /[a-zA-Z]+(:([0-9\.\-]+(,[0-9\.\-]+){1,5})|:([0-9\.\-]+))?/g;
        let params = r[1].match(pattern);
        let result = {};

        // Active State
        payload.activeState = params.shift();

        for (let param of params) {
            const nv = param.match(/^(.+):(.+)/);
            if (nv) {
                let type = nv[1];
                let value = nv[2].split(',');
                result[type] = value;
            }
        }

        { // Machine Position
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const mPos = _.get(result, 'MPos') || ['0.000', '0.000', '0.000']; // Defaults to [x, y, z]
            payload.machinePosition = {};
            for (let i = 0; i < mPos.length; ++i) {
                payload.machinePosition[axes[i]] = mPos[i];
            }
        }

        { // Work Position
            const axes = ['x', 'y', 'z', 'a', 'b', 'c'];
            const wPos = _.get(result, 'WPos') || ['0.000', '0.000', '0.000']; // Defaults to [x, y, z]
            payload.workPosition = {};
            for (let i = 0; i < wPos.length; ++i) {
                payload.workPosition[axes[i]] = wPos[i];
            }
        }

        { // Planner Buffer
            if (result.hasOwnProperty('Buf')) {
                payload.plannerBuffer = _.get(result, 'Buf[0]');
            }
        }

        { // RX Buffer
            if (result.hasOwnProperty('RX')) {
                payload.rxBuffer = _.get(result, 'RX[0]');
            }
        }

        { // Line Number
            if (result.hasOwnProperty('Ln')) {
                payload.lineNumber = _.get(result, 'Ln[0]');
            }
        }

        { // Realtime Rate
            if (result.hasOwnProperty('F')) {
                payload.realtimeRate = _.get(result, 'F[0]');
            }
        }

        { // Limit Pins
            if (result.hasOwnProperty('Lim')) {
                payload.limitPins = _.get(result, 'Lim[0]');
            }
        }

        return {
            type: GrblLineParserResultStatus,
            payload: payload
        };
    }
}

class GrblLineParserResultOk {
    static parse(line) {
        const r = line.match(/^ok$/);
        if (!r) {
            return null;
        }

        const payload = {};

        return {
            type: GrblLineParserResultOk,
            payload: payload
        };
    }
}

class GrblLineParserResultError {
    static parse(line) {
        const r = line.match(/^error:\s*(.+)$/);
        if (!r) {
            return null;
        }

        const payload = {
            message: r[1]
        };

        return {
            type: GrblLineParserResultError,
            payload: payload
        };
    }
}

class GrblLineParserResultGCodeModes {
    static parse(line) {
        const r = line.match(/^\[(.+)\]$/);
        if (!r) {
            return null;
        }

        const payload = {};
        const words = _(r[1].split(' '))
            .compact()
            .map((word) => {
                return _.trim(word);
            })
            .value();

        words.forEach((word) => {
            // Gx, Mx
            if (word.indexOf('G') === 0 || word.indexOf('M') === 0) {
                let r = _.find(GRBL_MODAL_GROUPS, (group) => {
                    return _.includes(group.modes, word);
                });

                if (r) {
                    _.set(payload, 'modal.' + r.group, word);
                }
            }

            // T: tool number
            if (word.indexOf('T') === 0) {
                _.set(payload, 'tool', word.substring(1));
            }

            // F: feed rate
            if (word.indexOf('F') === 0) {
                _.set(payload, 'feedrate', word.substring(1));
            }

            // S: spindle speed
            if (word.indexOf('S') === 0) {
                _.set(payload, 'spindle', word.substring(1));
            }
        });

        return {
            type: GrblLineParserResultGCodeModes,
            payload: payload
        };
    }
}

class GrblLineParserResultStartup {
    // Grbl 0.9j ['$' for help]
    static parse(line) {
        const r = line.match(/^Grbl\s*(\d+\.\d+[a-zA-Z]?)/);
        if (!r) {
            return null;
        }

        const payload = {
            version: r[1]
        };

        return {
            type: GrblLineParserResultStartup,
            payload: payload
        };
    }
}

class Grbl extends events.EventEmitter {
    status = {};
    parserstate = {
        modal: {
            motion: 'G0', // G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
            coordinate: 'G54', // G54, G55, G56, G57, G58, G59
            plane: 'G17', // G17: xy-plane, G18: xz-plane, G19: yz-plane
            units: 'G21', // G20: Inches, G21: Millimeters
            distance: 'G90', // G90: Absolute, G91: Relative
            feedrate: 'G94', // G93: Inverse Time Mode, G94: Units Per Minutes
            program: 'M0',
            spindle: 'M5',
            coolant: 'M9'
        },
        tool: '',
        feedrate: '',
        spindle: ''
    };
    parser = new GrblLineParser();

    getActiveState() {
        const { activeState } = this.status;

        // Idle, Run, Hold, Door, Home, Alarm, Check
        console.assert(_.includes(GRBL_ACTIVE_STATES, activeState), activeState);

        return activeState;
    }
    parse(data) {
        data = ('' + data).replace(/\s+$/, '');
        if (settings.debug) {
            // console.log('<<', data);
        }
        if (!data) {
            return;
        }

        this.emit('raw', data);

        const result = this.parser.parse(data) || {};
        const { type, payload } = result;

        if (type === GrblLineParserResultStatus) {
            if (!_.isEqual(this.status, payload)) {
                this.emit('statuschange', payload);
            }
            this.status = payload;
            this.emit('status', payload);
            return;
        }
        if (type === GrblLineParserResultOk) {
            this.emit('ok', payload);
            return;
        }
        if (type === GrblLineParserResultError) {
            this.emit('error', payload);
            return;
        }
        if (type === GrblLineParserResultGCodeModes) {
            if (!_.isEqual(this.parserstate, payload)) {
                this.emit('parserstatechange', payload);
            }
            this.parserstate = payload;
            this.emit('parserstate', payload);
            return;
        }
        if (type === GrblLineParserResultStartup) {
            this.emit('startup', payload);
            return;
        }
        if (data.length > 0) {
            this.emit('others', payload);
            return;
        }
    }
}

export {
    Grbl,
    GrblLineParser,
    GrblLineParserResultStatus,
    GrblLineParserResultOk,
    GrblLineParserResultError,
    GrblLineParserResultGCodeModes,
    GrblLineParserResultStartup
};
<|endoftext|>


<commit_before>// ==UserScript==
// @name        EPFL People
// @namespace   none
// @description A script to improve browsing on people.epfl.ch
// @include     http://people.epfl.ch/*
// @version     1
// @grant       GM_xmlhttpRequest
// @grant       GM_addStyle
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @author      EPFL-dojo
// ==/UserScript==

//Avoid conflicts
this.$ = this.jQuery = jQuery.noConflict(true);
$(document).ready(function()
{
  // get the h1 name content
  $.epfl_user = {
      "name": $("h1").text(),
      "sciper": $('a[href*="http://people.epfl.ch/cgi-bin/people?id="]').attr('href').match(/id=([0-9]{6})/)[1]
  };
  // change the main title content to add the sciper in it
  $("h1").text($.epfl_user["name"] + " #" + $.epfl_user["sciper"] + " ()");

  $.get("/cgi-bin/people/showcv?id=" + $.epfl_user["sciper"] + "&op=admindata&type=show&lang=en&cvlang=en", function(data){
    $.epfl_user["username"] = data.match(/Username: (\w+)\s/)[1];
    $("h1").text($.epfl_user["name"] + " #" + $.epfl_user["sciper"] + " (" + $.epfl_user["username"]+ ")");
    $('.presentation').append('Username : ' + $.epfl_user["username"]+'
');
  });
  $('.presentation').append('Sciper : ' + $.epfl_user["sciper"]+'
');

  // Add user's mailing list in the right column
  var cadiURL = 'http://cadiwww.epfl.ch/listes?sciper='+$.epfl_user["sciper"];
  GM_xmlhttpRequest({
    method: "GET",
    url: cadiURL,
    onload: function(response) {
      html = $.parseHTML( response.responseText );
      mailinglistUL = $(html).contents('ul');
      $('.right-col').append('
Mailing List

test

');
      $('#cadiML').html(mailinglistUL);
    }
  });
  GM_addStyle("#cadiMLdiv{ padding-left: 20px; } #cadiML ul ul { margin-left: 10px; }" );

  // var adminDataURL = "http://people.epfl.ch/cgi-bin/people?id="+sciper+"&op=admindata&lang=en&cvlang=en";
  /* Idea => add accred link

      <button class="icon"></button>
       Accreditations of Jean-Claude De Giorgi (fr)

*/
});
<commit_msg>Auto update URL set<commit_after>// ==UserScript==
// @name        EPFL People
// @namespace   none
// @description A script to improve browsing on people.epfl.ch
// @include     http://people.epfl.ch/*
// @version     1
// @grant       GM_xmlhttpRequest
// @grant       GM_addStyle
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @author      EPFL-dojo
// @downloadURL https://raw.githubusercontent.com/epfl-dojo/EPFL_People_UserScript/master/EPFL_People.user.js
// @updateURL   https://raw.githubusercontent.com/epfl-dojo/EPFL_People_UserScript/master/EPFL_People.user.js
// ==/UserScript==

//Avoid conflicts
this.$ = this.jQuery = jQuery.noConflict(true);
$(document).ready(function()
{
  // get the h1 name content
  $.epfl_user = {
      "name": $("h1").text(),
      "sciper": $('a[href*="http://people.epfl.ch/cgi-bin/people?id="]').attr('href').match(/id=([0-9]{6})/)[1]
  };
  // change the main title content to add the sciper in it
  $("h1").text($.epfl_user["name"] + " #" + $.epfl_user["sciper"] + " ()");

  $.get("/cgi-bin/people/showcv?id=" + $.epfl_user["sciper"] + "&op=admindata&type=show&lang=en&cvlang=en", function(data){
    $.epfl_user["username"] = data.match(/Username: (\w+)\s/)[1];
    $("h1").text($.epfl_user["name"] + " #" + $.epfl_user["sciper"] + " (" + $.epfl_user["username"]+ ")");
    $('.presentation').append('Username : ' + $.epfl_user["username"]+'
');
  });
  $('.presentation').append('Sciper : ' + $.epfl_user["sciper"]+'
');

  // Add user's mailing list in the right column
  var cadiURL = 'http://cadiwww.epfl.ch/listes?sciper='+$.epfl_user["sciper"];
  GM_xmlhttpRequest({
    method: "GET",
    url: cadiURL,
    onload: function(response) {
      html = $.parseHTML( response.responseText );
      mailinglistUL = $(html).contents('ul');
      $('.right-col').append('
Mailing List

test

');
      $('#cadiML').html(mailinglistUL);
    }
  });
  GM_addStyle("#cadiMLdiv{ padding-left: 20px; } #cadiML ul ul { margin-left: 10px; }" );

  // var adminDataURL = "http://people.epfl.ch/cgi-bin/people?id="+sciper+"&op=admindata&lang=en&cvlang=en";
  /* Idea => add accred link

      <button class="icon"></button>
       Accreditations of Jean-Claude De Giorgi (fr)

*/
});
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define */

define({
    // Relative to the samples folder
    "ADOBE_THIRD_PARTY"         : "http://www.adobe.com/go/thirdparty_kr/",
    "WEB_PLATFORM_DOCS_LICENSE" : "http://creativecommons.org/licenses/by/3.0/"
});
<commit_msg>Localized CC BY link<commit_after>/*
 * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define */

define({
    // Relative to the samples folder
    "ADOBE_THIRD_PARTY"         : "http://www.adobe.com/go/thirdparty_kr/",
    "WEB_PLATFORM_DOCS_LICENSE" : "http://creativecommons.org/licenses/by/3.0/deed.ko"
});
<|endoftext|>


<commit_before>/*global describe, global, before:false, it*/
import assert from 'assert'
import proxifyImageUrl from './ProxifyUrl'

describe('ProxifyUrl', () => {
    before(() => {
        global.$STM_Config = {img_proxy_prefix: 'https://steemitimages.com/'};
    });
    it('naked URL', () => {
        testCase('https://example.com/img.png', '100x200', 'https://steemitimages.com/100x200/https://example.com/img.png')
        testCase('https://example.com/img.png', '0x0', 'https://steemitimages.com/0x0/https://example.com/img.png')
        testCase('https://example.com/img.png', false, 'https://example.com/img.png')
    })
    it('naked steemit proxy URL', () => {
        testCase('https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', '256x512', 'https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
        testCase('https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', false, 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
    })
    it('proxied URL', () => {
        testCase('https://steemitimages.com/0x0/https://example.com/img.png', '100x200', 'https://steemitimages.com/100x200/https://example.com/img.png')
        testCase('https://steemitimages.com/256x512/https://peopledotcom.files.wordpress.com/2017/09/grumpy-harvey-cat.jpg?w=2000', '100x200', 'https://steemitimages.com/100x200/https://peopledotcom.files.wordpress.com/2017/09/grumpy-harvey-cat.jpg?w=2000')
        testCase('https://steemitimages.com/0x0/https://example.com/img.png', false, 'https://example.com/img.png')
    })
    it('double-proxied URL', () => {
        testCase('https://steemitimages.com/0x0/https://steemitimages.com/0x0/https://example.com/img.png', '100x200', 'https://steemitimages.com/100x200/https://example.com/img.png')
    })
})

const testCase = (inputUrl, outputDims, expectedUrl) => {
    const outputUrl = proxifyImageUrl(inputUrl, outputDims);
    assert.equal(outputUrl, expectedUrl, `(${inputUrl}, ${outputDims}) should return ${expectedUrl}. output was ${outputUrl}`)
}
<commit_msg>few more proxify tests. all pass<commit_after>/*global describe, global, before:false, it*/
import assert from 'assert'
import proxifyImageUrl from './ProxifyUrl'

describe('ProxifyUrl', () => {
    before(() => {
        global.$STM_Config = {img_proxy_prefix: 'https://steemitimages.com/'};
    });
    it('naked URL', () => {
        testCase('https://example.com/img.png', '100x200', 'https://steemitimages.com/100x200/https://example.com/img.png')
        testCase('https://example.com/img.png', '0x0', 'https://steemitimages.com/0x0/https://example.com/img.png')
        testCase('https://example.com/img.png', false, 'https://example.com/img.png')
    })
    it('naked steemit hosted URL', () => {
        testCase('https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', '256x512', 'https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
        testCase('https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', false, 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
    })
    it('proxied steemit hosted URL', () => {
        testCase('https://steemitimages.com/0x0/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', '256x512', 'https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
        testCase('https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', false, 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
    })
    it('proxied URL', () => {
        testCase('https://steemitimages.com/0x0/https://example.com/img.png', '100x200', 'https://steemitimages.com/100x200/https://example.com/img.png')
        testCase('https://steemitimages.com/256x512/https://peopledotcom.files.wordpress.com/2017/09/grumpy-harvey-cat.jpg?w=2000', '100x200', 'https://steemitimages.com/100x200/https://peopledotcom.files.wordpress.com/2017/09/grumpy-harvey-cat.jpg?w=2000')
        testCase('https://steemitimages.com/0x0/https://example.com/img.png', false, 'https://example.com/img.png')
    })
    it('double-proxied URL', () => {
        testCase('https://steemitimages.com/0x0/https://steemitimages.com/0x0/https://example.com/img.png', '100x200', 'https://steemitimages.com/100x200/https://example.com/img.png')
        testCase('https://steemitimages.com/0x0/https://steemitimages.com/256x512/https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg', false, 'https://steemitimages.com/DQmaJe2Tt5kmVUaFhse1KTEr4N1g9piMgD3YjPEQhkZi3HR/30day-positivity-challenge.jpg')
    })
})

const testCase = (inputUrl, outputDims, expectedUrl) => {
    const outputUrl = proxifyImageUrl(inputUrl, outputDims);
    assert.equal(outputUrl, expectedUrl, `(${inputUrl}, ${outputDims}) should return ${expectedUrl}. output was ${outputUrl}`)
}
<|endoftext|>


<commit_before>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

var fs = require('fs'),
    path = require('path');
    Canvas = require('canvas');

module.exports = function(paper) {
    var sourceMaps = {},
        sourceMapSupprt = 'require("source-map-support").install(paper.PaperScript.sourceMapSupport);\n';

    paper.PaperScript.sourceMapSupport = {
        retrieveSourceMap: function(source) {
            var map = sourceMaps[source];
            return map ? { url: source, map: map } : null;
        }
    };

    // Register the .pjs extension for automatic compilation as PaperScript
    require.extensions['.pjs'] = function(module, filename) {
        // Requiring a PaperScript on Node.js returns an initialize method which
        // needs to receive a Canvas object when called and returns the
        // PaperScope.
        module.exports = function(canvas) {
            var source = fs.readFileSync(filename, 'utf8'),
                code = sourceMapSupprt + source,
                compiled = paper.PaperScript.compile(code, {
                    url: filename,
                    source: source,
                    sourceMaps: true,
                    offset: -1 // remove sourceMapSupprt...
                }),
                scope = new paper.PaperScope();
            // Keep track of sourceMaps so retrieveSourceMap() can link them up
            scope.setup(canvas);
            scope.__filename = filename;
            scope.__dirname = path.dirname(filename);
            // Expose core methods and values
            scope.require = require;
            scope.console = console;
            sourceMaps[filename] = compiled.map;
            paper.PaperScript.execute(compiled, scope);
            return scope;
        };
    };

    paper.PaperScope.inject({
        createCanvas: function(width, height, type) {
            // Do not use CanvasProvider.getCanvas(), since we may be changing
            // the underlying node-canvas and don't want to release it after
            // back into the pool.
            var canvas = paper.document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            canvas.type = type;
            return canvas;
        },

        /**
         * @deprecated, use use {@link #createCanvas(width, height)} instead.
         */
        Canvas: '#createCanvas'
    });

    // Override requestAnimationFrame() to avoid setInterval() timers.
    paper.DomEvent.requestAnimationFrame = function(callback) {
    };

    // Node.js based image exporting code.
    paper.CanvasView.inject({
        // DOCS: CanvasView#exportFrames(param);
        exportFrames: function(param) {
            param = paper.Base.set({
                fps: 30,
                prefix: 'frame-',
                amount: 1
            }, param);
            if (!param.directory) {
                throw new Error('Missing param.directory');
            }
            var view = this,
                count = 0,
                frameDuration = 1 / param.fps,
                startTime = Date.now(),
                lastTime = startTime;

            // Start exporting frames by exporting the first frame:
            exportFrame(param);

            function exportFrame(param) {
                // Convert to a Base object, for #toString()
                view.emit('frame', new paper.Base({
                    delta: frameDuration,
                    time: frameDuration * count,
                    count: count
                }));
                var file = path.join(param.directory,
                        param.prefix + ('000000' + count).slice(-6) + '.png');
                var out = view.exportImage(file, function() {
                    // When the file has been closed, export the next fame:
                    var then = Date.now();
                    if (param.onProgress) {
                        param.onProgress({
                            count: count,
                            amount: param.amount,
                            percentage: Math.round(count / param.amount
                                    * 10000) / 100,
                            time: then - startTime,
                            delta: then - lastTime
                        });
                    }
                    lastTime = then;
                    if (++count < param.amount) {
                        exportFrame(param);
                    } else {
                        // Call onComplete handler when finished:
                        if (param.onComplete) {
                            param.onComplete();
                        }
                    }
                });
            }
        },

        // DOCS: CanvasView#exportImage(path, callback);
        exportImage: function(path, callback) {
            this.update();
            var out = fs.createWriteStream(path),
                stream = this._element.createPNGStream();
            // Pipe the png stream to the write stream:
            stream.pipe(out);
            if (callback) {
                out.on('close', callback);
            }
            return out;
        }
    });
};
<commit_msg>Automatically determine correct padding for numbers in View#exportFrames()<commit_after>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

var fs = require('fs'),
    path = require('path');
    Canvas = require('canvas');

module.exports = function(paper) {
    var sourceMaps = {},
        sourceMapSupprt = 'require("source-map-support").install(paper.PaperScript.sourceMapSupport);\n';

    paper.PaperScript.sourceMapSupport = {
        retrieveSourceMap: function(source) {
            var map = sourceMaps[source];
            return map ? { url: source, map: map } : null;
        }
    };

    // Register the .pjs extension for automatic compilation as PaperScript
    require.extensions['.pjs'] = function(module, filename) {
        // Requiring a PaperScript on Node.js returns an initialize method which
        // needs to receive a Canvas object when called and returns the
        // PaperScope.
        module.exports = function(canvas) {
            var source = fs.readFileSync(filename, 'utf8'),
                code = sourceMapSupprt + source,
                compiled = paper.PaperScript.compile(code, {
                    url: filename,
                    source: source,
                    sourceMaps: true,
                    offset: -1 // remove sourceMapSupprt...
                }),
                scope = new paper.PaperScope();
            // Keep track of sourceMaps so retrieveSourceMap() can link them up
            scope.setup(canvas);
            scope.__filename = filename;
            scope.__dirname = path.dirname(filename);
            // Expose core methods and values
            scope.require = require;
            scope.console = console;
            sourceMaps[filename] = compiled.map;
            paper.PaperScript.execute(compiled, scope);
            return scope;
        };
    };

    paper.PaperScope.inject({
        createCanvas: function(width, height, type) {
            // Do not use CanvasProvider.getCanvas(), since we may be changing
            // the underlying node-canvas and don't want to release it after
            // back into the pool.
            var canvas = paper.document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            canvas.type = type;
            return canvas;
        },

        /**
         * @deprecated, use use {@link #createCanvas(width, height)} instead.
         */
        Canvas: '#createCanvas'
    });

    // Override requestAnimationFrame() to avoid setInterval() timers.
    // NOTE: In Node.js, we only support manual updating for now, but
    // View#exportFrames() below offers a way to emulate animations by exporting
    // them frame by frame at the given frame-rate.
    paper.DomEvent.requestAnimationFrame = function(callback) {
    };

    // Node.js based image exporting code.
    paper.CanvasView.inject({
        // DOCS: CanvasView#exportFrames(options);
        exportFrames: function(options) {
            options = paper.Base.set({
                fps: 30,
                prefix: 'frame-',
                amount: 1,
            }, options);
            if (!options.directory)
                throw new Error('Missing options.directory');
            var view = this,
                count = 0,
                frameDuration = 1 / options.fps,
                startTime = Date.now(),
                lastTime = startTime,
                padding = options.padding || ((options.amount - 1) + '').length;
                paddedStr = Array(padding + 1).join('0');

            // Start exporting frames by exporting the first frame:
            exportFrame(options);

            function exportFrame() {
                // Convert to a Base object, for #toString()
                view.emit('frame', new paper.Base({
                    delta: frameDuration,
                    time: frameDuration * count,
                    count: count
                }));
                var file = path.join(options.directory, options.prefix +
                        (paddedStr + count).slice(-padding) + '.png');
                var out = view.exportImage(file, function() {
                    // Once the file has been closed, export the next fame:
                    var then = Date.now();
                    if (options.onProgress) {
                        options.onProgress({
                            count: count,
                            amount: options.amount,
                            percentage: Math.round(count / options.amount
                                    * 10000) / 100,
                            time: then - startTime,
                            delta: then - lastTime
                        });
                    }
                    lastTime = then;
                    if (++count < options.amount) {
                        exportFrame();
                    } else {
                        // Call onComplete handler when finished:
                        if (options.onComplete) {
                            options.onComplete();
                        }
                    }
                });
            }
        },

        // DOCS: CanvasView#exportImage(path, callback);
        exportImage: function(path, callback) {
            this.update();
            var out = fs.createWriteStream(path),
                stream = this._element.createPNGStream();
            // Pipe the png stream to the write stream:
            stream.pipe(out);
            if (callback) {
                out.on('close', callback);
            }
            return out;
        }
    });
};
<|endoftext|>