<commit_before>psc.namespace('admin');

psc.admin.UserAdmin = (function ($) {
  var user;

  var provisionableSites = new Array();
  PROVISIONABLE_SITES.each(function(site) {
    provisionableSites.push(site.identifier)
  });

  function selectRole(roleKey) {
    $('a.role').removeClass('selected');
    $('#role-' + roleKey).addClass('selected');

    if (roleKey === 'multiple-roles') {
      startEditingMultiple();
      $('input.roles-to-edit').change(selectRoleCheckbox);

    } else {
      startEditing(roleKey);
    }
  }

  function selectRoleTab(evt) {
    var roleKey = evt.target.id.substring("role-".length)
    selectRole(roleKey);
    syncAllVsOne();
    return false;
  }

  function selectRoleCheckbox(evt) {
    var checked = _($('input.roles-to-edit:checked')).map(function(elt) {
      return $(elt).val();
    });

    addRoleAndScopesToMultipleTemplate(checked);
    syncAllVsOne();
    return false;
  }

  function determineProvisionableStudies(role) {
    var isTM = _(role.uses || []).indexOf("template_management") >= 0;
    var isSP = _(role.uses || []).indexOf("site_participation") >= 0;
    if (isTM && isSP) {
      return PROVISIONABLE_STUDIES['template_management+site_participation'];
    } else if (isTM) {
      return PROVISIONABLE_STUDIES['template_management'];
    } else {
      // use participation even for roles that don't have uses
      return PROVISIONABLE_STUDIES['site_participation'];
    }
  }

  function startEditing(roleKey) {
    var role = _.detect(PROVISIONABLE_ROLES, function (role) { return role.key === roleKey });
    if (role) {
      var enableRoleControl = isControlEnabled('role-control', role);
      var enableSitesControl = isControlEnabled('sites-control', role);

      $('#role-editor-pane').html(resigTemplate('role_editor_template', {
          role: role, sites: PROVISIONABLE_SITES, studies: determineProvisionableStudies(role),
          enableRoleControl: enableRoleControl, enableSitesControl: enableSitesControl
        })).
        find('input.role-group-membership').attr('checked', !!user.memberships[role.key]).
        click(updateGroupMembership).end().
        parent().attr('role', roleKey);
      registerScopeControls('#role-editor-pane', role, 'site', 'sites');
      registerScopeControls('#role-editor-pane', role, 'study', 'studies');
    } else {
      alert("No such role " + roleKey);
    }
  }

  function startEditingMultiple(roleKeys) {
    var roleKeys = roleKeys || []
    var roles = _.select(PROVISIONABLE_ROLES, function (role) { return _.include(roleKeys, role.key)});

    var enableRoleControl = _(roles).any(function(r) {return isControlEnabled('role-control', r)});
    var enableSitesControl = _(roles).any(function(r) {return isControlEnabled('sites-control', r)});
    $('#role-editor-pane').html(resigTemplate('multiple_role_editor_template', {
      roles: roles, sites: PROVISIONABLE_SITES,
      studies: uniqueStudies(_(roles).map(function(r) {return determineProvisionableStudies(r)}).flatten()),
      enableRoleControl: enableRoleControl, enableSitesControl: enableSitesControl,
      utils: {mapRoleKeys: mapRoleKeys, mapRoleNames: mapRoleNames, escapeIdSpaces: escapeIdSpaces}
    }))

    registerMultipleGroupControl('#role-editor-pane', roles);
    registerMultipleScopeControls('#role-editor-pane', roles, 'site', 'sites')
    registerMultipleScopeControls('#role-editor-pane', roles, 'study', 'studies')

  }

  function addRoleAndScopesToMultipleTemplate(roleKeys) {
    var roleKeys = roleKeys || []
    var roles = _.select(PROVISIONABLE_ROLES, function (role) { return _.include(roleKeys, role.key)});

    var enableRoleControl = _(roles).any(function(r) {return isControlEnabled('role-control', r)});
    var enableSitesControl = _(roles).any(function(r) {return isControlEnabled('sites-control', r)});
    $('#scope-container').html(resigTemplate('role_and_scope_assignment_template', {
      roles: roles, sites: PROVISIONABLE_SITES,
      studies: uniqueStudies(_(roles).map(function(r) {return determineProvisionableStudies(r)}).flatten()),
      enableRoleControl: enableRoleControl, enableSitesControl: enableSitesControl,
      utils: {mapRoleKeys: mapRoleKeys, mapRoleNames: mapRoleNames, escapeIdSpaces: escapeIdSpaces}
    }))

    registerMultipleGroupControl('#role-editor-pane', roles);
    registerMultipleScopeControls('#role-editor-pane', roles, 'site', 'sites')
    registerMultipleScopeControls('#role-editor-pane', roles, 'study', 'studies')

  }

  function uniqueStudies(studies) {
    var unique = [];
    _(studies).each(function(s) {
      if (!_(unique).pluck('identifier').include(s.identifier)) {
        unique.push(s)
      }
    });
    return unique;
  }

  function isControlEnabled(controlKey, role) {
      var enableRoleControl = true;
      var enableSitesControl = true;
      var provisionableStudies = new Array();
      determineProvisionableStudies(role).each(function(study) {
          provisionableStudies.push(study.identifier)
      });
      var mem = user.memberships[role.key]
      if (mem != null) {
        // Disable role membership control when the user we are provisioning is a
        // member of sites and/or studies that are not in the list of provisionable studies.
        if (mem['sites'] != null && mem['studies'] != null) {
          if (!(isSubsetOfProvision(provisionableSites, mem['sites'])
              && isSubsetOfProvision(provisionableStudies, mem['studies']))) {
            enableRoleControl = false;
          }
        } else if (mem['studies'] != null) {
          if (!isSubsetOfProvision(provisionableStudies, mem['studies'])) {
            enableRoleControl = false;
          }
        } else if (mem['sites'] != null) {
          if (!isSubsetOfProvision(provisionableSites, mem['sites'])) {
            enableRoleControl = false;
          }
        }

        // Disable sites membership control when the user we are provisioning is a
        // member of all-sites and the all-sites membership is not in the list of provisionable sites.
        if (!_.isEmpty(provisionableSites) && !_.isEmpty(mem['sites'])) {
          if (!_.include(provisionableSites,'__ALL__') && _.include(mem['sites'],'__ALL__')) {
            enableSitesControl = false;
          }
        }
      }

    switch(controlKey) {
      case 'role-control': return enableRoleControl;
      case 'sites-control': return enableSitesControl;
      default: return null;
    }
  }

  function isSubsetOfProvision(provisionableList, membershipList) {
    if(!_.isEmpty(provisionableList) && !_.isEmpty(membershipList)) {
      return _.all(membershipList, function(ele){
        return _.include(provisionableList,ele)
      })
    }
  }

  function updateGroupMembership(evt) {
    var r = evt.target.value;
    if ($(evt.target).attr('checked')) {
      user.add(r);
    } else {
      user.remove(r);
    }
  }

  function registerMultipleGroupControl(pane, roles) {
    var state = determineTristateCheckboxState(roles);

    var input = $(pane).find('#multiple-group-membership:first');

    $(input).tristate({initialState: state});

    updateIntermediateStateLabel(state, pane, '#partial-multiple-group-membership-info', roles);

    $(input).bind('tristate-state-change', _(updateMultipleGroupMemberships).bind(this, mapRoleKeys(roles)));
    $(input).bind('tristate-state-change', _(function (pane, roles, evt) {
      var state = $(evt.target).attr('state');
      updateIntermediateStateLabel(state, pane, '#partial-multiple-group-membership-info', roles);
    }).bind(this, pane, roles));
  }

  function updateMultipleGroupMemberships(roleKeys, evt) {
    console.log("Updating user obj", roleKeys, evt)

    var state = $(evt.target).attr('state');

    _(roleKeys).each(function(k) {
      switch(state) {
      case 'checked':
        user.add(k); break;
      case 'unchecked':
        user.remove(k); break;
      default:
        console.log("State does not exist", state);
      }
    });
  }

  function updateIntermediateStateLabel(state, pane, label, roles, scopeType, scopeValue) {
    var label = $(pane).find(label + ':first');

    if (state == 'intermediate') {
      var roleKeys = mapRoleKeys(roles);
      var scope = buildScopeObject(scopeType, scopeValue);
      var matchingRoleKeys = user.matchingMemberships(roleKeys, scope);
      var matchingRoles = _(PROVISIONABLE_ROLES).select(function (role) {return _(matchingRoleKeys).include(role.key)});
      var nonMatchingRoles = _(roles).reject(function (role) {return _(matchingRoleKeys).include(role.key)});
      $(label).html('(Applies to ' +  mapRoleNames(matchingRoles).join(', ') + ', but not ' + mapRoleNames(nonMatchingRoles).join(', ') + ')').show();
    } else {
      $(label).hide().empty();
    }
  }

  function determineTristateCheckboxState(roles, scopeType, scopeValue) {
    var roleKeys = mapRoleKeys(roles);
    var scope = buildScopeObject(scopeType, scopeValue);

    var status = user.membershipsStatus(roleKeys, scope);
    console.log("Tri-state checkbox status", status, scopeType, scopeValue);
    switch(status) {
      case 'FULL':    return 'checked';
      case 'PARTIAL': return 'intermediate';
      case 'NONE':    return 'unchecked';
      default:
        console.log("Memberships status unknown: ", status);
        return 'unchecked';
    }
  }

  function registerScopeControls(pane, role, scopeType, scopeTypePlural) {
    $(pane).find('input.scope-' + scopeType).each(function (i, input) {
      var qMembership = {}; qMembership[scopeType] = $(input).attr(scopeType + '-identifier');
      $(input).attr(
          'checked',
          user.hasMembership(role.key, qMembership));
    }).click(_(updateMembershipScope).bind(this, role.key, scopeType, scopeTypePlural));
  }

  function registerMultipleScopeControls(pane, roles, scopeType, scopeTypePlural) {
    $(pane).find('input.scope-' + scopeType).each(function (i, input) {
      var scopeValue = $(input).attr(scopeType + '-identifier');
      var state = determineTristateCheckboxState(roles, scopeType, scopeValue);
      var label = '#partial-scope-' + scopeType + '-' + escapeIdSpaces(scopeValue) + '-info';
      $(input).tristate({initialState: state});
      updateIntermediateStateLabel(state, pane, label, roles, scopeType, scopeValue);
    }).bind('tristate-state-change', _(function(roles, scopeType, scopeTypePlural, evt) {
      updateMultipleMembershipScope(_(roles).map(function(r){return r.key}), scopeType, scopeTypePlural, evt);
      var scopeValue = $(evt.target).attr(scopeType + '-identifier');
      var state = determineTristateCheckboxState(roles, scopeType, scopeValue);
      var label = '#partial-scope-' + scopeType + '-' + escapeIdSpaces(scopeValue) + '-info';
      updateIntermediateStateLabel(state, pane, label, roles, scopeType, scopeValue);
    }).bind(this, roles, scopeType, scopeTypePlural));
  }

  function buildScopeObject(scopeType, scopeValue) {
    var scope = null;
    if (scopeType) {
      scope = {}; scope[scopeType] = scopeValue;
    }
    return scope;
  }

  function mapRoleKeys(roles) {
    return roles.map(function(r){return r.key});
  }

  function mapRoleNames(roles) {
    return _(roles).map(function(r){return r.name});
  }

  function escapeIdSpaces(id) {
    return id.replace(' ', '--space--');
  }

  function updateMembershipScope(roleKey, scopeType, scopeListName, evt) {
    console.log("Updating user obj", roleKey, scopeType, scopeListName, evt);
    var scope = {}; scope[scopeListName] = [ evt.target.getAttribute(scopeType + '-identifier') ];
    if ($(evt.target).attr('checked')) {
      user.add(roleKey, scope);
    } else {
      user.remove(roleKey, scope);
    }
  }

  function updateMultipleMembershipScope(roleKeys, scopeType, scopeListName, evt) {
    var scope = {}; scope[scopeListName] = [ evt.target.getAttribute(scopeType + '-identifier') ];
    var state = $(evt.target).attr('state')

    console.log("Updating user obj", roleKeys, scopeType, scopeListName, scope, state, evt);

    _(roleKeys).each(function(roleKey) {
      switch(state) {
      case 'checked':
        user.add(roleKey, scope); break;
      case 'unchecked':
        user.remove(roleKey, scope); break;
      default:
        console.log("State does not exist", state);
      }
    });
  }

  function syncRoleTabOnChange(evt, data) {
    if (user.hasMembership(data.role)) {
      $('a#role-' + data.role).addClass('member');
    } else {
      $('a#role-' + data.role).removeClass('member');
    }
  }

  function syncRoleEditorOnChange(evt, data) {
    var role = data.role;
    var editorRole = $('#role-editor').attr('role');
    if (role !== editorRole && editorRole.indexOf(',') !== -1) { return; }
    var input;
    if (data.scopeType) {
      input = $('#role-editor input#scope-' + data.scopeType + '-' + data.scopeIdentifier);
      setTimeout(syncAllVsOne, 0);
    } else {
      input = $('#role-editor input#group-' + data.role);
      if ($(input).length <= 0) {
        input = $('#role-editor input#multiple-group-membership');
      }
    }
    input.attr('checked', data.kind === 'add');
    if (input.attr('state')) {
      input.attr('state', data.kind === 'add' ? 'checked' : 'unchecked');
      $(input).parents('.row').find('.partial-membership').empty();
    }
  }

  function syncAllVsOne() {
    _(['scope-study', 'scope-site']).each(function (scopeClass) {
      var isAll = $('#role-editor input.all.' + scopeClass + ":checked").length > 0;
      if (isAll) {
        var oneSelector = '#role-editor input.one.' + scopeClass;

        var regular = $(oneSelector).not('[state]').
          filter(':checked').click().end()

        var tristate = $(oneSelector + '[state]').
          tristate('state', 'unchecked')

        regular.add(tristate).
          attr("disabled", true).
          closest('div.row').addClass('disabled');
      } else {
        $('#role-editor input.one.' + scopeClass).
          attr("disabled", false).
          closest('div.row').removeClass('disabled');
      }
    });
  }

  function syncUsername() {
    user.username = $('input#username').val();
  }

  function toggleRoleView(evt, action) {
    if(!action) {
      action = $('#show-all-toggle:contains(Show)').length > 0 ? 'hide' : 'show';
    }

    if (action === 'show') {
      $('#show-all-toggle').text('Show Suite Roles');
      $("div.role-tab[role-type='suite']").hide();
    } else {
      $('#show-all-toggle').text('Hide Suite Roles')
      $("div.role-tab[role-type='suite']").show();
    }
    return false;
  }

  return {
    init: function (u) {
      user = u;
      _(user.memberships).each(function (scopes, roleKey) {
        $('#role-' + roleKey).addClass('member');
      }, this);
      var firstRole;
      if ($("div.role-tab[role-type='psc'] a.role.member").length > 0) {
        firstRole = $('a.role.member')[0].id.substring("role-".length);
      } else {
        firstRole = 'study_subject_calendar_manager';
      }
      selectRole(firstRole);
      $('a.role').click(selectRoleTab);
      $(user).bind('membership-change', syncRoleTabOnChange).
        bind('membership-change', syncRoleEditorOnChange);
      $('input#username').keyup(syncUsername);
      syncAllVsOne();
      toggleRoleView(null, 'show');
      $('#show-all-toggle').click(toggleRoleView);
    },

    serializeRoleChanges: function () {
      if (user.username) {
        var changes = {}; changes[user.username] = user.changes;
        return YAHOO.lang.JSON.stringify(changes);
      } else {
        return "{}";
      }
    }
  };
})(jQuery);
<commit_msg>Remove duplicate checkbox registration when in the edit multiples roles mode.<commit_after>psc.namespace('admin');

