<commit_before>import Abilities from 'parser/core/modules/Abilities';
import EventsNormalizer from 'parser/core/EventsNormalizer';

const debug = false;

/*
 * This normalizer attempts to track all potentially relevant casts that
 * happened before the pull. It then fabricates cast events in order to help
 * other modules (like cast efficiency) be more accurate.
 *
 * Additionally, because there is currently no ability info on whether or not a
 * spell is instant or has a cast time, we cannot (yet) accurately fabricate
 * the right type of event (begincast + cast vs only a cast).
 */
class PrePullCooldowns extends EventsNormalizer {

  /*
   * Abilities is an analyzer, which means that accessing it from a
   * normalizer like this one is not ideal design. For now, to avoid having to
   * rewrite Abilities (a core module heavily coupled with pretty much every
   * specialization), just be aware that using any Ability properties that
   * require event data (like .cooldown if it's a func, etc.) will *not*
   * produce intended results. In this normalizer I only access parts of the
   * spellbook with static values.
   */
  static dependencies = {
    abilities: Abilities,
  };

  normalize(events) {

    // region Build cooldown search arrays
    /*
     * Rather than constantly querying Abilities, here we simplify into two
     * new arrays that we can modify without messing with the spellbook
     */
    const buffSpells = [];
    const damageSpells = [];

    // TODO what filtering should we use to determine what spells we care about?
    for (const ability of this.abilities.activeAbilities) {
      if (ability.buffSpellId) {
        if(ability.buffSpellId instanceof Array) {
          ability.buffSpellId.forEach(buffId => {
            buffSpells.push({ castId: ability.spell.id, buffId: buffId });
          });
        } else {
          buffSpells.push({ castId: ability.spell.id, buffId: ability.buffSpellId });
        }
      }
      if (ability.damageSpellIds) {
        damageSpells.push({ castId: ability.spell.id, damageIds: ability.damageSpellIds });
      }
    }
    // endregion

    const prepullCasts = [];
    let precastClassResources = null;

    const firstEventIndex = this.getFightStartIndex(events);
    const firstTimestamp = events[firstEventIndex].timestamp;
    const playerId = this.owner.playerId;

    for (let i = 0; i < events.length; i += 1) {
      const event = events[i];
      const targetId = event.targetID;
      const sourceId = event.sourceID;

      if (sourceId !== playerId) {
        continue;
      }

      if (event.type === 'applybuff') {
        // We rely on the buffapply normalizer to set the prepull property
        if (targetId !== playerId || !event.prepull) {
          continue;
        }

        for (let i = 0; i < buffSpells.length; i += 1) {
          if (buffSpells[i].buffId === event.ability.guid) {
            debug && console.debug(`Detected a precast buff cooldown: ${event.ability.name}`);
            prepullCasts.push(this.constructor._fabricateCastEvent(event, buffSpells[i].castId));
            buffSpells.splice(i, 1);
            break;
          }
        }
        continue;
      }

      if (event.type === 'cast') {

        /*
         * This will copy the first resource information to all precast events.
         * It's not pretty or 100% accurate, but it prevents errors on analyzers
         * that require resource information and usually wont be too far off.
         *
         * In the future, a better way to handle this would be to make sure any
         * analyzers that need the resource information check for .prepull, or
         * we gain access to spell data that lets us build the resource
         * information more accurately.
         */
        if (precastClassResources === null && event.classResources) {
          debug && console.debug("Setting prepull class resources to:", event.classResources);
          precastClassResources = event.classResources;
        }

        // If a cast is found for a damage spell, remove it from the search
        for (let i = 0; i < damageSpells.length; i += 1) {
          if (damageSpells[i].castId === event.ability.guid) {
            damageSpells.splice(i, 1);
            break;
          }
        }
        continue;
      }

      if (event.type === 'damage') {
        // If a damage event already has a cast event, it shouldn't be in the array
        for (let i = 0; i < damageSpells.length; i += 1) {
          if (damageSpells[i].damageIds.some(id => id === event.ability.guid)) {
            debug && console.debug(`Detected a precast damage cooldown: ${event.ability.name}`);
            prepullCasts.push(this.constructor._fabricateCastEvent(event, damageSpells[i].castId));
            damageSpells.splice(i, 1);
            break;
          }
        }
      }

    }

    /*
     * Potential issue: If players cast buffs long before the pull that have a
     * long duration, this normalizer doesn't know that and assumes they
     * cast it optimized right before the pull. This means that the next time
     * it gets cast we may get an error saying it was still on cooldown. To
     * resolve this, we could also listen for buffremove events and use that
     * to deduce the cast time. This would require ability info about durations.
     */
    // Working backwards, assume worst-case GCD timestamps
    let totalGCD = 0;
    for (let i = prepullCasts.length - 1; i >= 0; i -= 1) {
      const event = prepullCasts[i];
      totalGCD += this._resolveAbilityGcd(event.ability.guid);
      event.timestamp = firstTimestamp - totalGCD;
      event.classResources = precastClassResources;
    }
    events.unshift(...prepullCasts);
    return events;
  }

  _resolveAbilityGcd(id) {
    let ability = this.abilities.getAbility(id);
    if (!ability) {
      ability = this.abilities.getSpellBuffAbility(id);
    }
    const gcdProp = ability.gcd;
    if (!gcdProp) {
      return 0;
    }
    if (typeof gcdProp.static === 'number') {
      return gcdProp.static;
    }
    if (typeof gcdProp.base === 'number') {
      return gcdProp.base;
    }
    // We can't resolve the gcd functions because this is a normalizer, so if no flat numbers are set we just assume worst-case
    return 1500;
  }

  static _fabricateCastEvent(event, abilityId = null) {
    const ability = {
      abilityIcon: event.ability.abilityIcon,
      guid: abilityId || event.ability.guid,
      name: event.ability.name,
      type: event.ability.type,
    };

    return {
      type: 'cast',
      ability: ability,
      sourceID: event.sourceID,
      sourceIsFriendly: event.sourceIsFriendly,
      targetID: event.targetID,
      targetIsFriendly: event.targetIsFriendly,

      // Custom properties:
      prepull: true,
      __fabricated: true,
    };
  }

}

export default PrePullCooldowns;
<commit_msg>Update PrePullCooldowns normalizer: always fabricate instant prepull abilities before combat<commit_after>import Abilities from 'parser/core/modules/Abilities';
import EventsNormalizer from 'parser/core/EventsNormalizer';

import ApplyBuff from './ApplyBuff';

const debug = false;

/**
 * This normalizer attempts to track all potentially relevant casts that
 * happened before the pull. It then fabricates cast events in order to help
 * other modules (like cast efficiency) be more accurate.
 *
 * Additionally, because there is currently no ability info on whether or not a
 * spell is instant or has a cast time, we cannot (yet) accurately fabricate
 * the right type of event (begincast + cast vs only a cast).
 *
 * @property {Abilities} abilities
 * @property {ApplyBuff} applyBuff
 */
class PrePullCooldowns extends EventsNormalizer {
  /*
   * Abilities is an analyzer, which means that accessing it from a
   * normalizer like this one is not ideal design. For now, to avoid having to
   * rewrite Abilities (a core module heavily coupled with pretty much every
   * specialization), just be aware that using any Ability properties that
   * require event data (like .cooldown if it's a func, etc.) will *not*
   * produce intended results. In this normalizer I only access parts of the
   * spellbook with static values.
   */
  static dependencies = {
    abilities: Abilities,
    applyBuff: ApplyBuff, // we need fabricated events for untracked prepull applied buffs
  };

  /**
   * Rather than constantly querying Abilities, here we simplify into two
   * new arrays that we can modify without messing with the spellbook
   */
  getApplicableSpells() {
    const buffSpells = [];
    const damageSpells = [];

    // TODO what filtering should we use to determine what spells we care about?
    for (const ability of this.abilities.activeAbilities) {
      if (ability.buffSpellId) {
        if (ability.buffSpellId instanceof Array) {
          ability.buffSpellId.forEach(buffId => {
            buffSpells.push({
              castId: ability.spell.id,
              buffId: buffId,
            });
          });
        } else {
          buffSpells.push({
            castId: ability.spell.id,
            buffId: ability.buffSpellId,
          });
        }
      }
      if (ability.damageSpellIds) {
        damageSpells.push({
          castId: ability.spell.id,
          damageIds: ability.damageSpellIds,
        });
      }
    }

    return {
      buffSpells,
      damageSpells,
    };
  }

  normalize(events) {
    const { buffSpells, damageSpells } = this.getApplicableSpells();

    const prepullCasts = [];
    let precastClassResources = null;

    // When the fight started. Used for instants.
    const fightStartTimestamp = this.owner.fight.start_time;
    // When the player first cast something. Used for everything else (this is intended to optimally estimate channeled spells).
    const firstEventIndex = this.getFightStartIndex(events);
    const firstTimestamp = events[firstEventIndex].timestamp;
    const playerId = this.owner.playerId;

    for (let i = 0; i < events.length; i += 1) {
      const event = events[i];
      const targetId = event.targetID;
      const sourceId = event.sourceID;

      if (sourceId !== playerId) {
        continue;
      }

      if (event.type === 'applybuff') {
        // We rely on the ApplyBuff normalizer to set the prepull property
        if (targetId !== playerId || !event.prepull) {
          continue;
        }

        for (let i = 0; i < buffSpells.length; i += 1) {
          if (buffSpells[i].buffId === event.ability.guid) {
            debug && console.debug(`Detected a precast buff cooldown: ${event.ability.name}`);
            prepullCasts.push(this.constructor._fabricateCastEvent(event, buffSpells[i].castId));
            buffSpells.splice(i, 1);
            break;
          }
        }
        continue;
      }

      if (event.type === 'cast') {
        /**
         * This will copy the first resource information to all precast events.
         * It's not pretty or 100% accurate, but it prevents errors on analyzers
         * that require resource information and usually wont be too far off.
         *
         * In the future, a better way to handle this would be to make sure any
         * analyzers that need the resource information check for .prepull, or
         * we gain access to spell data that lets us build the resource
         * information more accurately.
         */
        if (precastClassResources === null && event.classResources) {
          debug && console.debug('Setting prepull class resources to:', event.classResources);
          precastClassResources = event.classResources;
        }

        // If a cast is found for a damage spell, remove it from the search
        for (let i = 0; i < damageSpells.length; i += 1) {
          if (damageSpells[i].castId === event.ability.guid) {
            damageSpells.splice(i, 1);
            break;
          }
        }
        continue;
      }

      if (event.type === 'damage') {
        // If a damage event already has a cast event, it shouldn't be in the array
        for (let i = 0; i < damageSpells.length; i += 1) {
          if (damageSpells[i].damageIds.some(id => id === event.ability.guid)) {
            debug && console.debug(`Detected a precast damage cooldown: ${event.ability.name}`);
            prepullCasts.push(this.constructor._fabricateCastEvent(event, damageSpells[i].castId));
            damageSpells.splice(i, 1);
            break;
          }
        }
      }
    }

    /**
     * Potential issue: If players cast buffs long before the pull that have a
     * long duration, this normalizer doesn't know that and assumes they
     * cast it optimized right before the pull. This means that the next time
     * it gets cast we may get an error saying it was still on cooldown. To
     * resolve this, we could also listen for buffremove events and use that
     * to deduce the cast time. This would require ability info about durations.
     */
      // Working backwards, assume worst-case GCD timestamps
    let totalGCD = 0;
    for (let i = prepullCasts.length - 1; i >= 0; i -= 1) {
      const event = prepullCasts[i];
      const gcd = this._resolveAbilityGcd(event.ability.guid);
      if (gcd === null) {
        // When the ability is off the GCD give it at least some margin so it properly appears as cast before the pull and out of combat
        event.timestamp = fightStartTimestamp - 100;
      } else {
        totalGCD += gcd;
        event.timestamp = firstTimestamp - totalGCD;
      }
      event.classResources = precastClassResources;
    }
    events.unshift(...prepullCasts);
    return events;
  }

