<commit_before>angular.module('os.biospecimen.models.specimen', ['os.common.models', 'os.biospecimen.models.form'])
  .factory('Specimen', function(osModel, $http, $parse, SpecimenRequirement, Form, Util) {

    function matches(name, regex) {
      return name && name.match(regex) != null;
    }

    function isSpecimenCentric(specimen) {
      return matches(specimen.ppid, /^(\$\$cp_reg_\d+\$\$)$/g) ||
               matches(specimen.visitName, /^(\$\$cp_visit_\d+\$\$)$/g);
    }

    var Specimen = osModel(
      'specimens',
      function(specimen) {
        if (specimen.specimensPool) {
          specimen.specimensPool = specimen.specimensPool.map(
            function(poolSpmn) {
              return new Specimen(poolSpmn);
            }
          );
        }

        if (specimen.children) {
          specimen.children = specimen.children.map(
            function(child) {
              return new Specimen(child);
            }
          );
        }

        specimen.$$specimenCentricCp = isSpecimenCentric(specimen);
      }
    );

    Specimen.listFor = function(cprId, visitDetail) {
      return Specimen.query(angular.extend({cprId: cprId}, visitDetail || {}));
    };

    Specimen.listByLabels = function(labels) {
      return Specimen.query({label: labels});
    };

    Specimen.flatten = function(specimens, parent, depth, pooledSpecimen) {
      var result = [];
      if (!specimens) {
        return result;
      }

      depth = depth || 0;
      angular.forEach(specimens, function(specimen) {
        result.push(specimen);
        specimen.depth = depth || 0;

        specimen.parent = specimen.parent || parent;
        specimen.pooledSpecimen = specimen.pooledSpecimen || pooledSpecimen;

        var hasSpecimensPool = false;
        if (depth == 0) {
          hasSpecimensPool = !!specimen.specimensPool && specimen.specimensPool.length > 0;
          if (hasSpecimensPool) {
            result = result.concat(Specimen.flatten(specimen.specimensPool, specimen, depth + 1, specimen));
          }
        }

        var hasChildren = (!!specimen.children && specimen.children.length > 0);
        specimen.hasChildren = hasSpecimensPool || hasChildren;
        if (hasChildren) {
          result = result.concat(Specimen.flatten(specimen.children, specimen, depth + 1));
        }

        if (specimen instanceof SpecimenRequirement) {
          return;
        }

        specimen.hasOnlyPendingChildren = hasOnlyPendingChildren(specimen.children);
        if (specimen.hasOnlyPendingChildren) {
          specimen.hasOnlyPendingChildren = hasOnlyPendingChildren(specimen.specimensPool);
        }
      });

      return result;
    };

    Specimen.save = function(specimens) {
      return $http.post(Specimen.url() + 'collect', specimens).then(Specimen.modelArrayRespTransform);
    };

    //Update specimens in bulk with same detail
    Specimen.bulkEdit = function(detail) {
      return $http.put(Specimen.url() + "bulk-update", detail).then(Specimen.modelArrayRespTransform);
    }

    //Update specimens in bulk by providing detail for each
    Specimen.bulkUpdate = function(specimens) {
      return $http.put(Specimen.url(), specimens).then(Specimen.modelArrayRespTransform);
    };

    Specimen.isUniqueLabel = function(cpShortTitle, label) {
      return $http.head(Specimen.url(), {params: {cpShortTitle: cpShortTitle, label: label}}).then(
        function(result) {
          return false;
        },

        function(result) {
          return true;
        }
      );
    };

    Specimen.getAnticipatedSpecimen = function(srId) {
      return SpecimenRequirement.getById(srId).then(
        function(sr) {
          return new Specimen(toSpecimenAttrs(sr));
        }
      );
    };

    Specimen.getRouteIds = function(specimenId) {
      return $http.get(Specimen.url() + specimenId + '/cpr-visit-ids').then(
        function(resp) {
          return resp.data;
        }
      );
    }

    Specimen.bulkDelete = function(specimenIds) {
      return $http.delete(Specimen.url(), {params: {id: specimenIds}}).then(
        function(result) {
          return result.data;
        }
      );
    }

    Specimen.bulkStatusUpdate = function(statusSpecs) {
      return $http.put(Specimen.url() + '/status', statusSpecs).then(
        function(result) {
          return result.data;
        }
      );
    }

    Specimen.getByIds = function(ids) {
      return Specimen.query({id: ids});
    }

    Specimen.prototype.getType = function() {
      return 'specimen';
    }

    Specimen.prototype.getDisplayName = function() {
      return this.label;
    };

    Specimen.prototype.hasSufficientQty = function() {
      var qty = this.initialQty;
      angular.forEach(this.children, function(child) {
        if (child.lineage == 'Aliquot') {
          qty -= child.initialQty;
        }
      });

      return qty >= 0;
    }

    Specimen.prototype.rootSpecimen = function() {
      var curr = this;
      while (curr.parent) {
        curr = curr.parent;
      }

      return curr;
    };

    Specimen.prototype.getExtensionCtxt = function(params) {
      return Specimen.getExtensionCtxt(params);
    }

    Specimen.prototype.getForms = function(params) {
      return Form.listFor(Specimen.url(), this.$id(), params);
    };

    Specimen.prototype.getRecords = function() {
      var url = Specimen.url() + this.$id() + '/extension-records';
      return Form.listRecords(url);
    };

    Specimen.prototype.getEvents = function(callback) {
      var events = [];

      if (!!this.$id()) {
        $http.get(Specimen.url() + '/' + this.$id() + '/events').then(
          function(result) {
            Util.unshiftAll(events, getEventsList(result.data));
            if (typeof callback == 'function') {
              callback(events);
            }
          }
        );
      }

      return events;
    };

    Specimen.prototype.$saveProps = function() {
      var props = ['children', 'depth', 'hasChildren', 'isOpened', 'specimensPool'];
      var that = this;
      props.forEach(function(prop) { delete that[prop]; });
      return this;
    };

    Specimen.prototype.close = function(reason) {
      var statusSpec = {status: 'Closed', reason: reason};
      return updateSpecimenStatus(this, statusSpec);
    }

    Specimen.prototype.reopen = function() {
      var statusSpec = {status: 'Active'};
      return updateSpecimenStatus(this, statusSpec);
    };

    Specimen.prototype.showVirtual = function() {
      return this.storageType == 'Virtual' && (!this.status || this.status == 'Pending');
    }

    Specimen.prototype.getMatchingRule = function(allocRules) {
      var result = -1;
      for (var i = 0; i < allocRules.length; ++i) {
        if ($parse(allocRules[i].criteria)({specimen: this})) {
          result = i;
          break;
        }
      }

      return {index: result, rule: result != -1 ? allocRules[result] : undefined};
    }

    function toSpecimenAttrs(sr) {
      sr.reqId = sr.id;
      sr.reqLabel = sr.name;
      sr.poolSpecimen = !!sr.pooledSpecimenReqId;

      var attrs = [
        'id', 'name', 'pooledSpecimenReqId',
        'collector', 'collectionProcedure', 'collectionContainer',
        'receiver', 'labelPrintCopies'
      ];

      attrs.forEach(function(attr) {
        delete sr[attr];
      });

      if (sr.children) {
        sr.children = sr.children.map(toSpecimenAttrs);
      }

      if (sr.specimensPool) {
        sr.specimensPool = sr.specimensPool.map(toSpecimenAttrs);
      }

      return sr;
    };

    function getEventsList(eventsRecs) { /* eventsRecs: [{event info, records: [event records]}] */
      var eventsList = [];
      angular.forEach(eventsRecs, function(eventRecs) {
        angular.forEach(eventRecs.records, function(record) {
          var user = null, time = null;
          for (var i = 0; i < record.fieldValues.length; ++i) {
            if (record.fieldValues[i].name == 'user') {
              user = record.fieldValues[i].value;
            } else if (record.fieldValues[i].name == 'time') {
              time = record.fieldValues[i].value;
            }
          }

          eventsList.push({
            id: record.recordId,
            formId: eventRecs.id,
            formCtxtId: record.fcId,
            name: eventRecs.caption,
            updatedBy: record.user,
            updateTime: record.updateTime,
            user: user,
            time: time
          });
        });
      });

      eventsList.sort(
        function(e1, e2) {
          var t1 = e1.time || 0;
          var t2 = e2.time || 0;
          return t2 - t1;
        }
      );
      return eventsList;
    }

    function updateSpecimenStatus(specimen, statusSpec) {
      return $http.put(Specimen.url() + '/' + specimen.$id() + '/status', statusSpec).then(
        function(result) {
          angular.extend(specimen, result.data);
          return new Specimen(result);
        }
      );
    }

    function hasOnlyPendingChildren(specimens) {
      if (!specimens || specimens.length == 0) {
        return true;
      }

      return specimens.every(
        function(spmn) {
          return !spmn.status || spmn.status == 'Pending';
        }
      );
    }

    return Specimen;
  });