psc.admin.UserAdmin = (function ($) {
  var user;

  var provisionableSites = new Array();
  PROVISIONABLE_SITES.each(function(site) {
    provisionableSites.push(site.identifier)
  });

  function selectRole(roleKey) {
    $('a.role').removeClass('selected');
    $('#role-' + roleKey).addClass('selected');

    if (roleKey === 'multiple-roles') {
      startEditingMultiple();
      $('input.roles-to-edit').change(selectRoleCheckbox);

    } else {
      startEditing(roleKey);
    }
  }

  function selectRoleTab(evt) {
    var roleKey = evt.target.id.substring("role-".length)
    selectRole(roleKey);
    syncAllVsOne();
    return false;
  }

  function selectRoleCheckbox(evt) {
    var checked = _($('input.roles-to-edit:checked')).map(function(elt) {
      return $(elt).val();
    });

    addRoleAndScopesToMultipleTemplate(checked);
    syncAllVsOne();
    return false;
  }

  function determineProvisionableStudies(role) {
    var isTM = _(role.uses || []).indexOf("template_management") >= 0;
    var isSP = _(role.uses || []).indexOf("site_participation") >= 0;
    if (isTM && isSP) {
      return PROVISIONABLE_STUDIES['template_management+site_participation'];
    } else if (isTM) {
      return PROVISIONABLE_STUDIES['template_management'];
    } else {
      // use participation even for roles that don't have uses
      return PROVISIONABLE_STUDIES['site_participation'];
    }
  }

  function startEditing(roleKey) {
    var role = _.detect(PROVISIONABLE_ROLES, function (role) { return role.key === roleKey });
    if (role) {
      var enableRoleControl = isControlEnabled('role-control', role);
      var enableSitesControl = isControlEnabled('sites-control', role);

      $('#role-editor-pane').html(resigTemplate('role_editor_template', {
          role: role, sites: PROVISIONABLE_SITES, studies: determineProvisionableStudies(role),
          enableRoleControl: enableRoleControl, enableSitesControl: enableSitesControl
        })).
        find('input.role-group-membership').attr('checked', !!user.memberships[role.key]).
        click(updateGroupMembership).end().
        parent().attr('role', roleKey);
      registerScopeControls('#role-editor-pane', role, 'site', 'sites');
      registerScopeControls('#role-editor-pane', role, 'study', 'studies');
    } else {
      alert("No such role " + roleKey);
    }
  }

  function startEditingMultiple(roleKeys) {
    var roleKeys = roleKeys || []
    var roles = _.select(PROVISIONABLE_ROLES, function (role) { return _.include(roleKeys, role.key)});

    var enableRoleControl = _(roles).any(function(r) {return isControlEnabled('role-control', r)});
    var enableSitesControl = _(roles).any(function(r) {return isControlEnabled('sites-control', r)});
    $('#role-editor-pane').html(resigTemplate('multiple_role_editor_template', {
      roles: roles, sites: PROVISIONABLE_SITES,
      studies: uniqueStudies(_(roles).map(function(r) {return determineProvisionableStudies(r)}).flatten()),
      enableRoleControl: enableRoleControl, enableSitesControl: enableSitesControl,
      utils: {mapRoleKeys: mapRoleKeys, mapRoleNames: mapRoleNames, escapeIdSpaces: escapeIdSpaces}
    }));
  }

  function addRoleAndScopesToMultipleTemplate(roleKeys) {
    roleKeys = roleKeys || []
    var roles = _.select(PROVISIONABLE_ROLES, function (role) { return _.include(roleKeys, role.key)});

    var enableRoleControl = _(roles).any(function(r) {return isControlEnabled('role-control', r)});
    var enableSitesControl = _(roles).any(function(r) {return isControlEnabled('sites-control', r)});
    $('#scope-container').html(resigTemplate('role_and_scope_assignment_template', {
      roles: roles, sites: PROVISIONABLE_SITES,
      studies: uniqueStudies(_(roles).map(function(r) {return determineProvisionableStudies(r)}).flatten()),
      enableRoleControl: enableRoleControl, enableSitesControl: enableSitesControl,
      utils: {mapRoleKeys: mapRoleKeys, mapRoleNames: mapRoleNames, escapeIdSpaces: escapeIdSpaces}
    }))

    registerMultipleGroupControl('#role-editor-pane', roles);
    registerMultipleScopeControls('#role-editor-pane', roles, 'site', 'sites')
    registerMultipleScopeControls('#role-editor-pane', roles, 'study', 'studies')

  }

  function uniqueStudies(studies) {
    var unique = [];
    _(studies).each(function(s) {
      if (!_(unique).pluck('identifier').include(s.identifier)) {
        unique.push(s)
      }
    });
    return unique;
  }

  function isControlEnabled(controlKey, role) {
      var enableRoleControl = true;
      var enableSitesControl = true;
      var provisionableStudies = new Array();
      determineProvisionableStudies(role).each(function(study) {
          provisionableStudies.push(study.identifier)
      });
      var mem = user.memberships[role.key]
      if (mem != null) {
        // Disable role membership control when the user we are provisioning is a
        // member of sites and/or studies that are not in the list of provisionable studies.
        if (mem['sites'] != null && mem['studies'] != null) {
          if (!(isSubsetOfProvision(provisionableSites, mem['sites'])
              && isSubsetOfProvision(provisionableStudies, mem['studies']))) {
            enableRoleControl = false;
          }
        } else if (mem['studies'] != null) {
          if (!isSubsetOfProvision(provisionableStudies, mem['studies'])) {
            enableRoleControl = false;
          }
        } else if (mem['sites'] != null) {
          if (!isSubsetOfProvision(provisionableSites, mem['sites'])) {
            enableRoleControl = false;
          }
        }

        // Disable sites membership control when the user we are provisioning is a
        // member of all-sites and the all-sites membership is not in the list of provisionable sites.
        if (!_.isEmpty(provisionableSites) && !_.isEmpty(mem['sites'])) {
          if (!_.include(provisionableSites,'__ALL__') && _.include(mem['sites'],'__ALL__')) {
            enableSitesControl = false;
          }
        }
      }

    switch(controlKey) {
      case 'role-control': return enableRoleControl;
      case 'sites-control': return enableSitesControl;
      default: return null;
    }
  }

  function isSubsetOfProvision(provisionableList, membershipList) {
    if(!_.isEmpty(provisionableList) && !_.isEmpty(membershipList)) {
      return _.all(membershipList, function(ele){
        return _.include(provisionableList,ele)
      })
    }
  }

  function updateGroupMembership(evt) {
    var r = evt.target.value;
    if ($(evt.target).attr('checked')) {
      user.add(r);
    } else {
      user.remove(r);
    }
  }

  function registerMultipleGroupControl(pane, roles) {
    var state = determineTristateCheckboxState(roles);

    var input = $(pane).find('#multiple-group-membership:first');

    $(input).tristate({initialState: state});

    updateIntermediateStateLabel(state, pane, '#partial-multiple-group-membership-info', roles);

    $(input).bind('tristate-state-change', _(updateMultipleGroupMemberships).bind(this, mapRoleKeys(roles)));
    $(input).bind('tristate-state-change', _(function (pane, roles, evt) {
      var state = $(evt.target).attr('state');
      updateIntermediateStateLabel(state, pane, '#partial-multiple-group-membership-info', roles);
    }).bind(this, pane, roles));
  }

  function updateMultipleGroupMemberships(roleKeys, evt) {
    console.log("Updating user obj", roleKeys, evt)

    var state = $(evt.target).attr('state');

    _(roleKeys).each(function(k) {
      switch(state) {
      case 'checked':
        user.add(k); break;
      case 'unchecked':
        user.remove(k); break;
      default:
        console.log("State does not exist", state);
      }
    });
  }

  function updateIntermediateStateLabel(state, pane, label, roles, scopeType, scopeValue) {
    var label = $(pane).find(label + ':first');

    if (state == 'intermediate') {
      var roleKeys = mapRoleKeys(roles);
      var scope = buildScopeObject(scopeType, scopeValue);
      var matchingRoleKeys = user.matchingMemberships(roleKeys, scope);
      var matchingRoles = _(PROVISIONABLE_ROLES).select(function (role) {return _(matchingRoleKeys).include(role.key)});
      var nonMatchingRoles = _(roles).reject(function (role) {return _(matchingRoleKeys).include(role.key)});
      $(label).html('(Applies to ' +  mapRoleNames(matchingRoles).join(', ') + ', but not ' + mapRoleNames(nonMatchingRoles).join(', ') + ')').show();
    } else {
      $(label).hide().empty();
    }
  }

  function determineTristateCheckboxState(roles, scopeType, scopeValue) {
    var roleKeys = mapRoleKeys(roles);
    var scope = buildScopeObject(scopeType, scopeValue);

    var status = user.membershipsStatus(roleKeys, scope);
    console.log("Tri-state checkbox status", status, scopeType, scopeValue);
    switch(status) {
      case 'FULL':    return 'checked';
      case 'PARTIAL': return 'intermediate';
      case 'NONE':    return 'unchecked';
      default:
        console.log("Memberships status unknown: ", status);
        return 'unchecked';
    }
  }

  function registerScopeControls(pane, role, scopeType, scopeTypePlural) {
    $(pane).find('input.scope-' + scopeType).each(function (i, input) {
      var qMembership = {}; qMembership[scopeType] = $(input).attr(scopeType + '-identifier');
      $(input).attr(
          'checked',
          user.hasMembership(role.key, qMembership));
    }).click(_(updateMembershipScope).bind(this, role.key, scopeType, scopeTypePlural));
  }

  function registerMultipleScopeControls(pane, roles, scopeType, scopeTypePlural) {
    $(pane).find('input.scope-' + scopeType).each(function (i, input) {
      var scopeValue = $(input).attr(scopeType + '-identifier');
      var state = determineTristateCheckboxState(roles, scopeType, scopeValue);
      var label = '#partial-scope-' + scopeType + '-' + escapeIdSpaces(scopeValue) + '-info';
      $(input).tristate({initialState: state});
      updateIntermediateStateLabel(state, pane, label, roles, scopeType, scopeValue);
    }).bind('tristate-state-change', _(function(roles, scopeType, scopeTypePlural, evt) {
      updateMultipleMembershipScope(_(roles).map(function(r){return r.key}), scopeType, scopeTypePlural, evt);
      var scopeValue = $(evt.target).attr(scopeType + '-identifier');
      var state = determineTristateCheckboxState(roles, scopeType, scopeValue);
      var label = '#partial-scope-' + scopeType + '-' + escapeIdSpaces(scopeValue) + '-info';
      updateIntermediateStateLabel(state, pane, label, roles, scopeType, scopeValue);
    }).bind(this, roles, scopeType, scopeTypePlural));
  }

  function buildScopeObject(scopeType, scopeValue) {
    var scope = null;
    if (scopeType) {
      scope = {}; scope[scopeType] = scopeValue;
    }
    return scope;
  }

  function mapRoleKeys(roles) {
    return roles.map(function(r){return r.key});
  }

  function mapRoleNames(roles) {
    return _(roles).map(function(r){return r.name});
  }

  function escapeIdSpaces(id) {
    return id.replace(' ', '--space--');
  }

  function updateMembershipScope(roleKey, scopeType, scopeListName, evt) {
    console.log("Updating user obj", roleKey, scopeType, scopeListName, evt);
    var scope = {}; scope[scopeListName] = [ evt.target.getAttribute(scopeType + '-identifier') ];
    if ($(evt.target).attr('checked')) {
      user.add(roleKey, scope);
    } else {
      user.remove(roleKey, scope);
    }
  }

  function updateMultipleMembershipScope(roleKeys, scopeType, scopeListName, evt) {
    var scope = {}; scope[scopeListName] = [ evt.target.getAttribute(scopeType + '-identifier') ];
    var state = $(evt.target).attr('state')

    console.log("Updating user obj", roleKeys, scopeType, scopeListName, scope, state, evt);

    _(roleKeys).each(function(roleKey) {
      switch(state) {
      case 'checked':
        user.add(roleKey, scope); break;
      case 'unchecked':
        user.remove(roleKey, scope); break;
      default:
        console.log("State does not exist", state);
      }
    });
  }

  function syncRoleTabOnChange(evt, data) {
    if (user.hasMembership(data.role)) {
      $('a#role-' + data.role).addClass('member');
    } else {
      $('a#role-' + data.role).removeClass('member');
    }
  }

  function syncRoleEditorOnChange(evt, data) {
    var role = data.role;
    var editorRole = $('#role-editor').attr('role');
    if (role !== editorRole && editorRole.indexOf(',') !== -1) { return; }
    var input;
    if (data.scopeType) {
      input = $('#role-editor input#scope-' + data.scopeType + '-' + data.scopeIdentifier);
      setTimeout(syncAllVsOne, 0);
    } else {
      input = $('#role-editor input#group-' + data.role);
      if ($(input).length <= 0) {
        input = $('#role-editor input#multiple-group-membership');
      }
    }
    input.attr('checked', data.kind === 'add');
    if (input.attr('state')) {
      input.attr('state', data.kind === 'add' ? 'checked' : 'unchecked');
      $(input).parents('.row').find('.partial-membership').empty();
    }
  }

  function syncAllVsOne() {
    _(['scope-study', 'scope-site']).each(function (scopeClass) {
      var isAll = $('#role-editor input.all.' + scopeClass + ":checked").length > 0;
      if (isAll) {
        var oneSelector = '#role-editor input.one.' + scopeClass;

        var regular = $(oneSelector).not('[state]').
          filter(':checked').click().end()

        var tristate = $(oneSelector + '[state]').
          tristate('state', 'unchecked')

        regular.add(tristate).
          attr("disabled", true).
          closest('div.row').addClass('disabled');
      } else {
        $('#role-editor input.one.' + scopeClass).
          attr("disabled", false).
          closest('div.row').removeClass('disabled');
      }
    });
  }

  function syncUsername() {
    user.username = $('input#username').val();
  }

  function toggleRoleView(evt, action) {
    if(!action) {
      action = $('#show-all-toggle:contains(Show)').length > 0 ? 'hide' : 'show';
    }

    if (action === 'show') {
      $('#show-all-toggle').text('Show Suite Roles');
      $("div.role-tab[role-type='suite']").hide();
    } else {
      $('#show-all-toggle').text('Hide Suite Roles')
      $("div.role-tab[role-type='suite']").show();
    }
    return false;
  }

  return {
    init: function (u) {
      user = u;
      _(user.memberships).each(function (scopes, roleKey) {
        $('#role-' + roleKey).addClass('member');
      }, this);
      var firstRole;
      if ($("div.role-tab[role-type='psc'] a.role.member").length > 0) {
        firstRole = $('a.role.member')[0].id.substring("role-".length);
      } else {
        firstRole = 'study_subject_calendar_manager';
      }
      selectRole(firstRole);
      $('a.role').click(selectRoleTab);
      $(user).bind('membership-change', syncRoleTabOnChange).
        bind('membership-change', syncRoleEditorOnChange);
      $('input#username').keyup(syncUsername);
      syncAllVsOne();
      toggleRoleView(null, 'show');
      $('#show-all-toggle').click(toggleRoleView);
    },

    serializeRoleChanges: function () {
      if (user.username) {
        var changes = {}; changes[user.username] = user.changes;
        return YAHOO.lang.JSON.stringify(changes);
      } else {
        return "{}";
      }
    }
  };
})(jQuery);
<|endoftext|>