  _resolveAbilityGcd(id) {
    let ability = this.abilities.getAbility(id);
    if (!ability) {
      ability = this.abilities.getSpellBuffAbility(id);
    }
    const gcdProp = ability.gcd;
    if (!gcdProp) {
      return null;
    }
    if (typeof gcdProp.static === 'number') {
      return gcdProp.static;
    }
    if (typeof gcdProp.base === 'number') {
      return gcdProp.base;
    }
    // We can't resolve the gcd functions because this is a normalizer, so if no flat numbers are set we just assume worst-case
    return 1500;
  }

  static _fabricateCastEvent(event, abilityId = null) {
    const ability = {
      abilityIcon: event.ability.abilityIcon,
      guid: abilityId || event.ability.guid,
      name: event.ability.name,
      type: event.ability.type,
    };

    return {
      type: 'cast',
      ability: ability,
      sourceID: event.sourceID,
      sourceIsFriendly: event.sourceIsFriendly,
      targetID: event.targetID,
      targetIsFriendly: event.targetIsFriendly,

      // Custom properties:
      prepull: true,
      __fabricated: true,
    };
  }
}

export default PrePullCooldowns;
<|endoftext|>


<commit_before>import React from 'react';
import { withRouter } from 'react-router';
import Reflux from 'reflux';
import Helmet from 'react-helmet';
import _ from 'lodash';

import HostingFilesStore from './HostingFilesStore';
import HostingFilesActions from './HostingFilesActions';
import HostingPublishDialogActions from './HostingPublishDialogActions';

import { RaisedButton } from 'material-ui';
import { colors as Colors } from 'material-ui/styles';
import { InnerToolbar, Container, Show } from '../../common';
import HostingFilesList from './HostingFilesList';
import HostingDialog from './HostingDialog';
import HostingPublishDialog from './HostingPublishDialog';

const HostingFilesView = React.createClass({
  mixins: [
    Reflux.connect(HostingFilesStore)
  ],

  componentDidMount() {
    const { hostingId } = this.props.params;

    HostingFilesActions.setHostingId(hostingId);
    HostingFilesActions.fetch();
  },

  isDefaultHosting() {
    const { hostingDetails } = this.state;

    if (hostingDetails) {
      return _.includes(hostingDetails.domains, 'default');
    }

    return false;
  },

  handleBackClick() {
    const { router, params } = this.props;
    const redirectPath = `/instances/${params.instanceName}/hosting/`;

    router.push(redirectPath);
  },

  handleUploadFiles(event) {
    event.stopPropagation();
    const { files } = event.target;

    if (files && files.length) {
      const filesToUpload = _.map(files, this.extendFilePath);

      this.setState({ filesToUpload });
    }
  },

  handleClearFiles() {
    this.setState({
      filesToUpload: []
    });
  },

  handleShowPublishDialog() {
    const { hostingId, instanceName } = this.props.params;

    HostingPublishDialogActions.showDialog({ id: hostingId, instanceName });
  },

  handleSendFiles() {
    const { filesToUpload } = this.state;
    const { hostingId } = this.props.params;

    HostingFilesActions.uploadFiles(hostingId, filesToUpload);
  },

  extendFilePath(file) {
    const firstSlashIndex = file.webkitRelativePath.indexOf('/');

    file.path = file.webkitRelativePath.substring(firstSlashIndex + 1);

    return file;
  },

  render() {
    const { isLoading, hideDialogs, items, filesToUpload, lastFileIndex, currentFileIndex, isUploading } = this.state;
    const hasFilesToUpload = filesToUpload.length > 0;
    const isDefaultHosting = this.isDefaultHosting();

    return (

        <Helmet title="Website Hosting" />
        <HostingDialog />
        <HostingPublishDialog />

        <InnerToolbar
          title="Website Hosting"
          style={{ padding: 0 }}
          backButton={true}
          backFallback={this.handleBackClick}
          forceBackFallback={true}
          backButtonTooltip="Go back to Hostings List"
        >
          <Show if={items.length && !isLoading}>
            <RaisedButton
              label={isDefaultHosting ? 'Published' : 'Publish'}
              onTouchTap={this.handleShowPublishDialog}
              primary={true}
              disabled={isDefaultHosting}
              disabledBackgroundColor={Colors.green500}
              disabledLabelColor="#FFF"
            />
          </Show>
        </InnerToolbar>

        <Container>
          <HostingFilesList
            isUploading={isUploading}
            lastFileIndex={lastFileIndex}
            currentFileIndex={currentFileIndex}
            handleClearFiles={this.handleClearFiles}
            filesCount={filesToUpload.length}
            handleUploadFiles={this.handleUploadFiles}
            handleSendFiles={this.handleSendFiles}
            hasFiles={hasFilesToUpload}
            isLoading={isLoading}
            items={items}
            hideDialogs={hideDialogs}
          />
        </Container>

    );
  }
});

export default withRouter(HostingFilesView);
<commit_msg>[DASH-2228] Apply comment - fix styles<commit_after>import React from 'react';
import { withRouter } from 'react-router';
import Reflux from 'reflux';
import Helmet from 'react-helmet';
import _ from 'lodash';

import HostingFilesStore from './HostingFilesStore';
import HostingFilesActions from './HostingFilesActions';
import HostingPublishDialogActions from './HostingPublishDialogActions';

import { RaisedButton } from 'material-ui';
import { colors as Colors } from 'material-ui/styles';
import { InnerToolbar, Container, Show } from '../../common';
import HostingFilesList from './HostingFilesList';
import HostingDialog from './HostingDialog';
import HostingPublishDialog from './HostingPublishDialog';

const HostingFilesView = React.createClass({
  mixins: [
    Reflux.connect(HostingFilesStore)
  ],

  componentDidMount() {
    const { hostingId } = this.props.params;

    HostingFilesActions.setHostingId(hostingId);
    HostingFilesActions.fetch();
  },

  isDefaultHosting() {
    const { hostingDetails } = this.state;

    if (hostingDetails) {
      return _.includes(hostingDetails.domains, 'default');
    }

    return false;
  },

  handleBackClick() {
    const { router, params } = this.props;
    const redirectPath = `/instances/${params.instanceName}/hosting/`;

    router.push(redirectPath);
  },

  handleUploadFiles(event) {
    event.stopPropagation();
    const { files } = event.target;

    if (files && files.length) {
      const filesToUpload = _.map(files, this.extendFilePath);

      this.setState({ filesToUpload });
    }
  },

  handleClearFiles() {
    this.setState({
      filesToUpload: []
    });
  },

  handleShowPublishDialog() {
    const { hostingId, instanceName } = this.props.params;

    HostingPublishDialogActions.showDialog({ id: hostingId, instanceName });
  },

  handleSendFiles() {
    const { filesToUpload } = this.state;
    const { hostingId } = this.props.params;

    HostingFilesActions.uploadFiles(hostingId, filesToUpload);
  },

  extendFilePath(file) {
    const firstSlashIndex = file.webkitRelativePath.indexOf('/');

    file.path = file.webkitRelativePath.substring(firstSlashIndex + 1);

    return file;
  },

  render() {
    const { isLoading, hideDialogs, items, filesToUpload, lastFileIndex, currentFileIndex, isUploading } = this.state;
    const hasFilesToUpload = filesToUpload.length > 0;
    const isDefaultHosting = this.isDefaultHosting();

    return (

        <Helmet title="Website Hosting" />
        <HostingDialog />
        <HostingPublishDialog />

        <InnerToolbar
          title="Website Hosting"
          backButton={true}
          backFallback={this.handleBackClick}
          forceBackFallback={true}
          backButtonTooltip="Go back to Hostings List"
        >
          <Show if={items.length && !isLoading}>
            <RaisedButton
              label={isDefaultHosting ? 'Published' : 'Publish'}
              onTouchTap={this.handleShowPublishDialog}
              primary={true}
              disabled={isDefaultHosting}
              disabledBackgroundColor={Colors.green500}
              disabledLabelColor="#FFF"
            />
          </Show>
        </InnerToolbar>

        <Container>
          <HostingFilesList
            isUploading={isUploading}
            lastFileIndex={lastFileIndex}
            currentFileIndex={currentFileIndex}
            handleClearFiles={this.handleClearFiles}
            filesCount={filesToUpload.length}
            handleUploadFiles={this.handleUploadFiles}
            handleSendFiles={this.handleSendFiles}
            hasFiles={hasFilesToUpload}
            isLoading={isLoading}
            items={items}
            hideDialogs={hideDialogs}
          />
        </Container>

    );
  }
});

export default withRouter(HostingFilesView);
<|endoftext|>


<commit_before>var mode = "none";

chrome.runtime.onMessage.addListener( function( request, sender, sendResponse ){
  if( request.type == "get_mode" ){
    sendResponse( mode );
    return;
  }

  var queryInfo = {
    active: true,
    windowId: chrome.windows.WINDOW_ID_CURRENT
  };

  chrome.tabs.query( queryInfo, function( result ){
    mode = request.mode;
    var currentTab = result.shift();
    chrome.tabs.sendMessage( currentTab.id, request, function(){} );
  } );
} );
<commit_msg>add tab change and update event<commit_after>var mode = "none";

chrome.runtime.onMessage.addListener( function( request, sender, sendResponse ){
  if( request.type == "get_mode" ){
    sendResponse( mode );
    return;
  }

  mode = request.mode;
  changePaintMode();
} );