<commit_msg>OPSMN-4113: Same storage location UI object was used by all aliquots. As a result, when location of first aliquot was selected, all other aliquots reflected the same location as well.<commit_after>angular.module('os.biospecimen.models.specimen', ['os.common.models', 'os.biospecimen.models.form'])
  .factory('Specimen', function(osModel, $http, $parse, SpecimenRequirement, Form, Util) {

    function matches(name, regex) {
      return name && name.match(regex) != null;
    }

    function isSpecimenCentric(specimen) {
      return matches(specimen.ppid, /^(\$\$cp_reg_\d+\$\$)$/g) ||
               matches(specimen.visitName, /^(\$\$cp_visit_\d+\$\$)$/g);
    }

    var Specimen = osModel(
      'specimens',
      function(specimen) {
        if (specimen.specimensPool) {
          specimen.specimensPool = specimen.specimensPool.map(
            function(poolSpmn) {
              return new Specimen(poolSpmn);
            }
          );
        }

        if (specimen.children) {
          specimen.children = specimen.children.map(
            function(child) {
              return new Specimen(child);
            }
          );
        }

        if (specimen.storageLocation) {
          specimen.storageLocation = angular.extend({}, specimen.storageLocation);
        }
        specimen.$$specimenCentricCp = isSpecimenCentric(specimen);
      }
    );

    Specimen.listFor = function(cprId, visitDetail) {
      return Specimen.query(angular.extend({cprId: cprId}, visitDetail || {}));
    };

    Specimen.listByLabels = function(labels) {
      return Specimen.query({label: labels});
    };

    Specimen.flatten = function(specimens, parent, depth, pooledSpecimen) {
      var result = [];
      if (!specimens) {
        return result;
      }

      depth = depth || 0;
      angular.forEach(specimens, function(specimen) {
        result.push(specimen);
        specimen.depth = depth || 0;

        specimen.parent = specimen.parent || parent;
        specimen.pooledSpecimen = specimen.pooledSpecimen || pooledSpecimen;

        var hasSpecimensPool = false;
        if (depth == 0) {
          hasSpecimensPool = !!specimen.specimensPool && specimen.specimensPool.length > 0;
          if (hasSpecimensPool) {
            result = result.concat(Specimen.flatten(specimen.specimensPool, specimen, depth + 1, specimen));
          }
        }

        var hasChildren = (!!specimen.children && specimen.children.length > 0);
        specimen.hasChildren = hasSpecimensPool || hasChildren;
        if (hasChildren) {
          result = result.concat(Specimen.flatten(specimen.children, specimen, depth + 1));
        }

        if (specimen instanceof SpecimenRequirement) {
          return;
        }

        specimen.hasOnlyPendingChildren = hasOnlyPendingChildren(specimen.children);
        if (specimen.hasOnlyPendingChildren) {
          specimen.hasOnlyPendingChildren = hasOnlyPendingChildren(specimen.specimensPool);
        }
      });

      return result;
    };

    Specimen.save = function(specimens) {
      return $http.post(Specimen.url() + 'collect', specimens).then(Specimen.modelArrayRespTransform);
    };

    //Update specimens in bulk with same detail
    Specimen.bulkEdit = function(detail) {
      return $http.put(Specimen.url() + "bulk-update", detail).then(Specimen.modelArrayRespTransform);
    }

    //Update specimens in bulk by providing detail for each
    Specimen.bulkUpdate = function(specimens) {
      return $http.put(Specimen.url(), specimens).then(Specimen.modelArrayRespTransform);
    };

    Specimen.isUniqueLabel = function(cpShortTitle, label) {
      return $http.head(Specimen.url(), {params: {cpShortTitle: cpShortTitle, label: label}}).then(
        function(result) {
          return false;
        },

        function(result) {
          return true;
        }
      );
    };

    Specimen.getAnticipatedSpecimen = function(srId) {
      return SpecimenRequirement.getById(srId).then(
        function(sr) {
          return new Specimen(toSpecimenAttrs(sr));
        }
      );
    };

    Specimen.getRouteIds = function(specimenId) {
      return $http.get(Specimen.url() + specimenId + '/cpr-visit-ids').then(
        function(resp) {
          return resp.data;
        }
      );
    }

    Specimen.bulkDelete = function(specimenIds) {
      return $http.delete(Specimen.url(), {params: {id: specimenIds}}).then(
        function(result) {
          return result.data;
        }
      );
    }

    Specimen.bulkStatusUpdate = function(statusSpecs) {
      return $http.put(Specimen.url() + '/status', statusSpecs).then(
        function(result) {
          return result.data;
        }
      );
    }

    Specimen.getByIds = function(ids) {
      return Specimen.query({id: ids});
    }

    Specimen.prototype.getType = function() {
      return 'specimen';
    }

    Specimen.prototype.getDisplayName = function() {
      return this.label;
    };

    Specimen.prototype.hasSufficientQty = function() {
      var qty = this.initialQty;
      angular.forEach(this.children, function(child) {
        if (child.lineage == 'Aliquot') {
          qty -= child.initialQty;
        }
      });

      return qty >= 0;
    }

    Specimen.prototype.rootSpecimen = function() {
      var curr = this;
      while (curr.parent) {
        curr = curr.parent;
      }

      return curr;
    };

    Specimen.prototype.getExtensionCtxt = function(params) {
      return Specimen.getExtensionCtxt(params);
    }

    Specimen.prototype.getForms = function(params) {
      return Form.listFor(Specimen.url(), this.$id(), params);
    };

    Specimen.prototype.getRecords = function() {
      var url = Specimen.url() + this.$id() + '/extension-records';
      return Form.listRecords(url);
    };

    Specimen.prototype.getEvents = function(callback) {
      var events = [];

      if (!!this.$id()) {
        $http.get(Specimen.url() + '/' + this.$id() + '/events').then(
          function(result) {
            Util.unshiftAll(events, getEventsList(result.data));
            if (typeof callback == 'function') {
              callback(events);
            }
          }
        );
      }

      return events;
    };

    Specimen.prototype.$saveProps = function() {
      var props = ['children', 'depth', 'hasChildren', 'isOpened', 'specimensPool'];
      var that = this;
      props.forEach(function(prop) { delete that[prop]; });
      return this;
    };

    Specimen.prototype.close = function(reason) {
      var statusSpec = {status: 'Closed', reason: reason};
      return updateSpecimenStatus(this, statusSpec);
    }

    Specimen.prototype.reopen = function() {
      var statusSpec = {status: 'Active'};
      return updateSpecimenStatus(this, statusSpec);
    };

    Specimen.prototype.showVirtual = function() {
      return this.storageType == 'Virtual' && (!this.status || this.status == 'Pending');
    }

    Specimen.prototype.getMatchingRule = function(allocRules) {
      var result = -1;
      for (var i = 0; i < allocRules.length; ++i) {
        if ($parse(allocRules[i].criteria)({specimen: this})) {
          result = i;
          break;
        }
      }

      return {index: result, rule: result != -1 ? allocRules[result] : undefined};
    }

    function toSpecimenAttrs(sr) {
      sr.reqId = sr.id;
      sr.reqLabel = sr.name;
      sr.poolSpecimen = !!sr.pooledSpecimenReqId;

      var attrs = [
        'id', 'name', 'pooledSpecimenReqId',
        'collector', 'collectionProcedure', 'collectionContainer',
        'receiver', 'labelPrintCopies'
      ];

      attrs.forEach(function(attr) {
        delete sr[attr];
      });

      if (sr.children) {
        sr.children = sr.children.map(toSpecimenAttrs);
      }

      if (sr.specimensPool) {
        sr.specimensPool = sr.specimensPool.map(toSpecimenAttrs);
      }

      return sr;
    };

    function getEventsList(eventsRecs) { /* eventsRecs: [{event info, records: [event records]}] */
      var eventsList = [];
      angular.forEach(eventsRecs, function(eventRecs) {
        angular.forEach(eventRecs.records, function(record) {
          var user = null, time = null;
          for (var i = 0; i < record.fieldValues.length; ++i) {
            if (record.fieldValues[i].name == 'user') {
              user = record.fieldValues[i].value;
            } else if (record.fieldValues[i].name == 'time') {
              time = record.fieldValues[i].value;
            }
          }

          eventsList.push({
            id: record.recordId,
            formId: eventRecs.id,
            formCtxtId: record.fcId,
            name: eventRecs.caption,
            updatedBy: record.user,
            updateTime: record.updateTime,
            user: user,
            time: time
          });
        });
      });

      eventsList.sort(
        function(e1, e2) {
          var t1 = e1.time || 0;
          var t2 = e2.time || 0;
          return t2 - t1;
        }
      );
      return eventsList;
    }

    function updateSpecimenStatus(specimen, statusSpec) {
      return $http.put(Specimen.url() + '/' + specimen.$id() + '/status', statusSpec).then(
        function(result) {
          angular.extend(specimen, result.data);
          return new Specimen(result);
        }
      );
    }

    function hasOnlyPendingChildren(specimens) {
      if (!specimens || specimens.length == 0) {
        return true;
      }

      return specimens.every(
        function(spmn) {
          return !spmn.status || spmn.status == 'Pending';
        }
      );
    }

    return Specimen;
  });
<|endoftext|>