<commit_before>'use strict';

angular.module('gpConnect').factory('Appointment', ['$rootScope', '$http', 'FhirEndpointLookup', 'fhirJWTFactory', 'gpcResource', function ($rootScope, $http, FhirEndpointLookup, fhirJWTFactory, gpcResource) {

    var findAllAppointments = function (patientNHSNumber, patientId, odsCode) {
        var odsCode = (typeof odsCode !== 'undefined') ? odsCode : $rootScope.patientOdsCode;

        return FhirEndpointLookup.getEndpoint(odsCode, "urn:nhs:names:services:gpconnect:fhir:rest:search:patient_appointments-1").then(function(response) {
            var endpointLookupResult = response;

            return $http.get(
                    endpointLookupResult.restUrlPrefix + '/Patient/' + patientId + '/Appointment',
                    {
                        headers: {
                            'Ssp-From': endpointLookupResult.fromASID,
                            'Ssp-To': endpointLookupResult.toASID,
                            'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:search:patient_appointments-1",
                            'Ssp-TraceID': fhirJWTFactory.guid(),
                            'Authorization': "Bearer " + fhirJWTFactory.getJWT("patient", "read", patientNHSNumber),
                            'Accept': "application/fhir+json"
                        }
                    }
            );
        });
    };

    var searchForFreeSlots = function (practiceOdsCode, practiceOrgType, startDateTime, endDateTime) {
           return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:search:slot-1").then(function(response) {
                var endpointLookupResult = response;

                var requiredParams = 'start=ge' +startDateTime+ '&end=le' +endDateTime+ '&fb-type=free&_include=Slot:schedule';
                var optionalParams = '_include:recurse=Schedule:actor:Practitioner&_include:recurse=Schedule:actor:Location';
                var searchFilterOrgType = 'searchFilter=' + gpcResource.getConst("VS_ORG_TYPE") + '%7C' + practiceOrgType;
                var searchFilterOdsCode = 'searchFilter=' + gpcResource.getConst("ID_ODS_ORGANIZATION_CODE") + '%7C' + practiceOdsCode;

                return $http.get(
                        endpointLookupResult.restUrlPrefix + '/Slot?' + requiredParams + '&' + optionalParams + '&' + searchFilterOrgType + '&' + searchFilterOdsCode,
                        {
                            headers: {
                                'Ssp-From': endpointLookupResult.fromASID,
                                'Ssp-To': endpointLookupResult.toASID,
                                'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:search:slot-1",
                                'Ssp-TraceID': fhirJWTFactory.guid(),
                                'Authorization': "Bearer " + fhirJWTFactory.getJWT("organization", "read", practiceOdsCode),
                                'Accept': "application/fhir+json",
                                'Content-Type': "application/fhir+json"
                            }
                        }
                );
            });

    };

    var findResourceByReference = function (practiceOdsCode, patientId, resourceReference) {
        if (resourceReference.indexOf("Location") > -1) {
            return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:read:location-1").then(function(response) {
                var endpointLookupResult = response;

                return $http.get(
                        endpointLookupResult.restUrlPrefix + '/' + resourceReference,
                        {
                            headers: {
                                'Ssp-From': endpointLookupResult.fromASID,
                                'Ssp-To': endpointLookupResult.toASID,
                                'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:read:location-1",
                                'Ssp-TraceID': fhirJWTFactory.guid(),
                                'Authorization': "Bearer " + fhirJWTFactory.getJWT("organization", "read", practiceOdsCode),
                                'Accept': "application/fhir+json"
                            }
                        }
                );
            });
        } else if (resourceReference.indexOf("Practitioner") > -1) {
            return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:read:practitioner-1").then(function(response) {
                var endpointLookupResult = response;

                return $http.get(
                        endpointLookupResult.restUrlPrefix + '/' + resourceReference,
                        {
                            headers: {
                                'Ssp-From': endpointLookupResult.fromASID,
                                'Ssp-To': endpointLookupResult.toASID,
                                'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:read:practitioner-1",
                                'Ssp-TraceID': fhirJWTFactory.guid(),
                                'Authorization': "Bearer " + fhirJWTFactory.getJWT("organization", "read", practiceOdsCode),
                                'Accept': "application/fhir+json"
                            }
                        }
                );
            });
        }
    };

    var create = function (practiceOdsCode, patientId, appointment) {
        return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:create:appointment-1").then(function(response) {
            var endpointLookupResult = response;

            return $http.post(
                    endpointLookupResult.restUrlPrefix + '/Appointment',
                    appointment,
                    {
                        headers: {
                            'Ssp-From': endpointLookupResult.fromASID,
                            'Ssp-To': endpointLookupResult.toASID,
                            'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:create:appointment-1",
                            'Authorization': "Bearer " + fhirJWTFactory.getJWT("patient", "write", patientId),
                            'Ssp-TraceID': fhirJWTFactory.guid(),
                            'Prefer': "return=representation",
                            'Accept': "application/fhir+json",
                            'Content-Type': "application/fhir+json"
                        }
                    }
            );
        });
    };

    var save = function (practiceOdsCode, patientNHSNumber, appointmentId, appointment) {
        return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:read:appointment-1").then(function(response) {
            var endpointLookupResult = response;

            return $http.put(
                    endpointLookupResult.restUrlPrefix + '/Appointment/' + appointmentId,
                    appointment,
                    {
                        headers: {
                            'Ssp-From': endpointLookupResult.fromASID,
                            'Ssp-To': endpointLookupResult.toASID,
                            'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:update:appointment-1",
                            'Prefer': "return=representation",
                            'Ssp-TraceID': fhirJWTFactory.guid(),
                            'Authorization': "Bearer " + fhirJWTFactory.getJWT("patient", "write", patientNHSNumber),
                            'Accept': "application/fhir+json",
                            'Content-Type': "application/fhir+json"
                        }
                    }
            );
        });
    };

	var cancel = function (practiceOdsCode, patientNHSNumber, appointmentId, appointment) {
        return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:read:appointment-1").then(function(response) {
            var endpointLookupResult = response;

            return $http.put(
                    endpointLookupResult.restUrlPrefix + '/Appointment/' + appointmentId,
                    appointment,
                    {
                        headers: {
                            'Ssp-From': endpointLookupResult.fromASID,
                            'Ssp-To': endpointLookupResult.toASID,
                            'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:cancel:appointment-1",
                            'Prefer': "return=representation",
                            'Ssp-TraceID': fhirJWTFactory.guid(),
                            'Authorization': "Bearer " + fhirJWTFactory.getJWT("patient", "write", patientNHSNumber),
                            'Accept': "application/fhir+json",
                            'Content-Type': "application/fhir+json"
                        }
                    }
            );
        });
    };

    return {
        findAllAppointments: findAllAppointments,
        searchForFreeSlots: searchForFreeSlots,
        findResourceByReference: findResourceByReference,
        create: create,
        save: save,
		cancel: cancel
    };
}]);<commit_msg>Change fb-type to status in front end<commit_after>'use strict';