chrome.tabs.onActivated.addListener(function(activeInfo) {
  mode = "none";
  changePaintMode();
} );

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
  mode = "none";
  changePaintMode();
} );

function changePaintMode(){
  var queryInfo = {
    active: true,
    windowId: chrome.windows.WINDOW_ID_CURRENT
  };

  chrome.tabs.query( queryInfo, function( result ){
    var currentTab = result.shift();
    chrome.tabs.sendMessage( currentTab.id, {
      type: "change_mode",
      mode: mode,
    } );
  } );

}
<|endoftext|>


<commit_before>// Notice I can omit the module name. The loader assumes modules map to a file
// path unless it's told otherwise.
define(function () {
    'use strict';

    // I could also have used the second argument to the factory. Vodori has decided to
    // list their modules at the top, since it's more Java like (and we use Java :-)).
    var methods = {},
    // There are plenty of others, but I want to keep this brief.
        EXPOSED = ['map', 'forEach', 'every', 'some', 'reduce'];

    var aProto = Array.prototype;
    var aSlice = aProto.slice;
    var methodName = '';

    var makeMethod = function (name) {
        return function (array) {
            //noinspection JSReferencingMutableVariableFromClosure
            return aProto[name].apply(array, aSlice.call(arguments, 1));
        };
    };

    for (var i = 0, len = EXPOSED.length; i < len; ++i) {
        methodName = EXPOSED[i];
        /**
         * Create a wrapper for whatever array methods are listed.
         * NOTE: This is not an appropriate real world solution.
         */
        methods[methodName] = makeMethod(methodName);
    }

    return methods;
});<commit_msg>Removing stale comments.<commit_after>// Notice I can omit the module name. The loader assumes modules map to a file
// path unless it's told otherwise.
define(function () {
    'use strict';

    var methods = {},
        // There are plenty of others, but I want to keep this brief.
        EXPOSED = ['map', 'forEach', 'every', 'some', 'reduce'];

    var aProto = Array.prototype;
    var aSlice = aProto.slice;
    var methodName = '';

    var makeMethod = function (name) {
        return function (array) {
            //noinspection JSReferencingMutableVariableFromClosure
            return aProto[name].apply(array, aSlice.call(arguments, 1));
        };
    };

    for (var i = 0, len = EXPOSED.length; i < len; ++i) {
        methodName = EXPOSED[i];
        /**
         * Create a wrapper for whatever array methods are listed.
         * NOTE: This is not an appropriate real world solution.
         */
        methods[methodName] = makeMethod(methodName);
    }

    return methods;
});<|endoftext|>


<commit_before>function serverError(data) {
    console.log(data);
    alert('Server error code ' + data.status + ': ' + data.responseText);
  }

function checkError(resp) {
    if (!('errorCode' in resp)) {
      return false;
    }
    //if (resp.errorCode === u2f.ErrorCodes['OK']) {
    if (resp.errorCode == 0) {
      return false;
    }
    var msg = 'U2F error code ' + resp.errorCode;
    for (name in u2f.ErrorCodes) {
      if (u2f.ErrorCodes[name] === resp.errorCode) {
        msg += ' (' + name + ')';
      }
    }
    if (resp.errorMessage) {
      msg += ': ' + resp.errorMessage;
    }
    console.log(msg);
    alert(msg);
    return true;
  }
  function hideAllU2FElements() {
      document.getElementById('auth_action_text').style.display="none";
      var manualStartVipDiv = document.getElementById("manual_start_vip_div")
      if (manualStartVipDiv) {
	      manualStartVipDiv.style.display="none";
      }
      var otpOrU2fMessageDiv = document.getElementById("otp_or_u2f_message")
      if (otpOrU2fMessageDiv) {
              otpOrU2fMessageDiv.style.display="none";
      }
  }

  function u2fSigned(resp) {
    //document.getElementById('auth_action_text').style.display="none";
    hideAllU2FElements();
    //console.log(resp);
    if (checkError(resp)) {
      return;
    }
    $.post('/u2f/SignResponse', JSON.stringify(resp)).done(function() {
      //alert('Success');
      var destination = document.getElementById("login_destination_input").getAttribute("value");
      alert(destination)
      window.location.href = destination;
    }).fail(serverError);
  }
  function sign() {
     document.getElementById('auth_action_text').style.display="block";
    $.getJSON('/u2f/SignRequest').done(function(req) {
      console.log(req);
      u2f.sign(req.appId, req.challenge, req.registeredKeys, u2fSigned, 45);
    }).fail(serverError);
  }

document.addEventListener('DOMContentLoaded', function () {
	  //document.getElementById('auth_button').addEventListener('click', sign);
	  sign();
});
<commit_msg>cleanup<commit_after>function serverError(data) {
    console.log(data);
    alert('Server error code ' + data.status + ': ' + data.responseText);
  }

function checkError(resp) {
    if (!('errorCode' in resp)) {
      return false;
    }
    //if (resp.errorCode === u2f.ErrorCodes['OK']) {
    if (resp.errorCode == 0) {
      return false;
    }
    var msg = 'U2F error code ' + resp.errorCode;
    for (name in u2f.ErrorCodes) {
      if (u2f.ErrorCodes[name] === resp.errorCode) {
        msg += ' (' + name + ')';
      }
    }
    if (resp.errorMessage) {
      msg += ': ' + resp.errorMessage;
    }
    console.log(msg);
    alert(msg);
    return true;
  }
  function hideAllU2FElements() {
      document.getElementById('auth_action_text').style.display="none";
      var manualStartVipDiv = document.getElementById("manual_start_vip_div")
      if (manualStartVipDiv) {
	      manualStartVipDiv.style.display="none";
      }
      var otpOrU2fMessageDiv = document.getElementById("otp_or_u2f_message")
      if (otpOrU2fMessageDiv) {
              otpOrU2fMessageDiv.style.display="none";
      }
  }

  function u2fSigned(resp) {
    //document.getElementById('auth_action_text').style.display="none";
    hideAllU2FElements();
    //console.log(resp);
    if (checkError(resp)) {
      return;
    }
    $.post('/u2f/SignResponse', JSON.stringify(resp)).done(function() {
      //alert('Success');
      var destination = document.getElementById("login_destination_input").getAttribute("value");
      window.location.href = destination;
    }).fail(serverError);
  }
  function sign() {
     document.getElementById('auth_action_text').style.display="block";
    $.getJSON('/u2f/SignRequest').done(function(req) {
      console.log(req);
      u2f.sign(req.appId, req.challenge, req.registeredKeys, u2fSigned, 45);
    }).fail(serverError);
  }

document.addEventListener('DOMContentLoaded', function () {
	  //document.getElementById('auth_button').addEventListener('click', sign);
	  sign();
});
<|endoftext|>


<commit_before>var SC = SC || {};

/*global d3 */

var SC = SC || {};
if (!SC.chart) { SC.chart = {}; }