<commit_before>var APITokenWS = (function() {
    "use strict";

    var columns,
        errorClass,
        hideClass,
        isValid,
        tableContainer,
        maxTokens;

    var init = function() {
        columns = ['Name', 'Token', 'Scopes', 'Last Used', 'Action'];
        errorClass  = 'errorfield';
        hideClass   = 'dynamic';
        tableContainer = '#tokens_list';
        maxTokens = 30;

        showLoadingImage($(tableContainer));

        BinarySocket.send({"api_token": "1"});

        $('#btnCreate').click(function(e) {
            e.preventDefault();
            e.stopPropagation();
            createToken();
        });
    };

    var responseHandler = function(response) {
        if('error' in response) {
            showMessage(response.error.message, false);
            return false;
        }

        clearMessages();

        var rebuildTable = true;
        var api_token = response.api_token;
        var newToken  = '';

        if('new_token' in api_token) {
            if(api_token.new_token === 1) {
                showFormMessage(text.localize('New token created.'), true);
                $('#txtName').val('');
                newToken = response.echo_req.new_token;
            }
        }
        else if('delete_token' in api_token) {
            rebuildTable = false;
            var deletedToken = response.echo_req.delete_token;
            if(api_token.delete_token !== 1) {
                showError(deletedToken, text.localize('An error occured.'));
            }
            else {
                $('#' + deletedToken).parents('tr').removeClass('new').addClass('deleting').fadeOut(700, function(){
                    $(this).remove();
                    // Hide the table if there is no Token remained
                    if(api_token.tokens.length === 0) {
                        $(tableContainer).addClass(hideClass);
                    }
                });
            }
        }

        if(rebuildTable) {
            populateTokensList(api_token, newToken);
        }

        // Hide form if tokens count reached the maximum limit
        if(api_token.tokens.length >= maxTokens) {
            $('#token_form').addClass(hideClass);
            showMessage(text.localize('The maximum number of tokens (%1) has been reached.').replace('%1', maxTokens), false);
        }
        else {
            $('#token_form').removeClass(hideClass);
        }
    };

    // -----------------------
    // ----- Tokens List -----
    // -----------------------
    var populateTokensList = function(api_token, newTokenName) {
        var $tableContainer = $(tableContainer);
        if(api_token.tokens.length === 0) {
            $tableContainer.addClass(hideClass);
            return;
        }

        $tableContainer.removeClass(hideClass);
        showLoadingImage($(tableContainer));

        var tokens = api_token.tokens;
        var $tokensTable = createEmptyTable('tokens_table');

        for(var i = 0; i < tokens.length; i++) {
            var $tableRow = createTableRow(tokens[i]);
            if(newTokenName && tokens[i].display_name === newTokenName) {
                $tableRow.addClass('new');
            }
            $tokensTable.find('tbody').append($tableRow);
        }

        $tableContainer.empty().append($tokensTable);

        $('.btnDelete').click(function(e) {
            e.preventDefault();
            e.stopPropagation();
            if(window.confirm(
                text.localize('Are you sure that you want to permanently delete token') +
                ': "' + $(this).parents('tr').find('td.name').text() + '"?')) {
                    deleteToken($(this).attr('id'));
            }
        });
    };

    String.prototype.capitalizeFirstLetter = function() {
        return this.charAt(0).toUpperCase() + this.slice(1);
    }

    var createTableRow = function(token) {
        var lastUsed = token.last_used ? token.last_used : text.localize('Never Used');
        var scopes = token.scopes.map(function (v) {
            return v.capitalizeFirstLetter();
        });
        var $tableRow = Table.createFlexTableRow(
            [
                token.display_name,
                token.token,
                scopes.join(', '),
                lastUsed,
                ''  // btnDelete
            ],
            columns,
            "data"
        );

        $tableRow.children('.action').html(
            $('', {class: 'button'})
                .append($('<button/>', {class: 'button btnDelete', text: text.localize('Delete'), id: token.token})
            )
        );

        return $tableRow;
    };

    var createEmptyTable = function(tableID) {
        var header = [];
        columns.map(function(col) {
            header.push(text.localize(col));
        });

        var metadata = {
            id: tableID,
            cols: columns
        };

        return Table.createFlexTable([], metadata, header);
    };

    // ---------------------------
    // ----- Form Validation -----
    // ---------------------------
    var formValidate = function() {
        clearMessages();
        isValid = true;

        var nameID  = '#txtName';
        var newName = $(nameID).val().trim();

        var letters = Content.localize().textLetters,
            numbers = Content.localize().textNumbers,
            space   = Content.localize().textSpace;

        // Token Name
        if(!isRequiredError(nameID) && !isCountError(nameID, 2, 32)){
            if(!(/^[a-zA-Z0-9\s\-]*$/).test(newName)) {
                showError(nameID, Content.errorMessage('reg', [letters, numbers, space, '-']));
            }
        }

        var scopes = $('input:checkbox[name="scopes[]"]:checked').map(function () {
            return this.value;
        }).get();
        if (scopes.length === 0) {
            showError('scopes', text.localize('Please select at least one scope.'));
        }

        return isValid ? newName : false;
    };

    var isRequiredError = function(fieldID) {
        if(!$(fieldID).val() || !(/.+/).test($(fieldID).val().trim())){
            showError(fieldID, Content.errorMessage('req'));
            return true;
        } else {
            return false;
        }
    };

    var isCountError = function(fieldID, min, max) {
        var fieldValue = $(fieldID).val().trim();
        if((fieldValue.length > 0 && fieldValue.length < min) || fieldValue.length > max) {
            showError(fieldID, Content.errorMessage('range', '(' + min + '-' + max + ')'));
            return true;
        } else {
            return false;
        }
    };

    // ---------------------------
    // ----- Actions Process -----
    // ---------------------------
    var createToken = function() {
        var is_valid = formValidate();
        if(is_valid !== false) {
            var newName = $('#txtName').val().trim();
            var scopes = $('input:checkbox[name="scopes[]"]:checked').map(function () {
                return this.value;
            }).get();

            BinarySocket.send({
                "api_token" : 1,
                "new_token" : newName,
                "new_token_scopes": scopes
            });
        }
    };

    var deleteToken = function(token) {
        if(token) {
            BinarySocket.send({
                "api_token"    : 1,
                "delete_token" : token
            });
        }
    };

    // -----------------------------
    // ----- Message Functions -----
    // -----------------------------
    var showMessage = function(msg, isSuccess) {
        $('#token_message > p')
            .attr('class', isSuccess ? 'success-msg' : 'errorfield')
            .html(isSuccess ? '

' + text.localize(msg) + '

' : text.localize(msg));
        $('#token_message').removeClass(hideClass);
    };

    var showFormMessage = function(msg, isSuccess) {
        var $elmID = $('#formMessage');
        $elmID
            .attr('class', isSuccess ? 'success-msg' : 'errorfield')
            .html(isSuccess ? '

' + text.localize(msg) + '

' : text.localize(msg))
            .css('display', 'block')
            .delay(3000)
            .fadeOut(1000);
    };

    var showError = function(fieldID, errMsg) {
        $(fieldID).parent().append($('
', {class: errorClass, text: errMsg}));
        isValid = false;
    };

    var clearMessages = function(fieldID) {
        $(fieldID ? fieldID : '#frmNewToken .' + errorClass).remove();
        $('#token_message').addClass(hideClass);
        $('#formMessage').html('');
    };

    return {
        init: init,
        responseHandler: responseHandler
    };
}());

pjax_config_page("api_tokenws", function() {
    return {
        onLoad: function() {
            if (!$.cookie('login')) {
                window.location.href = page.url.url_for('login');
                return;
            }

            BinarySocket.init({
                onmessage: function(msg) {
                    var response = JSON.parse(msg.data);
                    if (response) {
                        if (response.msg_type === "api_token") {
                            APITokenWS.responseHandler(response);
                        }
                    }
                    else {
                        console.log('some error occured');
                    }
                }
            });

            Content.populate();
            APITokenWS.init();
        }
    };
});
<commit_msg>with #<commit_after>var APITokenWS = (function() {
    "use strict";

    var columns,
        errorClass,
        hideClass,
        isValid,
        tableContainer,
        maxTokens;

    var init = function() {
        columns = ['Name', 'Token', 'Scopes', 'Last Used', 'Action'];
        errorClass  = 'errorfield';
        hideClass   = 'dynamic';
        tableContainer = '#tokens_list';
        maxTokens = 30;

        showLoadingImage($(tableContainer));

        BinarySocket.send({"api_token": "1"});

        $('#btnCreate').click(function(e) {
            e.preventDefault();
            e.stopPropagation();
            createToken();
        });
    };

    var responseHandler = function(response) {
        if('error' in response) {
            showMessage(response.error.message, false);
            return false;
        }

        clearMessages();

        var rebuildTable = true;
        var api_token = response.api_token;
        var newToken  = '';

        if('new_token' in api_token) {
            if(api_token.new_token === 1) {
                showFormMessage(text.localize('New token created.'), true);
                $('#txtName').val('');
                newToken = response.echo_req.new_token;
            }
        }
        else if('delete_token' in api_token) {
            rebuildTable = false;
            var deletedToken = response.echo_req.delete_token;
            if(api_token.delete_token !== 1) {
                showError(deletedToken, text.localize('An error occured.'));
            }
            else {
                $('#' + deletedToken).parents('tr').removeClass('new').addClass('deleting').fadeOut(700, function(){
                    $(this).remove();
                    // Hide the table if there is no Token remained
                    if(api_token.tokens.length === 0) {
                        $(tableContainer).addClass(hideClass);
                    }
                });
            }
        }

        if(rebuildTable) {
            populateTokensList(api_token, newToken);
        }

        // Hide form if tokens count reached the maximum limit
        if(api_token.tokens.length >= maxTokens) {
            $('#token_form').addClass(hideClass);
            showMessage(text.localize('The maximum number of tokens (%1) has been reached.').replace('%1', maxTokens), false);
        }
        else {
            $('#token_form').removeClass(hideClass);
        }
    };

    // -----------------------
    // ----- Tokens List -----
    // -----------------------
    var populateTokensList = function(api_token, newTokenName) {
        var $tableContainer = $(tableContainer);
        if(api_token.tokens.length === 0) {
            $tableContainer.addClass(hideClass);
            return;
        }

        $tableContainer.removeClass(hideClass);
        showLoadingImage($(tableContainer));

        var tokens = api_token.tokens;
        var $tokensTable = createEmptyTable('tokens_table');

        for(var i = 0; i < tokens.length; i++) {
            var $tableRow = createTableRow(tokens[i]);
            if(newTokenName && tokens[i].display_name === newTokenName) {
                $tableRow.addClass('new');
            }
            $tokensTable.find('tbody').append($tableRow);
        }

        $tableContainer.empty().append($tokensTable);

        $('.btnDelete').click(function(e) {
            e.preventDefault();
            e.stopPropagation();
            if(window.confirm(
                text.localize('Are you sure that you want to permanently delete token') +
                ': "' + $(this).parents('tr').find('td.name').text() + '"?')) {
                    deleteToken($(this).attr('id'));
            }
        });
    };

    String.prototype.capitalizeFirstLetter = function() {
        return this.charAt(0).toUpperCase() + this.slice(1);
    }

    var createTableRow = function(token) {
        var lastUsed = token.last_used ? token.last_used : text.localize('Never Used');
        var scopes = token.scopes.map(function (v) {
            return v.capitalizeFirstLetter();
        });
        var $tableRow = Table.createFlexTableRow(
            [
                token.display_name,
                token.token,
                scopes.join(', '),
                lastUsed,
                ''  // btnDelete
            ],
            columns,
            "data"
        );

        $tableRow.children('.action').html(
            $('', {class: 'button'})
                .append($('<button/>', {class: 'button btnDelete', text: text.localize('Delete'), id: token.token})
            )
        );

        return $tableRow;
    };

    var createEmptyTable = function(tableID) {
        var header = [];
        columns.map(function(col) {
            header.push(text.localize(col));
        });

        var metadata = {
            id: tableID,
            cols: columns
        };

        return Table.createFlexTable([], metadata, header);
    };

    // ---------------------------
    // ----- Form Validation -----
    // ---------------------------
    var formValidate = function() {
        clearMessages();
        isValid = true;

        var nameID  = '#txtName';
        var newName = $(nameID).val().trim();

        var letters = Content.localize().textLetters,
            numbers = Content.localize().textNumbers,
            space   = Content.localize().textSpace;

        // Token Name
        if(!isRequiredError(nameID) && !isCountError(nameID, 2, 32)){
            if(!(/^[a-zA-Z0-9\s\-]*$/).test(newName)) {
                showError(nameID, Content.errorMessage('reg', [letters, numbers, space, '-']));
            }
        }

        var scopes = $('input:checkbox[name="scopes[]"]:checked').map(function () {
            return this.value;
        }).get();
        if (scopes.length === 0) {
            showError('#scopes', text.localize('Please select at least one scope.'));
        }

        return isValid ? newName : false;
    };

    var isRequiredError = function(fieldID) {
        if(!$(fieldID).val() || !(/.+/).test($(fieldID).val().trim())){
            showError(fieldID, Content.errorMessage('req'));
            return true;
        } else {
            return false;
        }
    };

    var isCountError = function(fieldID, min, max) {
        var fieldValue = $(fieldID).val().trim();
        if((fieldValue.length > 0 && fieldValue.length < min) || fieldValue.length > max) {
            showError(fieldID, Content.errorMessage('range', '(' + min + '-' + max + ')'));
            return true;
        } else {
            return false;
        }
    };

    // ---------------------------
    // ----- Actions Process -----
    // ---------------------------
    var createToken = function() {
        var is_valid = formValidate();
        if(is_valid !== false) {
            var newName = $('#txtName').val().trim();
            var scopes = $('input:checkbox[name="scopes[]"]:checked').map(function () {
                return this.value;
            }).get();

            BinarySocket.send({
                "api_token" : 1,
                "new_token" : newName,
                "new_token_scopes": scopes
            });
        }
    };

    var deleteToken = function(token) {
        if(token) {
            BinarySocket.send({
                "api_token"    : 1,
                "delete_token" : token
            });
        }
    };

    // -----------------------------
    // ----- Message Functions -----
    // -----------------------------
    var showMessage = function(msg, isSuccess) {
        $('#token_message > p')
            .attr('class', isSuccess ? 'success-msg' : 'errorfield')
            .html(isSuccess ? '

' + text.localize(msg) + '

' : text.localize(msg));
        $('#token_message').removeClass(hideClass);
    };

    var showFormMessage = function(msg, isSuccess) {
        var $elmID = $('#formMessage');
        $elmID
            .attr('class', isSuccess ? 'success-msg' : 'errorfield')
            .html(isSuccess ? '

' + text.localize(msg) + '

' : text.localize(msg))
            .css('display', 'block')
            .delay(3000)
            .fadeOut(1000);
    };

    var showError = function(fieldID, errMsg) {
        $(fieldID).parent().append($('
', {class: errorClass, text: errMsg}));
        isValid = false;
    };

    var clearMessages = function(fieldID) {
        $(fieldID ? fieldID : '#frmNewToken .' + errorClass).remove();
        $('#token_message').addClass(hideClass);
        $('#formMessage').html('');
    };

    return {
        init: init,
        responseHandler: responseHandler
    };
}());

pjax_config_page("api_tokenws", function() {
    return {
        onLoad: function() {
            if (!$.cookie('login')) {
                window.location.href = page.url.url_for('login');
                return;
            }

            BinarySocket.init({
                onmessage: function(msg) {
                    var response = JSON.parse(msg.data);
                    if (response) {
                        if (response.msg_type === "api_token") {
                            APITokenWS.responseHandler(response);
                        }
                    }
                    else {
                        console.log('some error occured');
                    }
                }
            });

            Content.populate();
            APITokenWS.init();
        }
    };
});
<|endoftext|>


<commit_before>/* global describe, it, beforeEach */
/* eslint-disable no-new */

var assert = require('assert')
var ecdsa = require('../src/ecdsa')
var sinon = require('sinon')

var BigInteger = require('bigi')
var ECPair = require('../src/ecpair')
var HDNode = require('../src/hdnode')

var fixtures = require('./fixtures/hdnode.json')
var curve = ecdsa.__curve

var NETWORKS = require('../src/networks')
var NETWORKS_LIST = [] // Object.values(NETWORKS)
for (var networkName in NETWORKS) {
  NETWORKS_LIST.push(NETWORKS[networkName])
}

describe('HDNode', function () {
  describe('Constructor', function () {
    var keyPair, chainCode

    beforeEach(function () {
      var d = BigInteger.ONE

      keyPair = new ECPair(d, null)
      chainCode = new Buffer(32)
      chainCode.fill(1)
    })

    it('stores the keyPair/chainCode directly', function () {
      var hd = new HDNode(keyPair, chainCode)

      assert.strictEqual(hd.keyPair, keyPair)
      assert.strictEqual(hd.chainCode, chainCode)
    })

    it('has a default depth/index of 0', function () {
      var hd = new HDNode(keyPair, chainCode)

      assert.strictEqual(hd.depth, 0)
      assert.strictEqual(hd.index, 0)
    })

    it('throws on uncompressed keyPair', function () {
      keyPair.compressed = false

      assert.throws(function () {
        new HDNode(keyPair, chainCode)
      }, /BIP32 only allows compressed keyPairs/)
    })

    it('throws when an invalid length chain code is given', function () {
      assert.throws(function () {
        new HDNode(keyPair, new Buffer(20))
      }, /Expected 256-bit Buffer, got 160-bit/)
    })
  })

  describe('fromSeed*', function () {
    fixtures.valid.forEach(function (f) {
      it('calculates privKey and chainCode for ' + f.master.fingerprint, function () {
        var network = NETWORKS[f.network]
        var hd = HDNode.fromSeedHex(f.master.seed, network)

        assert.strictEqual(hd.keyPair.toWIF(), f.master.wif)
        assert.strictEqual(hd.chainCode.toString('hex'), f.master.chainCode)
      })
    })

    it('throws if IL is not within interval [1, n - 1] | IL === 0', sinon.test(function () {
      this.mock(BigInteger).expects('fromBuffer')
        .once().returns(BigInteger.ZERO)

      assert.throws(function () {
        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffff')
      }, /Private key must be greater than 0/)
    }))

    it('throws if IL is not within interval [1, n - 1] | IL === n', sinon.test(function () {
      this.mock(BigInteger).expects('fromBuffer')
        .once().returns(curve.n)

      assert.throws(function () {
        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffff')
      }, /Private key must be less than the curve order/)
    }))

    it('throws on low entropy seed', function () {
      assert.throws(function () {
        HDNode.fromSeedHex('ffffffffff')
      }, /Seed should be at least 128 bits/)
    })

    it('throws on too high entropy seed', function () {
      assert.throws(function () {
        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
      }, /Seed should be at most 512 bits/)
    })
  })

  describe('ECPair wrappers', function () {
    var keyPair, hd, hash

    beforeEach(function () {
      keyPair = ECPair.makeRandom()
      hash = new Buffer(32)

      var chainCode = new Buffer(32)
      hd = new HDNode(keyPair, chainCode)
    })

    describe('getAddress', function () {
      it('wraps keyPair.getAddress', sinon.test(function () {
        this.mock(keyPair).expects('getAddress')
          .once().withArgs().returns('foobar')

        assert.strictEqual(hd.getAddress(), 'foobar')
      }))
    })

    describe('getNetwork', function () {
      it('wraps keyPair.getNetwork', sinon.test(function () {
        this.mock(keyPair).expects('getNetwork')
          .once().withArgs().returns('network')

        assert.strictEqual(hd.getNetwork(), 'network')
      }))
    })

    describe('getPublicKeyBuffer', function () {
      it('wraps keyPair.getPublicKeyBuffer', sinon.test(function () {
        this.mock(keyPair).expects('getPublicKeyBuffer')
          .once().withArgs().returns('pubKeyBuffer')

        assert.strictEqual(hd.getPublicKeyBuffer(), 'pubKeyBuffer')
      }))
    })

    describe('sign', function () {
      it('wraps keyPair.sign', sinon.test(function () {
        this.mock(keyPair).expects('sign')
          .once().withArgs(hash).returns('signed')

        assert.strictEqual(hd.sign(hash), 'signed')
      }))
    })

    describe('verify', function () {
      var signature

      beforeEach(function () {
        signature = hd.sign(hash)
      })

      it('wraps keyPair.verify', sinon.test(function () {
        this.mock(keyPair).expects('verify')
          .once().withArgs(hash, signature).returns('verified')

        assert.strictEqual(hd.verify(hash, signature), 'verified')
      }))
    })
  })

  describe('toBase58', function () {
    fixtures.valid.forEach(function (f) {
      it('exports ' + f.master.base58 + ' (public) correctly', function () {
        var network = NETWORKS[f.network]
        var hd = HDNode.fromSeedHex(f.master.seed, network).neutered()

        assert.strictEqual(hd.toBase58(), f.master.base58)
      })
    })

    fixtures.valid.forEach(function (f) {
      it('exports ' + f.master.base58Priv + ' (private) correctly', function () {
        var network = NETWORKS[f.network]
        var hd = HDNode.fromSeedHex(f.master.seed, network)

        assert.strictEqual(hd.toBase58(), f.master.base58Priv)
      })
    })
  })

  describe('fromBase58', function () {
    fixtures.valid.forEach(function (f) {
      it('imports ' + f.master.base58 + ' (public) correctly', function () {
        var network = NETWORKS[f.network]
        var hd = HDNode.fromBase58(f.master.base58, network)

        assert.strictEqual(hd.toBase58(), f.master.base58)
        assert.strictEqual(hd.keyPair.network, network)
        assert.strictEqual(hd.isNeutered(), true)
      })
    })

    fixtures.valid.forEach(function (f) {
      it('imports ' + f.master.base58Priv + ' (private) correctly', function () {
        var network = NETWORKS[f.network]
        var hd = HDNode.fromBase58(f.master.base58Priv, network)

        assert.strictEqual(hd.toBase58(), f.master.base58Priv)
        assert.strictEqual(hd.keyPair.network, network)
        assert.strictEqual(hd.isNeutered(), false)
      })
    })

    fixtures.invalid.fromBase58.forEach(function (f) {
      it('throws on ' + f.string, function () {
        assert.throws(function () {
          var network = NETWORKS[f.network]

          HDNode.fromBase58(f.string, network)
        }, new RegExp(f.exception))
      })
    })
  })

  describe('getIdentifier', function () {
    var f = fixtures.valid[0]

    it('returns the identifier for ' + f.master.fingerprint, function () {
      var hd = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.strictEqual(hd.getIdentifier().toString('hex'), f.master.identifier)
    })
  })

  describe('getFingerprint', function () {
    var f = fixtures.valid[0]

    it('returns the fingerprint for ' + f.master.fingerprint, function () {
      var hd = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.strictEqual(hd.getFingerprint().toString('hex'), f.master.fingerprint)
    })
  })

  describe('neutered', function () {
    var f = fixtures.valid[0]

    it('strips all private information', function () {
      var hd = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
      var hdn = hd.neutered()

      assert.strictEqual(hdn.keyPair.d, undefined)
      assert.strictEqual(hdn.keyPair.Q, hd.keyPair.Q)
      assert.strictEqual(hdn.chainCode, hd.chainCode)
      assert.strictEqual(hdn.depth, hd.depth)
      assert.strictEqual(hdn.index, hd.index)
      assert.strictEqual(hdn.isNeutered(), true)
      assert.strictEqual(hd.isNeutered(), false)
    })
  })

  describe('derive', function () {
    function verifyVector (hd, v, depth) {
      assert.strictEqual(hd.keyPair.toWIF(), v.wif)
      assert.strictEqual(hd.keyPair.getPublicKeyBuffer().toString('hex'), v.pubKey)
      assert.strictEqual(hd.chainCode.toString('hex'), v.chainCode)
      assert.strictEqual(hd.depth, depth || 0)

      if (v.hardened) {
        assert.strictEqual(hd.index, v.m + HDNode.HIGHEST_BIT)
      } else {
        assert.strictEqual(hd.index, v.m)
      }
    }

    fixtures.valid.forEach(function (f) {
      var network = NETWORKS[f.network]
      var hd = HDNode.fromSeedHex(f.master.seed, network)
      var master = hd

      // FIXME: test data is only testing Private -> private for now
      f.children.forEach(function (c, i) {
        it(c.description + ' from ' + f.master.fingerprint, function () {
          if (c.hardened) {
            hd = hd.deriveHardened(c.m)
          } else {
            hd = hd.derive(c.m)
          }

          verifyVector(hd, c, i + 1)
        })
      })

      // testing deriving path from master
      f.children.forEach(function (c) {
        it(c.description + ' from ' + f.master.fingerprint + ' by path', function () {
          var path = c.description
          var child = master.derivePath(path)

          var pathSplit = path.split('/').slice(1)
          var pathNotM = pathSplit.join('/')
          var childNotM = master.derivePath(pathNotM)

          verifyVector(child, c, pathSplit.length)
          verifyVector(childNotM, c, pathSplit.length)
        })
      })

      // testing deriving path from the first child
      var firstChild = master.derivePath(f.children[0].description)

      f.children.slice(1).forEach(function (c) {
        it(c.description + ' from ' + f.children[0].fingerprint + ' by path', function () {
          var path = c.description

          var pathSplit = path.split('/').slice(2)
          var pathEnd = pathSplit.join('/')
          var pathEndM = 'm/' + path

          var child = firstChild.derivePath(pathEnd)
          verifyVector(child, c, pathSplit.length + 1)

          assert.throws(function () {
            firstChild.derivePath(pathEndM)
          }, /Not a master node/)
        })
      })
    })

    it('works for Private -> public (neutered)', function () {
      var f = fixtures.valid[1]
      var c = f.children[0]

      var master = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
      var child = master.derive(c.m).neutered()

      assert.strictEqual(child.toBase58(), c.base58)
    })

    it('works for Private -> public (neutered, hardened)', function () {
      var f = fixtures.valid[0]
      var c = f.children[0]

      var master = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
      var child = master.deriveHardened(c.m).neutered()

      assert.strictEqual(child.toBase58(), c.base58)
    })

    it('works for Public -> public', function () {
      var f = fixtures.valid[1]
      var c = f.children[0]

      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
      var child = master.derive(c.m)

      assert.strictEqual(child.toBase58(), c.base58)
    })

    it('throws on Public -> public (hardened)', function () {
      var f = fixtures.valid[0]
      var c = f.children[0]

      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.throws(function () {
        master.deriveHardened(c.m)
      }, /Could not derive hardened child key/)
    })

    it('throws on negative indexes', function () {
      var f = fixtures.valid[0]
      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.throws(function () {
        master.deriveHardened(-1)
      }, /Expected UInt31/)
      assert.throws(function () {
        master.derive(-1)
      }, /Expected UInt32/)
    })

    it('throws on high indexes', function () {
      var f = fixtures.valid[0]
      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.throws(function () {
        master.deriveHardened(0x80000000)
      }, /Expected UInt31/)
      assert.throws(function () {
        master.derive(0x100000000)
      }, /Expected UInt32/)
    })

    it('throws on non-numbers', function () {
      var f = fixtures.valid[0]
      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.throws(function () {
        master.deriveHardened()
      }, /Expected UInt31/)
      assert.throws(function () {
        master.derive()
      }, /Expected UInt32/)
      assert.throws(function () {
        master.deriveHardened('foo')
      }, /Expected UInt31/)
      assert.throws(function () {
        master.derive('foo')
      }, /Expected UInt32/)
    })
  })
})
<commit_msg>Doubling down on the path testing<commit_after>/* global describe, it, beforeEach */
/* eslint-disable no-new */

var assert = require('assert')
var ecdsa = require('../src/ecdsa')
var sinon = require('sinon')

var BigInteger = require('bigi')
var ECPair = require('../src/ecpair')
var HDNode = require('../src/hdnode')

var fixtures = require('./fixtures/hdnode.json')
var curve = ecdsa.__curve

var NETWORKS = require('../src/networks')
var NETWORKS_LIST = [] // Object.values(NETWORKS)
for (var networkName in NETWORKS) {
  NETWORKS_LIST.push(NETWORKS[networkName])
}

describe('HDNode', function () {
  describe('Constructor', function () {
    var keyPair, chainCode

    beforeEach(function () {
      var d = BigInteger.ONE

      keyPair = new ECPair(d, null)
      chainCode = new Buffer(32)
      chainCode.fill(1)
    })

    it('stores the keyPair/chainCode directly', function () {
      var hd = new HDNode(keyPair, chainCode)

      assert.strictEqual(hd.keyPair, keyPair)
      assert.strictEqual(hd.chainCode, chainCode)
    })

    it('has a default depth/index of 0', function () {
      var hd = new HDNode(keyPair, chainCode)

      assert.strictEqual(hd.depth, 0)
      assert.strictEqual(hd.index, 0)
    })

    it('throws on uncompressed keyPair', function () {
      keyPair.compressed = false

      assert.throws(function () {
        new HDNode(keyPair, chainCode)
      }, /BIP32 only allows compressed keyPairs/)
    })

    it('throws when an invalid length chain code is given', function () {
      assert.throws(function () {
        new HDNode(keyPair, new Buffer(20))
      }, /Expected 256-bit Buffer, got 160-bit/)
    })
  })

  describe('fromSeed*', function () {
    fixtures.valid.forEach(function (f) {
      it('calculates privKey and chainCode for ' + f.master.fingerprint, function () {
        var network = NETWORKS[f.network]
        var hd = HDNode.fromSeedHex(f.master.seed, network)

        assert.strictEqual(hd.keyPair.toWIF(), f.master.wif)
        assert.strictEqual(hd.chainCode.toString('hex'), f.master.chainCode)
      })
    })

    it('throws if IL is not within interval [1, n - 1] | IL === 0', sinon.test(function () {
      this.mock(BigInteger).expects('fromBuffer')
        .once().returns(BigInteger.ZERO)

      assert.throws(function () {
        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffff')
      }, /Private key must be greater than 0/)
    }))

    it('throws if IL is not within interval [1, n - 1] | IL === n', sinon.test(function () {
      this.mock(BigInteger).expects('fromBuffer')
        .once().returns(curve.n)

      assert.throws(function () {
        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffff')
      }, /Private key must be less than the curve order/)
    }))

    it('throws on low entropy seed', function () {
      assert.throws(function () {
        HDNode.fromSeedHex('ffffffffff')
      }, /Seed should be at least 128 bits/)
    })

    it('throws on too high entropy seed', function () {
      assert.throws(function () {
        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
      }, /Seed should be at most 512 bits/)
    })
  })

  describe('ECPair wrappers', function () {
    var keyPair, hd, hash

    beforeEach(function () {
      keyPair = ECPair.makeRandom()
      hash = new Buffer(32)

      var chainCode = new Buffer(32)
      hd = new HDNode(keyPair, chainCode)
    })

    describe('getAddress', function () {
      it('wraps keyPair.getAddress', sinon.test(function () {
        this.mock(keyPair).expects('getAddress')
          .once().withArgs().returns('foobar')

        assert.strictEqual(hd.getAddress(), 'foobar')
      }))
    })

    describe('getNetwork', function () {
      it('wraps keyPair.getNetwork', sinon.test(function () {
        this.mock(keyPair).expects('getNetwork')
          .once().withArgs().returns('network')

        assert.strictEqual(hd.getNetwork(), 'network')
      }))
    })

    describe('getPublicKeyBuffer', function () {
      it('wraps keyPair.getPublicKeyBuffer', sinon.test(function () {
        this.mock(keyPair).expects('getPublicKeyBuffer')
          .once().withArgs().returns('pubKeyBuffer')

        assert.strictEqual(hd.getPublicKeyBuffer(), 'pubKeyBuffer')
      }))
    })

    describe('sign', function () {
      it('wraps keyPair.sign', sinon.test(function () {
        this.mock(keyPair).expects('sign')
          .once().withArgs(hash).returns('signed')

        assert.strictEqual(hd.sign(hash), 'signed')
      }))
    })

    describe('verify', function () {
      var signature

      beforeEach(function () {
        signature = hd.sign(hash)
      })

      it('wraps keyPair.verify', sinon.test(function () {
        this.mock(keyPair).expects('verify')
          .once().withArgs(hash, signature).returns('verified')

        assert.strictEqual(hd.verify(hash, signature), 'verified')
      }))
    })
  })

  describe('toBase58', function () {
    fixtures.valid.forEach(function (f) {
      it('exports ' + f.master.base58 + ' (public) correctly', function () {
        var network = NETWORKS[f.network]
        var hd = HDNode.fromSeedHex(f.master.seed, network).neutered()

        assert.strictEqual(hd.toBase58(), f.master.base58)
      })
    })

    fixtures.valid.forEach(function (f) {
      it('exports ' + f.master.base58Priv + ' (private) correctly', function () {
        var network = NETWORKS[f.network]
        var hd = HDNode.fromSeedHex(f.master.seed, network)

        assert.strictEqual(hd.toBase58(), f.master.base58Priv)
      })
    })
  })

  describe('fromBase58', function () {
    fixtures.valid.forEach(function (f) {
      it('imports ' + f.master.base58 + ' (public) correctly', function () {
        var network = NETWORKS[f.network]
        var hd = HDNode.fromBase58(f.master.base58, network)

        assert.strictEqual(hd.toBase58(), f.master.base58)
        assert.strictEqual(hd.keyPair.network, network)
        assert.strictEqual(hd.isNeutered(), true)
      })
    })

    fixtures.valid.forEach(function (f) {
      it('imports ' + f.master.base58Priv + ' (private) correctly', function () {
        var network = NETWORKS[f.network]
        var hd = HDNode.fromBase58(f.master.base58Priv, network)

        assert.strictEqual(hd.toBase58(), f.master.base58Priv)
        assert.strictEqual(hd.keyPair.network, network)
        assert.strictEqual(hd.isNeutered(), false)
      })
    })

    fixtures.invalid.fromBase58.forEach(function (f) {
      it('throws on ' + f.string, function () {
        assert.throws(function () {
          var network = NETWORKS[f.network]

          HDNode.fromBase58(f.string, network)
        }, new RegExp(f.exception))
      })
    })
  })

  describe('getIdentifier', function () {
    var f = fixtures.valid[0]

    it('returns the identifier for ' + f.master.fingerprint, function () {
      var hd = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.strictEqual(hd.getIdentifier().toString('hex'), f.master.identifier)
    })
  })

  describe('getFingerprint', function () {
    var f = fixtures.valid[0]

    it('returns the fingerprint for ' + f.master.fingerprint, function () {
      var hd = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.strictEqual(hd.getFingerprint().toString('hex'), f.master.fingerprint)
    })
  })

  describe('neutered', function () {
    var f = fixtures.valid[0]

    it('strips all private information', function () {
      var hd = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
      var hdn = hd.neutered()

      assert.strictEqual(hdn.keyPair.d, undefined)
      assert.strictEqual(hdn.keyPair.Q, hd.keyPair.Q)
      assert.strictEqual(hdn.chainCode, hd.chainCode)
      assert.strictEqual(hdn.depth, hd.depth)
      assert.strictEqual(hdn.index, hd.index)
      assert.strictEqual(hdn.isNeutered(), true)
      assert.strictEqual(hd.isNeutered(), false)
    })
  })

  describe('derive', function () {
    function verifyVector (hd, v, depth) {
      assert.strictEqual(hd.keyPair.toWIF(), v.wif)
      assert.strictEqual(hd.keyPair.getPublicKeyBuffer().toString('hex'), v.pubKey)
      assert.strictEqual(hd.chainCode.toString('hex'), v.chainCode)
      assert.strictEqual(hd.depth, depth || 0)

      if (v.hardened) {
        assert.strictEqual(hd.index, v.m + HDNode.HIGHEST_BIT)
      } else {
        assert.strictEqual(hd.index, v.m)
      }
    }

    fixtures.valid.forEach(function (f) {
      var network = NETWORKS[f.network]
      var hd = HDNode.fromSeedHex(f.master.seed, network)
      var master = hd

      // FIXME: test data is only testing Private -> private for now
      f.children.forEach(function (c, i) {
        it(c.description + ' from ' + f.master.fingerprint, function () {
          if (c.hardened) {
            hd = hd.deriveHardened(c.m)
          } else {
            hd = hd.derive(c.m)
          }

          verifyVector(hd, c, i + 1)
        })
      })

      // testing deriving path from master
      f.children.forEach(function (c) {
        it(c.description + ' from ' + f.master.fingerprint + ' by path', function () {
          var path = c.description
          var child = master.derivePath(path)

          var pathSplit = path.split('/').slice(1)
          var pathNotM = pathSplit.join('/')
          var childNotM = master.derivePath(pathNotM)

          verifyVector(child, c, pathSplit.length)
          verifyVector(childNotM, c, pathSplit.length)
        })
      })

      // testing deriving path from children
      f.children.forEach(function (c, i) {
        var cn = master.derivePath(c.description)

        f.children.slice(i + 1).forEach(function (cc) {
          it(cc.description + ' from ' + c.fingerprint + ' by path', function () {
            var path = cc.description

            var pathSplit = path.split('/').slice(i + 2)
            var pathEnd = pathSplit.join('/')
            var pathEndM = 'm/' + path

            var child = cn.derivePath(pathEnd)
            verifyVector(child, cc, pathSplit.length + i + 1)

            assert.throws(function () {
              cn.derivePath(pathEndM)
            }, /Not a master node/)
          })
        })
      })
    })

    it('works for Private -> public (neutered)', function () {
      var f = fixtures.valid[1]
      var c = f.children[0]

      var master = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
      var child = master.derive(c.m).neutered()

      assert.strictEqual(child.toBase58(), c.base58)
    })

    it('works for Private -> public (neutered, hardened)', function () {
      var f = fixtures.valid[0]
      var c = f.children[0]

      var master = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
      var child = master.deriveHardened(c.m).neutered()

      assert.strictEqual(child.toBase58(), c.base58)
    })

    it('works for Public -> public', function () {
      var f = fixtures.valid[1]
      var c = f.children[0]

      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
      var child = master.derive(c.m)

      assert.strictEqual(child.toBase58(), c.base58)
    })

    it('throws on Public -> public (hardened)', function () {
      var f = fixtures.valid[0]
      var c = f.children[0]

      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.throws(function () {
        master.deriveHardened(c.m)
      }, /Could not derive hardened child key/)
    })

    it('throws on negative indexes', function () {
      var f = fixtures.valid[0]
      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.throws(function () {
        master.deriveHardened(-1)
      }, /Expected UInt31/)
      assert.throws(function () {
        master.derive(-1)
      }, /Expected UInt32/)
    })

    it('throws on high indexes', function () {
      var f = fixtures.valid[0]
      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.throws(function () {
        master.deriveHardened(0x80000000)
      }, /Expected UInt31/)
      assert.throws(function () {
        master.derive(0x100000000)
      }, /Expected UInt32/)
    })

    it('throws on non-numbers', function () {
      var f = fixtures.valid[0]
      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)

      assert.throws(function () {
        master.deriveHardened()
      }, /Expected UInt31/)
      assert.throws(function () {
        master.derive()
      }, /Expected UInt32/)
      assert.throws(function () {
        master.deriveHardened('foo')
      }, /Expected UInt31/)
      assert.throws(function () {
        master.derive('foo')
      }, /Expected UInt32/)
    })
  })
})
<|endoftext|>


<commit_before>'use strict';

require('dotenv').load();

module.exports = {
    port: Number(process.env.PORT) || 5001,
    token: process.env.SLACK_TOKEN, // Slack channel token
    domain: process.env.SLACK_DOMAIN, // Slack domain as in "mycompany.slack.com"
    channel: '#' + process.env.SLACK_CHANNEL, // Slack channel without # prefix
    username: process.env.SLACK_USERNAME || 'MyAwesomeBot'
};
<commit_msg>Reverting port to default 5000<commit_after>'use strict';

require('dotenv').load();

module.exports = {
    port: Number(process.env.PORT) || 5000,
    token: process.env.SLACK_TOKEN, // Slack channel token
    domain: process.env.SLACK_DOMAIN, // Slack domain as in "mycompany.slack.com"
    channel: '#' + process.env.SLACK_CHANNEL, // Slack channel without # prefix
    username: process.env.SLACK_USERNAME || 'MyAwesomeBot'
};
<|endoftext|>


<commit_before>import isPresent from 'is-present'
import {omit} from 'lodash'
import {d} from 'lightsaber/lib/log'
import React from 'react'
import debug from 'debug'

import server from '../../models/Server'

const error = debug('wn:error')

export default class Profile extends React.Component {

  constructor(props) {
    super(props)
    this.state = {
      uportAddress: this.props.uportAddress,
      name: null,
      skillClaims: [],
      errors: [],
    }
  }

  componentDidMount() {
    if (!this.state.uportAddress) {
      error(`Can't load user "${this.state.uportAddress}"`)
      return
    }
    const serverUrl = `${process.env.REACT_APP_API_SERVER}/users/${this.state.uportAddress}`
    server.get(serverUrl).then(response => {
      if (isPresent(response.data)) {
        // d(response.data)
        const newData = omit(response.data, 'uportAddress')
        this.setState(newData) // , () => d({state: this.state}))
      } else {
        error(`No data found for user ${this.state.uportAddress}`, `Server URL: ${serverUrl}`)
      }
    })
  }

  render() {
    return (

              { this.avatar() }

{this.state.name}

view reputon data

view uPort Ethereum contract

Skills

                  confirmations

                  # of projects

              { this.skills() }

Projects

Manic Mondays

Project Tuesday

Lorem Ipsum

    )
  }

  avatar = () => {
    if (this.state.avatarImageIpfsKey) {
      return
    }
  }

  skills = () => {
    return this.state.skillClaims.map((skill, index) => {
      return [

            {skill.confirmationsCount}

            {skill.name}

            {this.confirmations(skill)}

            {skill.projectCount}

      ]
    })
  }

  confirmations = (skill) => {
    return [

          {skill.confirmationsCount} confirmations from
          Project Neptune: {skill.confirmations.map(conf => conf.confirmerName).join(', ')}

          {skill.confirmationsCount} confirmations from
          Project Jupiter: {skill.confirmations.map(conf => conf.confirmerName).join(', ')}

    ]
  }
}
<commit_msg>Projects in profile; Update for new server API<commit_after>import isPresent from 'is-present'
import {omit} from 'lodash'
import {d} from 'lightsaber/lib/log'
import React from 'react'
import debug from 'debug'

import server from '../../models/Server'

const error = debug('wn:error')

export default class Profile extends React.Component {

  constructor(props) {
    super(props)
    this.state = {
      uportAddress: this.props.uportAddress,
      name: null,
      skills: [],
      projects: [],
    }
  }

  componentDidMount() {
    if (!this.state.uportAddress) {
      error(`Can't load user "${this.state.uportAddress}"`)
      return
    }
    const serverUrl = `${process.env.REACT_APP_API_SERVER}/users/${this.state.uportAddress}`
    server.get(serverUrl).then(response => {
      if (isPresent(response.data)) {
        // d(response.data)
        const newData = omit(response.data, 'uportAddress')
        this.setState(newData) // , () => d({state: this.state}))
      } else {
        error(`No data found for user ${this.state.uportAddress}`, `Server URL: ${serverUrl}`)
      }
    })
  }

  render() {
    return (

              { this.avatar() }

{this.state.name}

view reputon data

view uPort Ethereum contract

Skills

                  confirmations

                  # of projects

              { this.skills() }

Projects

              {this.state.projects.map(project =>
{project}
)}

    )
  }

  avatar = () => {
    if (this.state.avatarImageIpfsKey) {
      return
    }
  }

  skills = () => {
    return this.state.skills.map((skill, index) => {
      return [

            {skill.confirmationsCount}

            {skill.name}

            {this.confirmations(skill)}

            {skill.projectCount}

      ]
    })
  }

  confirmations = (skill) => {
    return [

          {skill.confirmationsCount} confirmations from {' '}
          {skill.confirmations.map(conf => conf.confirmerName).slice(0, 6).join(', ')}...

    ]
  }
}
<|endoftext|>


<commit_before>// This is the main application configuration file.  It is a Grunt
// configuration file, which you can learn more about here:
// https://github.com/cowboy/grunt/blob/master/docs/configuring.md
module.exports = function(grunt) {

  var couch_config = {
    fauxton: {
              db: 'http://localhost:5984/fauxton',
              app: './couchapp.js',
              options: {
                okay_if_missing: true
              }
            }
  };

  var cleanable = function(){
    // Whitelist files and directories to be cleaned
    var path = require('path');
    // You'll always want to clean these two directories
    var theListToClean = ["dist/", "app/load_addons.js"];
    // Now find the external addons you have and add them for cleaning up
    if (path.existsSync("settings.json")){
      var settings = grunt.file.readJSON("settings.json") || {deps: []};
      settings.deps.forEach(function(addon){
        // Only clean addons that are included from a local dir
        if (addon.path){
          theListToClean.push("app/addons/" + addon.name);
        }
      });
    }
    return theListToClean;
  }();

  grunt.initConfig({

    // The clean task ensures all files are removed from the dist/ directory so
    // that no files linger from previous builds.
    clean:  cleanable,

    // The lint task will run the build configuration and the application
    // JavaScript through JSHint and report any errors.  You can change the
    // options for this task, by reading this:
    // https://github.com/cowboy/grunt/blob/master/docs/task_lint.md
    lint: {
      files: [
        "build/config.js", "app/**/*.js"
      ]
    },

    less: {
      compile: {
        options: {
          paths: ["assets/less"]
        },
        files: {
          "dist/debug/css/index.css": "assets/less/fauxton.less"
        }
      }
    },

    // The jshint option for scripturl is set to lax, because the anchor
    // override inside main.js needs to test for them so as to not accidentally
    // route.
    jshint: {
      options: {
        scripturl: true
      }
    },

    // The jst task compiles all application templates into JavaScript
    // functions with the underscore.js template function from 1.2.4.  You can
    // change the namespace and the template options, by reading this:
    // https://github.com/gruntjs/grunt-contrib/blob/master/docs/jst.md
    //
    // The concat task depends on this file to exist, so if you decide to
    // remove this, ensure concat is updated accordingly.
    jst: {
      "dist/debug/templates.js": [
        "app/templates/**/*.html",
        "app/addons/**/templates/**/*.html"
      ]
    },

    // Create static html files from templates, for managing change of script
    // or css name.
    template: {
      couchdb:{
        src: 'assets/index.underscore',
        dest: '../../share/www/fauxton/index.html',
        variables: {
          assets_root: '/_utils/fauxton/',
          requirejs: 'require.min.js',
          base: '/_utils/fauxton/'
        }
      },
      couchdebug:{
        src: 'assets/index.underscore',
        dest: '../../share/www/fauxton/index.html',
        variables: {
          assets_root: '/_utils/fauxton/',
          requirejs: 'require.js',
          base: '/_utils/fauxton/'
        }
      },
      release: {
        src: 'assets/index.underscore',
        dest: 'dist/release/index.html',
        variables: {
          assets_root: '/',
          requirejs: 'require.min.js',
          base: '/'
        }
      },
      debug: {
        src: 'assets/index.underscore',
        dest: 'dist/debug/index.html',
        variables: {
          assets_root: '/',
          requirejs: 'require.js',
          base: '/'
        }
      },
      couchapp: {
        src: 'assets/index.underscore',
        dest: 'dist/debug/index.html',
        variables: {
          assets_root: '/fauxton/_design/fauxton/',
          requirejs: 'require.js',
          base: '/fauxton/_design/fauxton/index.html'
        }
      }
    },

    // The concatenate task is used here to merge the almond require/define
    // shim and the templates into the application code.  It's named
    // dist/debug/require.js, because we want to only load one script file in
    // index.html.
    concat: {
      requirejs: {
        src: ["assets/js/libs/almond.js", "dist/debug/templates.js", "dist/debug/require.js"],
        dest: "dist/debug/js/require.js"
      },

      debug: {
        src: ["dist/debug/css/index.css", 'assets/css/*.css'],
        dest: 'dist/debug/css/index.css'
      }

    },

    // This task uses the MinCSS Node.js project to take all your CSS files in
    // order and concatenate them into a single CSS file named index.css.  It
    // also minifies all the CSS as well.  This is named index.css, because we
    // only want to load one stylesheet in index.html.
    mincss: {
      "dist/release/css/index.css": [
        "dist/debug/css/index.css", 'assets/css/*.css',
        "app/addons/**/assets/css/*.css"
      ]
    },

    // Takes the built require.js file and minifies it for filesize benefits.
    min: {
      "dist/release/js/require.min.js": [
        "dist/debug/js/require.js"
      ]
    },

    // Running the server without specifying an action will run the defaults,
    // port: 8000 and host: 127.0.0.1.  If you would like to change these
    // defaults, simply add in the properties `port` and `host` respectively.
    // Alternatively you can omit the port and host properties and the server
    // task will instead default to process.env.PORT or process.env.HOST.
    //
    // Changing the defaults might look something like this:
    //
    // server: {
    //   host: "127.0.0.1", port: 9001
    //   debug: { ... can set host and port here too ...
    //  }
    //
    //  To learn more about using the server task, please refer to the code
    //  until documentation has been written.
    server: {
      // Ensure the favicon is mapped correctly.
      files: { "favicon.ico": "favicon.ico" },

      debug: {
        // Ensure the favicon is mapped correctly.
        "index": "./dist/debug/index.html",
        files: { "favicon.ico": "favicon.ico" },

        // Map `server:debug` to `debug` folders.
        folders: {
          "app": "dist/debug",
          "assets/js/libs": "dist/debug",
          "css": "dist/debug/css",
          "js": "dist/debug/js"
        }
      },

      proxies: {
        '': {
          host: 'localhost',
          port: 5984,
          https: false
        }
      },

      release: {
        // This makes it easier for deploying, by defaulting to any IP.
        host: "0.0.0.0",

        // Ensure the favicon is mapped correctly.
        files: { "favicon.ico": "favicon.ico" },

        // Map `server:release` to `release` folders.
        folders: {
          "app": "dist/release",
          "assets/js/libs": "dist/release",
          "assets/css": "dist/release"
        }
      }
    },

    // This task uses James Burke's excellent r.js AMD build tool.  In the
    // future other builders may be contributed as drop-in alternatives.
    requirejs: {
      // Include the main configuration file.
      mainConfigFile: "app/config.js",

      // Output file.
      out: "dist/debug/require.js",

      // Root application module.
      name: "config",

      // Do not wrap everything in an IIFE.
      wrap: false
    },

    // The headless QUnit testing environment is provided for "free" by Grunt.
    // Simply point the configuration to your test directory.
    qunit: {
      all: ["test/qunit/*.html"]
    },

    // The headless Jasmine testing is provided by grunt-jasmine-task. Simply
    // point the configuration to your test directory.
    jasmine: {
      all: ["test/jasmine/*.html"]
    },

    // Copy build artifacts and library code into the distribution

    copy: {
      couchdb: {
        files: {
          // this gets built in the template task
          //"../../share/www/fauxton/index.html": "dist/release/index.html",
          "../../share/www/fauxton/js/": "dist/release/js/**",
          // no images... yet
          "../../share/www/fauxton/img/": "dist/release/img/**",
          "../../share/www/fauxton/css/": "dist/release/css/**"
        }
      },
      couchdebug: {
        files: {
          // this gets built in the template task
          //"../../share/www/fauxton/index.html": "dist/release/index.html",
          "../../share/www/fauxton/js/": "dist/debug/js/**",
          // no images... yet
          "../../share/www/fauxton/img/": "dist/debug/img/**",
          "../../share/www/fauxton/css/": "dist/debug/css/**",
          // Must be possible to improve this...
          "../../share/www/fauxton/app/": "dist/debug/**"
        }
      },
      dist:{
        files:{
          "dist/release/js/": "assets/js/**",
          //"dist/release/css/**": "assets/css/**"
          "dist/release/img/": "assets/img/**"
        }
      },
      debug:{
        files:{
          "dist/debug/js/": "assets/js/**",
          //"dist/debug/css/": "dist/release/css/**"
          "dist/debug/img/": "assets/img/**"
        }
      }
    },

    get_deps: {
      "default": {
        src: "settings.json"
      }
    },

    gen_load_addons: {
      "default": {
        src: "settings.json"
      }
    },

    mkcouchdb: couch_config,
    rmcouchdb: couch_config,
    couchapp: couch_config

  });

  // Load fauxton specific tasks
  grunt.loadTasks('tasks');
  // Load the couchapp task
  grunt.loadNpmTasks('grunt-couchapp');
  // Load the copy task
  grunt.loadNpmTasks('grunt-contrib-copy');
  // Load the exec task
  grunt.loadNpmTasks('grunt-exec');

  // clean out previous build artefacts, lint and unit test
  grunt.registerTask('test', 'clean lint'); //qunit
  // Fetch dependencies (from git or local dir), lint them and make load_addons
  grunt.registerTask('dependencies', 'get_deps lint gen_load_addons:default');
  // build templates, js and css
  grunt.registerTask('build', 'jst requirejs concat:requirejs less');
  // minify code and css, ready for release.
  grunt.registerTask("minify", "min mincss");
  // deafult task - push to CouchDB
  grunt.registerTask("default", "test dependencies build release install");
  grunt.registerTask("dev", "debug server:debug");
  // make a debug install
  grunt.registerTask("debug", "test dependencies build template:debug copy:debug concat:debug");
  // make an install that is server by mochiweb under _utils
  grunt.registerTask("couchdebug", "debug template:couchdebug copy:couchdebug");
  // make an install that can be deployed as a couchapp
  grunt.registerTask("couchapp_setup", "debug template:couchapp");
  grunt.registerTask("couchdb", "test dependencies build minify template:couchdb copy:couchdb");
  // build a release
  grunt.registerTask("release", "test dependencies build minify template:release copy:dist");
  // install fauxton as couchapp
  grunt.registerTask('couchapp_install', 'rmcouchdb:fauxton mkcouchdb:fauxton couchapp:fauxton');
  grunt.registerTask('couchapp_deploy', 'couchapp_setup couchapp_install');

};
<commit_msg>Assets for addons<commit_after>// This is the main application configuration file.  It is a Grunt
// configuration file, which you can learn more about here:
// https://github.com/cowboy/grunt/blob/master/docs/configuring.md

module.exports = function(grunt) {
  var path = require('path');
  var couch_config = {
    fauxton: {
              db: 'http://localhost:5984/fauxton',
              app: './couchapp.js',
              options: {
                okay_if_missing: true
              }
            }
  };

  function processAddons(callback){
    if (path.existsSync("settings.json")){
      var settings = grunt.file.readJSON("settings.json") || {deps: []};
      settings.deps.forEach(callback);
    }
  }

  var cleanable = function(){
    // Whitelist files and directories to be cleaned

    // You'll always want to clean these two directories
    var theListToClean = ["dist/", "app/load_addons.js"];
    // Now find the external addons you have and add them for cleaning up
    processAddons(function(addon){
      // Only clean addons that are included from a local dir
      if (addon.path){
        theListToClean.push("app/addons/" + addon.name);
      }
    });
    return theListToClean;
  }();

  var assets = function(){
    // Base assets
    var theAssets = {
      less:{
        paths: ["assets/less"],
        files: {
          "dist/debug/css/fauxton.css": "assets/less/fauxton.less"
        }
      }
    };
    // Less files from addons
    processAddons(function(addon){
      var root = addon.path || "app/addons/" + addon.name;
      var lessPath = root + "/assets/less";
      if(path.existsSync(lessPath)){
        // .less files exist for this addon
        theAssets.less.paths.push(lessPath);
        theAssets.less.files["dist/debug/css/" + addon.name + ".css"] =
            lessPath + "/" + addon.name + ".less";
      }
    });

    return theAssets;
  }();

  grunt.initConfig({

    // The clean task ensures all files are removed from the dist/ directory so
    // that no files linger from previous builds.
    clean:  cleanable,

    // The lint task will run the build configuration and the application
    // JavaScript through JSHint and report any errors.  You can change the
    // options for this task, by reading this:
    // https://github.com/cowboy/grunt/blob/master/docs/task_lint.md
    lint: {
      files: [
        "build/config.js", "app/**/*.js"
      ]
    },

    less: {
      compile: {
        options: {
          paths: assets.less.paths
        },
        files: assets.less.files
      }
    },

    // The jshint option for scripturl is set to lax, because the anchor
    // override inside main.js needs to test for them so as to not accidentally
    // route.
    jshint: {
      options: {
        scripturl: true
      }
    },

    // The jst task compiles all application templates into JavaScript
    // functions with the underscore.js template function from 1.2.4.  You can
    // change the namespace and the template options, by reading this:
    // https://github.com/gruntjs/grunt-contrib/blob/master/docs/jst.md
    //
    // The concat task depends on this file to exist, so if you decide to
    // remove this, ensure concat is updated accordingly.
    jst: {
      "dist/debug/templates.js": [
        "app/templates/**/*.html",
        "app/addons/**/templates/**/*.html"
      ]
    },

    // Create static html files from templates, for managing change of script
    // or css name.
    template: {
      couchdb:{
        src: 'assets/index.underscore',
        dest: '../../share/www/fauxton/index.html',
        variables: {
          assets_root: '/_utils/fauxton/',
          requirejs: 'require.min.js',
          base: '/_utils/fauxton/'
        }
      },
      couchdebug:{
        src: 'assets/index.underscore',
        dest: '../../share/www/fauxton/index.html',
        variables: {
          assets_root: '/_utils/fauxton/',
          requirejs: 'require.js',
          base: '/_utils/fauxton/'
        }
      },
      release: {
        src: 'assets/index.underscore',
        dest: 'dist/release/index.html',
        variables: {
          assets_root: '/',
          requirejs: 'require.min.js',
          base: '/'
        }
      },
      debug: {
        src: 'assets/index.underscore',
        dest: 'dist/debug/index.html',
        variables: {
          assets_root: '/',
          requirejs: 'require.js',
          base: '/'
        }
      },
      couchapp: {
        src: 'assets/index.underscore',
        dest: 'dist/debug/index.html',
        variables: {
          assets_root: '/fauxton/_design/fauxton/',
          requirejs: 'require.js',
          base: '/fauxton/_design/fauxton/index.html'
        }
      }
    },

    // The concatenate task is used here to merge the almond require/define
    // shim and the templates into the application code.  It's named
    // dist/debug/require.js, because we want to only load one script file in
    // index.html.
    concat: {
      requirejs: {
        src: ["assets/js/libs/almond.js", "dist/debug/templates.js", "dist/debug/require.js"],
        dest: "dist/debug/js/require.js"
      },

      debug: {
        src: ["dist/debug/css/*.css", 'assets/css/*.css'],
        dest: 'dist/debug/css/index.css'
      }

    },

    // This task uses the MinCSS Node.js project to take all your CSS files in
    // order and concatenate them into a single CSS file named index.css.  It
    // also minifies all the CSS as well.  This is named index.css, because we
    // only want to load one stylesheet in index.html.
    mincss: {
      "dist/release/css/index.css": [
        "dist/debug/css/index.css", 'assets/css/*.css',
        "app/addons/**/assets/css/*.css"
      ]
    },

    // Takes the built require.js file and minifies it for filesize benefits.
    min: {
      "dist/release/js/require.min.js": [
        "dist/debug/js/require.js"
      ]
    },

    // Running the server without specifying an action will run the defaults,
    // port: 8000 and host: 127.0.0.1.  If you would like to change these
    // defaults, simply add in the properties `port` and `host` respectively.
    // Alternatively you can omit the port and host properties and the server
    // task will instead default to process.env.PORT or process.env.HOST.
    //
    // Changing the defaults might look something like this:
    //
    // server: {
    //   host: "127.0.0.1", port: 9001
    //   debug: { ... can set host and port here too ...
    //  }
    //
    //  To learn more about using the server task, please refer to the code
    //  until documentation has been written.
    server: {
      // Ensure the favicon is mapped correctly.
      files: { "favicon.ico": "favicon.ico" },

      debug: {
        // Ensure the favicon is mapped correctly.
        "index": "./dist/debug/index.html",
        files: { "favicon.ico": "favicon.ico" },

        // Map `server:debug` to `debug` folders.
        folders: {
          "app": "dist/debug",
          "assets/js/libs": "dist/debug",
          "css": "dist/debug/css",
          "js": "dist/debug/js"
        }
      },

      proxies: {
        '': {
          host: 'localhost',
          port: 5984,
          https: false
        }
      },

      release: {
        // This makes it easier for deploying, by defaulting to any IP.
        host: "0.0.0.0",

        // Ensure the favicon is mapped correctly.
        files: { "favicon.ico": "favicon.ico" },

        // Map `server:release` to `release` folders.
        folders: {
          "app": "dist/release",
          "assets/js/libs": "dist/release",
          "assets/css": "dist/release"
        }
      }
    },

    // This task uses James Burke's excellent r.js AMD build tool.  In the
    // future other builders may be contributed as drop-in alternatives.
    requirejs: {
      // Include the main configuration file.
      mainConfigFile: "app/config.js",

      // Output file.
      out: "dist/debug/require.js",

      // Root application module.
      name: "config",

      // Do not wrap everything in an IIFE.
      wrap: false
    },

    // The headless QUnit testing environment is provided for "free" by Grunt.
    // Simply point the configuration to your test directory.
    qunit: {
      all: ["test/qunit/*.html"]
    },

    // The headless Jasmine testing is provided by grunt-jasmine-task. Simply
    // point the configuration to your test directory.
    jasmine: {
      all: ["test/jasmine/*.html"]
    },

    // Copy build artifacts and library code into the distribution

    copy: {
      couchdb: {
        files: {
          // this gets built in the template task
          //"../../share/www/fauxton/index.html": "dist/release/index.html",
          "../../share/www/fauxton/js/": "dist/release/js/**",
          // no images... yet
          "../../share/www/fauxton/img/": "dist/release/img/**",
          "../../share/www/fauxton/css/": "dist/release/css/**"
        }
      },
      couchdebug: {
        files: {
          // this gets built in the template task
          //"../../share/www/fauxton/index.html": "dist/release/index.html",
          "../../share/www/fauxton/js/": "dist/debug/js/**",
          // no images... yet
          "../../share/www/fauxton/img/": "dist/debug/img/**",
          "../../share/www/fauxton/css/": "dist/debug/css/**",
          // Must be possible to improve this...
          "../../share/www/fauxton/app/": "dist/debug/**"
        }
      },
      dist:{
        files:{
          "dist/release/js/": "assets/js/**",
          //"dist/release/css/**": "assets/css/**"
          "dist/release/img/": "assets/img/**"
        }
      },
      debug:{
        files:{
          "dist/debug/js/": "assets/js/**",
          //"dist/debug/css/": "dist/release/css/**"
          "dist/debug/img/": "assets/img/**"
        }
      }
    },

    get_deps: {
      "default": {
        src: "settings.json"
      }
    },

    gen_load_addons: {
      "default": {
        src: "settings.json"
      }
    },

    mkcouchdb: couch_config,
    rmcouchdb: couch_config,
    couchapp: couch_config

  });

  // Load fauxton specific tasks
  grunt.loadTasks('tasks');
  // Load the couchapp task
  grunt.loadNpmTasks('grunt-couchapp');
  // Load the copy task
  grunt.loadNpmTasks('grunt-contrib-copy');
  // Load the exec task
  grunt.loadNpmTasks('grunt-exec');

  // clean out previous build artefacts, lint and unit test
  grunt.registerTask('test', 'clean lint'); //qunit
  // Fetch dependencies (from git or local dir), lint them and make load_addons
  grunt.registerTask('dependencies', 'get_deps lint gen_load_addons:default');
  // build templates, js and css
  grunt.registerTask('build', 'jst requirejs concat:requirejs less');
  // minify code and css, ready for release.
  grunt.registerTask("minify", "min mincss");
  // deafult task - push to CouchDB
  grunt.registerTask("default", "test dependencies build release install");
  grunt.registerTask("dev", "debug server:debug");
  // make a debug install
  grunt.registerTask("debug", "test dependencies build template:debug copy:debug concat:debug");
  // make an install that is server by mochiweb under _utils
  grunt.registerTask("couchdebug", "debug template:couchdebug copy:couchdebug");
  // make an install that can be deployed as a couchapp
  grunt.registerTask("couchapp_setup", "debug template:couchapp");
  grunt.registerTask("couchdb", "test dependencies build minify template:couchdb copy:couchdb");
  // build a release
  grunt.registerTask("release", "test dependencies build minify template:release copy:dist");
  // install fauxton as couchapp
  grunt.registerTask('couchapp_install', 'rmcouchdb:fauxton mkcouchdb:fauxton couchapp:fauxton');
  grunt.registerTask('couchapp_deploy', 'couchapp_setup couchapp_install');

};
<|endoftext|>