angular.module('gpConnect').factory('Appointment', ['$rootScope', '$http', 'FhirEndpointLookup', 'fhirJWTFactory', 'gpcResource', function ($rootScope, $http, FhirEndpointLookup, fhirJWTFactory, gpcResource) {

    var findAllAppointments = function (patientNHSNumber, patientId, odsCode) {
        var odsCode = (typeof odsCode !== 'undefined') ? odsCode : $rootScope.patientOdsCode;

        return FhirEndpointLookup.getEndpoint(odsCode, "urn:nhs:names:services:gpconnect:fhir:rest:search:patient_appointments-1").then(function(response) {
            var endpointLookupResult = response;

            return $http.get(
                    endpointLookupResult.restUrlPrefix + '/Patient/' + patientId + '/Appointment',
                    {
                        headers: {
                            'Ssp-From': endpointLookupResult.fromASID,
                            'Ssp-To': endpointLookupResult.toASID,
                            'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:search:patient_appointments-1",
                            'Ssp-TraceID': fhirJWTFactory.guid(),
                            'Authorization': "Bearer " + fhirJWTFactory.getJWT("patient", "read", patientNHSNumber),
                            'Accept': "application/fhir+json"
                        }
                    }
            );
        });
    };

    var searchForFreeSlots = function (practiceOdsCode, practiceOrgType, startDateTime, endDateTime) {
           return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:search:slot-1").then(function(response) {
                var endpointLookupResult = response;

                var requiredParams = 'start=ge' +startDateTime+ '&end=le' +endDateTime+ '&status=free&_include=Slot:schedule';
                var optionalParams = '_include:recurse=Schedule:actor:Practitioner&_include:recurse=Schedule:actor:Location';
                var searchFilterOrgType = 'searchFilter=' + gpcResource.getConst("VS_ORG_TYPE") + '%7C' + practiceOrgType;
                var searchFilterOdsCode = 'searchFilter=' + gpcResource.getConst("ID_ODS_ORGANIZATION_CODE") + '%7C' + practiceOdsCode;

                return $http.get(
                        endpointLookupResult.restUrlPrefix + '/Slot?' + requiredParams + '&' + optionalParams + '&' + searchFilterOrgType + '&' + searchFilterOdsCode,
                        {
                            headers: {
                                'Ssp-From': endpointLookupResult.fromASID,
                                'Ssp-To': endpointLookupResult.toASID,
                                'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:search:slot-1",
                                'Ssp-TraceID': fhirJWTFactory.guid(),
                                'Authorization': "Bearer " + fhirJWTFactory.getJWT("organization", "read", practiceOdsCode),
                                'Accept': "application/fhir+json",
                                'Content-Type': "application/fhir+json"
                            }
                        }
                );
            });

    };

    var findResourceByReference = function (practiceOdsCode, patientId, resourceReference) {
        if (resourceReference.indexOf("Location") > -1) {
            return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:read:location-1").then(function(response) {
                var endpointLookupResult = response;

                return $http.get(
                        endpointLookupResult.restUrlPrefix + '/' + resourceReference,
                        {
                            headers: {
                                'Ssp-From': endpointLookupResult.fromASID,
                                'Ssp-To': endpointLookupResult.toASID,
                                'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:read:location-1",
                                'Ssp-TraceID': fhirJWTFactory.guid(),
                                'Authorization': "Bearer " + fhirJWTFactory.getJWT("organization", "read", practiceOdsCode),
                                'Accept': "application/fhir+json"
                            }
                        }
                );
            });
        } else if (resourceReference.indexOf("Practitioner") > -1) {
            return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:read:practitioner-1").then(function(response) {
                var endpointLookupResult = response;

                return $http.get(
                        endpointLookupResult.restUrlPrefix + '/' + resourceReference,
                        {
                            headers: {
                                'Ssp-From': endpointLookupResult.fromASID,
                                'Ssp-To': endpointLookupResult.toASID,
                                'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:read:practitioner-1",
                                'Ssp-TraceID': fhirJWTFactory.guid(),
                                'Authorization': "Bearer " + fhirJWTFactory.getJWT("organization", "read", practiceOdsCode),
                                'Accept': "application/fhir+json"
                            }
                        }
                );
            });
        }
    };

    var create = function (practiceOdsCode, patientId, appointment) {
        return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:create:appointment-1").then(function(response) {
            var endpointLookupResult = response;

            return $http.post(
                    endpointLookupResult.restUrlPrefix + '/Appointment',
                    appointment,
                    {
                        headers: {
                            'Ssp-From': endpointLookupResult.fromASID,
                            'Ssp-To': endpointLookupResult.toASID,
                            'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:create:appointment-1",
                            'Authorization': "Bearer " + fhirJWTFactory.getJWT("patient", "write", patientId),
                            'Ssp-TraceID': fhirJWTFactory.guid(),
                            'Prefer': "return=representation",
                            'Accept': "application/fhir+json",
                            'Content-Type': "application/fhir+json"
                        }
                    }
            );
        });
    };

    var save = function (practiceOdsCode, patientNHSNumber, appointmentId, appointment) {
        return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:read:appointment-1").then(function(response) {
            var endpointLookupResult = response;

            return $http.put(
                    endpointLookupResult.restUrlPrefix + '/Appointment/' + appointmentId,
                    appointment,
                    {
                        headers: {
                            'Ssp-From': endpointLookupResult.fromASID,
                            'Ssp-To': endpointLookupResult.toASID,
                            'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:update:appointment-1",
                            'Prefer': "return=representation",
                            'Ssp-TraceID': fhirJWTFactory.guid(),
                            'Authorization': "Bearer " + fhirJWTFactory.getJWT("patient", "write", patientNHSNumber),
                            'Accept': "application/fhir+json",
                            'Content-Type': "application/fhir+json"
                        }
                    }
            );
        });
    };

	var cancel = function (practiceOdsCode, patientNHSNumber, appointmentId, appointment) {
        return FhirEndpointLookup.getEndpoint(practiceOdsCode, "urn:nhs:names:services:gpconnect:fhir:rest:read:appointment-1").then(function(response) {
            var endpointLookupResult = response;

            return $http.put(
                    endpointLookupResult.restUrlPrefix + '/Appointment/' + appointmentId,
                    appointment,
                    {
                        headers: {
                            'Ssp-From': endpointLookupResult.fromASID,
                            'Ssp-To': endpointLookupResult.toASID,
                            'Ssp-InteractionID': "urn:nhs:names:services:gpconnect:fhir:rest:cancel:appointment-1",
                            'Prefer': "return=representation",
                            'Ssp-TraceID': fhirJWTFactory.guid(),
                            'Authorization': "Bearer " + fhirJWTFactory.getJWT("patient", "write", patientNHSNumber),
                            'Accept': "application/fhir+json",
                            'Content-Type': "application/fhir+json"
                        }
                    }
            );
        });
    };

    return {
        findAllAppointments: findAllAppointments,
        searchForFreeSlots: searchForFreeSlots,
        findResourceByReference: findResourceByReference,
        create: create,
        save: save,
		cancel: cancel
    };
}]);<|endoftext|>