SC.chart.pie = function () {
	"use strict";
	var data,
		color,
		outerHeight = 256, //16 em
		outerWidth = 600,
		pieChartWidth,
		donutWidth = 35, //Sets donut chart width
		keyChartWidth,
		svgGroup,
		keyIndicatorContainer,
		pieContainerSelector,
		options = {},
		keyColours = ["#256194", "#0494d7", "#8fb7e1", "#a3cf5d", "#7a9900", "#d00a2d", "#f15c21", "#fcce07", "#a743b3", "#593d83", "#65656a", "#193b53"],
		pieChartColours = d3.scale.ordinal().range(keyColours),
		container,
		pieChart,
		keyIndicator;

	var noDataColor = ["#ebeff2", "#f5f5f5"];
	var noDataValue = {
		values: [{
			value: 100
		}]
	};

	var pie = d3.layout.pie()
		.sort(null)
		.startAngle(0 * Math.PI) // startAngle where chart begins (in radians)
		.endAngle(2 * Math.PI) // endAngle where chart ends (in radians)
		.value(function (d) { return d.values; });

	var key = function (dataValues) {
		var index = d3.range(dataValues.length);
		var keyData = [];
		index.forEach(function (i) {
			keyData[i] = { data: dataValues[i] };
		});
		return keyData;
	};

	function chart(elementSelector) {
		chart.reDrawChart(elementSelector);
	}

	chart.reDrawChart = function (elementSelector) {
		if (container) {
			container.remove();
		}

		if (options.HideLegend === true) {
			if (outerWidth > outerHeight) {
				pieChartWidth = outerHeight;
			} else {
				pieChartWidth = outerWidth;
			}
		} else {
			if (outerWidth / 2 > outerHeight) {
				pieChartWidth = outerHeight;
			} else {
				pieChartWidth = outerWidth / 2;
			}

			keyChartWidth = outerWidth - pieChartWidth;
		}

		pieContainerSelector = elementSelector;
		container = d3.select(elementSelector).append('div')
			.attr("class", "sc-pie-chart-container")
			.attr("height", outerHeight);

		this.drawChart();
	};

	chart.drawChart = function () {
		pieChart = container.append("div")
		.attr("class", "sc-pie-chart")
		.attr("width", pieChartWidth)
		.attr("height", outerHeight);

		pieChart.append("div")
			.attr("class", "sc-pie-chart-refresh-icon")
			.style("display", "none");

		var svg = pieChart.append("svg");

		if (options.HideLegend !== true) {
			keyIndicator = container
				.append("div")
				.attr("class", "sc-pie-chart-key")
				.style("width", keyChartWidth + 'px')
				.attr("height", outerHeight);

			if (data !== undefined && data.values.length > 0) {
				chart.drawKey(keyIndicator);
			}
			chart.drawPieChart(svg);

			return chart;
		}
	};

	chart.drawPieChart = function (svg) {
		svgGroup = svg
			.attr("height", outerHeight)
			.attr("width", pieChartWidth)
			.append("g")
			.attr("transform",
				"translate(" + pieChartWidth / 2 + "," + outerHeight / 2 + ")");

		drawArcs();
	};

	// Draw chart legend
	chart.drawKey = function (keyIndicator) {
		if (options.HideLegend === true) {
			return;
		}

		keyIndicator.append("div").attr('class', 'sc-pie-chart-keyHeader').text(data.title);
		var keyValues = key(data.values);

		keyIndicatorContainer = keyIndicator.append("div");
		var list = keyIndicatorContainer.append('ul');
		var li = list.selectAll("li")
			.data(keyValues)
			.enter()
			.append("li").style("cursor", function (d) {
				return (d.data.url !== "other") ? "default" : "pointer";
			});

		// Sets animation type (default is 'exp-in-out')
		var animationType = $(pieContainerSelector).data('animation-type') || 'exp-in-out';

		// Sets animation speed in milliseconds (default is 1200)
		var animationSpeed = $(pieContainerSelector).data('animation-speed') || 1200;

		//Animation type for key
		// Sets optional animation for key
		var KeyAnimationType = $(pieContainerSelector).data('key-animation-type') || animationType;

		// Sets optional animation speed for key in milliseconds (default is 1200)
		var KeyAnimationSpeed = $(pieContainerSelector).data('key-animation-speed') || animationSpeed;

		li.append('div')
			.transition()
			.duration(KeyAnimationSpeed)
			.ease(KeyAnimationType)
			.style('width', '1.125em')
			.style('height', '1.125em')
			.style('background-color', function (d, i) { return keyColours[i]; });

		var keyText = li.append('div')
			.text(function (d) { return d.data.label; })
			.style('opacity', '0');

		keyText.transition()
			.duration(KeyAnimationSpeed)
			.ease(KeyAnimationType)
			.style('opacity', '1');
	};

	function drawArcs() {
		var arc = d3.svg.arc();

		// Gets specified chart type
		//var chartType = this.options.chartType || 'pie';	//$(pieContainerSelector).data('chart-type')
		var chartType = $(pieContainerSelector).data('chart-type') || 'pie';

		// Sets animation type (default is 'exp-in-out')
		var animationType = $(pieContainerSelector).data('animation-type') || 'exp-in-out';

		// Sets animation speed in milliseconds (default is 1200)
		var animationSpeed = $(pieContainerSelector).data('animation-speed') || 1200;

		if (options.HideLegend === true) {
			if (chartType == 'donut') {
				arc.outerRadius(outerHeight / 2.5)
					.innerRadius((outerHeight / 2.5) - donutWidth);
			} else if (chartType == 'pie') {
				arc.outerRadius(outerHeight / 2.5)
					.innerRadius(0);
			} else {
				arc.outerRadius(outerHeight / 2.5)
					.innerRadius(0);
			}

		} else {
			// Donut chart-type
			if (chartType == 'donut') {
				if ((outerWidth / 2) > outerHeight) {
					arc.outerRadius(outerHeight / 2.5)
						.innerRadius((outerHeight / 2.5) - donutWidth);
				} else if ((outerWidth / 1.5) > outerHeight) {
					arc.outerRadius(outerHeight / 2.75)
						.innerRadius((outerHeight / 2.75) - donutWidth);
				} else {
					arc.outerRadius(outerWidth / 4.5)
						.innerRadius((outerHeight / 3) - donutWidth);
				}
			}
				// Pie chart-type
			else if (chartType == 'pie') {
				if ((outerWidth / 2) > outerHeight) {
					arc.outerRadius(outerHeight / 2.5)
						.innerRadius(0);
				} else {
					arc.outerRadius(outerWidth / 4.5)
						.innerRadius(0);
				}
			}
				// Default chart-type(pie) if nothing is specified
			else {
				if ((outerWidth / 2) > outerHeight) {
					arc.outerRadius(outerHeight / 2.5)
						.innerRadius(0);
				} else {
					arc.outerRadius(outerWidth / 4.5)
						.innerRadius(0);
				}
			}
		}
		var noData = (data === undefined || data.values.length === 0) ? true : false;
		if (noData) {
			var title = (data !== undefined) ? data.title : '';
			data = noDataValue;
			data.title = title;
		}

		var pieValues = pie(data.values);

		if (!noData) {
			var g = svgGroup.selectAll(".arc")
				.data(pieValues)
				.enter().append("g")
				.attr("class", "arc")
					.each(function (arc) {
						if (isNaN(arc.startAngle))
							arc.startAngle = 0;

						if (isNaN(arc.endAngle))
							arc.endAngle = 0;
					});

			// Animation parameters
			g.append("path")
				.attr("d", arc)
					.style("fill", function (d, i) { return noData ? noDataColor : pieChartColours(i); })
				.transition()
				.ease(animationType)
				.duration(animationSpeed)
				.attrTween("d", tweenPie)
					.style("cursor", function (d) {
						return (d.data.url !== "other") ? "default" : "pointer";
					});
		} else {
			drawEmptyPieChart();
			showInformationMessage();
			data = undefined;
		}

		function drawEmptyPieChart() {
			var grads = svgGroup.append("defs").selectAll("radialGradient").data(pie(pieValues))
			.enter().append("radialGradient")
			.attr("gradientUnits", "userSpaceOnUse")
			.attr("cx", 0)
			.attr("cy", 0)
			.attr("r", "50%")
			.attr("id", function (d, i) { return "grad" + i; });

			grads.append("stop").attr("offset", "75%").style("stop-color", noDataColor[1]);
			grads.append("stop").attr("offset", "100%").style("stop-color", noDataColor[0]);

			svgGroup.selectAll("path")
				.data(pie(pieValues))
				.enter().append("path")
				.attr("fill", function (d, i) { return "url(#grad" + i + ")"; })
				.attr("d", arc);
		}

		function showInformationMessage() {
			keyIndicator.append("div").attr('class', 'sc-pie-chart-keyHeader').text(data.title);
			keyIndicator.append("div")
				.attr('class', 'sc-chart-noDataMessage')
				.text(options.noDataAvailable);
		}

		// Adds tween to each arc / startAngle is where tween starts and endAngle is where tween ends
		function tweenPie(b) {
			var i = d3.interpolate({ startAngle: 0 * Math.PI, endAngle: 0 * Math.PI }, b);
			return function (t) {
				return arc(i(t));
			};
		}
	}

	chart.on = function (type, listener) {
		if (listener) {
			if (svgGroup) {
				svgGroup.selectAll("path")
					.on(type, listener);
			}
			if (keyIndicatorContainer) {
				keyIndicatorContainer.selectAll("li")
					.on(type, listener);
			}
		}
		return chart;
	};

	chart.colors = function (value) {
		if (!arguments.length) {
			return keyColours;
		}
		keyColours = value;
		pieChartColours = d3.scale.ordinal().range(keyColours);

		return chart;
	};

	chart.data = function (values) {
		data = values;
		return chart;
	};

	chart.height = function (value) {
		if (!arguments.length) {
			return outerHeight;
		}

		if (value > 0) {
			outerHeight = value;
		}

		return chart;
	};

	chart.width = function (value) {
		if (!arguments.length) {
			return outerWidth;
		}
		outerWidth = value;

		return chart;
	};

	chart.updateData = function (values) {
		data = values;
		drawArcs();

		return chart;
	};

	chart.options = function (value) {
		if (!arguments.length) {
			return options;
		}
		options = $.extend(options, value);

		return chart;
	};

	chart.updateChart = function () {
		if (container) {
			if (pieChart) {
				pieChart.remove();
			}
			if (keyIndicator) {
				keyIndicator.remove();
			}
		}

		this.drawChart();
	};

	return chart;
	};
<commit_msg>updated to pie chart<commit_after>var SC = SC || {};

/*global d3 */

var SC = SC || {};
if (!SC.chart) { SC.chart = {}; }

