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

  angular
    .module('lorryApp')
    .directive('serviceDefinitionEdit', serviceDefinitionEdit);

  serviceDefinitionEdit.$inject = ['$rootScope', '$document', 'lodash', 'viewHelpers'];

  function serviceDefinitionEdit($rootScope, $document, lodash, viewHelpers) {
    return {
      scope: {
        sectionName: '=',
        serviceDefinition: '='
      },
      restrict: 'E',
      replace: 'true',
      templateUrl: '/scripts/directives/service-definition-edit.html',
      link: function (scope, element) {

        scope.transformToJson = function () {
          if (!scope.newSectionName) {
            scope.newSectionName = scope.sectionName;
          }
          if (scope.editableJson) {
            scope.$parent.editedServiceYamlDocumentJson = scope.transformToYamlDocumentFragment(scope.editableJson);
          } else {
            scope.editableJson = scope.transformToEditableJson(scope.$parent.editedServiceYamlDocumentJson);
            // since image/build section is mandatory, add it to the json if not present
            if (!lodash.findWhere(scope.editableJson, {name: 'image'}) &&
              !lodash.findWhere(scope.editableJson, {name: 'build'})) {
              scope.editableJson.push({name: 'image', value: ''});
            }
            // since extends section should always have subkeys file & service, add it to the json if not present
            fixExtendsKeyStructure();
          }
          interweaveWithErrors(scope.editableJson);
        };

        scope.transformToEditableJson = function (json) {
          var fixedJson = [];
          angular.forEach(json, function(svalue, skey) {
            var sectionObj = {};
            var lines = [];

            // if sequence type keys have string value, convert them to array
            svalue = convertSeqKeyValueToArray(svalue, skey);

            // if environment key values are a sequence, convert them to a hash array
            svalue = convertEnvironmentSeqOrHashToArray(svalue, skey);

            // weird way to check if the array is a real array
            // or the array has objects in it
            // if [{"foo": "bar"}] the length is undefined
            // if ["foo", "bar"] the length is 2
            if (Array.isArray(svalue) && svalue.length === 'undefined') {
              angular.forEach(svalue,  function(lvalue, lkey) {
                var lineObj = {
                  name: lkey,
                  value: lvalue
                };
                lines.push(lineObj);
              });
            }
            if (skey !== 'editMode') {
              sectionObj.name = skey;
              if (lines.length > 0) {
                sectionObj.value = lines;
              } else {
                sectionObj.value = svalue;
              }
              fixedJson.push(sectionObj);
            }
          });

          return fixedJson;
        };

        scope.sectionClasses = function() {
          return scope.topLevelError ? 'error' : '';
        };

        scope.transformToYamlDocumentFragment = function (editedJson) {
          var yamlFrag = {};
          angular.forEach(editedJson, function(svalue) {
            if (svalue.name === 'environment') {
              yamlFrag[svalue.name] = convertSeqSyntaxToHashSyntaxForEnvironmentVars(svalue);
            } else {
              yamlFrag[svalue.name] = svalue.value;
            }
          });
          return yamlFrag;
        };

        var convertSeqSyntaxToHashSyntaxForEnvironmentVars = function (svalue) {
          var obj = {};
          var newEnvTracker = [];
          for(var i = 0; i < svalue.value.length; i++) {
            var item = svalue.value[i];
            // look for the first occurance of ':' or '='
            // favor the ':' syntax when mixed chars ae present
            if (item !== '') {
              var subval = '', subkey = '';
              // if incoming value has neither : nor = e.g. DOCKER_HOST
              if (item.indexOf(':') === -1 && item.indexOf('=') === -1) {
                obj[item] = null;
              } else {
                // if incoming value has : syntax
                var index = item.indexOf(':');
                if ( index !== -1) {
                  subkey = item.substring(0, index);
                  subval = item.substring(index+1, item.length);
                  subval = subval === 'null' ? null : subval;
                } else {
                  // if incoming value has = syntax
                  subval = ''; subkey = '';
                  index = item.indexOf('=');
                  if ( index !== -1) {
                    subkey = item.substring(0, index);
                    subval = item.substring(index+1, item.length);
                    subval = subval === 'null' ? null : subval;
                  }
                }
                obj[subkey] = subval;
              }
              // If items for the environment key was marked for deletion
              // substitute the index no. by the actual key
              var envTracker = $rootScope.markAsDeletedTracker.environment;
              if (angular.isDefined(envTracker) && !lodash.isEmpty(envTracker)) {
                if (lodash.includes(envTracker, i)) {
                  newEnvTracker.push(subkey);
                }
              }
            }
          }
          $rootScope.markAsDeletedTracker.environment = newEnvTracker;
          return obj;
        };

        scope.saveServiceDefinition = function (isFormValid) {
          if (isFormValid) {
            scope.$parent.editedServiceYamlDocumentJson = scope.transformToYamlDocumentFragment(scope.editableJson);
            scope.$emit('saveService', scope.sectionName, scope.newSectionName, scope.$parent.editedServiceYamlDocumentJson);
            // reset edited json
            scope.editableJson = [];
          }
          editCompleted();
        };

        scope.cancelEditing = function () {
          // reset scratch form values
          scope.newSectionName = '';
          scope.editableJson = [];
          // since image/build section is mandatory, add it to the json if not present
          if (!lodash.findWhere(scope.editableJson, {name: 'image'}) &&
            !lodash.findWhere(scope.editableJson, {name: 'build'})) {
            scope.editableJson.push({name: 'image', value: ''});
          }

          scope.$emit('cancelEditing', scope.sectionName);
          editCompleted();
        };

        var editCompleted = function() {
          viewHelpers.animatedScrollTo(element);
        };

        scope.addNewKey = function (key) {
          if (lodash.includes($rootScope.validKeys, key)) {
            var keyValue;
            // restrict the create from scratch for 'command' key to a string type
            if (key === 'command') {
              keyValue = '';
            } else {
              keyValue = scope.createNewEmptyValueForKey(key);
            }
            scope.editableJson.push({name: key, value: keyValue});
            scope.transformToJson();
          }
        };

        scope.$on('addNewValueForExistingKey', function (e, key) {
          var node = lodash.findWhere(scope.editableJson, {name: key});
          if (node) {
            var keyValue = scope.createNewEmptyValueForKey(key);
            if (Array.isArray(keyValue)) {
              node.value.push(keyValue[0]);
              scope.transformToJson();
            }
          }
        });

        scope.$on('markKeyForDeletion', function (e, key) {
          var node = lodash.findWhere(scope.editableJson, {name: key});
          if (node) {
            scope.markItemForDeletion(key, null);
          }
        });

        scope.$on('markKeyItemForDeletion', function (e, key, index) {
          var node = lodash.findWhere(scope.editableJson, {name: key});
          if (node) {
            scope.markItemForDeletion(key, index);
          }
        });

        scope.buildValidKeyList = function () {
          if (!lodash.isEmpty($rootScope.validKeys)) {
            var existingKeys = lodash.pluck(scope.editableJson, 'name');
            if (lodash.includes(existingKeys, 'image') || lodash.includes(existingKeys, 'build')) {
              existingKeys = lodash.union(existingKeys, ['image', 'build']);
            }
            var unsortedList = lodash.difference($rootScope.validKeys, existingKeys);
            return lodash.sortBy(unsortedList);
          }
        };

        scope.createNewEmptyValueForKey = function(key) {
          var keyValue;

          if (isKeyTypeSequence(key)) {
            keyValue = [''];
          } else if (isKeyTypeString(key)) {
            keyValue = '';
          } else if (key === 'extends') {
            keyValue = {file: '', service: ''};
          } else {
            keyValue = '';
          }
          return keyValue;
        };

        scope.markItemForDeletion = function(key, index) {
          var tracker = $rootScope.markAsDeletedTracker;

          // toggle add/remove items from the delete marker
          if (tracker.hasOwnProperty(key)) {
            if (index !== null) {
              if (lodash.includes(tracker[key], index)) {
                // remove the item from tracker
                lodash.remove(tracker[key], function (v) {
                  return v === index;
                });
                // if no items in tracker, delete the key
                if (lodash.size(tracker[key]) === 0) {
                  delete tracker[key];
                }
              } else {
                // add the item to the tracker
                tracker[key].push(index);
              }
            } else {
              delete tracker[key];
            }
          } else {
            // add key/index to tracker
            tracker[key] = [];
            if (index !== null) {
              tracker[key].push(index);
            } else {
              tracker[key].push('delete me');
            }
          }
        };

        scope.doesServiceNameExists = function (serviceName) {
          // if the service is being edited, allow the original section name to be used
          return (serviceName === scope.sectionName) ? false : lodash.includes(scope.$parent.serviceNames(), serviceName);
        };

        scope.hasTopLevelErrors = function() {
          return !lodash.isEmpty(scope.topLevelError);
        };

        scope.topLevelTooltip = function() {
          return (scope.topLevelError || []).join('<br/>');
        };

        var fixExtendsKeyStructure = function () {
          var node = lodash.findWhere(scope.editableJson, {name: 'extends'});
          if (node) {
            node.value = node.value ? node.value : { value: '' };
            var obj = {};
            obj.file = node.value.file ? node.value.file : '';
            obj.service = node.value.service ? node.value.service : '';
            node.value = obj;
          }
        };

        var convertSeqKeyValueToArray = function (svalue, skey) {
          // unless it is the hybrid 'command' key
          if (skey !== 'command') {
            // if sequence type keys have string value, convert them to array
            if (isKeyTypeSequence(skey)) {
              if (!Array.isArray(svalue)) {
                var temp = svalue;
                svalue = [];
                svalue.push(temp);
              }
            }
          }
          return svalue;
        };

        var convertEnvironmentSeqOrHashToArray = function (svalue, skey) {
          if (skey !== 'environment') {
            return svalue;
          }

          var valueArr = [];
          if (Array.isArray(svalue) && angular.isObject(svalue)) {
            angular.forEach(svalue, function(lvalue) {
              if (angular.isObject(lvalue)) {
                // {'ENV_KEY_1': 'some value'} -> ['ENV_KEY_1:some value']
                angular.forEach(lvalue,  function(lv, lk) {
                  valueArr.push(lk+':'+lv);
                });
              } else {
                // ['ENV_KEY_1=some value'] -> don't change
                valueArr.push(lvalue);
              }
            });
          }
          return valueArr;
        };

        var isKeyTypeSequence = function (skey) {
          var seqKeys = ['command', 'links', 'external_links', 'ports', 'expose', 'volumes', 'volumes_from', 'environment', 'env_file', 'dns', 'cap_add', 'cap_drop', 'dns_search', 'labels'];
          return lodash.includes(seqKeys, skey);
        };

        var isKeyTypeString = function (skey) {
          var stringKeys = ['image', 'build', 'net', 'pid', 'working_dir', 'entrypoint', 'user', 'hostname', 'domainname', 'mac_address', 'mem_limit', 'memswap_limit', 'privileged', 'restart', 'stdin_open', 'tty', 'cpu_shares', 'cpuset'];
          return lodash.includes(stringKeys, skey);
        };

        function interweaveWithErrors(editableJson) {
          var currentKey,
          count = 0;

          lodash.forEach(scope.serviceDefinition, function(line) {
            if (lodash.isEmpty(line.lineKey)) {
              count += 1;
            } else {
              currentKey = line.lineKey;
              count = 0;
            }

            checkFor('Errors', line, count, currentKey);
            checkFor('Warnings', line, count, currentKey);
          });

          function checkFor(type, line, count, currentKey) {
            var collectionType = type.toLowerCase(),
                messages = collectMessagesFrom(line[collectionType]);
            if (line[collectionType] && line[collectionType].length > 0) {
              var lineWithErrors = {};
              if (lodash.isEmpty(line.lineKey)) {
                lineWithErrors = lodash.findWhere(editableJson, { name: currentKey }) || {};
                var s = 'sub' + type;
                if (!lineWithErrors[s]) {
                  lineWithErrors[s] = {};
                }
                lineWithErrors[s][count] = messages;
              } else {
                lineWithErrors = lodash.findWhere(editableJson, { name: line.lineKey });
                if (lineWithErrors) {
                  lineWithErrors[collectionType] = messages;
                } else {
                  scope.topLevelError = messages;
                }
              }
            }

            function collectMessagesFrom(collection) {
              return lodash.map(collection, function(item) {
                var singular = collectionType.replace(/s$/,''),
                    object = item[singular] || {};
                return object.message;
              });
            }
          }
        }

        function initialize() {
          scope.transformToJson();
        }

        initialize();

      }
    };
  }
})();
<commit_msg>Add key for read_only.<commit_after>(function () {
  'use strict';

  angular
    .module('lorryApp')
    .directive('serviceDefinitionEdit', serviceDefinitionEdit);

  serviceDefinitionEdit.$inject = ['$rootScope', '$document', 'lodash', 'viewHelpers'];

  function serviceDefinitionEdit($rootScope, $document, lodash, viewHelpers) {
    return {
      scope: {
        sectionName: '=',
        serviceDefinition: '='
      },
      restrict: 'E',
      replace: 'true',
      templateUrl: '/scripts/directives/service-definition-edit.html',
      link: function (scope, element) {

        scope.transformToJson = function () {
          if (!scope.newSectionName) {
            scope.newSectionName = scope.sectionName;
          }
          if (scope.editableJson) {
            scope.$parent.editedServiceYamlDocumentJson = scope.transformToYamlDocumentFragment(scope.editableJson);
          } else {
            scope.editableJson = scope.transformToEditableJson(scope.$parent.editedServiceYamlDocumentJson);
            // since image/build section is mandatory, add it to the json if not present
            if (!lodash.findWhere(scope.editableJson, {name: 'image'}) &&
              !lodash.findWhere(scope.editableJson, {name: 'build'})) {
              scope.editableJson.push({name: 'image', value: ''});
            }
            // since extends section should always have subkeys file & service, add it to the json if not present
            fixExtendsKeyStructure();
          }
          interweaveWithErrors(scope.editableJson);
        };

        scope.transformToEditableJson = function (json) {
          var fixedJson = [];
          angular.forEach(json, function(svalue, skey) {
            var sectionObj = {};
            var lines = [];

            // if sequence type keys have string value, convert them to array
            svalue = convertSeqKeyValueToArray(svalue, skey);

            // if environment key values are a sequence, convert them to a hash array
            svalue = convertEnvironmentSeqOrHashToArray(svalue, skey);

            // weird way to check if the array is a real array
            // or the array has objects in it
            // if [{"foo": "bar"}] the length is undefined
            // if ["foo", "bar"] the length is 2
            if (Array.isArray(svalue) && svalue.length === 'undefined') {
              angular.forEach(svalue,  function(lvalue, lkey) {
                var lineObj = {
                  name: lkey,
                  value: lvalue
                };
                lines.push(lineObj);
              });
            }
            if (skey !== 'editMode') {
              sectionObj.name = skey;
              if (lines.length > 0) {
                sectionObj.value = lines;
              } else {
                sectionObj.value = svalue;
              }
              fixedJson.push(sectionObj);
            }
          });

          return fixedJson;
        };

        scope.sectionClasses = function() {
          return scope.topLevelError ? 'error' : '';
        };

        scope.transformToYamlDocumentFragment = function (editedJson) {
          var yamlFrag = {};
          angular.forEach(editedJson, function(svalue) {
            if (svalue.name === 'environment') {
              yamlFrag[svalue.name] = convertSeqSyntaxToHashSyntaxForEnvironmentVars(svalue);
            } else {
              yamlFrag[svalue.name] = svalue.value;
            }
          });
          return yamlFrag;
        };

        var convertSeqSyntaxToHashSyntaxForEnvironmentVars = function (svalue) {
          var obj = {};
          var newEnvTracker = [];
          for(var i = 0; i < svalue.value.length; i++) {
            var item = svalue.value[i];
            // look for the first occurance of ':' or '='
            // favor the ':' syntax when mixed chars ae present
            if (item !== '') {
              var subval = '', subkey = '';
              // if incoming value has neither : nor = e.g. DOCKER_HOST
              if (item.indexOf(':') === -1 && item.indexOf('=') === -1) {
                obj[item] = null;
              } else {
                // if incoming value has : syntax
                var index = item.indexOf(':');
                if ( index !== -1) {
                  subkey = item.substring(0, index);
                  subval = item.substring(index+1, item.length);
                  subval = subval === 'null' ? null : subval;
                } else {
                  // if incoming value has = syntax
                  subval = ''; subkey = '';
                  index = item.indexOf('=');
                  if ( index !== -1) {
                    subkey = item.substring(0, index);
                    subval = item.substring(index+1, item.length);
                    subval = subval === 'null' ? null : subval;
                  }
                }
                obj[subkey] = subval;
              }
              // If items for the environment key was marked for deletion
              // substitute the index no. by the actual key
              var envTracker = $rootScope.markAsDeletedTracker.environment;
              if (angular.isDefined(envTracker) && !lodash.isEmpty(envTracker)) {
                if (lodash.includes(envTracker, i)) {
                  newEnvTracker.push(subkey);
                }
              }
            }
          }
          $rootScope.markAsDeletedTracker.environment = newEnvTracker;
          return obj;
        };

        scope.saveServiceDefinition = function (isFormValid) {
          if (isFormValid) {
            scope.$parent.editedServiceYamlDocumentJson = scope.transformToYamlDocumentFragment(scope.editableJson);
            scope.$emit('saveService', scope.sectionName, scope.newSectionName, scope.$parent.editedServiceYamlDocumentJson);
            // reset edited json
            scope.editableJson = [];
          }
          editCompleted();
        };

        scope.cancelEditing = function () {
          // reset scratch form values
          scope.newSectionName = '';
          scope.editableJson = [];
          // since image/build section is mandatory, add it to the json if not present
          if (!lodash.findWhere(scope.editableJson, {name: 'image'}) &&
            !lodash.findWhere(scope.editableJson, {name: 'build'})) {
            scope.editableJson.push({name: 'image', value: ''});
          }

          scope.$emit('cancelEditing', scope.sectionName);
          editCompleted();
        };

        var editCompleted = function() {
          viewHelpers.animatedScrollTo(element);
        };

        scope.addNewKey = function (key) {
          if (lodash.includes($rootScope.validKeys, key)) {
            var keyValue;
            // restrict the create from scratch for 'command' key to a string type
            if (key === 'command') {
              keyValue = '';
            } else {
              keyValue = scope.createNewEmptyValueForKey(key);
            }
            scope.editableJson.push({name: key, value: keyValue});
            scope.transformToJson();
          }
        };

        scope.$on('addNewValueForExistingKey', function (e, key) {
          var node = lodash.findWhere(scope.editableJson, {name: key});
          if (node) {
            var keyValue = scope.createNewEmptyValueForKey(key);
            if (Array.isArray(keyValue)) {
              node.value.push(keyValue[0]);
              scope.transformToJson();
            }
          }
        });

        scope.$on('markKeyForDeletion', function (e, key) {
          var node = lodash.findWhere(scope.editableJson, {name: key});
          if (node) {
            scope.markItemForDeletion(key, null);
          }
        });

        scope.$on('markKeyItemForDeletion', function (e, key, index) {
          var node = lodash.findWhere(scope.editableJson, {name: key});
          if (node) {
            scope.markItemForDeletion(key, index);
          }
        });

        scope.buildValidKeyList = function () {
          if (!lodash.isEmpty($rootScope.validKeys)) {
            var existingKeys = lodash.pluck(scope.editableJson, 'name');
            if (lodash.includes(existingKeys, 'image') || lodash.includes(existingKeys, 'build')) {
              existingKeys = lodash.union(existingKeys, ['image', 'build']);
            }
            var unsortedList = lodash.difference($rootScope.validKeys, existingKeys);
            return lodash.sortBy(unsortedList);
          }
        };

        scope.createNewEmptyValueForKey = function(key) {
          var keyValue;

          if (isKeyTypeSequence(key)) {
            keyValue = [''];
          } else if (isKeyTypeString(key)) {
            keyValue = '';
          } else if (key === 'extends') {
            keyValue = {file: '', service: ''};
          } else {
            keyValue = '';
          }
          return keyValue;
        };

        scope.markItemForDeletion = function(key, index) {
          var tracker = $rootScope.markAsDeletedTracker;

          // toggle add/remove items from the delete marker
          if (tracker.hasOwnProperty(key)) {
            if (index !== null) {
              if (lodash.includes(tracker[key], index)) {
                // remove the item from tracker
                lodash.remove(tracker[key], function (v) {
                  return v === index;
                });
                // if no items in tracker, delete the key
                if (lodash.size(tracker[key]) === 0) {
                  delete tracker[key];
                }
              } else {
                // add the item to the tracker
                tracker[key].push(index);
              }
            } else {
              delete tracker[key];
            }
          } else {
            // add key/index to tracker
            tracker[key] = [];
            if (index !== null) {
              tracker[key].push(index);
            } else {
              tracker[key].push('delete me');
            }
          }
        };

        scope.doesServiceNameExists = function (serviceName) {
          // if the service is being edited, allow the original section name to be used
          return (serviceName === scope.sectionName) ? false : lodash.includes(scope.$parent.serviceNames(), serviceName);
        };

        scope.hasTopLevelErrors = function() {
          return !lodash.isEmpty(scope.topLevelError);
        };

        scope.topLevelTooltip = function() {
          return (scope.topLevelError || []).join('<br/>');
        };

        var fixExtendsKeyStructure = function () {
          var node = lodash.findWhere(scope.editableJson, {name: 'extends'});
          if (node) {
            node.value = node.value ? node.value : { value: '' };
            var obj = {};
            obj.file = node.value.file ? node.value.file : '';
            obj.service = node.value.service ? node.value.service : '';
            node.value = obj;
          }
        };

        var convertSeqKeyValueToArray = function (svalue, skey) {
          // unless it is the hybrid 'command' key
          if (skey !== 'command') {
            // if sequence type keys have string value, convert them to array
            if (isKeyTypeSequence(skey)) {
              if (!Array.isArray(svalue)) {
                var temp = svalue;
                svalue = [];
                svalue.push(temp);
              }
            }
          }
          return svalue;
        };

        var convertEnvironmentSeqOrHashToArray = function (svalue, skey) {
          if (skey !== 'environment') {
            return svalue;
          }

          var valueArr = [];
          if (Array.isArray(svalue) && angular.isObject(svalue)) {
            angular.forEach(svalue, function(lvalue) {
              if (angular.isObject(lvalue)) {
                // {'ENV_KEY_1': 'some value'} -> ['ENV_KEY_1:some value']
                angular.forEach(lvalue,  function(lv, lk) {
                  valueArr.push(lk+':'+lv);
                });
              } else {
                // ['ENV_KEY_1=some value'] -> don't change
                valueArr.push(lvalue);
              }
            });
          }
          return valueArr;
        };

        var isKeyTypeSequence = function (skey) {
          var seqKeys = ['command', 'links', 'external_links', 'ports', 'expose', 'volumes', 'volumes_from', 'environment', 'env_file', 'dns', 'cap_add', 'cap_drop', 'dns_search', 'labels'];
          return lodash.includes(seqKeys, skey);
        };

        var isKeyTypeString = function (skey) {
          var stringKeys = ['image', 'build', 'net', 'pid', 'working_dir', 'entrypoint', 'user', 'hostname', 'domainname', 'mac_address', 'mem_limit', 'memswap_limit', 'privileged', 'restart', 'stdin_open', 'tty', 'cpu_shares', 'cpuset', 'read_only'];
          return lodash.includes(stringKeys, skey);
        };

        function interweaveWithErrors(editableJson) {
          var currentKey,
          count = 0;

          lodash.forEach(scope.serviceDefinition, function(line) {
            if (lodash.isEmpty(line.lineKey)) {
              count += 1;
            } else {
              currentKey = line.lineKey;
              count = 0;
            }

            checkFor('Errors', line, count, currentKey);
            checkFor('Warnings', line, count, currentKey);
          });

          function checkFor(type, line, count, currentKey) {
            var collectionType = type.toLowerCase(),
                messages = collectMessagesFrom(line[collectionType]);
            if (line[collectionType] && line[collectionType].length > 0) {
              var lineWithErrors = {};
              if (lodash.isEmpty(line.lineKey)) {
                lineWithErrors = lodash.findWhere(editableJson, { name: currentKey }) || {};
                var s = 'sub' + type;
                if (!lineWithErrors[s]) {
                  lineWithErrors[s] = {};
                }
                lineWithErrors[s][count] = messages;
              } else {
                lineWithErrors = lodash.findWhere(editableJson, { name: line.lineKey });
                if (lineWithErrors) {
                  lineWithErrors[collectionType] = messages;
                } else {
                  scope.topLevelError = messages;
                }
              }
            }

            function collectMessagesFrom(collection) {
              return lodash.map(collection, function(item) {
                var singular = collectionType.replace(/s$/,''),
                    object = item[singular] || {};
                return object.message;
              });
            }
          }
        }

        function initialize() {
          scope.transformToJson();
        }

        initialize();

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


<commit_before>
module("About Operators (topics/about_operators.js)");

test("addition", function() {
  var result = 0;
  //starting i at 0, add i to result and increment i by 1 until i is equal to 5
  for (var i = 0; i <= 5; i++) {
    result = result + i;
  }
  equal(__, result, "What is the value of result?");
});

test("assignment addition", function() {
  var result = 0;
  for (var i = 0; i <=5; i++) {
    //the code below is just like saying result = result + i; but is more concise
    result += i;
  }
  equal(__, result, "What is the value of result?");
});

test("subtraction", function() {
  var result = 5;
  for (var i = 0; i <= 2; i++) {
    result = result - i;
  }
  equal(__, result, "What is the value of result?");
});

test("assignment subtraction", function() {
  var result = 5;
  for (var i = 0; i <= 2; i++) {
    result -= i;
  }
  equal(__, result, "What is the value of result?");
});

//Assignment operators are available for multiplication and division as well
//let's do one more, the modulo operator, used for showing division remainder

test("modulus", function() {
  var result = 10;
  var x = 5;
  //again this is exactly the same as result = result % x
  result %= x;
  equal(__, result, "What is the value of result?");
});
<commit_msg>Fixes koans about operators<commit_after>
module("About Operators (topics/about_operators.js)");

test("addition", function() {
  var result = 0;
  //starting i at 0, add i to result and increment i by 1 until i is equal to 5
  for (var i = 0; i <= 5; i++) {
    result = result + i;
  }
  // 0 + 1 + 2 + 3 + 4 + 5
  equal(15, result, "What is the value of result?");
});

test("assignment addition", function() {
  var result = 0;
  for (var i = 0; i <=5; i++) {
    //the code below is just like saying result = result + i; but is more concise
    result += i;
  }
  equal(15, result, "What is the value of result?");
});

test("subtraction", function() {
  var result = 5;
  for (var i = 0; i <= 2; i++) {
    result = result - i;
  }

  // 5 - 0 - 1 - 2
  equal(2, result, "What is the value of result?");
});

test("assignment subtraction", function() {
  var result = 5;
  for (var i = 0; i <= 2; i++) {
    result -= i;
  }
  equal(2, result, "What is the value of result?");
});

//Assignment operators are available for multiplication and division as well
//let's do one more, the modulo operator, used for showing division remainder

test("modulus", function() {
  var result = 10;
  var x = 5;
  //again this is exactly the same as result = result % x
  result %= x;
  equal(0, result, "What is the value of result?");
});
<|endoftext|>


<commit_before>var UP = 0;
var RIGHT = 1;
var DOWN = 2;
var LEFT = 3;

var canvas, context;
var width, height;

var player, ball, blocks, background;

var points, lives;

var keyLeft, keyRight, restart;

var audio;

var playerImg;
var ballImg;
var blockImg;

function init() {
	canvas = document.getElementById("canvas");
	context = canvas.getContext("2d");

	width = canvas.width;
	height = canvas.height;

	points = 0;
	lives = 3;

	audio = new Audio('bu.mp3');

	playerImg = new Image();
	playerImg.src = 'assets/ic_player.png';

	ballImg = new Image();
	ballImg.src = 'assets/ic_ball.png';

	blockImg = new Image();
	blockImg.src = 'assets/ic_block.png';

	background = new background();
	showPoints = new showPoints();
	showLives = new showLives();
	gameOver = new gameOver();
	youWin = new youWin();
	player = new player(width / 2, height, 100, 10, 10);
	ball = new ball(width / 2, height / 2, 5, 10);
	blocks = new blocks();
	blocks.init();

	keyRight = false;
	keyLeft = false;
	restart = false;
	win = false;

	document.addEventListener('keyup', keyUp, false);
	document.addEventListener('keydown', keyDown, false);

	setInterval(gameLoop, 30);
}

function keyDown(e) {
	if (e.keyCode == 37) {
		keyLeft = true;
	} else if (e.keyCode == 39) {
		keyRight = true;
	} else if (e.keyCode == 13) {
		restart = true;
	}
}

function keyUp(e) {
	if (e.keyCode == 37) {
		keyLeft = false;
	} else if (e.keyCode == 39) {
		keyRight = false;
	}
}

function gameLoop() {
	if ((lives >= 0) && (!win)) {
		context.clearRect(0, 0, width, height);

		// Titulo / Linha divisoria
		background.draw(context);

		// Pontos
		showPoints.draw(context);

		// Vidas
		showLives.draw(context);

		// Jogador
		player.update();
		player.draw(context);

		// Blocos
		blocks.draw(context);

		// Bola
		ball.update(player, blocks);
		ball.draw(context);

	} else if ((lives >= 0) && (win)) {
		context.clearRect(0, 0, width, height);
		youWin.draw(context);
		if (restart) {
			reset();
		}
	} else {
		context.clearRect(0, 0, width, height);
		gameOver.draw(context);
		if (restart) {
			reset();
		}
	}
}

function reset() {
	win = false;
	points = 0;
	lives = 3;
	restart = false;

	blocks.init();
}

function background() {
	this.draw = function(context) {
		fundo = new Image();
		fundo.src = 'assets/bg_breakout.png';
		context.drawImage(fundo, 0, 0);
	};
}

function showPoints() {
	this.draw = function(context) {
		// Score
		context.font = "21pt Cassannet Outline";
		context.fillStyle = "white";
		context.fillText("Pontos: " + points, (width / 2) + 100, 35);
	};
}

function showLives() {
	this.draw = function(context) {
		// Placar
		context.font = "21pt Cassannet Outline";
		context.fillStyle = "white";
		context.fillText("Vidas: " + lives, (width / 2) + 240, 35);
	};
}

function gameOver() {
	this.draw = function(context) {
		gameOverScreen = new Image();
		gameOverScreen.src = 'assets/bg_gameover.png';
		context.drawImage(gameOverScreen, 0, 0);
	};
}

function youWin() {
	this.draw = function(context) {
		winScreen = new Image();
		winScreen.src = 'assets/bg_win.png';
		context.drawImage(winScreen, 0, 0);
	};
}

function ball(x, y, radius, speed) {
	this.x = x;
	this.y = y;
	this.radius = radius;
	this.speed = speed;
	this.angle = Math.floor(Math.random() * 21) - 10;
	this.direction = DOWN;

	this.draw = function(context) {
		context.drawImage(ballImg, this.x, this.y);
	};

	this.update = function(player, blocks) {
		// se a bola enconstar no jogador
		if (player.collision(this)) {
			this.direction = UP;

			// se o jogador estiver indo para esquerda quando tocar na bola...
			if (keyLeft) {
				// mandamos a bola na diagonal pra esquerda
				angle = Math.floor(Math.random() * 10) - 9;
			}
			// se o jogador estiver indo para direita quando tocar na bola...
			else {
				// mandamos a bola na diagonal pra direita
				angle = Math.floor((Math.random() * 10));
			}
		} else if (blocks.collisions(ball)) {
			if (blocks.items.length == 0) {
				win = true;
			}

			if (this.direction == DOWN) {
				this.direction = UP;
			} else {
				this.direction = DOWN;
			}
		} else if ((this.y + this.radius) < 81) {
			this.direction = DOWN;
		}

		// se a bola bater na lateral da tela...
		if ((this.x - this.radius <= 32) || (this.x + radius > width - 52)) {
			// multiplicamos por -1 para inverter o sinal e a direção da bola
			// no
			// eixo X
			this.angle = this.angle * -1;
		}
		// movemos a bola para cima ou para baixo, de acordo com o cáculo acima
		this.x += this.angle;

		if (this.direction == DOWN) {
			this.y += this.speed;
		} else {
			this.y -= this.speed;
		}

		// morreu
		if ((this.y + this.radius) > height) {
			lives--;
			this.x = width / 2;
			this.y = height / 2;
		}
	};
}

function player(x, y, w, h, speed) {
	this.x = x - (w / 2);
	this.y = y - h;
	this.w = w;
	this.h = h;
	this.speed = speed;

	this.draw = function(context) {
		context.drawImage(playerImg, this.x, this.y);
	};

	this.update = function() {
		if ((keyRight) && ((this.x + this.w) <= width - 52)) {
			this.x += 10;
		}

		if ((keyLeft) && (this.x >= 40)) {
			this.x -= 10;
		}
	};

	this.collision = function(ball) {
		// se a bola enconstar na jogador(eixo Y)...
		if ((ball.y + ball.radius) > this.y) {
			// se a bola enconstar na jogador(eixo X)...
			if ((ball.x + ball.radius > player.x)
					&& (ball.x - ball.radius < this.x + this.w)) {
				return true;
			}
		}

		return false;
	};
}

function block(x, y, w, h) {
	this.x = x;
	this.y = y;
	this.w = w;
	this.h = h;

	this.draw = function() {
		context.drawImage(blockImg, this.x, this.y);
	};

	this.collision = function(ball) {
		// se a bola enconstar no bloco
		if (ball.y + ball.radius >= this.y
				&& ball.y - ball.radius <= this.y + this.h) {
			if (ball.x + ball.radius >= this.x
					&& ball.x - ball.radius <= this.x + this.w) {
				// marcou ponto
				points++;
				audio.play();
				return true;
			}
		}

		return false;
	};
}

function blocks() {
	this.items = new Array();

	this.init = function() {

		this.items = new Array();

		for (var j = 100; j < 220; j += 30) {
			for (var i = 50; i < 568; i += 102) {
				this.items.push(new block(i, j, 93, 30));
			}
		}
	};

	this.draw = function(context) {
		for (var i = 0; i < this.items.length; i++) {
			this.items[i].draw(context);
		}
	};

	this.collisions = function(ball) {
		for (var i = 0; i < this.items.length; i++) {
			if (this.items[i].collision(ball)) {
				this.items.splice(i, 1);
				return true;
			}
		}

		return false;
	};
}<commit_msg>ajuste no tratamento apos a morte<commit_after>var UP = 0;
var RIGHT = 1;
var DOWN = 2;
var LEFT = 3;

var canvas, context;
var width, height;

var player, ball, blocks, background;

var points, lives;

var keyLeft, keyRight, restart;

var audio;

var playerImg;
var ballImg;
var blockImg;

function init() {
	canvas = document.getElementById("canvas");
	context = canvas.getContext("2d");

	width = canvas.width;
	height = canvas.height;

	points = 0;
	lives = 3;

	audio = new Audio('bu.mp3');

	playerImg = new Image();
	playerImg.src = 'assets/ic_player.png';

	ballImg = new Image();
	ballImg.src = 'assets/ic_ball.png';

	blockImg = new Image();
	blockImg.src = 'assets/ic_block.png';

	background = new background();
	showPoints = new showPoints();
	showLives = new showLives();
	gameOver = new gameOver();
	youWin = new youWin();
	player = new player(width / 2, height, 100, 10, 10);
	ball = new ball(width / 2, height / 2, 5, 10);
	blocks = new blocks();
	blocks.init();

	keyRight = false;
	keyLeft = false;
	restart = false;
	win = false;

	document.addEventListener('keyup', keyUp, false);
	document.addEventListener('keydown', keyDown, false);

	setInterval(gameLoop, 30);
}

function keyDown(e) {
	if (e.keyCode == 37) {
		keyLeft = true;
	} else if (e.keyCode == 39) {
		keyRight = true;
	} else if (e.keyCode == 13) {
		restart = true;
	}
}

function keyUp(e) {
	if (e.keyCode == 37) {
		keyLeft = false;
	} else if (e.keyCode == 39) {
		keyRight = false;
	}
}

function gameLoop() {
	if ((lives >= 0) && (!win)) {
		context.clearRect(0, 0, width, height);

		// Titulo / Linha divisoria
		background.draw(context);

		// Pontos
		showPoints.draw(context);

		// Vidas
		showLives.draw(context);

		// Jogador
		player.update();
		player.draw(context);

		// Blocos
		blocks.draw(context);

		// Bola
		ball.update(player, blocks);
		ball.draw(context);

	} else if ((lives >= 0) && (win)) {
		context.clearRect(0, 0, width, height);
		youWin.draw(context);
		if (restart) {
			reset();
		}
	} else {
		context.clearRect(0, 0, width, height);
		gameOver.draw(context);
		if (restart) {
			reset();
		}
	}
}

function reset() {
	win = false;
	points = 0;
	lives = 3;
	restart = false;

	blocks.init();
}

function background() {
	this.draw = function(context) {
		fundo = new Image();
		fundo.src = 'assets/bg_breakout.png';
		context.drawImage(fundo, 0, 0);
	};
}

function showPoints() {
	this.draw = function(context) {
		// Score
		context.font = "21pt Cassannet Outline";
		context.fillStyle = "white";
		context.fillText("Pontos: " + points, (width / 2) + 100, 35);
	};
}

function showLives() {
	this.draw = function(context) {
		// Placar
		context.font = "21pt Cassannet Outline";
		context.fillStyle = "white";
		context.fillText("Vidas: " + lives, (width / 2) + 240, 35);
	};
}

function gameOver() {
	this.draw = function(context) {
		gameOverScreen = new Image();
		gameOverScreen.src = 'assets/bg_gameover.png';
		context.drawImage(gameOverScreen, 0, 0);
	};
}

function youWin() {
	this.draw = function(context) {
		winScreen = new Image();
		winScreen.src = 'assets/bg_win.png';
		context.drawImage(winScreen, 0, 0);
	};
}

function ball(x, y, radius, speed) {
	this.x = x;
	this.y = y;
	this.radius = radius;
	this.speed = speed;
	this.angle = Math.floor(Math.random() * 21) - 10;
	this.direction = DOWN;

	this.draw = function(context) {
		context.drawImage(ballImg, this.x, this.y);
	};

	this.update = function(player, blocks) {
		// se a bola enconstar no jogador
		if (player.collision(this)) {
			this.direction = UP;

			// se o jogador estiver indo para esquerda quando tocar na bola...
			if (keyLeft) {
				// mandamos a bola na diagonal pra esquerda
				angle = Math.floor(Math.random() * 10) - 9;
			}
			// se o jogador estiver indo para direita quando tocar na bola...
			else {
				// mandamos a bola na diagonal pra direita
				angle = Math.floor((Math.random() * 10));
			}
		} else if (blocks.collisions(ball)) {
			if (blocks.items.length == 0) {
				win = true;
			}

			if (this.direction == DOWN) {
				this.direction = UP;
			} else {
				this.direction = DOWN;
			}
		} else if ((this.y + this.radius) < 81) {
			this.direction = DOWN;
		}

		// se a bola bater na lateral da tela...
		if ((this.x - this.radius <= 32) || (this.x + radius > width - 52)) {
			// multiplicamos por -1 para inverter o sinal e a direção da bola
			// no
			// eixo X
			this.angle = this.angle * -1;
		}
		// movemos a bola para cima ou para baixo, de acordo com o cáculo acima
		this.x += this.angle;

		if (this.direction == DOWN) {
			this.y += this.speed;
		} else {
			this.y -= this.speed;
		}

		// morreu
		if ((this.y + this.radius) > height) {
			lives--;
			this.x = width / 2;
			this.y = height / 2;
			this.angle = Math.floor(Math.random() * 21) - 10;

			player.reset();
		}
	};
}

function player(x, y, w, h, speed) {
	this.x = x - (w / 2);
	this.y = y - h;
	this.w = w;
	this.h = h;
	this.speed = speed;

	this.draw = function(context) {
		context.drawImage(playerImg, this.x, this.y);
	};

	this.update = function() {
		if ((keyRight) && ((this.x + this.w) <= width - 52)) {
			this.x += 10;
		}

		if ((keyLeft) && (this.x >= 40)) {
			this.x -= 10;
		}
	};

	this.collision = function(ball) {
		// se a bola enconstar na jogador(eixo Y)...
		if ((ball.y + ball.radius) > this.y) {
			// se a bola enconstar na jogador(eixo X)...
			if ((ball.x + ball.radius > player.x)
					&& (ball.x - ball.radius < this.x + this.w)) {
				return true;
			}
		}

		return false;
	};

	this.reset = function() {
		// reseta para a poscao inicial
		this.x = x - (w / 2);
	};
}

function block(x, y, w, h) {
	this.x = x;
	this.y = y;
	this.w = w;
	this.h = h;

	this.draw = function() {
		context.drawImage(blockImg, this.x, this.y);
	};

	this.collision = function(ball) {
		// se a bola enconstar no bloco
		if (ball.y + ball.radius >= this.y
				&& ball.y - ball.radius <= this.y + this.h) {
			if (ball.x + ball.radius >= this.x
					&& ball.x - ball.radius <= this.x + this.w) {
				// marcou ponto
				points++;
				audio.play();
				return true;
			}
		}

		return false;
	};
}

function blocks() {
	this.items = new Array();

	this.init = function() {

		this.items = new Array();

		for (var j = 100; j < 220; j += 30) {
			for (var i = 50; i < 568; i += 102) {
				this.items.push(new block(i, j, 93, 30));
			}
		}
	};

	this.draw = function(context) {
		for (var i = 0; i < this.items.length; i++) {
			this.items[i].draw(context);
		}
	};

	this.collisions = function(ball) {
		for (var i = 0; i < this.items.length; i++) {
			if (this.items[i].collision(ball)) {
				this.items.splice(i, 1);
				return true;
			}
		}

		return false;
	};
}<|endoftext|>


<commit_before>'use strict';

const HTMLBuilder = require('./htmlBuilder');
const get = require('lodash.get');
const set = require('lodash.set');
const reduce = require('lodash.reduce');
const DataCollector = require('./dataCollector');
const renderer = require('./renderer');

// lets keep this in the HTML context, since we need things from the
// regular options object in the output
const defaultConfig = {
  html: {
    showAllWaterfallSummary: false,
    pageSummaryMetrics: [
      'transferSize.total',
      'requests.total',
      'thirdParty.requests',
      'transferSize.javascript',
      'transferSize.css',
      'transferSize.image',
      'score.performance'
    ],
    summaryBoxes: [
      'score.score',
      'score.accessibility',
      'score.bestpractice',
      'score.privacy',
      'score.performance',
      'timings.firstPaint',
      'timings.fullyLoaded',
      'timings.pageLoadTime',
      'timings.FirstVisualChange',
      'timings.LastVisualChange',
      'timings.SpeedIndex',
      'timings.PerceptualSpeedIndex',
      'timings.VisualReadiness',
      'timings.VisualComplete',
      'requests.total',
      'requests.javascript',
      'requests.css',
      'requests.image',
      'transferSize.total',
      'transferSize.html',
      'transferSize.javascript',
      'contentSize.javascript',
      'transferSize.css',
      'transferSize.image',
      'thirdParty.transferSize',
      'thirdParty.requests',
      'lighthouse.performance',
      'lighthouse.accessibility',
      'lighthouse.best-practices',
      'lighthouse.seo',
      'lighthouse.pwa',
      'webpagetest.SpeedIndex',
      'webpagetest.lastVisualChange',
      'webpagetest.render',
      'webpagetest.visualComplete',
      'webpagetest.visualComplete95',
      'webpagetest.TTFB',
      'webpagetest.fullyLoaded',
      'gpsi.speedscore',
      'axe.critical',
      'axe.serious',
      'axe.minor',
      'axe.moderate',
      'cpu.longTasksTotalDuration',
      'cpu.longTasks'
    ]
  }
};

module.exports = {
  open(context, options) {
    this.make = context.messageMaker('html').make;
    // we have to overwrite the default summary metrics, if given
    // instead of recursively merging the cli array param
    this.options = Object.assign({}, defaultConfig, options);
    this.HTMLBuilder = new HTMLBuilder(context, this.options);
    this.dataCollector = new DataCollector(context.resultUrls);
    this.maxAssets = get(options, 'maxAssets', 20);
    this.alias = {};
    this.context = context;
    // we have a couple of default regitered datatypes
    this.collectDataFrom = [
      'browsertime.run',
      'browsertime.console',
      'browsertime.pageSummary',
      'pagexray.run',
      'pagexray.pageSummary',
      'coach.run',
      'coach.pageSummary',
      'webpagetest.run',
      'webpagetest.pageSummary',
      'thirdparty.run',
      'thirdparty.pageSummary'
    ];
  },
  processMessage(message, queue) {
    const dataCollector = this.dataCollector;
    const make = this.make;

    // If this type is registered
    if (this.collectDataFrom.indexOf(message.type) > -1) {
      dataCollector.addDataForUrl(
        message.url,
        message.type,
        message.data,
        message.runIndex
      );
    } else {
      switch (message.type) {
        case 'error': {
          dataCollector.addErrorForUrl(
            message.url,
            message.source,
            message.data
          );
          break;
        }
        // we always want to add data from our HARs
        case 'webpagetest.har':
        case 'browsertime.har': {
          dataCollector.addDataForUrl(
            message.url,
            message.type,
            message.data,
            message.runIndex
          );
          break;
        }

        case 'html.pug': {
          // we got a pug from plugins, let compile and cache them
          renderer.addTemplate(message.data.id, message.data.pug);
          // and also keep the types so we can render them
          this.HTMLBuilder.addType(
            message.data.id,
            message.data.name,
            message.data.type
          );
          // make sure we pickup the data for this pug
          this.collectDataFrom.push(message.data.id + '.' + message.data.type);
          break;
        }

        case 'browsertime.alias': {
          this.alias[message.url] = message.data;
          break;
        }

        case 'html.css': {
          this.HTMLBuilder.addInlineCSS(message.data);
          break;
        }

        case 'aggregateassets.summary': {
          if (message.group === 'total') {
            const assetList = reduce(
              message.data,
              (assetList, asset) => {
                assetList.push(asset);
                return assetList;
              },
              []
            );

            const count = this.maxAssets,
              fullCount = Object.keys(assetList).length,
              topAssets = assetList
                .sort((a, b) => b.requestCount - a.requestCount)
                .splice(0, count);
            dataCollector.addSummary('assets', {
              topAssets,
              count,
              fullCount
            });
          }
          break;
        }

        case 'largestassets.summary': {
          if (message.group === 'total') {
            const assetsBySize = {};
            for (const contentType of Object.keys(message.data)) {
              assetsBySize[contentType] = message.data[contentType];
              dataCollector.addSummary('toplist', {
                assetsBySize
              });
            }
          }
          break;
        }
        case 'largestthirdpartyassets.summary': {
          if (message.group === 'total') {
            dataCollector.addSummary('toplist', {
              thirdPartyAssetsBySize: message.data
            });
          }
          break;
        }
        case 'slowestassets.summary': {
          if (message.group === 'total') {
            const slowestAssets = message.data;
            dataCollector.addSummary('toplist', {
              slowestAssets
            });
          }
          break;
        }

        case 'slowestthirdpartyassets.summary': {
          if (message.group === 'total') {
            dataCollector.addSummary('toplist', {
              thirdPartySlowestAssets: message.data
            });
          }
          break;
        }

        case 'domains.summary': {
          if (message.group === 'total') {
            const domainList = reduce(
              message.data,
              (domainList, domainStats) => {
                domainList.push(domainStats);
                return domainList;
              },
              []
            );

            const count = 200,
              fullCount = domainList.length,
              topDomains = domainList
                .sort((a, b) => b.requestCount - a.requestCount)
                .splice(0, count);
            dataCollector.addSummary('domains', {
              topDomains,
              count,
              fullCount
            });
          }
          break;
        }
        case 'webpagetest.summary':
        case 'coach.summary':
        case 'pagexray.summary':
        case 'browsertime.summary':
        case 'axe.summary': {
          if (message.group === 'total') {
            const data = {};
            set(data, message.type, message.data);
            dataCollector.addSummary('index', data);
            dataCollector.addSummary('detailed', data);
          }
          break;
        }
        case 'browsertime.config': {
          if (message.data.screenshot === true) {
            dataCollector.useBrowsertimeScreenshots(
              message.data.screenshotType
            );
          }
          break;
        }
        case 'sitespeedio.render': {
          return this.HTMLBuilder.render(dataCollector).then(() => {
            queue.postMessage(make('html.finished'));
          });
        }
      }
    }
  },
  config: defaultConfig
};
<commit_msg>cleanup list<commit_after>'use strict';

const HTMLBuilder = require('./htmlBuilder');
const get = require('lodash.get');
const set = require('lodash.set');
const reduce = require('lodash.reduce');
const DataCollector = require('./dataCollector');
const renderer = require('./renderer');

// lets keep this in the HTML context, since we need things from the
// regular options object in the output
const defaultConfig = {
  html: {
    showAllWaterfallSummary: false,
    pageSummaryMetrics: [
      'transferSize.total',
      'requests.total',
      'thirdParty.requests',
      'transferSize.javascript',
      'transferSize.css',
      'transferSize.image',
      'score.performance'
    ],
    summaryBoxes: [
      'score.score',
      'score.accessibility',
      'score.bestpractice',
      'score.privacy',
      'score.performance',
      'timings.firstPaint',
      'timings.fullyLoaded',
      'timings.pageLoadTime',
      'timings.FirstVisualChange',
      'timings.LastVisualChange',
      'timings.SpeedIndex',
      'timings.PerceptualSpeedIndex',
      'timings.VisualReadiness',
      'timings.VisualComplete',
      'requests.total',
      'requests.javascript',
      'requests.css',
      'requests.image',
      'transferSize.total',
      'transferSize.html',
      'transferSize.javascript',
      'contentSize.javascript',
      'transferSize.css',
      'transferSize.image',
      'thirdParty.transferSize',
      'thirdParty.requests',
      'webpagetest.SpeedIndex',
      'webpagetest.lastVisualChange',
      'webpagetest.render',
      'webpagetest.visualComplete',
      'webpagetest.visualComplete95',
      'webpagetest.TTFB',
      'webpagetest.fullyLoaded',
      'axe.critical',
      'axe.serious',
      'axe.minor',
      'axe.moderate',
      'cpu.longTasksTotalDuration',
      'cpu.longTasks'
    ]
  }
};

module.exports = {
  open(context, options) {
    this.make = context.messageMaker('html').make;
    // we have to overwrite the default summary metrics, if given
    // instead of recursively merging the cli array param
    this.options = Object.assign({}, defaultConfig, options);
    this.HTMLBuilder = new HTMLBuilder(context, this.options);
    this.dataCollector = new DataCollector(context.resultUrls);
    this.maxAssets = get(options, 'maxAssets', 20);
    this.alias = {};
    this.context = context;
    // we have a couple of default regitered datatypes
    this.collectDataFrom = [
      'browsertime.run',
      'browsertime.console',
      'browsertime.pageSummary',
      'pagexray.run',
      'pagexray.pageSummary',
      'coach.run',
      'coach.pageSummary',
      'webpagetest.run',
      'webpagetest.pageSummary',
      'thirdparty.run',
      'thirdparty.pageSummary'
    ];
  },
  processMessage(message, queue) {
    const dataCollector = this.dataCollector;
    const make = this.make;

    // If this type is registered
    if (this.collectDataFrom.indexOf(message.type) > -1) {
      dataCollector.addDataForUrl(
        message.url,
        message.type,
        message.data,
        message.runIndex
      );
    } else {
      switch (message.type) {
        case 'error': {
          dataCollector.addErrorForUrl(
            message.url,
            message.source,
            message.data
          );
          break;
        }
        // we always want to add data from our HARs
        case 'webpagetest.har':
        case 'browsertime.har': {
          dataCollector.addDataForUrl(
            message.url,
            message.type,
            message.data,
            message.runIndex
          );
          break;
        }

        case 'html.pug': {
          // we got a pug from plugins, let compile and cache them
          renderer.addTemplate(message.data.id, message.data.pug);
          // and also keep the types so we can render them
          this.HTMLBuilder.addType(
            message.data.id,
            message.data.name,
            message.data.type
          );
          // make sure we pickup the data for this pug
          this.collectDataFrom.push(message.data.id + '.' + message.data.type);
          break;
        }

        case 'browsertime.alias': {
          this.alias[message.url] = message.data;
          break;
        }

        case 'html.css': {
          this.HTMLBuilder.addInlineCSS(message.data);
          break;
        }

        case 'aggregateassets.summary': {
          if (message.group === 'total') {
            const assetList = reduce(
              message.data,
              (assetList, asset) => {
                assetList.push(asset);
                return assetList;
              },
              []
            );

            const count = this.maxAssets,
              fullCount = Object.keys(assetList).length,
              topAssets = assetList
                .sort((a, b) => b.requestCount - a.requestCount)
                .splice(0, count);
            dataCollector.addSummary('assets', {
              topAssets,
              count,
              fullCount
            });
          }
          break;
        }

        case 'largestassets.summary': {
          if (message.group === 'total') {
            const assetsBySize = {};
            for (const contentType of Object.keys(message.data)) {
              assetsBySize[contentType] = message.data[contentType];
              dataCollector.addSummary('toplist', {
                assetsBySize
              });
            }
          }
          break;
        }
        case 'largestthirdpartyassets.summary': {
          if (message.group === 'total') {
            dataCollector.addSummary('toplist', {
              thirdPartyAssetsBySize: message.data
            });
          }
          break;
        }
        case 'slowestassets.summary': {
          if (message.group === 'total') {
            const slowestAssets = message.data;
            dataCollector.addSummary('toplist', {
              slowestAssets
            });
          }
          break;
        }

        case 'slowestthirdpartyassets.summary': {
          if (message.group === 'total') {
            dataCollector.addSummary('toplist', {
              thirdPartySlowestAssets: message.data
            });
          }
          break;
        }

        case 'domains.summary': {
          if (message.group === 'total') {
            const domainList = reduce(
              message.data,
              (domainList, domainStats) => {
                domainList.push(domainStats);
                return domainList;
              },
              []
            );

            const count = 200,
              fullCount = domainList.length,
              topDomains = domainList
                .sort((a, b) => b.requestCount - a.requestCount)
                .splice(0, count);
            dataCollector.addSummary('domains', {
              topDomains,
              count,
              fullCount
            });
          }
          break;
        }
        case 'webpagetest.summary':
        case 'coach.summary':
        case 'pagexray.summary':
        case 'browsertime.summary':
        case 'axe.summary': {
          if (message.group === 'total') {
            const data = {};
            set(data, message.type, message.data);
            dataCollector.addSummary('index', data);
            dataCollector.addSummary('detailed', data);
          }
          break;
        }
        case 'browsertime.config': {
          if (message.data.screenshot === true) {
            dataCollector.useBrowsertimeScreenshots(
              message.data.screenshotType
            );
          }
          break;
        }
        case 'sitespeedio.render': {
          return this.HTMLBuilder.render(dataCollector).then(() => {
            queue.postMessage(make('html.finished'));
          });
        }
      }
    }
  },
  config: defaultConfig
};
<|endoftext|>


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

'use strict';

// [START oslogin_quickstart]
if (
  !process.env.GCLOUD_PROJECT ||
  !process.env.GOOGLE_APPLICATION_CREDENTIALS
) {
  throw new Error(
    'Usage: GCLOUD_PROJECT=<project_id> GOOGLE_APPLICATION_CREDENTIALS=<path to key json file> node #{$0}'
  );
}

const oslogin = require('@google-cloud/os-login');

const projectId = process.env.GCLOUD_PROJECT;

const client = new oslogin.OsLoginServiceClient({
  projectId: projectId,
});

const request = {
  name: 'users/1234abcd',
};

client
  .getLoginProfile(request)
  .then(responses => {
    const loginProfile = responses[0];
    console.log(loginProfile);
  })
  .catch(err => {
    console.error('ERROR:', err);
  });
// [END oslogin_quickstart]
<commit_msg>refactor(samples): replace promise with await async (#114)<commit_after>// Copyright 2017, Google LLC All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

async function main() {
  // [START oslogin_quickstart]
  if (
    !process.env.GCLOUD_PROJECT ||
    !process.env.GOOGLE_APPLICATION_CREDENTIALS
  ) {
    throw new Error(
      'Usage: GCLOUD_PROJECT=<project_id> GOOGLE_APPLICATION_CREDENTIALS=<path to key json file> node #{$0}'
    );
  }

  const oslogin = require('@google-cloud/os-login');

  const projectId = process.env.GCLOUD_PROJECT;

  const client = new oslogin.OsLoginServiceClient({
    projectId: projectId,
  });

  const request = {
    name: 'users/1234abcd',
  };

  const [loginProfile] = await client.getLoginProfile(request);
  console.log(loginProfile);
  // [END oslogin_quickstart]
}

main().catch(console.error);
<|endoftext|>


<commit_before>/* Theme Name:iDea - Clean & Powerful Bootstrap Theme
 * Author:HtmlCoder
 * Author URI:http://www.htmlcoder.me
 * Author e-mail:htmlcoder.me@gmail.com
 * Version:1.0.0
 * Created:October 2014
 * License URI:http://wrapbootstrap.com
 * File Description: Place here your custom scripts
 */
function googleTranslateElementInit(){
    new google.translate.TranslateElement({pageLanguage: 'zh-CN', layout: google.translate.TranslateElement.FloatPosition.TOP_LEFT,multilanguagePage: true, gaTrack: true, gaId: 'UA-98114394-1'}, 'google_translate_element');
};
function init() {
    var map = new BMap.Map("map");            // 创建Map实例
    // 23.2543310000,113.0110250000
    var point = new BMap.Point(113.0110250000,23.2543310000); // 创建点坐标
    map.centerAndZoom(point,10);
    // map.enableScrollWheelZoom();                 //启用滚轮放大缩小
    var mapType1 = new BMap.MapTypeControl({mapTypes: [BMAP_NORMAL_MAP,BMAP_HYBRID_MAP]});
    var mapType2 = new BMap.MapTypeControl({anchor: BMAP_ANCHOR_TOP_LEFT});
    var overView = new BMap.OverviewMapControl();
    var overViewOpen = new BMap.OverviewMapControl({isOpen:true, anchor: BMAP_ANCHOR_BOTTOM_RIGHT});
    map.addControl(mapType1);          //2D图，卫星图
    map.addControl(mapType2);          //左上角，默认地图控件
    map.setCurrentCity("三水");        //由于有3D图，需要设置城市哦
    map.addControl(overView);          //添加默认缩略地图控件
    map.addControl(overViewOpen);      //右下角，打开
    var myIcon = new BMap.Icon("dist/images/loc.png", new BMap.Size(144,80));
    var marker = new BMap.Marker(point, {icon: myIcon});  // 创建标注
    map.addOverlay(marker);               // 将标注添加到地图中
    marker.setAnimation(BMAP_ANIMATION_BOUNCE); //跳动的动画
    // 添加带有定位的导航控件
    var navigationControl = new BMap.NavigationControl({
        // 靠左上角位置
        anchor: BMAP_ANCHOR_BOTTOM_LEFT,
        // LARGE类型
        type: BMAP_NAVIGATION_CONTROL_LARGE,
        // 启用显示定位
        // enableGeolocation: true
    });
    map.addControl(navigationControl);
}  <commit_msg>提交百度统计代码<commit_after>/* Theme Name:iDea - Clean & Powerful Bootstrap Theme
 * Author:HtmlCoder
 * Author URI:http://www.htmlcoder.me
 * Author e-mail:htmlcoder.me@gmail.com
 * Version:1.0.0
 * Created:October 2014
 * License URI:http://wrapbootstrap.com
 * File Description: Place here your custom scripts
 */
function googleTranslateElementInit(){
    new google.translate.TranslateElement({pageLanguage: 'zh-CN', layout: google.translate.TranslateElement.FloatPosition.TOP_LEFT,multilanguagePage: true, gaTrack: true, gaId: 'UA-98114394-1'}, 'google_translate_element');
};
function init() {
    var map = new BMap.Map("map");            // 创建Map实例
    // 23.2543310000,113.0110250000
    var point = new BMap.Point(113.0110250000,23.2543310000); // 创建点坐标
    map.centerAndZoom(point,10);
    // map.enableScrollWheelZoom();                 //启用滚轮放大缩小
    var mapType1 = new BMap.MapTypeControl({mapTypes: [BMAP_NORMAL_MAP,BMAP_HYBRID_MAP]});
    var mapType2 = new BMap.MapTypeControl({anchor: BMAP_ANCHOR_TOP_LEFT});
    var overView = new BMap.OverviewMapControl();
    var overViewOpen = new BMap.OverviewMapControl({isOpen:true, anchor: BMAP_ANCHOR_BOTTOM_RIGHT});
    map.addControl(mapType1);          //2D图，卫星图
    map.addControl(mapType2);          //左上角，默认地图控件
    map.setCurrentCity("三水");        //由于有3D图，需要设置城市哦
    map.addControl(overView);          //添加默认缩略地图控件
    map.addControl(overViewOpen);      //右下角，打开
    var myIcon = new BMap.Icon("dist/images/loc.png", new BMap.Size(144,80));
    var marker = new BMap.Marker(point, {icon: myIcon});  // 创建标注
    map.addOverlay(marker);               // 将标注添加到地图中
    marker.setAnimation(BMAP_ANIMATION_BOUNCE); //跳动的动画
    // 添加带有定位的导航控件
    var navigationControl = new BMap.NavigationControl({
        // 靠左上角位置
        anchor: BMAP_ANCHOR_BOTTOM_LEFT,
        // LARGE类型
        type: BMAP_NAVIGATION_CONTROL_LARGE,
        // 启用显示定位
        // enableGeolocation: true
    });
    map.addControl(navigationControl);
}
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?f80fd4df90476a926eae590912bea3bc";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})(); <|endoftext|>


<commit_before>'use strict';

// date output of |date "+DATE: %m/%d/%y TIME: %H:%M:%S"| command.
var LAST_UPDATE = 'DATE: 04/29/15 TIME: 16:30:22';

var DEBUG = true;
var CACHE_NAME = 'foo';
var cached = [
  '/index.html',
  '/test.html',
  '/css/app.css',
  '/js/app.js',
  '/img/mozilla.png'
];

if (!self.debug) {
  self.debug = function debug(message) {
    dump("Execution context(" + LAST_UPDATE + "): " + message + "\n");
  };
}

self.addEventListener('message', msg => {
  debug('event from client - ' + msg.data);
  self.clients.matchAll().then(function(res) {
    if (!res.length) {
      debug("no clients are currently controlled!");
      return;
    }
    res[0].postMessage(msg.data === 'ping' ? 'pong' : msg.data);
  });
});

self.addEventListener('install', evt => {
  if (DEBUG) {
    debug('install event fired!');
  }

  function delaysAsInstalled() {
    debug('opening cache...');
    return caches.open(CACHE_NAME).then((cache) => {
      debug('opened cache so adding content!');
      return cache.addAll(cached);
    });
  }
  evt.waitUntil(delaysAsInstalled());
});

self.addEventListener('activate', evt => {
  if (DEBUG) {
    debug('activate event fired!');
  }
  function delaysAsActivated() {
    return Promise.resolve();
  }
  evt.waitUntil(delaysAsActivated());
});

self.addEventListener('fetch', evt => {
  var request = evt.request;
  var url = new URL(request.url);

  if (DEBUG) {
    debug('fetching ' + url.pathname);
  }

  evt.respondWith(
    caches.match(request).then((response) => {
      if (response) {
        return response;
      } else {
        var fetchRequest = request.clone();
        return fetch(fetchRequest).then((response) => {
          if (!response ||
              (response.status !== 200) || (response.type !== 'basic')) {
            return response;
          }
          var responseToCache = response.clone();
          caches.open(CACHE_NAME).then((cache) => {
            cache.put(request, responseToCache);
          });
          return response;
        });
      }
    })
  );
});
<commit_msg>Update service worker scritp<commit_after>'use strict';

// date output of |date "+DATE: %m/%d/%y TIME: %H:%M:%S"| command.
var LAST_UPDATE = 'DATE: 04/30/15 TIME: 09:24:09';

var DEBUG = true;
var CACHE_NAME = 'foo';
var cached = [
  '/index.html',
  '/test.html',
  '/css/app.css',
  '/js/app.js',
  '/img/mozilla.png'
];

if (!self.debug) {
  self.debug = function debug(message) {
    dump("Execution context(" + LAST_UPDATE + "): " + message + "\n");
  };
}

self.addEventListener('message', msg => {
  debug('event from client - ' + msg.data);
  self.clients.matchAll().then(function(res) {
    if (!res.length) {
      debug("no clients are currently controlled!");
      return;
    }
    res[0].postMessage(msg.data === 'ping' ? 'pong' : msg.data);
  });
});

self.addEventListener('install', evt => {
  if (DEBUG) {
    debug('install event fired!');
  }

  function delaysAsInstalled() {
    debug('opening cache...');
    return caches.open(CACHE_NAME).then((cache) => {
      debug('opened cache so adding content!');
      return cache.addAll(cached);
    });
  }
  evt.waitUntil(delaysAsInstalled());
});

self.addEventListener('activate', evt => {
  if (DEBUG) {
    debug('activate event fired!');
  }
  function delaysAsActivated() {
    return Promise.resolve();
  }
  evt.waitUntil(delaysAsActivated());
});

self.addEventListener('fetch', evt => {
  var request = evt.request;
  var url = new URL(request.url);

  if (DEBUG) {
    debug('fetching ' + url.pathname);
  }

  evt.respondWith(
    caches.match(request).then((response) => {
      if (response) {
        return response;
      } else {
        var fetchRequest = request.clone();
        return fetch(fetchRequest).then((response) => {
          if (!response ||
              (response.status !== 200) || (response.type !== 'basic')) {
            return response;
          }
          var responseToCache = response.clone();
          caches.open(CACHE_NAME).then((cache) => {
            cache.put(request, responseToCache);
          });
          return response;
        });
      }
    })
  );
});
<|endoftext|>


<commit_before>class Node_Tree {
  constructor(val) {
    this.val = val;
    this.parent = null;
    this.children = [];
  }
}

class Node_Trie {
  constructor(val) {
    /*
    ** The node stores a single character as its value.
    ** Child nodes are stored in an object instead of an array for constant-time lookup
    ** because every child node will have a unique value/letter
    */
    this.val = val;
    this.children = {};
  }
}

export { Node_Tree, Node_Trie };<commit_msg>Add Node class for BST<commit_after>class Node_Tree {
  constructor(val) {
    this.val = val;
    this.parent = null;
    this.children = [];
  }
}

class Node_Trie {
  constructor(val) {
    /*
    ** The node stores a single character as its value.
    ** Child nodes are stored in an object instead of an array for constant-time lookup
    ** because every child node will have a unique value/letter
    */
    this.val = val;
    this.children = {};
  }
}

class Node_BST {
  constructor(val) {
    this.val   = val;
    this.left  = null;
    this.right = null;
  }
}

export { Node_Tree, Node_Trie, Node_BST };<|endoftext|>


<commit_before>module.exports = {
    "env": {
        "node": true,
        "mocha": true
    },
    "parser": "@typescript-eslint/parser",
    "plugins": ["@typescript-eslint"],
    "extends": ["plugin:@typescript-eslint/recommended"],
    "rules": {
        "indent": [
            "error",
            4
        ],
        "quotes": [
            "error",
            "double"
        ],
        "semi": [
            "error",
            "always"
        ],
        "curly": [
            "error",
            "all"
        ],
        "strict": [
            "error",
            "safe"
        ],
        "eqeqeq": [
            "error",
            "always"
        ],
        "one-var": [
            "error",
            "never"
        ],
        "multiline-ternary": [
            "error",
            "always"
        ]
    }
};
<commit_msg>Add config for Prettier<commit_after>module.exports = {
    "env": {
        "node": true,
        "mocha": true
    },
    "parser": "@typescript-eslint/parser",
    "plugins": ["@typescript-eslint", "prettier"],
    "extends": ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
    "rules": {

        // Conflicts with Prettier
        "@typescript-eslint/indent": "off",

        // Conflicts with some rest API parameters
        "@typescript-eslint/camelcase": "off",

        "eqeqeq": [
            "error",
            "always"
        ],

        "one-var": [
            "error",
            "never"
        ],
    }
};
<|endoftext|>


<commit_before>// Helpers for custom tasks, mainly around promises / exec
var exec = require('faithful-exec');
var shjs = require('shelljs');

module.exports = function (grunt) {
    // URI paths for our tasks to use
    grunt.dist = './dist/';
    grunt.uriTask = './grunt/';
    grunt.uriSrc = './src/UI';
    grunt.uriBuild = './build/';

    function promising(task, promise) {
        var done = task.async();
        promise.then(function () {
            done();
        }, function (error) {
            grunt.log.write(error + '\n');
            done(false);
        });
    }

    function system(cmd) {
        grunt.log.write('% ' + cmd + '\n');
        return exec(cmd).then(function (result) {
            grunt.log.write(result.stderr + result.stdout);
        }, function (error) {
            grunt.log.write(error.stderr + '\n');
            throw 'Failed to run \'' + cmd + '\'';
        });
    }

    function ensureCleanMaster() {
        return exec('git symbolic-ref HEAD').then(function (result) {
            if (result.stdout.trim() !== 'refs/heads/master') throw 'Not on master branch, aborting';
            return exec('git status --porcelain');
        }).then(function (result) {
            if (result.stdout.trim() !== '') throw 'Working copy is dirty, aborting';
        });
    }

    // Each task has it's own JS file.
    var tasks = {};
    tasks.pkg = grunt.file.readJSON('package.json');

    // General tasks
    tasks = require(grunt.uriTask + 'clean.js')(grunt, tasks);
    tasks = require(grunt.uriTask + 'watch.js')(grunt, tasks);

    // Concatenation Tasks
    tasks = require(grunt.uriTask + 'concat-js.js')(grunt, tasks);

    // Documentation Generator
    tasks = require(grunt.uriTask + 'ngdocs.js')(grunt, tasks);

    // Compass Tasks
    tasks = require(grunt.uriTask + 'sass.js')(grunt, tasks);

    // Minify Tasks
    tasks = require(grunt.uriTask + 'minify-html.js')(grunt, tasks);
    tasks = require(grunt.uriTask + 'minify-js.js')(grunt, tasks);

    grunt.registerTask('docs', 'Generate documentation', [
        'ngdocs'
    ]);

    grunt.registerTask('build', 'Perform a normal build', [
        'clean',
        'sass:prod',
        'sass:dev',
        'htmlmin:prod',
        'concat:js',
        'uglify:js',
        'ngdocs'
    ]);

    grunt.registerTask('default', [
        'build'
    ]);

    grunt.registerTask('publish-pages', 'Publish a clean build, docs, and sample to github.io', function () {
        promising(this,
            ensureCleanMaster()
                .then(function () {
                    shjs.rm('-rf', 'build');
                    return system('git checkout gh-pages');
                }).then(function () {
                    return system('git merge master');
                }).then(function () {
                    return system('grunt build');
                }).then(function () {
                    return system('git add --all');
                }).then(function () {
                    return system('git commit -m \'Automatic gh-pages build\'');
                }).then(function () {
                    return system('git checkout master');
                })
        );
    });

    grunt.registerTask('push-pages', 'Push published pages', function () {
        promising(this,
            ensureCleanMaster().then(function () {
                shjs.rm('-rf', 'build');
                return system('git checkout gh-pages');
            }).then(function () {
                return system('git push origin gh-pages');
            }).then(function () {
                return system('git checkout master');
            })
        );
    });

    // Initialize The Grunt Configuration
    grunt.initConfig(tasks);
};
<commit_msg>updated<commit_after>// Helpers for custom tasks, mainly around promises / exec
var exec = require('faithful-exec');
var shjs = require('shelljs');

module.exports = function (grunt) {
    // URI paths for our tasks to use
    grunt.dist = './dist/';
    grunt.uriTask = './grunt/';
    grunt.uriSrc = './src/UI';
    grunt.uriBuild = './build/';

    function promising(task, promise) {
        var done = task.async();
        promise.then(function () {
            done();
        }, function (error) {
            grunt.log.write(error + '\n');
            done(false);
        });
    }

    function system(cmd) {
        grunt.log.write('% ' + cmd + '\n');
        return exec(cmd).then(function (result) {
            grunt.log.write(result.stderr + result.stdout);
        }, function (error) {
            grunt.log.write(error.stderr + '\n');
            throw 'Failed to run \'' + cmd + '\'';
        });
    }

    function ensureCleanMaster() {
        return exec('git symbolic-ref HEAD').then(function (result) {
            if (result.stdout.trim() !== 'refs/heads/master') throw 'Not on master branch, aborting';
            return exec('git status --porcelain');
        }).then(function (result) {
            if (result.stdout.trim() !== '') throw 'Working copy is dirty, aborting';
        });
    }

    // Each task has it's own JS file.
    var tasks = {};
    tasks.pkg = grunt.file.readJSON('package.json');

    // General tasks
    tasks = require(grunt.uriTask + 'clean.js')(grunt, tasks);
    tasks = require(grunt.uriTask + 'watch.js')(grunt, tasks);

    // Concatenation Tasks
    tasks = require(grunt.uriTask + 'concat-js.js')(grunt, tasks);

    // Documentation Generator
    tasks = require(grunt.uriTask + 'ngdocs.js')(grunt, tasks);

    // Compass Tasks
    tasks = require(grunt.uriTask + 'sass.js')(grunt, tasks);

    // Minify Tasks
    tasks = require(grunt.uriTask + 'minify-html.js')(grunt, tasks);
    tasks = require(grunt.uriTask + 'minify-js.js')(grunt, tasks);

    grunt.registerTask('docs', 'Generate documentation', [
        'ngdocs'
    ]);

    grunt.registerTask('build', 'Perform a normal build', [
        'clean',
        'sass:prod',
        'sass:dev',
        'htmlmin:prod',
        'concat:js',
        'uglify:js',
        'ngdocs'
    ]);

    grunt.registerTask('default', [
        'build'
    ]);

    grunt.registerTask('publish-pages', 'Publish a clean build, docs, and sample to github.io', function () {
        promising(this,
            ensureCleanMaster()
                .then(function () {
                    shjs.rm('-rf', 'build');
                    return system('git checkout gh-pages');
                }).then(function () {
                    return system('git merge master');
                }).then(function () {
                    return system('grunt build');
                }).then(function () {
                    return system('git add --all');
                }).then(function () {
                    return system('git commit -m "Automatic gh-pages build"');
                }).then(function () {
                    return system('git checkout master');
                })
        );
    });

    grunt.registerTask('push-pages', 'Push published pages', function () {
        promising(this,
            ensureCleanMaster().then(function () {
                shjs.rm('-rf', 'build');
                return system('git checkout gh-pages');
            }).then(function () {
                return system('git push origin gh-pages');
            }).then(function () {
                return system('git checkout master');
            })
        );
    });

    // Initialize The Grunt Configuration
    grunt.initConfig(tasks);
};
<|endoftext|>


<commit_before>module.exports = function (grunt)
{

    /**
     * Configuration
     */

    grunt.initConfig({

        pkg: grunt.file.readJSON('package.json'),

        banner: '/*!\n' +
            ' * <%= pkg.name %> v<%= pkg.version %>\n' +
            ' * Homepage: <%= pkg.homepage %>\n' +
            ' * Copyright 2014-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
            ' * Licensed under <%= pkg.license %>\n' +
            ' * Based on Bootswatch (http://bootswatch.com/)\n' +
            '*/\n',

        builddir: "./themes",

        swatch: {
            default:{},
            united:{},
            yeti:{}
        },

        clean: {
            build: {
                src: []
            }
        },

        concat: {
            options: {
                banner: '<%= banner %>',
                stripBanners: false
            },
            dist: {
                src: [],
                dest: ''
            }
        },

        uglify: {
            bootstrap: {
                files: {
                    'src/js/bootstrap.min.js': [
                        'src/js/bootstrap/transition.js',
                        'src/js/bootstrap/alert.js',
                        'src/js/bootstrap/button.js',
                        'src/js/bootstrap/carousel.js',
                        'src/js/bootstrap/collapse.js',
                        'src/js/bootstrap/dropdown.js',
                        'src/js/bootstrap/modal.js',
                        'src/js/bootstrap/tooltip.js',
                        'src/js/bootstrap/popover.js',
                        'src/js/bootstrap/scrollspy.js',
                        'src/js/bootstrap/tab.js',
                        'src/js/bootstrap/affix.js'
                    ],
                    'src/js/jquery-2.1.0.min.js': [
                        'src/js/jquery-2.1.0.js'
                    ]

                }
            }
        },

        sass: {
            dist: {
                options: {
                  compress: false
                },
                files: {}
            }
        },
    });

    /**
     * Load Tasks
     */

    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-sass');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-concat');

    /**
     * Register Custom Tasks
     */

    /**
     * Build task
     * @param theme
     */
    grunt.registerTask('build', 'build a regular theme', function(theme) {

        var concatSrc;
        var concatDest;
        var sassDest;
        var sassSrc;
        var files = {};
        var dist = {};

        // global build.scss
        concatSrc  = '<%=builddir%>/global/build.scss';

        // dis for build.scss
        concatDest = '<%=builddir%>/' + theme + '/build.scss';

        // sass from build.scss
        sassSrc    = [ '<%=builddir%>/' + theme + '/' + 'build.scss' ];

        // sass to bootstrap.css
        sassDest   = '<%=builddir%>/' + theme + '/bootstrap.css';

        // concat
        dist = {src: concatSrc, dest: concatDest};
        grunt.config('concat.dist', dist);

        //files
        files = {}; files[sassDest] = sassSrc;

        //sass
        grunt.config('sass.dist.files', files);

        //clean
        grunt.config('clean.build.src', [sassSrc]);

        // runs tasks
        grunt.task.run(['concat', 'sass:dist', 'clean:build']);
    });

    /**
     * Run build task for every theme on swatch object
     */
    grunt.registerMultiTask('swatch', 'build a theme', function() {
        var theme = this.target;
        grunt.task.run('build:' + theme);
    });

    /**
     * Set swatch task as default
     */
    grunt.registerTask('default', 'build a theme', function() {
        grunt.task.run('swatch');
    });
};
<commit_msg>task watch all is added<commit_after>module.exports = function (grunt)
{

    /**
     * Configuration
     */

    grunt.initConfig({

        pkg: grunt.file.readJSON('package.json'),

        banner: '/*!\n' +
            ' * <%= pkg.name %> v<%= pkg.version %>\n' +
            ' * Homepage: <%= pkg.homepage %>\n' +
            ' * Copyright 2014-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
            ' * Licensed under <%= pkg.license %>\n' +
            ' * Based on Bootswatch (http://bootswatch.com/)\n' +
            '*/\n',

        builddir: "./themes",

        swatch: {
            default:{},
            united:{},
            yeti:{}
        },

        clean: {
            build: {
                src: []
            }
        },

        concat: {
            options: {
                banner: '<%= banner %>',
                stripBanners: false
            },
            dist: {
                src: [],
                dest: ''
            }
        },

        uglify: {
            bootstrap: {
                files: {
                    'src/js/bootstrap.min.js': [
                        'src/js/bootstrap/transition.js',
                        'src/js/bootstrap/alert.js',
                        'src/js/bootstrap/button.js',
                        'src/js/bootstrap/carousel.js',
                        'src/js/bootstrap/collapse.js',
                        'src/js/bootstrap/dropdown.js',
                        'src/js/bootstrap/modal.js',
                        'src/js/bootstrap/tooltip.js',
                        'src/js/bootstrap/popover.js',
                        'src/js/bootstrap/scrollspy.js',
                        'src/js/bootstrap/tab.js',
                        'src/js/bootstrap/affix.js'
                    ],
                    'src/js/jquery-2.1.0.min.js': [
                        'src/js/jquery-2.1.0.js'
                    ]

                }
            }
        },

        sass: {
            dist: {
                files: {}
            }
        },

        watch: {

            default: {
                files: ['<%=builddir%>/default/*.scss'],
                tasks: ['build:default']
            },
        }
    });

    /**
     * Load Tasks
     */

    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-sass');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-concat');

    /**
     * Register Custom Tasks
     */

    /**
     * Build task
     * @param theme
     */
    grunt.registerTask('build', 'build a regular theme', function(theme) {

        var concatSrc;
        var concatDest;
        var sassDest;
        var sassSrc;
        var files = {};
        var dist = {};

        // global build.scss
        concatSrc  = '<%=builddir%>/global/build.scss';

        // dis for build.scss
        concatDest = '<%=builddir%>/' + theme + '/build.scss';

        // sass from build.scss
        sassSrc    = [ '<%=builddir%>/' + theme + '/' + 'build.scss' ];

        // sass to bootstrap.css
        sassDest   = '<%=builddir%>/' + theme + '/bootstrap.css';

        // concat
        dist = {src: concatSrc, dest: concatDest};
        grunt.config('concat.dist', dist);

        //files
        files = {}; files[sassDest] = sassSrc;

        //sass
        grunt.config('sass.dist.files', files);

        //clean
        grunt.config('clean.build.src', [sassSrc]);

        // runs tasks
        grunt.task.run(['concat', 'sass:dist', 'clean:build']);
    });

    /**
     * Run build task for every theme on swatch object
     */
    grunt.registerMultiTask('swatch', 'build a theme', function() {
        var theme = this.target;
        grunt.task.run('build:' + theme);
    });

    /**
     * Set swatch task as default
     */
    grunt.registerTask('default', 'build a theme', function() {
        grunt.task.run('swatch');
    });

    /**
     * Watch all themes
     */
    grunt.registerTask('watch-themes', 'watch all themes', function() {

        var watch_config = {};

        //get all themes
        var themes = grunt.config.get('swatch');

        // set configurations on watch object
        for(var theme in themes)
        {
            watch_config[theme] = {
                files: ['<%=builddir%>/' + theme + '/*.scss'],
                tasks: ['build:'+theme]
            };
        }

        // configure watch task
        grunt.config('watch', watch_config);

        //run watch task
        grunt.task.run('watch');
    });
};
<|endoftext|>


<commit_before>
describe("app.views.ProfileHeader", function() {
  beforeEach(function() {
    this.model = factory.personWithProfile({
      diaspora_id: "my@pod",
      name: "User Name",
      relationship: 'mutual',
      profile: { tags: ['test'] }
    });
    this.view = new app.views.ProfileHeader({model: this.model});
    loginAs(factory.userAttrs());
  });

  context("#presenter", function() {
    it("contains necessary elements", function() {
      expect(this.view.presenter()).toEqual(jasmine.objectContaining({
        diaspora_id: "my@pod",
        name: "User Name",
        is_blocked: false,
        is_own_profile: false,
        has_tags: true,
        show_profile_btns: true,
        relationship: 'mutual',
        is_sharing: true,
        is_receiving: true,
        is_mutual: true,
        profile: jasmine.objectContaining({
          tags: ['test']
        })
      }));
    });
  });

  describe("showMessageModal", function() {
    beforeEach(function() {
      $("body").append("
").append(spec.readFixture("conversations_modal"));
    });

    it("calls app.helpers.showModal", function() {
      spyOn(app.helpers, "showModal");
      this.view.showMessageModal();
      expect(app.helpers.showModal);
    });

    it("app.views.ConversationsForm with correct parameterswhen modal is loaded", function() {
      gon.conversationPrefill = [
        {id: 1, name: "diaspora user", handle: "diaspora-user@pod.tld"},
        {id: 2, name: "other diaspora user", handle: "other-diaspora-user@pod.tld"},
        {id: 3, name: "user@pod.tld", handle: "user@pod.tld"}
      ];

      spyOn(app.views.ConversationsForm.prototype, "initialize");
      this.view.showMessageModal();
      $("#conversationModal").trigger("modal:loaded");
      expect(app.views.ConversationsForm.prototype.initialize)
        .toHaveBeenCalledWith({prefill: gon.conversationPrefill});
    });
  });
});
<commit_msg>Improve profile header jasmine test<commit_after>
describe("app.views.ProfileHeader", function() {
  beforeEach(function() {
    this.model = factory.personWithProfile({
      diaspora_id: "my@pod",
      name: "User Name",
      relationship: 'mutual',
      profile: { tags: ['test'] }
    });
    this.view = new app.views.ProfileHeader({model: this.model});
    loginAs(factory.userAttrs());
  });

  context("#presenter", function() {
    it("contains necessary elements", function() {
      expect(this.view.presenter()).toEqual(jasmine.objectContaining({
        diaspora_id: "my@pod",
        name: "User Name",
        is_blocked: false,
        is_own_profile: false,
        has_tags: true,
        show_profile_btns: true,
        relationship: 'mutual',
        is_sharing: true,
        is_receiving: true,
        is_mutual: true,
        profile: jasmine.objectContaining({
          tags: ['test']
        })
      }));
    });
  });

  describe("showMessageModal", function() {
    beforeEach(function() {
      spec.content().append("
");
    });

    it("calls app.helpers.showModal", function() {
      spyOn(app.helpers, "showModal");
      this.view.showMessageModal();
      expect(app.helpers.showModal).toHaveBeenCalled();
    });

    it("initializes app.views.ConversationsForm with correct parameters when modal is loaded", function() {
      gon.conversationPrefill = [
        {id: 1, name: "diaspora user", handle: "diaspora-user@pod.tld"},
        {id: 2, name: "other diaspora user", handle: "other-diaspora-user@pod.tld"},
        {id: 3, name: "user@pod.tld", handle: "user@pod.tld"}
      ];

      spyOn(app.views.ConversationsForm.prototype, "initialize");
      this.view.showMessageModal();
      $("#conversationModal").trigger("modal:loaded");
      expect(app.views.ConversationsForm.prototype.initialize)
        .toHaveBeenCalledWith({prefill: gon.conversationPrefill});
    });
  });
});
<|endoftext|>