<commit_before>/*
 MIT License http://www.opensource.org/licenses/mit-license.php
 Author Tobias Koppers @sokra
 */
"use strict";

const asyncLib = require("neo-async");
const {
	Tapable,
	AsyncSeriesWaterfallHook,
	SyncWaterfallHook,
	SyncBailHook,
	SyncHook,
	HookMap
} = require("tapable");
const NormalModule = require("./NormalModule");
const RawModule = require("./RawModule");
const RuleSet = require("./RuleSet");
const cachedMerge = require("./util/cachedMerge");

const EMPTY_RESOLVE_OPTIONS = {};

const loaderToIdent = data => {
	if (!data.options) return data.loader;
	if (typeof data.options === "string") return data.loader + "?" + data.options;
	if (typeof data.options !== "object")
		throw new Error("loader options must be string or object");
	if (data.ident) return data.loader + "??" + data.ident;
	return data.loader + "?" + JSON.stringify(data.options);
};

const identToLoaderRequest = resultString => {
	const idx = resultString.indexOf("?");
	if (idx >= 0) {
		const loader = resultString.substr(0, idx);
		const options = resultString.substr(idx + 1);
		return {
			loader,
			options
		};
	} else {
		return {
			loader: resultString,
			options: undefined
		};
	}
};

const dependencyCache = new WeakMap();

class NormalModuleFactory extends Tapable {
	constructor(context, resolverFactory, options) {
		super();
		this.hooks = {
			resolver: new SyncWaterfallHook(["resolver"]),
			factory: new SyncWaterfallHook(["factory"]),
			beforeResolve: new AsyncSeriesWaterfallHook(["data"]),
			afterResolve: new AsyncSeriesWaterfallHook(["data"]),
			createModule: new SyncBailHook(["data"]),
			module: new SyncWaterfallHook(["module", "data"]),
			createParser: new HookMap(() => new SyncBailHook(["parserOptions"])),
			parser: new HookMap(() => new SyncHook(["parser", "parserOptions"])),
			createGenerator: new HookMap(
				() => new SyncBailHook(["generatorOptions"])
			),
			generator: new HookMap(
				() => new SyncHook(["generator", "generatorOptions"])
			)
		};
		this._pluginCompat.tap("NormalModuleFactory", options => {
			switch (options.name) {
				case "before-resolve":
				case "after-resolve":
					options.async = true;
					break;
				case "parser":
					this.hooks.parser
						.for("javascript/auto")
						.tap(options.fn.name || "unnamed compat plugin", options.fn);
					return true;
			}
			let match;
			match = /^parser (.+)$/.exec(options.name);
			if (match) {
				this.hooks.parser
					.for(match[1])
					.tap(
						options.fn.name || "unnamed compat plugin",
						options.fn.bind(this)
					);
				return true;
			}
			match = /^create-parser (.+)$/.exec(options.name);
			if (match) {
				this.hooks.createParser
					.for(match[1])
					.tap(
						options.fn.name || "unnamed compat plugin",
						options.fn.bind(this)
					);
				return true;
			}
		});
		this.resolverFactory = resolverFactory;
		this.ruleSet = new RuleSet(options.defaultRules.concat(options.rules));
		this.cachePredicate =
			typeof options.unsafeCache === "function"
				? options.unsafeCache
				: Boolean.bind(null, options.unsafeCache);
		this.context = context || "";
		this.parserCache = Object.create(null);
		this.generatorCache = Object.create(null);
		this.hooks.factory.tap("NormalModuleFactory", () => (result, callback) => {
			let resolver = this.hooks.resolver.call(null);

			// Ignored
			if (!resolver) return callback();

			resolver(result, (err, data) => {
				if (err) return callback(err);

				// Ignored
				if (!data) return callback();

				// direct module
				if (typeof data.source === "function") return callback(null, data);

				this.hooks.afterResolve.callAsync(data, (err, result) => {
					if (err) return callback(err);

					// Ignored
					if (!result) return callback();

					let createdModule = this.hooks.createModule.call(result);
					if (!createdModule) {
						if (!result.request) {
							return callback(new Error("Empty dependency (no request)"));
						}

						createdModule = new NormalModule(result);
					}

					createdModule = this.hooks.module.call(createdModule, result);

					return callback(null, createdModule);
				});
			});
		});
		this.hooks.resolver.tap("NormalModuleFactory", () => (data, callback) => {
			const contextInfo = data.contextInfo;
			const context = data.context;
			const request = data.request;

			const noPreAutoLoaders = request.startsWith("-!");
			const noAutoLoaders = noPreAutoLoaders || request.startsWith("!");
			const noPrePostAutoLoaders = request.startsWith("!!");
			let elements = request
				.replace(/^-?!+/, "")
				.replace(/!!+/g, "!")
				.split("!");
			let resource = elements.pop();
			elements = elements.map(identToLoaderRequest);

			const loaderResolver = this.getResolver("loader");
			const normalResolver = this.getResolver("normal", data.resolveOptions);

			asyncLib.parallel(
				[
					callback =>
						this.resolveRequestArray(
							contextInfo,
							context,
							elements,
							loaderResolver,
							callback
						),
					callback => {
						if (resource === "" || resource[0] === "?") {
							return callback(null, {
								resource
							});
						}

						normalResolver.resolve(
							contextInfo,
							context,
							resource,
							{},
							(err, resource, resourceResolveData) => {
								if (err) return callback(err);
								callback(null, {
									resourceResolveData,
									resource
								});
							}
						);
					}
				],
				(err, results) => {
					if (err) return callback(err);
					let loaders = results[0];
					const resourceResolveData = results[1].resourceResolveData;
					resource = results[1].resource;

					// translate option idents
					try {
						for (const item of loaders) {
							if (typeof item.options === "string" && item.options[0] === "?") {
								const ident = item.options.substr(1);
								item.options = this.ruleSet.findOptionsByIdent(ident);
								item.ident = ident;
							}
						}
					} catch (e) {
						return callback(e);
					}

					if (resource === false) {
						// ignored
						return callback(
							null,
							new RawModule(
								"/* (ignored) */",
								`ignored ${context} ${request}`,
								`${request} (ignored)`
							)
						);
					}

					const userRequest = loaders
						.map(loaderToIdent)
						.concat([resource])
						.join("!");

					let resourcePath = resource;
					let resourceQuery = "";
					const queryIndex = resourcePath.indexOf("?");
					if (queryIndex >= 0) {
						resourceQuery = resourcePath.substr(queryIndex);
						resourcePath = resourcePath.substr(0, queryIndex);
					}

					const result = this.ruleSet.exec({
						resource: resourcePath,
						resourceQuery,
						issuer: contextInfo.issuer,
						compiler: contextInfo.compiler
					});
					const settings = {};
					const useLoadersPost = [];
					const useLoaders = [];
					const useLoadersPre = [];
					for (const r of result) {
						if (r.type === "use") {
							if (r.enforce === "post" && !noPrePostAutoLoaders)
								useLoadersPost.push(r.value);
							else if (
								r.enforce === "pre" &&
								!noPreAutoLoaders &&
								!noPrePostAutoLoaders
							)
								useLoadersPre.push(r.value);
							else if (!r.enforce && !noAutoLoaders && !noPrePostAutoLoaders)
								useLoaders.push(r.value);
						} else if (
							typeof r.value === "object" &&
							r.value !== null &&
							typeof settings[r.type] === "object" &&
							settings[r.type] !== null
						) {
							settings[r.type] = cachedMerge(settings[r.type], r.value);
						} else {
							settings[r.type] = r.value;
						}
					}
					asyncLib.parallel(
						[
							this.resolveRequestArray.bind(
								this,
								contextInfo,
								this.context,
								useLoadersPost,
								loaderResolver
							),
							this.resolveRequestArray.bind(
								this,
								contextInfo,
								this.context,
								useLoaders,
								loaderResolver
							),
							this.resolveRequestArray.bind(
								this,
								contextInfo,
								this.context,
								useLoadersPre,
								loaderResolver
							)
						],
						(err, results) => {
							if (err) return callback(err);
							loaders = results[0].concat(loaders, results[1], results[2]);
							process.nextTick(() => {
								const type = settings.type;
								const resolveOptions = settings.resolve;
								callback(null, {
									context: context,
									request: loaders
										.map(loaderToIdent)
										.concat([resource])
										.join("!"),
									dependencies: data.dependencies,
									userRequest,
									rawRequest: request,
									loaders,
									resource,
									resourceResolveData,
									settings,
									type,
									parser: this.getParser(type, settings.parser),
									generator: this.getGenerator(type, settings.generator),
									resolveOptions
								});
							});
						}
					);
				}
			);
		});
	}