SC.chart.pie = function () {
	"use strict";
	var data,
		color,
		outerHeight = 256, //16 em
		outerWidth = 600,
		pieChartWidth,
		donutWidth = 35, //Sets donut chart width
		keyChartWidth,
		svgGroup,
		keyIndicatorContainer,
		pieContainerSelector,
		options = {},
		keyColours = ["#256194", "#0494d7", "#8fb7e1", "#a3cf5d", "#7a9900", "#d00a2d", "#f15c21", "#fcce07", "#a743b3", "#593d83", "#65656a", "#193b53"],
		pieChartColours = d3.scale.ordinal().range(keyColours),
		container,
		pieChart,
		keyIndicator;

	var pie = d3.layout.pie()
		.sort(null)
		.startAngle(0 * Math.PI)
		.endAngle(2 * Math.PI)
		.value(function (d) { return d.values; });

	var key = function (dataValues) {
		var index = d3.range(dataValues.length);
		var keyData = [];
		index.forEach(function (i) {
			keyData[i] = { data: dataValues[i] };
		});
		return keyData;
	};

	function chart(elementSelector) {
		chart.reDrawChart(elementSelector);
	}

	chart.reDrawChart = function (elementSelector) {
		if (container) {
			container.remove();
		}

		if (options.HideLegend === true) {
			if (outerWidth > outerHeight) {
				pieChartWidth = outerHeight;
			} else {
				pieChartWidth = outerWidth;
			}
		} else {
			if (outerWidth / 2 > outerHeight) {
				pieChartWidth = outerHeight;
			} else {
				pieChartWidth = outerWidth / 2;
			}

			keyChartWidth = outerWidth - pieChartWidth;
		}

		pieContainerSelector = elementSelector;
		container = d3.select(elementSelector).append('div')
			.attr("class", "sc-pie-chart-container")
			.attr("height", outerHeight);

		this.drawChart();
	};

	chart.drawChart = function () {
		pieChart = container.append("div")
		.attr("class", "sc-pie-chart")
		.attr("width", pieChartWidth)
		.attr("height", outerHeight);

		pieChart.append("div")
			.attr("class", "sc-pie-chart-refresh-icon")
			.style("display", "none");

		var svg = pieChart.append("svg");

		if (options.HideLegend !== true) {
			keyIndicator = container
				.append("div")
				.attr("class", "sc-pie-chart-key")
				.style("width", keyChartWidth + 'px')
				.attr("height", outerHeight);

			if (data !== undefined && data.values.length > 0) {
				chart.drawKey(keyIndicator);
			}
			chart.drawPieChart(svg);

			return chart;
		}
	};

	chart.drawPieChart = function (svg) {
		svgGroup = svg
			.attr("height", outerHeight)
			.attr("width", pieChartWidth)
			.append("g")
			.attr("transform",
				"translate(" + pieChartWidth / 2 + "," + outerHeight / 2 + ")");

		drawArcs();
	};

	chart.drawKey = function (keyIndicator) {
		if (options.HideLegend === true) {
			return;
		}

		keyIndicator.append("div").attr('class', 'sc-pie-chart-keyHeader').text(data.title);
		var keyValues = key(data.values);

		keyIndicatorContainer = keyIndicator.append("div");
		var list = keyIndicatorContainer.append('ul');
		var li = list.selectAll("li")
			.data(keyValues)
			.enter()
			.append("li").style("cursor", function (d) {
				return (d.data.url !== "other") ? "default" : "pointer";
			});

		// Sets animation type (default is 'exp-in-out')
		var animationType = $(pieContainerSelector).data('animation-type') || 'exp-in-out';

		// Sets animation speed in milliseconds (default is 1200)
		var animationSpeed = $(pieContainerSelector).data('animation-speed') || 1200;

		//Animation type for key
		// Sets optional animation for key
		var KeyAnimationType = $(pieContainerSelector).data('key-animation-type') || animationType;

		// Sets optional animation speed for key in milliseconds (default is 1200)
		var KeyAnimationSpeed = $(pieContainerSelector).data('key-animation-speed') || animationSpeed;

		li.append('div')
			.transition()
			.duration(KeyAnimationSpeed)
			.ease(KeyAnimationType)
			.style('width', '1.125em')
			.style('height', '1.125em')
			.style('background-color', function (d, i) { return keyColours[i]; });

		var keyText = li.append('div')
			.text(function (d) {
                return d.data.key;
            })
			.style('opacity', '0');

		keyText.transition()
			.duration(KeyAnimationSpeed)
			.ease(KeyAnimationType)
			.style('opacity', '1');
	};

	function drawArcs() {
		var arc = d3.svg.arc();

		// Gets specified chart type
		//var chartType = this.options.chartType || 'pie';	//$(pieContainerSelector).data('chart-type')
		var chartType = $(pieContainerSelector).data('chart-type') || 'pie';

		// Sets animation type (default is 'exp-in-out')
		var animationType = $(pieContainerSelector).data('animation-type') || 'exp-in-out';

		// Sets animation speed in milliseconds (default is 1200)
		var animationSpeed = $(pieContainerSelector).data('animation-speed') || 1200;

		if (options.HideLegend === true) {
				arc.outerRadius(outerHeight / 2.5)
					.innerRadius(0);
		} else {
            if ((outerWidth / 2) > outerHeight) {
                arc.outerRadius(outerHeight / 2.5)
                    .innerRadius(0);
            } else {
                arc.outerRadius(outerWidth / 4.5)
                    .innerRadius(0);
            }
		}

		var pieValues = pie(data.values);

        var g = svgGroup.selectAll(".arc")
            .data(pieValues)
            .enter().append("g")
            .attr("class", "arc")
                .each(function (arc) {
                    if (isNaN(arc.startAngle))
                        arc.startAngle = 0;

                    if (isNaN(arc.endAngle))
                        arc.endAngle = 0;
                });

        // Animation parameters
        g.append("path")
            .attr("d", arc)
                .style("fill", function (d, i) { return pieChartColours(i); })
            .transition()
            .ease(animationType)
            .duration(animationSpeed)
            .attrTween("d", tweenPie)
                .style("cursor", function (d) {
                    return (d.data.url !== "other") ? "default" : "pointer";
                });

		function drawEmptyPieChart() {
			var grads = svgGroup.append("defs").selectAll("radialGradient").data(pie(pieValues))
			.enter().append("radialGradient")
			.attr("gradientUnits", "userSpaceOnUse")
			.attr("cx", 0)
			.attr("cy", 0)
			.attr("r", "50%")
			.attr("id", function (d, i) { return "grad" + i; });

			svgGroup.selectAll("path")
				.data(pie(pieValues))
				.enter().append("path")
				.attr("fill", function (d, i) { return "url(#grad" + i + ")"; })
				.attr("d", arc);
		}

		function tweenPie(b) {
			var i = d3.interpolate({ startAngle: 0 * Math.PI, endAngle: 0 * Math.PI }, b);
			return function (t) {
				return arc(i(t));
			};
		}
	}

	chart.on = function (type, listener) {
		if (listener) {
			if (svgGroup) {
				svgGroup.selectAll("path")
					.on(type, listener);
			}
			if (keyIndicatorContainer) {
				keyIndicatorContainer.selectAll("li")
					.on(type, listener);
			}
		}
		return chart;
	};

	chart.colors = function (value) {
		if (!arguments.length) {
			return keyColours;
		}
		keyColours = value;
		pieChartColours = d3.scale.ordinal().range(keyColours);

		return chart;
	};

	chart.data = function (values) {
		data = values;
		return chart;
	};

	chart.height = function (value) {
		if (!arguments.length) {
			return outerHeight;
		}

		if (value > 0) {
			outerHeight = value;
		}

		return chart;
	};

	chart.width = function (value) {
		if (!arguments.length) {
			return outerWidth;
		}
		outerWidth = value;

		return chart;
	};

	chart.updateData = function (values) {
		data = values;
		drawArcs();

		return chart;
	};

	chart.options = function (value) {
		if (!arguments.length) {
			return options;
		}
		options = $.extend(options, value);

		return chart;
	};

	chart.updateChart = function () {
		if (container) {
			if (pieChart) {
				pieChart.remove();
			}
			if (keyIndicator) {
				keyIndicator.remove();
			}
		}

		this.drawChart();
	};

	return chart;
	};
<|endoftext|>


<commit_before>/* @flow weak */

/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import { View, StyleSheet } from 'react-native';

import { PageButton, BottomConfirmModal, ToggleBar } from '../widgets';
import globalStyles from '../globalStyles';
import { GenericTablePage } from './GenericTablePage';
import { formatStatus } from '../utilities';

const DATA_TYPES_DISPLAYED = ['Stocktake'];

/**
* Renders the page for displaying Stocktakes.
* @prop   {Realm}               database    App wide database.
* @prop   {func}                navigateTo  CallBack for navigation stack.
* @state  {Realm.Results}       stocktakes  Realm.Result object containing all Items.
*/
export class StocktakesPage extends GenericTablePage {
  constructor(props) {
    super(props);
    this.state.sortBy = 'createdDate';
    this.state.isAscending = false;
    this.state.showCurrent = true;
    this.state.stocktakes = props.database.objects('Stocktake');
    this.columns = COLUMNS;
    this.dataTypesDisplayed = DATA_TYPES_DISPLAYED;
    this.getUpdatedData = this.getUpdatedData.bind(this);
    this.onRowPress = this.onRowPress.bind(this);
    this.onNewStockTake = this.onNewStockTake.bind(this);
    this.onDeleteConfirm = this.onDeleteConfirm.bind(this);
    this.onDeleteCancel = this.onDeleteCancel.bind(this);
    this.onToggleStatusFilter = this.onToggleStatusFilter.bind(this);
  }

  onRowPress(stocktake) {
    this.props.navigateTo(
      'stocktakeEditor',
      `${stocktake.name}`,
      { stocktake: stocktake },
    );
  }

  onNewStockTake() {
    this.props.navigateTo('stocktakeManager', 'New Stocktake');
  }

  onDeleteConfirm() {
    const { stocktakes, selection } = this.state;
    const { database } = this.props;
    database.write(() => {
      const stocktakesToDelete = [];
      for (let i = 0; i < selection.length; i++) {
        const stocktake = stocktakes.find(s => s.id === selection[i]);
        if (stocktake.isValid() && !stocktake.isFinalised) stocktakesToDelete.push(stocktake);
      }
      database.delete('Stocktake', stocktakesToDelete);
    });
    this.setState({ selection: [] });
    this.refreshData();
  }

  onDeleteCancel() {
    this.setState({ selection: [] });
    this.refreshData();
  }

  onToggleStatusFilter(isCurrent) {
    this.setState({
      showCurrent: isCurrent,
    }, this.refreshData);
  }

  /**
   * Returns updated data according to searchTerm, sortBy and isAscending.
   */
  getUpdatedData(searchTerm, sortBy, isAscending) {
    const { stocktakes, showCurrent } = this.state;
    const toggleFilter = showCurrent ? 'status != "finalised"' : 'status == "finalised"';
    const data = stocktakes
                  .filtered(toggleFilter)
                  .sorted(sortBy, !isAscending); // 2nd arg: reverse sort order if true
    return data;
  }

  renderCell(key, stocktake) {
    switch (key) {
      default:
      case 'name':
        return stocktake.name;
      case 'createdDate':
        return stocktake.createdDate.toDateString();
      case 'status':
        return formatStatus(stocktake.status);
      case 'selected':
        return {
          type: 'checkable',
          icon: 'md-remove-circle',
          isDisabled: stocktake.isFinalised,
        };
    }
  }

  render() {
    const { showCurrent, selection } = this.state;
    return (
      <View style={globalStyles.pageContentContainer}>
        <View style={globalStyles.container}>
          <View style={globalStyles.pageTopSectionContainer}>
            <ToggleBar
              style={globalStyles.toggleBar}
              textOffStyle={globalStyles.toggleText}
              textOnStyle={globalStyles.toggleTextSelected}
              toggleOffStyle={globalStyles.toggleOption}
              toggleOnStyle={globalStyles.toggleOptionSelected}
              toggles={[
                {
                  text: 'Current',
                  onPress: () => this.onToggleStatusFilter(true),
                  isOn: showCurrent,
                },
                {
                  text: 'Past',
                  onPress: () => this.onToggleStatusFilter(false),
                  isOn: !showCurrent,
                },
              ]}
            />
            <View style={localStyles.buttonViewTop}>
              <PageButton
                text="New StockTake"
                loadingText="Creating..."
                onPress={this.onNewStockTake}
              />
            </View>
          </View>
          {this.renderDataTable()}
          <BottomConfirmModal
            isOpen={selection.length > 0 && showCurrent}
            questionText="Are you sure you want to delete these stocktakes?"
            onCancel={() => this.onDeleteCancel()}
            onConfirm={() => this.onDeleteConfirm()}
            confirmText="Delete"
          />
        </View>
      </View>
    );
  }
}

StocktakesPage.propTypes = {
  database: React.PropTypes.object,
  navigateTo: React.PropTypes.func.isRequired,
};

const COLUMNS = [
  {
    key: 'name',
    width: 6,
    title: 'NAME',
  },
  {
    key: 'createdDate',
    width: 2,
    title: 'CREATED DATE',
    sortable: true,
  },
  {
    key: 'status',
    width: 2,
    title: 'STATUS',
  },
  {
    key: 'selected',
    width: 1,
    title: 'DELETE',
    alignText: 'center',
  },
];

const localStyles = StyleSheet.create({
  buttonViewTop: {
    justifyContent: 'flex-end',
    alignItems: 'center',
  },
});
<commit_msg>much sort for stocktakespage wow<commit_after>/* @flow weak */

/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import { View, StyleSheet } from 'react-native';

import { PageButton, BottomConfirmModal, ToggleBar } from '../widgets';
import globalStyles from '../globalStyles';
import { GenericTablePage } from './GenericTablePage';
import { formatStatus } from '../utilities';

const DATA_TYPES_DISPLAYED = ['Stocktake'];

/**
* Renders the page for displaying Stocktakes.
* @prop   {Realm}               database    App wide database.
* @prop   {func}                navigateTo  CallBack for navigation stack.
* @state  {Realm.Results}       stocktakes  Realm.Result object containing all Items.
*/
export class StocktakesPage extends GenericTablePage {
  constructor(props) {
    super(props);
    this.state.sortBy = 'createdDate';
    this.state.isAscending = false;
    this.state.showCurrent = true;
    this.state.stocktakes = props.database.objects('Stocktake');
    this.columns = COLUMNS;
    this.dataTypesDisplayed = DATA_TYPES_DISPLAYED;
    this.getUpdatedData = this.getUpdatedData.bind(this);
    this.onRowPress = this.onRowPress.bind(this);
    this.onNewStockTake = this.onNewStockTake.bind(this);
    this.onDeleteConfirm = this.onDeleteConfirm.bind(this);
    this.onDeleteCancel = this.onDeleteCancel.bind(this);
    this.onToggleStatusFilter = this.onToggleStatusFilter.bind(this);
  }

  onRowPress(stocktake) {
    this.props.navigateTo(
      'stocktakeEditor',
      `${stocktake.name}`,
      { stocktake: stocktake },
    );
  }

  onNewStockTake() {
    this.props.navigateTo('stocktakeManager', 'New Stocktake');
  }

  onDeleteConfirm() {
    const { stocktakes, selection } = this.state;
    const { database } = this.props;
    database.write(() => {
      const stocktakesToDelete = [];
      for (let i = 0; i < selection.length; i++) {
        const stocktake = stocktakes.find(s => s.id === selection[i]);
        if (stocktake.isValid() && !stocktake.isFinalised) stocktakesToDelete.push(stocktake);
      }
      database.delete('Stocktake', stocktakesToDelete);
    });
    this.setState({ selection: [] });
    this.refreshData();
  }

  onDeleteCancel() {
    this.setState({ selection: [] });
    this.refreshData();
  }

  onToggleStatusFilter(isCurrent) {
    this.setState({
      showCurrent: isCurrent,
    }, this.refreshData);
  }

  /**
   * Returns updated data according to searchTerm, sortBy and isAscending.
   */
  getUpdatedData(searchTerm, sortBy, isAscending) {
    const { stocktakes, showCurrent } = this.state;
    const toggleFilter = showCurrent ? 'status != "finalised"' : 'status == "finalised"';
    const data = stocktakes
                  .filtered(toggleFilter)
                  .sorted(sortBy, !isAscending); // 2nd arg: reverse sort order if true
    return data;
  }

  renderCell(key, stocktake) {
    switch (key) {
      default:
      case 'name':
        return stocktake.name;
      case 'createdDate':
        return stocktake.createdDate.toDateString();
      case 'status':
        return formatStatus(stocktake.status);
      case 'selected':
        return {
          type: 'checkable',
          icon: 'md-remove-circle',
          isDisabled: stocktake.isFinalised,
        };
    }
  }

  render() {
    const { showCurrent, selection } = this.state;
    return (
      <View style={globalStyles.pageContentContainer}>
        <View style={globalStyles.container}>
          <View style={globalStyles.pageTopSectionContainer}>
            <ToggleBar
              style={globalStyles.toggleBar}
              textOffStyle={globalStyles.toggleText}
              textOnStyle={globalStyles.toggleTextSelected}
              toggleOffStyle={globalStyles.toggleOption}
              toggleOnStyle={globalStyles.toggleOptionSelected}
              toggles={[
                {
                  text: 'Current',
                  onPress: () => this.onToggleStatusFilter(true),
                  isOn: showCurrent,
                },
                {
                  text: 'Past',
                  onPress: () => this.onToggleStatusFilter(false),
                  isOn: !showCurrent,
                },
              ]}
            />
            <View style={localStyles.buttonViewTop}>
              <PageButton
                text="New StockTake"
                loadingText="Creating..."
                onPress={this.onNewStockTake}
              />
            </View>
          </View>
          {this.renderDataTable()}
          <BottomConfirmModal
            isOpen={selection.length > 0 && showCurrent}
            questionText="Are you sure you want to delete these stocktakes?"
            onCancel={() => this.onDeleteCancel()}
            onConfirm={() => this.onDeleteConfirm()}
            confirmText="Delete"
          />
        </View>
      </View>
    );
  }
}

StocktakesPage.propTypes = {
  database: React.PropTypes.object,
  navigateTo: React.PropTypes.func.isRequired,
};

const COLUMNS = [
  {
    key: 'name',
    width: 6,
    title: 'NAME',
  },
  {
    key: 'createdDate',
    width: 2,
    title: 'CREATED DATE',
    sortable: true,
  },
  {
    key: 'status',
    width: 2,
    title: 'STATUS',
    sortable: true,
  },
  {
    key: 'selected',
    width: 1,
    title: 'DELETE',
    alignText: 'center',
  },
];

const localStyles = StyleSheet.create({
  buttonViewTop: {
    justifyContent: 'flex-end',
    alignItems: 'center',
  },
});
<|endoftext|>


<commit_before>import { createHmac } from 'crypto';

export default async function handleWebhook(req, res) {
  // verify the webhook signature request against the
  // unmodified, unparsed body
  const body = await getRawBody(req);
  if (!body) {
    res.status(400).send('Bad request (no body)');
    return;
  }

  const jsonBody = JSON.parse(body);

  console.log(jsonBody);

  // secret
  const secret = process.env.NEXT_PUBLIC_REVALIDATION;

  if (req.query.secret === secret) {
    const slug = jsonBody.fields?.slug[0];

    console.log(slug);

    // issue opened or edited
    // comment created or edited
    console.log('[Next.js] Revalidating /');
    await res.revalidate('/');
    if (slug) {
      console.log(`[Next.js] Revalidating /${slug}`);
      await res.revalidate(`/${slug}`);
    }

    return res.status(200).send('Success!');
  } else {
    return res.status(403).send('Forbidden');
  }
}

function getRawBody(req) {
  return new Promise((resolve, reject) => {
    let bodyChunks = [];
    req.on('end', () => {
      const rawBody = Buffer.concat(bodyChunks).toString('utf8');
      resolve(rawBody);
    });
    req.on('data', (chunk) => bodyChunks.push(chunk));
  });
}

export const config = {
  api: {
    bodyParser: false,
  },
};
<commit_msg>fix: api revalidation test<commit_after>import { createHmac } from 'crypto';

export default async function handleWebhook(req, res) {
  // verify the webhook signature request against the
  // unmodified, unparsed body
  const body = await getRawBody(req);
  if (!body) {
    res.status(400).send('Bad request (no body)');
    return;
  }

  const jsonBody = JSON.parse(body);

  console.log(jsonBody);

  const slug = jsonBody.fields.slug[0];

  // secret
  const secret = process.env.NEXT_PUBLIC_REVALIDATION;

  if (req.query.secret === secret) {
    console.log(slug);

    // issue opened or edited
    // comment created or edited
    console.log('[Next.js] Revalidating /');
    await res.revalidate('/');
    if (slug) {
      console.log(`[Next.js] Revalidating /${slug}`);
      await res.revalidate(`/${slug}`);
    }

    return res.status(200).send('Success!');
  } else {
    return res.status(403).send('Forbidden');
  }
}

function getRawBody(req) {
  return new Promise((resolve, reject) => {
    let bodyChunks = [];
    req.on('end', () => {
      const rawBody = Buffer.concat(bodyChunks).toString('utf8');
      resolve(rawBody);
    });
    req.on('data', (chunk) => bodyChunks.push(chunk));
  });
}

export const config = {
  api: {
    bodyParser: false,
  },
};
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 by CoNarrative
 */
glu.regAdapter('radiogroup', {
    extend : 'field',
    valueBindings:{
        eventName:'change',
        eventConverter:function (field, newVal) {
            return field.getValue()[field.items.getAt(0).name];
        },
        setComponentProperty:function(value,oldvalue,options,control){
            control.suspendCheckChange++;
			var obj = {};
			obj[control.items.getAt(0).name] = value;
            control.setValue(obj);
            control.lastValue = value;
            control.suspendCheckChange--;
        }
    },
	itemsBindings:{
        custom:function (context) {
            glu.provider.itemsHelper.bindItems(context);
		}
	},
	isChildArray : function(propName, value){
        return propName==='editors' || propName==='items';
    }
});

glu.regAdapter('checkboxgroup', {
    extend : 'field',
    /*valueBindings:{
        eventName:'change',
        eventConverter:function (control, checked) {
            if (checked) {
                return checked.inputValue;
            }
            else {
                return control
            }

        }
    },*/
	itemsBindings:{
        custom:function (context) {
            glu.provider.itemsHelper.bindItems(context);
		}
	},
	isChildArray : function(propName, value){
        return propName==='editors' || propName==='items';
    }
});<commit_msg>trying to get radiogroup working<commit_after>/*
 * Copyright (C) 2012 by CoNarrative
 */
glu.regAdapter('radiogroup', {
    extend : 'field',
    valueBindings:{
        eventName:'change',
        eventConverter:function (field, newVal) {
            return field.getValue()[field.items.getAt(0).name];
        },
        setComponentProperty:function(value,oldvalue,options,control){
            control.suspendCheckChange++;
			var obj = {};
			obj[control.items.getAt(0).name] = value;
            control.setValue(obj);
            control.lastValue = value;
            control.suspendCheckChange--;
        }
    },
	itemsBindings:{
        custom:function (context) {
            glu.provider.itemsHelper.bindItems(context);
		}
	},
	isChildArray : function(propName, value){
        return propName==='editors' || propName==='items';
    }
});

glu.regAdapter('checkboxgroup', {
    extend : 'field',
    valueBindings:{
        eventName:'change',
        eventConverter:function (control, checked) {
			var checks = [];
			for( var key in checked ){
				if( checked[key] == 'on' ){
					checks.push(key);
				}
			}
			return checks;
        },
		setComponentProperty: function(newValue, oldValue, options, control){
			var obj = {};
			for( var i = 0; i < newValue.length; i++){
				obj[newValue[i]] = true;
			}
			control.setValue(obj);
		}
    },
	itemsBindings:{
        custom:function (context) {
            glu.provider.itemsHelper.bindItems(context);
		}
	},
	isChildArray : function(propName, value){
        return propName==='editors' || propName==='items';
    }
});<|endoftext|>