	create(data, callback) {
		const dependencies = data.dependencies;
		const cacheEntry = dependencyCache.get(dependencies[0]);
		if (cacheEntry) return callback(null, cacheEntry);
		const context = data.context || this.context;
		const resolveOptions = data.resolveOptions || EMPTY_RESOLVE_OPTIONS;
		const request = dependencies[0].request;
		const contextInfo = data.contextInfo || {};
		this.hooks.beforeResolve.callAsync(
			{
				contextInfo,
				resolveOptions,
				context,
				request,
				dependencies
			},
			(err, result) => {
				if (err) return callback(err);

				// Ignored
				if (!result) return callback();

				const factory = this.hooks.factory.call(null);

				// Ignored
				if (!factory) return callback();

				factory(result, (err, module) => {
					if (err) return callback(err);

					if (module && this.cachePredicate(module)) {
						for (const d of dependencies) {
							dependencyCache.set(d, module);
						}
					}

					callback(null, module);
				});
			}
		);
	}

	resolveRequestArray(contextInfo, context, array, resolver, callback) {
		if (array.length === 0) return callback(null, []);
		asyncLib.map(
			array,
			(item, callback) => {
				resolver.resolve(
					contextInfo,
					context,
					item.loader,
					{},
					(err, result) => {
						if (
							err &&
							/^[^/]*$/.test(item.loader) &&
							!/-loader$/.test(item.loader)
						) {
							return resolver.resolve(
								contextInfo,
								context,
								item.loader + "-loader",
								{},
								err2 => {
									if (!err2) {
										err.message =
											err.message +
											"\n" +
											"BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.\n" +
											`                 You need to specify '${
												item.loader
											}-loader' instead of '${item.loader}',\n` +
											"                 see https://webpack.js.org/guides/migrating/#automatic-loader-module-name-extension-removed";
									}
									callback(err);
								}
							);
						}
						if (err) return callback(err);

						const optionsOnly = item.options
							? {
									options: item.options
							  }
							: undefined;
						return callback(
							null,
							Object.assign({}, item, identToLoaderRequest(result), optionsOnly)
						);
					}
				);
			},
			callback
		);
	}

	getParser(type, parserOptions) {
		let ident = type;
		if (parserOptions) {
			if (parserOptions.ident) ident = `${type}|${parserOptions.ident}`;
			else ident = JSON.stringify([type, parserOptions]);
		}
		if (ident in this.parserCache) {
			return this.parserCache[ident];
		}
		return (this.parserCache[ident] = this.createParser(type, parserOptions));
	}

	createParser(type, parserOptions = {}) {
		const parser = this.hooks.createParser.for(type).call(parserOptions);
		if (!parser) {
			throw new Error(`No parser registered for ${type}`);
		}
		this.hooks.parser.for(type).call(parser, parserOptions);
		return parser;
	}

	getGenerator(type, generatorOptions) {
		let ident = type;
		if (generatorOptions) {
			if (generatorOptions.ident) ident = `${type}|${generatorOptions.ident}`;
			else ident = JSON.stringify([type, generatorOptions]);
		}
		if (ident in this.generatorCache) {
			return this.generatorCache[ident];
		}
		return (this.generatorCache[ident] = this.createGenerator(
			type,
			generatorOptions
		));
	}

	createGenerator(type, generatorOptions = {}) {
		const generator = this.hooks.createGenerator
			.for(type)
			.call(generatorOptions);
		if (!generator) {
			throw new Error(`No generator registered for ${type}`);
		}
		this.hooks.generator.for(type).call(generator, generatorOptions);
		return generator;
	}

	getResolver(type, resolveOptions) {
		return this.resolverFactory.get(
			type,
			resolveOptions || EMPTY_RESOLVE_OPTIONS
		);
	}
}

module.exports = NormalModuleFactory;
<commit_msg>Fix link<commit_after>/*
 MIT License http://www.opensource.org/licenses/mit-license.php
 Author Tobias Koppers @sokra
 */
"use strict";

const asyncLib = require("neo-async");
const {
	Tapable,
	AsyncSeriesWaterfallHook,
	SyncWaterfallHook,
	SyncBailHook,
	SyncHook,
	HookMap
} = require("tapable");
const NormalModule = require("./NormalModule");
const RawModule = require("./RawModule");
const RuleSet = require("./RuleSet");
const cachedMerge = require("./util/cachedMerge");

const EMPTY_RESOLVE_OPTIONS = {};

const loaderToIdent = data => {
	if (!data.options) return data.loader;
	if (typeof data.options === "string") return data.loader + "?" + data.options;
	if (typeof data.options !== "object")
		throw new Error("loader options must be string or object");
	if (data.ident) return data.loader + "??" + data.ident;
	return data.loader + "?" + JSON.stringify(data.options);
};

const identToLoaderRequest = resultString => {
	const idx = resultString.indexOf("?");
	if (idx >= 0) {
		const loader = resultString.substr(0, idx);
		const options = resultString.substr(idx + 1);
		return {
			loader,
			options
		};
	} else {
		return {
			loader: resultString,
			options: undefined
		};
	}
};

const dependencyCache = new WeakMap();

class NormalModuleFactory extends Tapable {
	constructor(context, resolverFactory, options) {
		super();
		this.hooks = {
			resolver: new SyncWaterfallHook(["resolver"]),
			factory: new SyncWaterfallHook(["factory"]),
			beforeResolve: new AsyncSeriesWaterfallHook(["data"]),
			afterResolve: new AsyncSeriesWaterfallHook(["data"]),
			createModule: new SyncBailHook(["data"]),
			module: new SyncWaterfallHook(["module", "data"]),
			createParser: new HookMap(() => new SyncBailHook(["parserOptions"])),
			parser: new HookMap(() => new SyncHook(["parser", "parserOptions"])),
			createGenerator: new HookMap(
				() => new SyncBailHook(["generatorOptions"])
			),
			generator: new HookMap(
				() => new SyncHook(["generator", "generatorOptions"])
			)
		};
		this._pluginCompat.tap("NormalModuleFactory", options => {
			switch (options.name) {
				case "before-resolve":
				case "after-resolve":
					options.async = true;
					break;
				case "parser":
					this.hooks.parser
						.for("javascript/auto")
						.tap(options.fn.name || "unnamed compat plugin", options.fn);
					return true;
			}
			let match;
			match = /^parser (.+)$/.exec(options.name);
			if (match) {
				this.hooks.parser
					.for(match[1])
					.tap(
						options.fn.name || "unnamed compat plugin",
						options.fn.bind(this)
					);
				return true;
			}
			match = /^create-parser (.+)$/.exec(options.name);
			if (match) {
				this.hooks.createParser
					.for(match[1])
					.tap(
						options.fn.name || "unnamed compat plugin",
						options.fn.bind(this)
					);
				return true;
			}
		});
		this.resolverFactory = resolverFactory;
		this.ruleSet = new RuleSet(options.defaultRules.concat(options.rules));
		this.cachePredicate =
			typeof options.unsafeCache === "function"
				? options.unsafeCache
				: Boolean.bind(null, options.unsafeCache);
		this.context = context || "";
		this.parserCache = Object.create(null);
		this.generatorCache = Object.create(null);
		this.hooks.factory.tap("NormalModuleFactory", () => (result, callback) => {
			let resolver = this.hooks.resolver.call(null);

			// Ignored
			if (!resolver) return callback();

			resolver(result, (err, data) => {
				if (err) return callback(err);

				// Ignored
				if (!data) return callback();

				// direct module
				if (typeof data.source === "function") return callback(null, data);

				this.hooks.afterResolve.callAsync(data, (err, result) => {
					if (err) return callback(err);

					// Ignored
					if (!result) return callback();

					let createdModule = this.hooks.createModule.call(result);
					if (!createdModule) {
						if (!result.request) {
							return callback(new Error("Empty dependency (no request)"));
						}

						createdModule = new NormalModule(result);
					}

					createdModule = this.hooks.module.call(createdModule, result);

					return callback(null, createdModule);
				});
			});
		});
		this.hooks.resolver.tap("NormalModuleFactory", () => (data, callback) => {
			const contextInfo = data.contextInfo;
			const context = data.context;
			const request = data.request;

			const noPreAutoLoaders = request.startsWith("-!");
			const noAutoLoaders = noPreAutoLoaders || request.startsWith("!");
			const noPrePostAutoLoaders = request.startsWith("!!");
			let elements = request
				.replace(/^-?!+/, "")
				.replace(/!!+/g, "!")
				.split("!");
			let resource = elements.pop();
			elements = elements.map(identToLoaderRequest);

			const loaderResolver = this.getResolver("loader");
			const normalResolver = this.getResolver("normal", data.resolveOptions);

			asyncLib.parallel(
				[
					callback =>
						this.resolveRequestArray(
							contextInfo,
							context,
							elements,
							loaderResolver,
							callback
						),
					callback => {
						if (resource === "" || resource[0] === "?") {
							return callback(null, {
								resource
							});
						}

						normalResolver.resolve(
							contextInfo,
							context,
							resource,
							{},
							(err, resource, resourceResolveData) => {
								if (err) return callback(err);
								callback(null, {
									resourceResolveData,
									resource
								});
							}
						);
					}
				],
				(err, results) => {
					if (err) return callback(err);
					let loaders = results[0];
					const resourceResolveData = results[1].resourceResolveData;
					resource = results[1].resource;

					// translate option idents
					try {
						for (const item of loaders) {
							if (typeof item.options === "string" && item.options[0] === "?") {
								const ident = item.options.substr(1);
								item.options = this.ruleSet.findOptionsByIdent(ident);
								item.ident = ident;
							}
						}
					} catch (e) {
						return callback(e);
					}

					if (resource === false) {
						// ignored
						return callback(
							null,
							new RawModule(
								"/* (ignored) */",
								`ignored ${context} ${request}`,
								`${request} (ignored)`
							)
						);
					}

					const userRequest = loaders
						.map(loaderToIdent)
						.concat([resource])
						.join("!");

					let resourcePath = resource;
					let resourceQuery = "";
					const queryIndex = resourcePath.indexOf("?");
					if (queryIndex >= 0) {
						resourceQuery = resourcePath.substr(queryIndex);
						resourcePath = resourcePath.substr(0, queryIndex);
					}

					const result = this.ruleSet.exec({
						resource: resourcePath,
						resourceQuery,
						issuer: contextInfo.issuer,
						compiler: contextInfo.compiler
					});
					const settings = {};
					const useLoadersPost = [];
					const useLoaders = [];
					const useLoadersPre = [];
					for (const r of result) {
						if (r.type === "use") {
							if (r.enforce === "post" && !noPrePostAutoLoaders)
								useLoadersPost.push(r.value);
							else if (
								r.enforce === "pre" &&
								!noPreAutoLoaders &&
								!noPrePostAutoLoaders
							)
								useLoadersPre.push(r.value);
							else if (!r.enforce && !noAutoLoaders && !noPrePostAutoLoaders)
								useLoaders.push(r.value);
						} else if (
							typeof r.value === "object" &&
							r.value !== null &&
							typeof settings[r.type] === "object" &&
							settings[r.type] !== null
						) {
							settings[r.type] = cachedMerge(settings[r.type], r.value);
						} else {
							settings[r.type] = r.value;
						}
					}
					asyncLib.parallel(
						[
							this.resolveRequestArray.bind(
								this,
								contextInfo,
								this.context,
								useLoadersPost,
								loaderResolver
							),
							this.resolveRequestArray.bind(
								this,
								contextInfo,
								this.context,
								useLoaders,
								loaderResolver
							),
							this.resolveRequestArray.bind(
								this,
								contextInfo,
								this.context,
								useLoadersPre,
								loaderResolver
							)
						],
						(err, results) => {
							if (err) return callback(err);
							loaders = results[0].concat(loaders, results[1], results[2]);
							process.nextTick(() => {
								const type = settings.type;
								const resolveOptions = settings.resolve;
								callback(null, {
									context: context,
									request: loaders
										.map(loaderToIdent)
										.concat([resource])
										.join("!"),
									dependencies: data.dependencies,
									userRequest,
									rawRequest: request,
									loaders,
									resource,
									resourceResolveData,
									settings,
									type,
									parser: this.getParser(type, settings.parser),
									generator: this.getGenerator(type, settings.generator),
									resolveOptions
								});
							});
						}
					);
				}
			);
		});
	}