<commit_before>define(['require', 'module', 'jquery', 'URIjs', './discover_content_type'], function (require, module, $, URI, ContentTypeDiscovery) {

    var PlainResourceFetcher = function(parentFetcher, baseUrl){

        var self = this;
        var _packageDocumentAbsoluteUrl;
        var _packageDocumentRelativePath;

        // INTERNAL FUNCTIONS

        function fetchFileContents(pathRelativeToPackageRoot, readCallback, onerror) {
            var fileUrl = self.resolveURI(pathRelativeToPackageRoot);

            if (typeof pathRelativeToPackageRoot === 'undefined') {
                throw 'Fetched file relative path is undefined!';
            }

            var xhr = new XMLHttpRequest();
            xhr.open('GET', fileUrl, true);
            xhr.responseType = 'arraybuffer';
            xhr.onerror = onerror;

            xhr.onload = function (loadEvent) {
                readCallback(xhr.response);
            };

            xhr.send();
        }

        // PUBLIC API

        this.initialize = function(callback) {

            parentFetcher.getXmlFileDom('META-INF/container.xml', function (containerXmlDom) {
                _packageDocumentRelativePath = parentFetcher.getRootFile(containerXmlDom);
                _packageDocumentAbsoluteUrl = self.resolveURI(_packageDocumentRelativePath);

                callback();

            }, function(error) {
                console.error("unable to find package document: " + error);
                _packageDocumentAbsoluteUrl = baseUrl;

                callback();
            });
        };

        this.resolveURI = function (pathRelativeToPackageRoot) {
            return baseUrl + "/" + pathRelativeToPackageRoot;
        };

        this.getPackageUrl = function() {
            return _packageDocumentAbsoluteUrl;
        };

        this.fetchFileContentsText = function(pathRelativeToPackageRoot, fetchCallback, onerror) {
            var fileUrl = self.resolveURI(pathRelativeToPackageRoot);

            if (typeof fileUrl === 'undefined') {
                throw 'Fetched file URL is undefined!';
            }
            $.ajax({
                url: fileUrl,
                dataType: 'text',
                async: true,
                success: function (result) {
                    fetchCallback(result);
                },
                error: function (xhr, status, errorThrown) {
                    console.error('Error when AJAX fetching ' + fileUrl);
                    console.error(status);
                    console.error(errorThrown);
                    onerror(errorThrown);
                }
            });
        };

        this.fetchFileContentsBlob = function(pathRelativeToPackageRoot, fetchCallback, onerror) {

            var decryptionFunction = parentFetcher.getDecryptionFunctionForRelativePath(pathRelativeToPackageRoot);
            if (decryptionFunction) {
                var origFetchCallback = fetchCallback;
                fetchCallback = function (unencryptedBlob) {
                    decryptionFunction(unencryptedBlob, function (decryptedBlob) {
                        origFetchCallback(decryptedBlob);
                    });
                };
            }
            fetchFileContents(pathRelativeToPackageRoot, function (contentsArrayBuffer) {
                var blob = new Blob([contentsArrayBuffer], {
                    type: ContentTypeDiscovery.identifyContentTypeFromFileName(pathRelativeToPackageRoot)
                });
                fetchCallback(blob);
            }, onerror);
        };

        this.getPackageDom = function (callback, onerror) {
            self.fetchFileContentsText(_packageDocumentRelativePath, function (packageXml) {
                var packageDom = parentFetcher.markupParser.parseXml(packageXml);
                callback(packageDom);
            }, onerror);
        };

    };

    return PlainResourceFetcher;
});
<commit_msg>jQuery ajax issues on Firefox with custom URI scheme / protocol handlers (isLocal must be true)<commit_after>define(['require', 'module', 'jquery', 'URIjs', './discover_content_type'], function (require, module, $, URI, ContentTypeDiscovery) {

    var PlainResourceFetcher = function(parentFetcher, baseUrl){

        var self = this;
        var _packageDocumentAbsoluteUrl;
        var _packageDocumentRelativePath;

        // INTERNAL FUNCTIONS

        function fetchFileContents(pathRelativeToPackageRoot, readCallback, onerror) {
            var fileUrl = self.resolveURI(pathRelativeToPackageRoot);

            if (typeof pathRelativeToPackageRoot === 'undefined') {
                throw 'Fetched file relative path is undefined!';
            }

            var xhr = new XMLHttpRequest();
            xhr.open('GET', fileUrl, true);
            xhr.responseType = 'arraybuffer';
            xhr.onerror = onerror;

            xhr.onload = function (loadEvent) {
                readCallback(xhr.response);
            };

            xhr.send();
        }

        // PUBLIC API

        this.initialize = function(callback) {

            parentFetcher.getXmlFileDom('META-INF/container.xml', function (containerXmlDom) {
                _packageDocumentRelativePath = parentFetcher.getRootFile(containerXmlDom);
                _packageDocumentAbsoluteUrl = self.resolveURI(_packageDocumentRelativePath);

                callback();

            }, function(error) {
                console.error("unable to find package document: " + error);
                _packageDocumentAbsoluteUrl = baseUrl;

                callback();
            });
        };

        this.resolveURI = function (pathRelativeToPackageRoot) {
            return baseUrl + "/" + pathRelativeToPackageRoot;
        };

        this.getPackageUrl = function() {
            return _packageDocumentAbsoluteUrl;
        };

        this.fetchFileContentsText = function(pathRelativeToPackageRoot, fetchCallback, onerror) {
            var fileUrl = self.resolveURI(pathRelativeToPackageRoot);

            if (typeof fileUrl === 'undefined') {
                throw 'Fetched file URL is undefined!';
            }
            $.ajax({
                isLocal: fileUrl.indexOf("http") === 0 ? false : true,
                url: fileUrl,
                dataType: 'text', //https://api.jquery.com/jQuery.ajax/
                async: true,
                success: function (result) {
                    fetchCallback(result);
                },
                error: function (xhr, status, errorThrown) {
                    console.error('Error when AJAX fetching ' + fileUrl);
                    console.error(status);
                    console.error(errorThrown);

                    // isLocal = false with custom URI scheme / protocol results in false fail on Firefox (Chrome okay)
                    if (status === "error" && (!errorThrown || !errorThrown.length) && xhr.responseText && xhr.responseText.length)
                    {
                        console.error(xhr);
                        if (typeof xhr.getResponseHeader !== "undefined") console.error(xhr.getResponseHeader("Content-Type"));
                        if (typeof xhr.getAllResponseHeaders !== "undefined") console.error(xhr.getAllResponseHeaders());
                        if (typeof xhr.responseText !== "undefined") console.error(xhr.responseText);

                        // success
                        fetchCallback(xhr.responseText);
                        return;
                    }

                    onerror(errorThrown);
                }
            });
        };

        this.fetchFileContentsBlob = function(pathRelativeToPackageRoot, fetchCallback, onerror) {

            var decryptionFunction = parentFetcher.getDecryptionFunctionForRelativePath(pathRelativeToPackageRoot);
            if (decryptionFunction) {
                var origFetchCallback = fetchCallback;
                fetchCallback = function (unencryptedBlob) {
                    decryptionFunction(unencryptedBlob, function (decryptedBlob) {
                        origFetchCallback(decryptedBlob);
                    });
                };
            }
            fetchFileContents(pathRelativeToPackageRoot, function (contentsArrayBuffer) {
                var blob = new Blob([contentsArrayBuffer], {
                    type: ContentTypeDiscovery.identifyContentTypeFromFileName(pathRelativeToPackageRoot)
                });
                fetchCallback(blob);
            }, onerror);
        };

        this.getPackageDom = function (callback, onerror) {
            self.fetchFileContentsText(_packageDocumentRelativePath, function (packageXml) {
                var packageDom = parentFetcher.markupParser.parseXml(packageXml);
                callback(packageDom);
            }, onerror);
        };

    };

    return PlainResourceFetcher;
});
<|endoftext|>


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

"use strict";

var iotdb = require('iotdb');
var _ = iotdb._;
var errors = require("./errors");

var join = require('url-join');

var logger = iotdb.logger({
    name: 'iotdb-transport',
    module: 'helpers',
});

/* --- helper functions --- */
/**
 *  Make one Transport control another.
 *
 *  @param {Transport} master_transport
 *
 *  @param {Transport} slave_transport
 *
 *  @param {dictionary|undefined} paramd
 *  Optional parameters
 *
 *  @param {boolean} paramd.verbose
 *
 *  @param {array} paramd.bands
 *  List of bands to operate on. By default
 *  "istate", "ostate", "model", "meta".
 *  All subsequent paramd.* values, except as noted:
 *  if true will become this value.
 *
 *  @param {boolean|array} paramd.update
 *  Whenever primary_transport is updated on these bands,
 *  update secondary_transport.
 *  By default true.
 *
 *  @param {boolean|array} paramd.updated
 *  Whenever secondary_transport is updated on these bands,
 *  update primary_transport.
 *  By default false.
 *  If you set this to true (or some bands), the secondary_transport
 *  can update the primary_transport which is
 *  awesome and scary, just like your mom.
 *
 *  @param {boolean|array} paramd.get
 *  Calls to get on secondary_transport (on the bands) will
 *  actually be calling the primary_transport
 *  By default true.
 *
 *  @param {boolean} paramd.list
 *  Calls to list on secondary_transport will
 *  actually be calling the primary_transport. Note
 *  that this is band independent!
 *  By default true.
 *
 *  @param {boolean|array} paramd.copy
 *  All Records from the primary_transport (on
 *  the bands) will be copied to the
 *  secondary_transport.
 *  By default true.
 */
var bind = function (primary_transport, secondary_transport, paramd) {
    var bi;
    var band;

    paramd = _.defaults(paramd, {
        verbose: false,
        bands: ["istate", "ostate", "model", "meta"],
        user: null,
        update: true,
        updated: false, // N.B.
        get: true,
        list: true,
        added: true,
        copy: true,
    });

    var _go = function (value) {
        return value !== [];
    };

    var _normalize = function (key) {
        var value = paramd[key];
        if (value === true) {
            paramd[key] = paramd.bands;
        } else if (value === false) {
            paramd[key] = [];
        } else if (!_.is.Array(value)) {
            throw new Error("bad value - expected Array or Boolean: key=" + key + " value=" + value);
        }
    };

    _normalize("update");
    _normalize("updated");
    _normalize("get");
    _normalize("list");
    _normalize("added");
    _normalize("copy");

    // updates to the src update the dst
    if (_go(paramd.update)) {
        primary_transport.updated({
            user: paramd.user,
        }, function (ud) {
            if (paramd.update.indexOf(ud.band) === -1) {
                return;
            }

            secondary_transport.put(ud, _.noop);
        });
    }

    // updates to the dst update the src - note no user!
    if (_go(paramd.updated)) {
        secondary_transport.updated({
            user: paramd.user,
        }, function (ud) {
            if (paramd.updated.indexOf(ud.band) === -1) {
                return;
            }

            primary_transport.put(ud, _.noop);
        });
    }

    // …
    if (_go(paramd.get)) {
        var _secondary_get = secondary_transport.get;

        secondary_transport.get = function (gd, callback) {
            if (paramd.get.indexOf(gd.band) === -1) {
                callback({
                    id: gd.id,
                    band: gd.band,
                    user: gd.user,
                    value: null,
                    error: new errors.NotFound(),
                });
            } else {
                return primary_transport.get(gd, callback);
            }
        };
    }

    // …
    if (_go(paramd.list)) {
        secondary_transport.bands = function () {
            primary_transport.bands.apply(primary_transport, Array.prototype.slice.call(arguments));
        };

        secondary_transport.list = function (paramd, callback) {
            primary_transport.list(paramd, function (resultd) {
                callback(resultd);
            });
        };
    }

    // …
    if (_go(paramd.added)) {
        secondary_transport.added = function () {
            primary_transport.added(primary_transport, Array.prototype.slice.call(arguments));
        };
    }

    // copy
    if (_go(paramd.copy)) {
        var get_callback = function (error, d) {
            if (error) {
                return;
            }
            if (!d.value) {
                return;
            }

            secondary_transport.put(d, _.noop);
        };

        var list_callback = function (d) {
            if (d.end) {
                return;
            }

            for (bi in paramd.copy) {
                var copy_band = paramd.copy[bi];

                primary_transport.get({
                    id: d.id,
                    band: copy_band,
                    user: d.user,
                }, get_callback);
            }
        };

        primary_transport.added({
            user: paramd.user,
        }, function(error, d) {
            if (error) {
                return;
            }

            list_callback(d);
        });

        primary_transport.list({
            user: paramd.user,
        }, list_callback);
    }
};