	create(data, callback) {
		const dependencies = data.dependencies;
		const cacheEntry = dependencyCache.get(dependencies[0]);
		if (cacheEntry) return callback(null, cacheEntry);
		const context = data.context || this.context;
		const resolveOptions = data.resolveOptions || EMPTY_RESOLVE_OPTIONS;
		const request = dependencies[0].request;
		const contextInfo = data.contextInfo || {};
		this.hooks.beforeResolve.callAsync(
			{
				contextInfo,
				resolveOptions,
				context,
				request,
				dependencies
			},
			(err, result) => {
				if (err) return callback(err);

				// Ignored
				if (!result) return callback();

				const factory = this.hooks.factory.call(null);

				// Ignored
				if (!factory) return callback();

				factory(result, (err, module) => {
					if (err) return callback(err);

					if (module && this.cachePredicate(module)) {
						for (const d of dependencies) {
							dependencyCache.set(d, module);
						}
					}

					callback(null, module);
				});
			}
		);
	}

	resolveRequestArray(contextInfo, context, array, resolver, callback) {
		if (array.length === 0) return callback(null, []);
		asyncLib.map(
			array,
			(item, callback) => {
				resolver.resolve(
					contextInfo,
					context,
					item.loader,
					{},
					(err, result) => {
						if (
							err &&
							/^[^/]*$/.test(item.loader) &&
							!/-loader$/.test(item.loader)
						) {
							return resolver.resolve(
								contextInfo,
								context,
								item.loader + "-loader",
								{},
								err2 => {
									if (!err2) {
										err.message =
											err.message +
											"\n" +
											"BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.\n" +
											`                 You need to specify '${
												item.loader
											}-loader' instead of '${item.loader}',\n` +
											"                 see https://webpack.js.org/migrate/3/#automatic-loader-module-name-extension-removed";
									}
									callback(err);
								}
							);
						}
						if (err) return callback(err);

						const optionsOnly = item.options
							? {
									options: item.options
							  }
							: undefined;
						return callback(
							null,
							Object.assign({}, item, identToLoaderRequest(result), optionsOnly)
						);
					}
				);
			},
			callback
		);
	}

	getParser(type, parserOptions) {
		let ident = type;
		if (parserOptions) {
			if (parserOptions.ident) ident = `${type}|${parserOptions.ident}`;
			else ident = JSON.stringify([type, parserOptions]);
		}
		if (ident in this.parserCache) {
			return this.parserCache[ident];
		}
		return (this.parserCache[ident] = this.createParser(type, parserOptions));
	}

	createParser(type, parserOptions = {}) {
		const parser = this.hooks.createParser.for(type).call(parserOptions);
		if (!parser) {
			throw new Error(`No parser registered for ${type}`);
		}
		this.hooks.parser.for(type).call(parser, parserOptions);
		return parser;
	}

	getGenerator(type, generatorOptions) {
		let ident = type;
		if (generatorOptions) {
			if (generatorOptions.ident) ident = `${type}|${generatorOptions.ident}`;
			else ident = JSON.stringify([type, generatorOptions]);
		}
		if (ident in this.generatorCache) {
			return this.generatorCache[ident];
		}
		return (this.generatorCache[ident] = this.createGenerator(
			type,
			generatorOptions
		));
	}

	createGenerator(type, generatorOptions = {}) {
		const generator = this.hooks.createGenerator
			.for(type)
			.call(generatorOptions);
		if (!generator) {
			throw new Error(`No generator registered for ${type}`);
		}
		this.hooks.generator.for(type).call(generator, generatorOptions);
		return generator;
	}

	getResolver(type, resolveOptions) {
		return this.resolverFactory.get(
			type,
			resolveOptions || EMPTY_RESOLVE_OPTIONS
		);
	}
}

module.exports = NormalModuleFactory;
<|endoftext|>


<commit_before>define([], function() {
    'use strict';
    return {
	getTimeBeginEnd: function(log_data) {
	    var logKeys = Object.keys(log_data);
	    var range = {
		begin: -1,
		end: -1
	    };
	    logKeys.map(function(key) {
		var log = log_data[key];
		if (range.begin == -1 || range.begin > log.begin) {
		    range.begin = log.begin;
		}
		if (range.end == -1 || range.end < log.end) {
		    range.end = log.end;
		}
	    });
	    return range;
	},
	alignLogs: function(log_data, begin, end) {
	    var logKeys = Object.keys(log_data);
	    logKeys.map(function(key) {
		var log = log_data[key];
		var beginY = log.data[0][1];
		var endY = log.data[log.data.length-1][1];
		log.data.push([begin, beginY]);
		log.data.push([end, endY]);
	    });
	    return log_data;
	},
	getDataFromAttribute: function(attribute) {
	    var log_data = {};
	    // get numerical data of the form:
	    //   ROSMOD::<DATA NAME>::<TIMESTAMP>::<DATA VALUE>
	    // or get text logs of the form
	    //   ROSMOD::<DATA NAME>::<TIMESTAMP>::<SINGLE LINE TEXT LOG>
	    //var re = /ROSMOD::(.+)::(\d+)::(-?\d+(?:\.\d+)?)/gi;
	    var re = /ROSMOD::(.+)::(\d+)::(.+)/gi;
	    var result = re.exec(attribute);
	    var annY = 1;
	    var annYIncrement = 0;
	    while(result != null) {
		var alias = result[1];
		if (!log_data[alias]) {
		    log_data[alias] = {
			name : alias,
			data : [],
			begin: -1,
			end: -1,
			annotations: [],
			_lastAnnX: 0
		    };
		}
		var time = parseFloat(result[2]);
		time = time / 1000000.0;
		// KEEP TRACK OF THE BEGIN AND END OF THIS LOG
		if (log_data[alias].begin == -1) {
		    log_data[alias].begin = time;
		}
		if (log_data[alias].end == -1) {
		    log_data[alias].end = time;
		}
		else if (log_data[alias].end < time) {
		    log_data[alias].end = time;
		}
		// WHAT KIND OF LOG IS THIS?
		var data = parseFloat(result[3]);
		if (isNaN(data)) {
		    // the data/text didn't start with a number, so must be annotation
		    //if (Math.floor(time) == Math.floor(log_data[alias]._lastAnnX))
		    //time += 1; // make a minor difference to annotations can be clicked
		    log_data[alias].annotations.push({
			x: time,
			y: annY,
			text: result[3]
		    });
		    //log_data[alias]._lastAnnX = time;
		    annY += annYIncrement;
		    log_data[alias].data.push([time, annY]);
		}
		else {
		    // a number was successfully parsed from the log, plot it
		    log_data[alias].data.push([time, data]);
		}
		result = re.exec(attribute);
	    }
	    return log_data;
	}
    };
});
<commit_msg>minor fix for result plot alignment.<commit_after>define([], function() {
    'use strict';
    return {
	getTimeBeginEnd: function(log_data) {
	    var logKeys = Object.keys(log_data);
	    var range = {
		begin: -1,
		end: -1
	    };
	    logKeys.map(function(key) {
		var log = log_data[key];
		if (range.begin == -1 || range.begin > log.begin) {
		    range.begin = log.begin;
		}
		if (range.end == -1 || range.end < log.end) {
		    range.end = log.end;
		}
	    });
	    return range;
	},
	alignLogs: function(log_data, begin, end) {
	    var logKeys = Object.keys(log_data);
	    logKeys.map(function(key) {
		var log = log_data[key];
		var beginY = log.data[0][1];
		var endY = log.data[log.data.length-1][1];
                log.data = [[begin, beginY]].concat(log.data);
		log.data.push([end, endY]);
	    });
	    return log_data;
	},
	getDataFromAttribute: function(attribute) {
	    var log_data = {};
	    // get numerical data of the form:
	    //   ROSMOD::<DATA NAME>::<TIMESTAMP>::<DATA VALUE>
	    // or get text logs of the form
	    //   ROSMOD::<DATA NAME>::<TIMESTAMP>::<SINGLE LINE TEXT LOG>
	    //var re = /ROSMOD::(.+)::(\d+)::(-?\d+(?:\.\d+)?)/gi;
	    var re = /ROSMOD::(.+)::(\d+)::(.+)/gi;
	    var result = re.exec(attribute);
	    var annY = 1;
	    var annYIncrement = 0;
	    while(result != null) {
		var alias = result[1];
		if (!log_data[alias]) {
		    log_data[alias] = {
			name : alias,
			data : [],
			begin: -1,
			end: -1,
			annotations: [],
			_lastAnnX: 0
		    };
		}
		var time = parseFloat(result[2]);
		time = time / 1000000.0;
		// KEEP TRACK OF THE BEGIN AND END OF THIS LOG
		if (log_data[alias].begin == -1) {
		    log_data[alias].begin = time;
		}
		if (log_data[alias].end == -1) {
		    log_data[alias].end = time;
		}
		else if (log_data[alias].end < time) {
		    log_data[alias].end = time;
		}
		// WHAT KIND OF LOG IS THIS?
		var data = parseFloat(result[3]);
		if (isNaN(data)) {
		    // the data/text didn't start with a number, so must be annotation
		    //if (Math.floor(time) == Math.floor(log_data[alias]._lastAnnX))
		    //time += 1; // make a minor difference to annotations can be clicked
		    log_data[alias].annotations.push({
			x: time,
			y: annY,
			text: result[3]
		    });
		    //log_data[alias]._lastAnnX = time;
		    annY += annYIncrement;
		    log_data[alias].data.push([time, annY]);
		}
		else {
		    // a number was successfully parsed from the log, plot it
		    log_data[alias].data.push([time, data]);
		}
		result = re.exec(attribute);
	    }
	    return log_data;
	}
    };
});
<|endoftext|>