/**
 */
var channel = function (paramd, id, band) {
    if (!_.is.Dictionary(paramd)) {
        throw new Error("channel: 'paramd' must be a Dictionary");
    }
    if (id && !_.is.String(id)) {
        throw new Error("channel: 'id' must be a String or undefined");
    }
    if (band && !_.is.String(band)) {
        throw new Error("channel: 'band' must be a String or undefined");
    }

    paramd = _.defaults(paramd, {
        prefix: "",
        encode: function (s) {
            return s;
        },
    });

    var channel = paramd.prefix;
    if (id) {
        channel = join(channel, paramd.encode(id));

        if (band && !paramd.flat_band) {
            channel = join(channel, paramd.encode(band));
        }
    }

    return channel;
};

/**
 */
var unchannel = function (paramd, path) {
    if (!_.is.Dictionary(paramd)) {
        throw new Error("unchannel: 'paramd' must be a Dictionary");
    }
    if (!_.is.String(path)) {
        throw new Error("unchannel: 'path' must be a String");
    }

    paramd = _.defaults(paramd, {
        prefix: "",
        decode: function (s) {
            return s;
        },
        dot_id: false,
        dot_band: false,
    });

    var subpath = path.substring(paramd.prefix.length);
    subpath = subpath.replace(/^\/*/, '');
    subpath = subpath.replace(/\/*$/, '');
    subpath = subpath.replace(/\/+/g, '/');

    var parts = subpath.split("/");
    parts = _.map(parts, paramd.decode);

    var id;
    if (parts.length === 1) {
        id = parts[0];
        if (!paramd.dot_id && id.match(/^[.]/)) {
            return;
        }

        if (paramd.flat_band) {
            return [id, paramd.flat_band, ];
        } else {
            return [id, ".", ];
        }
    } else if (parts.length === 2) {
        id = parts[0];
        if (!paramd.dot_id && id.match(/^[.]/)) {
            return;
        }

        var band = parts[1];
        if (!paramd.dot_band, band.match(/^[.]/)) {
            return;
        }

        if (paramd.flat_band) {
            return [id, paramd.flat_band, ];
        } else {
            return [id, band, ];
        }
    } else {
        return;
    }
};

/**
 *  API
 */
exports.bind = bind;
exports.unchannel = unchannel;
exports.channel = channel;
<commit_msg>updated() modernized<commit_after>/*
 *  transporter.js
 *
 *  David Janes
 *  IOTDB.org
 *  2015-03-21
 *
 *  Copyright [2013-2015] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

var iotdb = require('iotdb');
var _ = iotdb._;
var errors = require("./errors");

var join = require('url-join');

var logger = iotdb.logger({
    name: 'iotdb-transport',
    module: 'helpers',
});

/* --- helper functions --- */
/**
 *  Make one Transport control another.
 *
 *  @param {Transport} master_transport
 *
 *  @param {Transport} slave_transport
 *
 *  @param {dictionary|undefined} paramd
 *  Optional parameters
 *
 *  @param {boolean} paramd.verbose
 *
 *  @param {array} paramd.bands
 *  List of bands to operate on. By default
 *  "istate", "ostate", "model", "meta".
 *  All subsequent paramd.* values, except as noted:
 *  if true will become this value.
 *
 *  @param {boolean|array} paramd.update
 *  Whenever primary_transport is updated on these bands,
 *  update secondary_transport.
 *  By default true.
 *
 *  @param {boolean|array} paramd.updated
 *  Whenever secondary_transport is updated on these bands,
 *  update primary_transport.
 *  By default false.
 *  If you set this to true (or some bands), the secondary_transport
 *  can update the primary_transport which is
 *  awesome and scary, just like your mom.
 *
 *  @param {boolean|array} paramd.get
 *  Calls to get on secondary_transport (on the bands) will
 *  actually be calling the primary_transport
 *  By default true.
 *
 *  @param {boolean} paramd.list
 *  Calls to list on secondary_transport will
 *  actually be calling the primary_transport. Note
 *  that this is band independent!
 *  By default true.
 *
 *  @param {boolean|array} paramd.copy
 *  All Records from the primary_transport (on
 *  the bands) will be copied to the
 *  secondary_transport.
 *  By default true.
 */
var bind = function (primary_transport, secondary_transport, paramd) {
    var bi;
    var band;

    paramd = _.defaults(paramd, {
        verbose: false,
        bands: ["istate", "ostate", "model", "meta"],
        user: null,
        update: true,
        updated: false, // N.B.
        get: true,
        list: true,
        added: true,
        copy: true,
    });

    var _go = function (value) {
        return value !== [];
    };

    var _normalize = function (key) {
        var value = paramd[key];
        if (value === true) {
            paramd[key] = paramd.bands;
        } else if (value === false) {
            paramd[key] = [];
        } else if (!_.is.Array(value)) {
            throw new Error("bad value - expected Array or Boolean: key=" + key + " value=" + value);
        }
    };

    _normalize("update");
    _normalize("updated");
    _normalize("get");
    _normalize("list");
    _normalize("added");
    _normalize("copy");

    // updates to the src update the dst
    if (_go(paramd.update)) {
        primary_transport.updated({
            user: paramd.user,
        }, function (error, ud) {
            if (error) {
                return;
            }

            if (paramd.update.indexOf(ud.band) === -1) {
                return;
            }

            secondary_transport.put(ud, _.noop);
        });
    }

    // updates to the dst update the src - note no user!
    if (_go(paramd.updated)) {
        secondary_transport.updated({
            user: paramd.user,
        }, function (error, ud) {
            if (error) {
                return;
            }
            if (paramd.updated.indexOf(ud.band) === -1) {
                return;
            }

            primary_transport.put(ud, _.noop);
        });
    }

    // …
    if (_go(paramd.get)) {
        var _secondary_get = secondary_transport.get;

        secondary_transport.get = function (gd, callback) {
            if (paramd.get.indexOf(gd.band) === -1) {
                callback({
                    id: gd.id,
                    band: gd.band,
                    user: gd.user,
                    value: null,
                    error: new errors.NotFound(),
                });
            } else {
                return primary_transport.get(gd, callback);
            }
        };
    }

    // …
    if (_go(paramd.list)) {
        secondary_transport.bands = function () {
            primary_transport.bands.apply(primary_transport, Array.prototype.slice.call(arguments));
        };

        secondary_transport.list = function (paramd, callback) {
            primary_transport.list(paramd, function (resultd) {
                callback(resultd);
            });
        };
    }

    // …
    if (_go(paramd.added)) {
        secondary_transport.added = function () {
            primary_transport.added(primary_transport, Array.prototype.slice.call(arguments));
        };
    }

    // copy
    if (_go(paramd.copy)) {
        var get_callback = function (error, d) {
            if (error) {
                return;
            }
            if (!d.value) {
                return;
            }

            secondary_transport.put(d, _.noop);
        };

        var list_callback = function (d) {
            if (d.end) {
                return;
            }

            for (bi in paramd.copy) {
                var copy_band = paramd.copy[bi];

                primary_transport.get({
                    id: d.id,
                    band: copy_band,
                    user: d.user,
                }, get_callback);
            }
        };

        primary_transport.added({
            user: paramd.user,
        }, function(error, d) {
            if (error) {
                return;
            }

            list_callback(d);
        });

        primary_transport.list({
            user: paramd.user,
        }, list_callback);
    }
};

/**
 */
var channel = function (paramd, id, band) {
    if (!_.is.Dictionary(paramd)) {
        throw new Error("channel: 'paramd' must be a Dictionary");
    }
    if (id && !_.is.String(id)) {
        throw new Error("channel: 'id' must be a String or undefined");
    }
    if (band && !_.is.String(band)) {
        throw new Error("channel: 'band' must be a String or undefined");
    }

    paramd = _.defaults(paramd, {
        prefix: "",
        encode: function (s) {
            return s;
        },
    });

    var channel = paramd.prefix;
    if (id) {
        channel = join(channel, paramd.encode(id));

        if (band && !paramd.flat_band) {
            channel = join(channel, paramd.encode(band));
        }
    }

    return channel;
};

/**
 */
var unchannel = function (paramd, path) {
    if (!_.is.Dictionary(paramd)) {
        throw new Error("unchannel: 'paramd' must be a Dictionary");
    }
    if (!_.is.String(path)) {
        throw new Error("unchannel: 'path' must be a String");
    }

    paramd = _.defaults(paramd, {
        prefix: "",
        decode: function (s) {
            return s;
        },
        dot_id: false,
        dot_band: false,
    });

    var subpath = path.substring(paramd.prefix.length);
    subpath = subpath.replace(/^\/*/, '');
    subpath = subpath.replace(/\/*$/, '');
    subpath = subpath.replace(/\/+/g, '/');

    var parts = subpath.split("/");
    parts = _.map(parts, paramd.decode);

    var id;
    if (parts.length === 1) {
        id = parts[0];
        if (!paramd.dot_id && id.match(/^[.]/)) {
            return;
        }

        if (paramd.flat_band) {
            return [id, paramd.flat_band, ];
        } else {
            return [id, ".", ];
        }
    } else if (parts.length === 2) {
        id = parts[0];
        if (!paramd.dot_id && id.match(/^[.]/)) {
            return;
        }

        var band = parts[1];
        if (!paramd.dot_band, band.match(/^[.]/)) {
            return;
        }

        if (paramd.flat_band) {
            return [id, paramd.flat_band, ];
        } else {
            return [id, band, ];
        }
    } else {
        return;
    }
};

/**
 *  API
 */
exports.bind = bind;
exports.unchannel = unchannel;
exports.channel = channel;
<|endoftext|>