<commit_before>/*
  Logs a warning / informational message when user tries to
  invoke 'solidity-coverage' as a shell command. This file
  is listed as the package.json "bin".
*/
const AppUI = require('../lib/ui').AppUI;

(new AppUI()).report('command');
<commit_msg>Add missing hash bang to .bin warning (#466)<commit_after>#!/usr/bin/env node

/*
  Logs a warning / informational message when user tries to
  invoke 'solidity-coverage' as a shell command. This file
  is listed as the package.json "bin".
*/
const AppUI = require('../lib/ui').AppUI;

(new AppUI()).report('command');
<|endoftext|>


<commit_before>//     Backbone.Controller 0.3.0
//     (c) Artyom Trityak
//     Backbone.Controller may be freely distributed under the MIT license.
//     For all details and documentation:
//     https://github.com/artyomtrityak/backbone.controller

(function(root, factory) {

  // Set up Backbone.Controller appropriately for the environment. Start with AMD.
  if (typeof define === 'function' && define.amd) {
    define(['underscore', 'backbone', 'exports'], function(_, Backbone, exports) {
      // Export global even in AMD case in case this script is loaded with
      // others that may still expect a global Backbone.
      root.Backbone.Controller = factory(root, exports, _, Backbone);
      return root.Backbone.Controller;
    });

  // Next for Node.js or CommonJS.
  } else if (typeof exports !== 'undefined') {
    var _ = require('underscore'),
        Backbone = require('Backbone');
    module.exports = factory(root, exports, _, Backbone);

  // Finally, as a browser global.
  } else {
    root.Backbone.Controller = factory(root, {}, root._, root.Backbone);
  }

}(this, function(root, exports, _, Backbone) {

  // Binds your routes to Backbone router.
  // Allows define routes separated in each controller.
  // For example:
  //
  //  Backbone.Controller.extend({
  //    routes: {
  //      '': 'index',
  //      'cat/:query/p:page': 'showCat'
  //    },
  //
  //    initialize: function() {
  //      // do init stuff
  //    },
  //
  //    index: function() {
  //      // create index model and view
  //    },
  //
  //    showCat: function(query, page) {
  //      // create cat model and view
  //      // if something - call navigate as proxy to Backbone.Router.navigate
  //      this.navigate('dogs/', {trigger: true});
  //    }
  //  });
  //
  //  For router initialization router option should be given.
  //  For example:
  //
  //  var Application = Backbone.Router.extend({
  //    controllers: {},
  //
  //    initialize: function() {
  //      this.controllers.home = new HomeController({router: this});
  //      this.controllers.search = new SearchController({router: this});
  //
  //      Backbone.history.start();
  //    }
  //  });
  //
  //  ========
  //
  //  Auto router
  //
  //  var CatsController = Backbone.Controller.extend({
  //    routes: {
  //      '': 'index',
  //      'cat/:query/p:page': 'showCat'
  //    },
  //
  //    onBeforeRequest: function(url, param1, param2 ...) {
  //      // do before request actions
  //    },
  //
  //    onAfterRequest: function(url, param1, param2 ...) {
  //      // do after request actions
  //    },
  //
  //    remove: function() {
  //      // make cleanup
  //    }
  //    ...
  //  });
  //
  //  var cats = new CatsController({router: true});
  //
  var bindRoutes = function(Router) {
    for (var url in this.routes) {
      // Using default Backbone.js route method.
      // Same URLs from different controllers are not allowed.
      // Last controller with same URL will be used.
      Router.route(url, url, _.bind(onRoute, this, url));
    }
  },
  onRoute = function() {
    var args = _.toArray(arguments),
        url = args[0],
        methodName = this.routes[url],
        params = args.slice(1);

    // Call remove if router goes to another controller
    if (cachedController && cachedController !== this &&
      typeof cachedController.remove === 'function') {

      cachedController.remove.apply(cachedController);
    }
    cachedController = this;

    // Call onBeforeRoute before route
    if (typeof this.onBeforeRoute === 'function') {
      this.onBeforeRoute.apply(this, args);
    }

    // Call route method with routing parameters like :id, *path etc
    this[methodName].apply(this, params);

    // Call onAfterRoute after route
    if (typeof this.onAfterRoute === 'function') {
      this.onAfterRoute.apply(this, args);
    }
  },
  cachedRouter,
  cachedController;

  Backbone.Controller = function(options){
    this.options = options || {};
    if (_.isFunction(this.initialize)){
      this.initialize(this.options);
    }
    if (this.options.router === true) {
      // Save/get to/from closure router instance for binding routes
      cachedRouter = cachedRouter || new Backbone.Router();
      this.options.router = cachedRouter;
    }
    if (this.options.router) {
      cachedRouter = this.options.router;
      bindRoutes.call(this, this.options.router);
    }
  };

  // Method uses cached Backbone Router and allows navigate to another route
  Backbone.Controller.prototype.navigate = function() {
    var params = _.toArray(arguments).slice(0);
    cachedRouter.navigate.apply(this, params);
  };

  Backbone.Controller.extend = Backbone.Router.extend;

  // Supporting default Backbone events like on, off, trigger, listenTo etc
  // Provides remove method which can be called on controller removal.
  _.extend(Backbone.Controller.prototype, Backbone.Events, {
    remove: function() {
      this.stopListening();
    }
  });

  return Backbone.Controller;

}));
<commit_msg>Update backbone.controller.js<commit_after>//     Backbone.Controller 0.3.0
//     (c) Artyom Trityak
//     Backbone.Controller may be freely distributed under the MIT license.
//     For all details and documentation:
//     https://github.com/artyomtrityak/backbone.controller

(function(root, factory) {

  // Set up Backbone.Controller appropriately for the environment. Start with AMD.
  if (typeof define === 'function' && define.amd) {
    define(['underscore', 'backbone', 'exports'], function(_, Backbone, exports) {
      // Export global even in AMD case in case this script is loaded with
      // others that may still expect a global Backbone.
      root.Backbone.Controller = factory(root, exports, _, Backbone);
      return root.Backbone.Controller;
    });

  // Next for Node.js or CommonJS.
  } else if (typeof exports !== 'undefined') {
    var _ = require('underscore'),
        Backbone = require('backbone');
    module.exports = factory(root, exports, _, Backbone);

  // Finally, as a browser global.
  } else {
    root.Backbone.Controller = factory(root, {}, root._, root.Backbone);
  }

}(this, function(root, exports, _, Backbone) {

  // Binds your routes to Backbone router.
  // Allows define routes separated in each controller.
  // For example:
  //
  //  Backbone.Controller.extend({
  //    routes: {
  //      '': 'index',
  //      'cat/:query/p:page': 'showCat'
  //    },
  //
  //    initialize: function() {
  //      // do init stuff
  //    },
  //
  //    index: function() {
  //      // create index model and view
  //    },
  //
  //    showCat: function(query, page) {
  //      // create cat model and view
  //      // if something - call navigate as proxy to Backbone.Router.navigate
  //      this.navigate('dogs/', {trigger: true});
  //    }
  //  });
  //
  //  For router initialization router option should be given.
  //  For example:
  //
  //  var Application = Backbone.Router.extend({
  //    controllers: {},
  //
  //    initialize: function() {
  //      this.controllers.home = new HomeController({router: this});
  //      this.controllers.search = new SearchController({router: this});
  //
  //      Backbone.history.start();
  //    }
  //  });
  //
  //  ========
  //
  //  Auto router
  //
  //  var CatsController = Backbone.Controller.extend({
  //    routes: {
  //      '': 'index',
  //      'cat/:query/p:page': 'showCat'
  //    },
  //
  //    onBeforeRequest: function(url, param1, param2 ...) {
  //      // do before request actions
  //    },
  //
  //    onAfterRequest: function(url, param1, param2 ...) {
  //      // do after request actions
  //    },
  //
  //    remove: function() {
  //      // make cleanup
  //    }
  //    ...
  //  });
  //
  //  var cats = new CatsController({router: true});
  //
  var bindRoutes = function(Router) {
    for (var url in this.routes) {
      // Using default Backbone.js route method.
      // Same URLs from different controllers are not allowed.
      // Last controller with same URL will be used.
      Router.route(url, url, _.bind(onRoute, this, url));
    }
  },
  onRoute = function() {
    var args = _.toArray(arguments),
        url = args[0],
        methodName = this.routes[url],
        params = args.slice(1);

    // Call remove if router goes to another controller
    if (cachedController && cachedController !== this &&
      typeof cachedController.remove === 'function') {

      cachedController.remove.apply(cachedController);
    }
    cachedController = this;

    // Call onBeforeRoute before route
    if (typeof this.onBeforeRoute === 'function') {
      this.onBeforeRoute.apply(this, args);
    }

    // Call route method with routing parameters like :id, *path etc
    this[methodName].apply(this, params);

    // Call onAfterRoute after route
    if (typeof this.onAfterRoute === 'function') {
      this.onAfterRoute.apply(this, args);
    }
  },
  cachedRouter,
  cachedController;

  Backbone.Controller = function(options){
    this.options = options || {};
    if (_.isFunction(this.initialize)){
      this.initialize(this.options);
    }
    if (this.options.router === true) {
      // Save/get to/from closure router instance for binding routes
      cachedRouter = cachedRouter || new Backbone.Router();
      this.options.router = cachedRouter;
    }
    if (this.options.router) {
      cachedRouter = this.options.router;
      bindRoutes.call(this, this.options.router);
    }
  };

  // Method uses cached Backbone Router and allows navigate to another route
  Backbone.Controller.prototype.navigate = function() {
    var params = _.toArray(arguments).slice(0);
    cachedRouter.navigate.apply(this, params);
  };

  Backbone.Controller.extend = Backbone.Router.extend;

  // Supporting default Backbone events like on, off, trigger, listenTo etc
  // Provides remove method which can be called on controller removal.
  _.extend(Backbone.Controller.prototype, Backbone.Events, {
    remove: function() {
      this.stopListening();
    }
  });

  return Backbone.Controller;

}));
<|endoftext|>