<commit_before>import React, { Component } from 'react'
import { connect } from 'react-redux'
import { View, BackAndroid, Alert } from 'react-native'
import AwesomeButton from 'react-native-awesome-button'

import { Actions } from 'react-native-router-flux'

import { TitleBar } from '../components/TitleBar'
import { RouteInfoForStop } from '../components/RouteInfo'
import AccessibilityView from '../components/AccessibilityView'
import {DefaultText} from '../components/textComponents'

import styles from '../styles/stylesheet'
import colors from '../styles/colors'
import strings from '../resources/translations'

import { fetchRouteStops } from '../actions/fetchRouteStops'
import { sendStoprequest } from '../actions/sendStoprequest'
import { cancelStopRequest } from '../actions/cancelStopRequest'

const UPDATE_INTERVAL_IN_SECS = 10

class RouteStopRequestPage extends Component{

    constructor(props)
  {
        super(props)

        this.state = {
            renderConfirm: true,
            minutesLeftToStart: strings.minutes,
            minutesLeftToEnd: strings.minutes
        }

        this.sceneName = 'routeStopRequest'
    }

    createInterval = (props) =>
    {
        this.fetchInterval = setInterval(() =>
        {
            if (!props.isFetchingStops)
            {
                props.fetchRouteStops(this.props.vehicle.trip_id, this.props.startStop.stopId, true)
            }
        }, UPDATE_INTERVAL_IN_SECS * 1000)
    }

    componentWillMount = () =>
    {
        this.props.fetchRouteStops(this.props.vehicle.trip_id, this.props.startStop.stopId, true)
        this.createInterval(this.props)
        BackAndroid.addEventListener('hardwareBackPress', this.backAndroidHandler)
    }

    componentWillUnmount = () =>
    {
        clearInterval(this.fetchInterval)
        this.fetchInterval = false
        BackAndroid.removeEventListener('hardwareBackPress', this.backAndroidHandler)
    }

    componentWillReceiveProps = (nextProps) =>
      {
        if (nextProps.scene.name != this.sceneName) return

        if (!this.fetchInterval)
        {
            this.createInterval(this.props)
            BackAndroid.addEventListener('hardwareBackPress', this.backAndroidHandler)
        }

        this.setState({renderConfirm: !nextProps.successfulStopRequest})

        for (let index in nextProps.routeStops)
        {
            let routeStop = nextProps.routeStops[index]

            if (routeStop.stop_code == this.props.startStop.stopCode || routeStop.stop_code == this.props.stop.stopCode)
            {
                let minutesLeft = ''

                if (routeStop.arrives_in < 0)
                {
                    minutesLeft = strings.vehiclePassedStop
                }
                else if (routeStop.arrives_in == 0)
                {
                    minutesLeft = strings.now
                }
                else
                {
                    minutesLeft = routeStop.arrives_in + ' ' + strings.minutes
                }

                if (routeStop.stop_code == this.props.startStop.stopCode)
                {
                    this.setState({minutesLeftToStart: minutesLeft})
                }
                else
                {
                    this.setState({minutesLeftToEnd: minutesLeft})
                }
            }
        }
    }

    backAndroidHandler = () =>
    {
        if (this.state.renderConfirm)
        {
            return false
        }

        this.showStopRequestCancelConfirmation()

        return true
    }

    showStopRequestCancelConfirmation = () =>
    {
        function cancelStopRequestCallback(error) {
            if(!error) {
                Actions.pop()
            } else {
                Alert.alert( strings.stopRequestCancellationErrorTitle, strings.stopRequestCancellationErrorMsg,
                    [ {text: 'Ok', onPress: () => {}}] )
            }
        }

        Alert.alert(
            strings.cancelStopRequest, '',
            [
                {
                    text: strings.no,
                    onPress: () =>
                    {}
                },
                {
                    text: strings.yes,
                    onPress: () =>
                    {
                        this.props.cancelStopRequest(this.props.destinationRequestId, cancelStopRequestCallback)
                    }
                }
            ],
            { cancelable: false }
        )
    }

    renderRouteInfo = () =>
    {
        return (
          <View>
            <View>
              <RouteInfoForStop stopName={this.props.startStop.stopName} stopCode={this.props.startStop.stopCode} vehicleMinutesLeft={this.state.minutesLeftToStart}/>
            </View>
            <View>
              <RouteInfoForStop stopName={this.props.stop.stopName} stopCode={this.props.stop.stopCode} vehicleMinutesLeft={this.state.minutesLeftToEnd}/>
            </View>
          </View>
        )
    }

    renderSlider = () =>
  {
        const sendStopRequest = () =>
        {
            Alert.alert(
              strings.doYouReallyWantToMakeTheStopRequest, '',
                [
                    {
                        text: strings.no,
                        onPress: () =>
                        {}
                    },
                    {
                        text: strings.yes,
                        onPress: () =>
                        {
                            this.props.sendStoprequest(this.props.vehicle, this.props.stop, this.props.fcmToken, true)
                        }
                    }
                ],
                { cancelable: false }
          )
        }

        if (this.state.renderConfirm)
        {
            return (<View style={styles.padding10}>
                      <AwesomeButton labelStyle={styles.buttonLabel}
                      states={{
                          default: {
                              text: strings.stop,
                              onPress: sendStopRequest,
                              backgroundColor: colors.HSLgreen
                          }
                      }} />
                    </View>)
        }
    }

    renderButton = () =>
    {
        const goToFrontPage = () =>
        {
            Alert.alert(
                strings.doYouReallyWantToGoToFrontPage, '',
                [
                    {
                        text: strings.no,
                        onPress: () =>
                        {}
                    },
                    {
                        text: strings.yes,
                        onPress: () =>
                        {
                            clearInterval(this.fetchInterval)
                            this.fetchInterval = false
                            BackAndroid.removeEventListener('hardwareBackPress', this.backAndroidHandler)
                            Actions.start()
                        }
                    }
                ],
                { cancelable: false }
            )
        }

        if (this.props.successfulStopRequest)
        {
            return (<View style={styles.padding10}>
                      <AwesomeButton labelStyle={styles.buttonLabel}
                      states={{
                          default: {
                              text: strings.goToBackToFrontPage,
                              onPress: goToFrontPage,
                              backgroundColor: colors.HSLpink
                          }
                      }} />
                    </View>)
        }
    }

    render()
  {
        return (
        <AccessibilityView style={styles.flex1} name="stopRequest">
            {this.props.successfulStopRequest && <View style={styles.stopRequestSentBackground}>
                <DefaultText style={styles.stopRequestSentText}>{strings.stopsent}</DefaultText>
                <AwesomeButton labelStyle={styles.buttonLabel} states={{
                    default: {
                        text: strings.cancel,
                        onPress: this.showStopRequestCancelConfirmation,
                        backgroundColor: colors.HSLalarmRed
                    }
                }} />
            </View>}
          <TitleBar title={this.props.vehicle.line + ' ' + this.props.vehicle.destination} />
          <View style={styles.flex3}>
            {this.renderRouteInfo()}
          </View>
          <View style={styles.flex1}>
            {this.renderButton()}
          </View>
          {this.renderSlider()}
        </AccessibilityView>
        )
    }
}

const mapStateToProps = (state) =>
{
    return {
        routeStops: state.fetchRouteStopsReducer.routeStops,
        isFetchingStops: state.fetchRouteStopsReducer.isFetchingStops,
        routeIsReady: state.fetchRouteStopsReducer.routeIsReady,
        errorFetchingStops: state.fetchRouteStopsReducer.errorFetchingStops,
        error: state.stopRequestReducer.error,
        scene: state.routes.scene,
        startStop: state.stopRequestReducer.startStop,
        vehicle: state.stopRequestReducer.currentVehicle,
        fcmToken: state.fcmReducer.token,
        destinationRequestId: state.stopRequestReducer.destinationRequestId,
        successfulStopRequest: state.stopRequestReducer.sentStoprequestFromVehicle
    }
}

const mapDispatchToProps = (dispatch) =>
{
    return {
        sendStoprequest: (busId, stopId, fcmToken, fromVehicle) =>
       {
            dispatch(sendStoprequest(busId, stopId, fcmToken, fromVehicle))
        },
        fetchRouteStops: (tripId, BusId, current) =>
        {
            dispatch(fetchRouteStops(tripId, BusId, current))
        },
        cancelStopRequest: (requestId, cancelStopRequestCallback) =>
        {
            dispatch(cancelStopRequest(requestId, true))
            .then((stopRequestCancellationError) => cancelStopRequestCallback(stopRequestCancellationError))
        }
    }
}

RouteStopRequestPage.propTypes = {
    fetchRouteStops: React.PropTypes.func.isRequired,
    vehicle: React.PropTypes.shape({
        trip_id: React.PropTypes.string.isRequired,
        vehicle_type: React.PropTypes.number.isRequired,
        line: React.PropTypes.string.isRequired,
        destination: React.PropTypes.string.isRequired,
        arrival: React.PropTypes.number.isRequired
    }),
    startStop: React.PropTypes.shape({
        stopCode: React.PropTypes.string.isRequired,
        stopName: React.PropTypes.string.isRequired,
        stopId: React.PropTypes.string.isRequired
    }),
    stop: React.PropTypes.shape({
        stopCode: React.PropTypes.string.isRequired,
        stopName: React.PropTypes.string.isRequired,
        stopId: React.PropTypes.string.isRequired
    }),
    sendStoprequest: React.PropTypes.func.isRequired,
    successfulStopRequest: React.PropTypes.func.isRequired,
    resetState: React.PropTypes.func.isRequired,
    fcmToken: React.PropTypes.string.token,
    destinationRequestId: React.PropTypes.number.isRequired,
    cancelStopRequest: React.PropTypes.func.isRequired
}

export default connect(mapStateToProps, mapDispatchToProps)(RouteStopRequestPage)
<commit_msg>func->bool<commit_after>import React, { Component } from 'react'
import { connect } from 'react-redux'
import { View, BackAndroid, Alert } from 'react-native'
import AwesomeButton from 'react-native-awesome-button'

import { Actions } from 'react-native-router-flux'

import { TitleBar } from '../components/TitleBar'
import { RouteInfoForStop } from '../components/RouteInfo'
import AccessibilityView from '../components/AccessibilityView'
import {DefaultText} from '../components/textComponents'

import styles from '../styles/stylesheet'
import colors from '../styles/colors'
import strings from '../resources/translations'

import { fetchRouteStops } from '../actions/fetchRouteStops'
import { sendStoprequest } from '../actions/sendStoprequest'
import { cancelStopRequest } from '../actions/cancelStopRequest'

const UPDATE_INTERVAL_IN_SECS = 10

class RouteStopRequestPage extends Component{

    constructor(props)
  {
        super(props)

        this.state = {
            renderConfirm: true,
            minutesLeftToStart: strings.minutes,
            minutesLeftToEnd: strings.minutes
        }

        this.sceneName = 'routeStopRequest'
    }

    createInterval = (props) =>
    {
        this.fetchInterval = setInterval(() =>
        {
            if (!props.isFetchingStops)
            {
                props.fetchRouteStops(this.props.vehicle.trip_id, this.props.startStop.stopId, true)
            }
        }, UPDATE_INTERVAL_IN_SECS * 1000)
    }

    componentWillMount = () =>
    {
        this.props.fetchRouteStops(this.props.vehicle.trip_id, this.props.startStop.stopId, true)
        this.createInterval(this.props)
        BackAndroid.addEventListener('hardwareBackPress', this.backAndroidHandler)
    }

    componentWillUnmount = () =>
    {
        clearInterval(this.fetchInterval)
        this.fetchInterval = false
        BackAndroid.removeEventListener('hardwareBackPress', this.backAndroidHandler)
    }

    componentWillReceiveProps = (nextProps) =>
      {
        if (nextProps.scene.name != this.sceneName) return

        if (!this.fetchInterval)
        {
            this.createInterval(this.props)
            BackAndroid.addEventListener('hardwareBackPress', this.backAndroidHandler)
        }

        this.setState({renderConfirm: !nextProps.successfulStopRequest})

        for (let index in nextProps.routeStops)
        {
            let routeStop = nextProps.routeStops[index]

            if (routeStop.stop_code == this.props.startStop.stopCode || routeStop.stop_code == this.props.stop.stopCode)
            {
                let minutesLeft = ''

                if (routeStop.arrives_in < 0)
                {
                    minutesLeft = strings.vehiclePassedStop
                }
                else if (routeStop.arrives_in == 0)
                {
                    minutesLeft = strings.now
                }
                else
                {
                    minutesLeft = routeStop.arrives_in + ' ' + strings.minutes
                }

                if (routeStop.stop_code == this.props.startStop.stopCode)
                {
                    this.setState({minutesLeftToStart: minutesLeft})
                }
                else
                {
                    this.setState({minutesLeftToEnd: minutesLeft})
                }
            }
        }
    }

    backAndroidHandler = () =>
    {
        if (this.state.renderConfirm)
        {
            return false
        }

        this.showStopRequestCancelConfirmation()

        return true
    }

    showStopRequestCancelConfirmation = () =>
    {
        function cancelStopRequestCallback(error) {
            if(!error) {
                Actions.pop()
            } else {
                Alert.alert( strings.stopRequestCancellationErrorTitle, strings.stopRequestCancellationErrorMsg,
                    [ {text: 'Ok', onPress: () => {}}] )
            }
        }

        Alert.alert(
            strings.cancelStopRequest, '',
            [
                {
                    text: strings.no,
                    onPress: () =>
                    {}
                },
                {
                    text: strings.yes,
                    onPress: () =>
                    {
                        this.props.cancelStopRequest(this.props.destinationRequestId, cancelStopRequestCallback)
                    }
                }
            ],
            { cancelable: false }
        )
    }

    renderRouteInfo = () =>
    {
        return (
          <View>
            <View>
              <RouteInfoForStop stopName={this.props.startStop.stopName} stopCode={this.props.startStop.stopCode} vehicleMinutesLeft={this.state.minutesLeftToStart}/>
            </View>
            <View>
              <RouteInfoForStop stopName={this.props.stop.stopName} stopCode={this.props.stop.stopCode} vehicleMinutesLeft={this.state.minutesLeftToEnd}/>
            </View>
          </View>
        )
    }

    renderSlider = () =>
  {
        const sendStopRequest = () =>
        {
            Alert.alert(
              strings.doYouReallyWantToMakeTheStopRequest, '',
                [
                    {
                        text: strings.no,
                        onPress: () =>
                        {}
                    },
                    {
                        text: strings.yes,
                        onPress: () =>
                        {
                            this.props.sendStoprequest(this.props.vehicle, this.props.stop, this.props.fcmToken, true)
                        }
                    }
                ],
                { cancelable: false }
          )
        }

        if (this.state.renderConfirm)
        {
            return (<View style={styles.padding10}>
                      <AwesomeButton labelStyle={styles.buttonLabel}
                      states={{
                          default: {
                              text: strings.stop,
                              onPress: sendStopRequest,
                              backgroundColor: colors.HSLgreen
                          }
                      }} />
                    </View>)
        }
    }

    renderButton = () =>
    {
        const goToFrontPage = () =>
        {
            Alert.alert(
                strings.doYouReallyWantToGoToFrontPage, '',
                [
                    {
                        text: strings.no,
                        onPress: () =>
                        {}
                    },
                    {
                        text: strings.yes,
                        onPress: () =>
                        {
                            clearInterval(this.fetchInterval)
                            this.fetchInterval = false
                            BackAndroid.removeEventListener('hardwareBackPress', this.backAndroidHandler)
                            Actions.start()
                        }
                    }
                ],
                { cancelable: false }
            )
        }

        if (this.props.successfulStopRequest)
        {
            return (<View style={styles.padding10}>
                      <AwesomeButton labelStyle={styles.buttonLabel}
                      states={{
                          default: {
                              text: strings.goToBackToFrontPage,
                              onPress: goToFrontPage,
                              backgroundColor: colors.HSLpink
                          }
                      }} />
                    </View>)
        }
    }

    render()
  {
        return (
        <AccessibilityView style={styles.flex1} name="stopRequest">
            {this.props.successfulStopRequest && <View style={styles.stopRequestSentBackground}>
                <DefaultText style={styles.stopRequestSentText}>{strings.stopsent}</DefaultText>
                <AwesomeButton labelStyle={styles.buttonLabel} states={{
                    default: {
                        text: strings.cancel,
                        onPress: this.showStopRequestCancelConfirmation,
                        backgroundColor: colors.HSLalarmRed
                    }
                }} />
            </View>}
          <TitleBar title={this.props.vehicle.line + ' ' + this.props.vehicle.destination} />
          <View style={styles.flex3}>
            {this.renderRouteInfo()}
          </View>
          <View style={styles.flex1}>
            {this.renderButton()}
          </View>
          {this.renderSlider()}
        </AccessibilityView>
        )
    }
}

const mapStateToProps = (state) =>
{
    return {
        routeStops: state.fetchRouteStopsReducer.routeStops,
        isFetchingStops: state.fetchRouteStopsReducer.isFetchingStops,
        routeIsReady: state.fetchRouteStopsReducer.routeIsReady,
        errorFetchingStops: state.fetchRouteStopsReducer.errorFetchingStops,
        error: state.stopRequestReducer.error,
        scene: state.routes.scene,
        startStop: state.stopRequestReducer.startStop,
        vehicle: state.stopRequestReducer.currentVehicle,
        fcmToken: state.fcmReducer.token,
        destinationRequestId: state.stopRequestReducer.destinationRequestId,
        successfulStopRequest: state.stopRequestReducer.sentStoprequestFromVehicle
    }
}

const mapDispatchToProps = (dispatch) =>
{
    return {
        sendStoprequest: (busId, stopId, fcmToken, fromVehicle) =>
       {
            dispatch(sendStoprequest(busId, stopId, fcmToken, fromVehicle))
        },
        fetchRouteStops: (tripId, BusId, current) =>
        {
            dispatch(fetchRouteStops(tripId, BusId, current))
        },
        cancelStopRequest: (requestId, cancelStopRequestCallback) =>
        {
            dispatch(cancelStopRequest(requestId, true))
            .then((stopRequestCancellationError) => cancelStopRequestCallback(stopRequestCancellationError))
        }
    }
}

RouteStopRequestPage.propTypes = {
    fetchRouteStops: React.PropTypes.func.isRequired,
    vehicle: React.PropTypes.shape({
        trip_id: React.PropTypes.string.isRequired,
        vehicle_type: React.PropTypes.number.isRequired,
        line: React.PropTypes.string.isRequired,
        destination: React.PropTypes.string.isRequired,
        arrival: React.PropTypes.number.isRequired
    }),
    startStop: React.PropTypes.shape({
        stopCode: React.PropTypes.string.isRequired,
        stopName: React.PropTypes.string.isRequired,
        stopId: React.PropTypes.string.isRequired
    }),
    stop: React.PropTypes.shape({
        stopCode: React.PropTypes.string.isRequired,
        stopName: React.PropTypes.string.isRequired,
        stopId: React.PropTypes.string.isRequired
    }),
    sendStoprequest: React.PropTypes.func.isRequired,
    successfulStopRequest: React.PropTypes.bool.isRequired,
    resetState: React.PropTypes.func.isRequired,
    fcmToken: React.PropTypes.string.token,
    destinationRequestId: React.PropTypes.number.isRequired,
    cancelStopRequest: React.PropTypes.func.isRequired
}

export default connect(mapStateToProps, mapDispatchToProps)(RouteStopRequestPage)
<|endoftext|>


<commit_before>const axios = require('axios')
const _ = require('lodash/fp')

const { WALLET_SCORE_THRESHOLD } = require('../../../constants')

const NAME = 'CipherTrace'
const SUPPORTED_COINS = ['BTC', 'ETH', 'BCH', 'LTC', 'BNB', 'RSK']

function getClient(account) {
  if (_.isNil(account) || !account.enabled) return null

  const [ctv1, username, secretKey] = account.authorizationValue.split(':')
  if (_.isNil(ctv1) || _.isNil(username) || _.isNil(secretKey)) {
    throw new Error('Invalid CipherTrace configuration')
  }

  const apiVersion = ctv1.slice(-2)
  const authHeader = {
    "Authorization": account.authorizationValue
  }
  return { apiVersion, authHeader }
}

function rateWallet(account, cryptoCode, address) {
  const client = getClient(account)
  if (!_.includes(_.toUpper(cryptoCode), SUPPORTED_COINS) || _.isNil(client)) return Promise.resolve(null)

  const { apiVersion, authHeader } = client
  const threshold = _.isNil(account) ? WALLET_SCORE_THRESHOLD : account.scoreThreshold

  return axios.get(`https://rest.ciphertrace.com/aml/${apiVersion}/${_.toLower(cryptoCode)}/risk?address=${address}`, {
    headers: authHeader
  })
    .then(res => ({ address, score: res.data.risk, isValid: res.data.risk < threshold }))
}

function isValidWalletScore(account, score) {
  const client = getClient(account)
  if (_.isNil(client)) return Promise.resolve(true)

  const threshold = _.isNil(account) ? WALLET_SCORE_THRESHOLD : account.scoreThreshold
  return Promise.resolve(score < threshold)
}

module.exports = {
  NAME,
  rateWallet,
  isValidWalletScore
}
<commit_msg>fix: remove unreachable fallback value for score threshold<commit_after>const axios = require('axios')
const _ = require('lodash/fp')

const NAME = 'CipherTrace'
const SUPPORTED_COINS = ['BTC', 'ETH', 'BCH', 'LTC', 'BNB', 'RSK']

function getClient(account) {
  if (_.isNil(account) || !account.enabled) return null

  const [ctv1, username, secretKey] = account.authorizationValue.split(':')
  if (_.isNil(ctv1) || _.isNil(username) || _.isNil(secretKey)) {
    throw new Error('Invalid CipherTrace configuration')
  }

  const apiVersion = ctv1.slice(-2)
  const authHeader = {
    "Authorization": account.authorizationValue
  }
  return { apiVersion, authHeader }
}

function rateWallet(account, cryptoCode, address) {
  const client = getClient(account)
  if (!_.includes(_.toUpper(cryptoCode), SUPPORTED_COINS) || _.isNil(client)) return Promise.resolve(null)

  const { apiVersion, authHeader } = client
  const threshold = account.scoreThreshold

  return axios.get(`https://rest.ciphertrace.com/aml/${apiVersion}/${_.toLower(cryptoCode)}/risk?address=${address}`, {
    headers: authHeader
  })
    .then(res => ({ address, score: res.data.risk, isValid: res.data.risk < threshold }))
}

function isValidWalletScore(account, score) {
  const client = getClient(account)
  if (_.isNil(client)) return Promise.resolve(true)

  const threshold = account.scoreThreshold
  return Promise.resolve(score < threshold)
}

module.exports = {
  NAME,
  rateWallet,
  isValidWalletScore
}
<|endoftext|>


<commit_before>
var serveModule = require("../../lib/phonegap/serve"),
    http = require("http"),
    server = require("connect-phonegap"),
    cordova = require('cordova-lib').cordova,
    project = require("../../lib/phonegap/util/project"),
    preparePromise = null,
    serve = null;

var dummyPromise = { then: function() {} },
    realPromise = { then: function(f) { f(); } };

describe("PhoneGap serve", function () {

    describe("module", function () {

        it("should export at object", function() {
            expect(serveModule).toEqual(any(Object));
        });

        it("should export an object with a create parameter", function() {
            expect(serveModule.create).toEqual(any(Function));
        });

    });

    describe("when called", function() {
        var validOptions,
            wrapper;

        beforeEach(function() {
            // valid options
            validOptions = {
                port:3939,
                autoreload:true,
                localtunnel:false
            };
            // define wrapper as a stub
            wrapper = {
                emit: function(){},
                on: function(){}
            };

            // initialize the serve function with wrapper
            serve = serveModule.create(wrapper);

            // declare spies
            spyOn(project,'cd').andReturn(true);

            preparePromise = dummyPromise;
            spyOn(cordova.raw, 'prepare').andCallFake(function() {
                return preparePromise;
            });

            spyOn(server,'listen').andReturn({ on: function() { return this; }});
        });

        it("should be a function", function() {
            expect(serve).toEqual(any(Function));
        });

        it("should require options parameter", function(){
            expect(function() {
                serve();
            }).toThrow();
        });

        it("should return the wrapper object given to create", function () {
            var ret = serve({});
            expect(ret).toEqual(wrapper);
        });

        it("should accept empty options", function(){
            expect(function() {
                serve({});
            }).not.toThrow();
        });

        it("should not require callback parameter", function(){
            expect(function() {
                serve(validOptions);
            }).not.toThrow();
        });

        it("should not require options.port", function(){
            expect(function() {
                serve({port:undefined});
            }).not.toThrow();
        });

        it("should not require options.port", function(){
            expect(function() {
                serve({port:undefined});
            }).not.toThrow();
        });

        it("should change to the project directory", function (){
            serve(validOptions);
            expect(project.cd).toHaveBeenCalled();
        });

        it('should prepare the build first', function() {
            serve({});
            expect(cordova.raw.prepare).toHaveBeenCalled();
            expect(cordova.raw.prepare).toHaveBeenCalledWith([]);
        });

        it("should call connect-phonegap listen", function (){
            preparePromise = realPromise;
            serve({});
            expect(server.listen).toHaveBeenCalled();
        });

        it("should call connect-phonegap listen with valid options passed through", function (){
            preparePromise = realPromise;
            serve(validOptions);
            expect(server.listen).toHaveBeenCalledWith(validOptions);
        });

        describe("if called with invalid options", function () {
            var invalidOptions,
                defaultOptions;

            beforeEach(function () {
                invalidOptions = {
                    port: undefined,
                    autoreload:"batman",
                    localtunnel:"wonderwoman"
                };
                defaultOptions = {
                    port: 3000,
                    autoreload: true,
                    localtunnel: false
                };

            });

            it("should call connect-phonegap listen with default options", function (){
                preparePromise = realPromise;
                serve(invalidOptions);
                expect(server.listen.argsForCall).toEqual([[defaultOptions]]);
            });

            it("should call connect-phonegap listen with corrected autoreload option", function (){
                defaultOptions.autoreload = "batman";
                preparePromise = realPromise;
                serve(defaultOptions);
                expect(server.listen.argsForCall[0][0].autoreload).toEqual(true);
            });

            it("should call connect-phonegap listen with corrected localtunnel option", function (){
                defaultOptions.localtunnel = "batman";
                preparePromise = realPromise;
                serve(defaultOptions);
                expect(server.listen.argsForCall[0][0].localtunnel).toEqual(false);
            });

        });
    });
});
<commit_msg>[#413] updated phonegap serve spec for actual cordova call made, which changed with the fix to issue #412<commit_after>
var serveModule = require("../../lib/phonegap/serve"),
    http = require("http"),
    server = require("connect-phonegap"),
    cordova = require('cordova-lib').cordova,
    project = require("../../lib/phonegap/util/project"),
    preparePromise = null,
    serve = null;

var dummyPromise = { then: function() {} },
    realPromise = { then: function(f) { f(); } };

describe("PhoneGap serve", function () {

    describe("module", function () {

        it("should export at object", function() {
            expect(serveModule).toEqual(any(Object));
        });

        it("should export an object with a create parameter", function() {
            expect(serveModule.create).toEqual(any(Function));
        });

    });

    describe("when called", function() {
        var validOptions,
            wrapper;

        beforeEach(function() {
            // valid options
            validOptions = {
                port:3939,
                autoreload:true,
                localtunnel:false
            };
            // define wrapper as a stub
            wrapper = {
                emit: function(){},
                on: function(){}
            };

            // initialize the serve function with wrapper
            serve = serveModule.create(wrapper);

            // declare spies
            spyOn(project,'cd').andReturn(true);

            preparePromise = dummyPromise;
            spyOn(cordova, 'prepare').andCallFake(function(platforms, callback) {
                callback(true);
            });

            spyOn(server,'listen').andReturn({ on: function() { return this; }});
        });

        it("should be a function", function() {
            expect(serve).toEqual(any(Function));
        });

        it("should require options parameter", function(){
            expect(function() {
                serve();
            }).toThrow();
        });

        it("should return the wrapper object given to create", function () {
            var ret = serve({});
            expect(ret).toEqual(wrapper);
        });

        it("should accept empty options", function(){
            expect(function() {
                serve({});
            }).not.toThrow();
        });

        it("should not require callback parameter", function(){
            expect(function() {
                serve(validOptions);
            }).not.toThrow();
        });

        it("should not require options.port", function(){
            expect(function() {
                serve({port:undefined});
            }).not.toThrow();
        });

        it("should not require options.port", function(){
            expect(function() {
                serve({port:undefined});
            }).not.toThrow();
        });

        it("should change to the project directory", function (){
            serve(validOptions);
            expect(project.cd).toHaveBeenCalled();
        });

        it('should prepare the build first', function() {
            serve({});
            expect(cordova.prepare).toHaveBeenCalled();
            expect(cordova.prepare).toHaveBeenCalledWith([], jasmine.any(Function));
        });

        it("should call connect-phonegap listen", function (){
            preparePromise = realPromise;
            serve({});
            expect(server.listen).toHaveBeenCalled();
        });

        it("should call connect-phonegap listen with valid options passed through", function (){
            preparePromise = realPromise;
            serve(validOptions);
            expect(server.listen).toHaveBeenCalledWith(validOptions);
        });

        describe("if called with invalid options", function () {
            var invalidOptions,
                defaultOptions;

            beforeEach(function () {
                invalidOptions = {
                    port: undefined,
                    autoreload:"batman",
                    localtunnel:"wonderwoman"
                };
                defaultOptions = {
                    port: 3000,
                    autoreload: true,
                    localtunnel: false
                };

            });

            it("should call connect-phonegap listen with default options", function (){
                preparePromise = realPromise;
                serve(invalidOptions);
                expect(server.listen.argsForCall).toEqual([[defaultOptions]]);
            });

            it("should call connect-phonegap listen with corrected autoreload option", function (){
                defaultOptions.autoreload = "batman";
                preparePromise = realPromise;
                serve(defaultOptions);
                expect(server.listen.argsForCall[0][0].autoreload).toEqual(true);
            });

            it("should call connect-phonegap listen with corrected localtunnel option", function (){
                defaultOptions.localtunnel = "batman";
                preparePromise = realPromise;
                serve(defaultOptions);
                expect(server.listen.argsForCall[0][0].localtunnel).toEqual(false);
            });

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


<commit_before>const AliyunSTS = require('./index.js');

let aliyunSts = new AliyunSTS('Eud6M1yBZq0Ax3vG', 'euoyxkZ1kdsG0CE5nvm7AuqdNF0m1T&');
aliyunSts.assumeRole('acs:ram::1889630797507648:role/aliyunossdefaultrole', 'test', 3600, function (status, object) {
    console.log(status);
    console.log(typeof object);
    console.log(object);
});<commit_msg>aliyun-sts-1 工作流演示<commit_after>const AliyunSTS = require('./index.js');

// 调用接口
let aliyunSts = new AliyunSTS('Eud6M1yBZq0Ax3vG', 'euoyxkZ1kdsG0CE5nvm7AuqdNF0m1T&');
aliyunSts.assumeRole('acs:ram::1889630797507648:role/aliyunossdefaultrole', 'test', 3600, function (status, object) {
    console.log(status);
    console.log(typeof object);
    console.log(object);
});<|endoftext|>


<commit_before>// test-assert-greater.js -- Test assert.greater()
//
// Copyright 2017 Fuzzy.ai <evan@fuzzy.ai>
//
// 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.

/* jshint esversion: 6 */

'use strict'

const fs = require('fs')

const _ = require('lodash')
const debug = require('debug')('perjury:test-assert-greater')

const vows = require('../lib/index')
const assert = vows.assert

const js = JSON.stringify

const shouldSucceed = (actual, expected) => {
  const batch = {
    topic () {
      try {
        assert.greater(actual, expected)
        this.callback(null)
      } catch (err) {
        this.callback(err)
      }
    },
    'it works': (err) => {
      assert.ifError(err)
    }
  }
  return batch
}

const shouldFail = (actual, expected) => {
  const batch = {
    topic () {
      try {
        assert.greater(actual, expected)
        this.callback(new Error('Unexpected success'))
      } catch (err) {
        this.callback(null)
      }
    },
    'it works': (err) => {
      assert.ifError(err)
    }
  }
  return batch
}

vows
  .describe('assert.greater()')
  .addBatch({
    'When actual > extended': shouldSucceed(2, 1)
  })
  .addBatch({
    'When actual < extended': shouldFail(1, 2)
  })
  .addBatch({
    'When actual == extended': shouldFail(1, 1)
  })
  .export(module)
<commit_msg>Fix lint errors in assert-greater test<commit_after>// test-assert-greater.js -- Test assert.greater()
//
// Copyright 2017 Fuzzy.ai <evan@fuzzy.ai>
//
// 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.

/* jshint esversion: 6 */

'use strict'

const vows = require('../lib/index')
const {assert} = vows

const shouldSucceed = (actual, expected) => {
  const batch = {
    topic () {
      try {
        assert.greater(actual, expected)
        this.callback(null)
      } catch (err) {
        this.callback(err)
      }
    },
    'it works': (err) => {
      assert.ifError(err)
    }
  }
  return batch
}

const shouldFail = (actual, expected) => {
  const batch = {
    topic () {
      try {
        assert.greater(actual, expected)
        this.callback(new Error('Unexpected success'))
      } catch (err) {
        this.callback(null)
      }
    },
    'it works': (err) => {
      assert.ifError(err)
    }
  }
  return batch
}

vows
  .describe('assert.greater()')
  .addBatch({
    'When actual > extended': shouldSucceed(2, 1)
  })
  .addBatch({
    'When actual < extended': shouldFail(1, 2)
  })
  .addBatch({
    'When actual == extended': shouldFail(1, 1)
  })
  .export(module)
<|endoftext|>


<commit_before>import { lib, xelib } from './lib';
import { elementContext, Fail, flagContext, GetNativeValue, GetString,
         GetStringValue, SetNativeValue, wcb } from './helpers';
import { PCardinal, PInteger, PDouble } from './types';

// ELEMENT VALUE METHODS
Object.assign(xelib, {
    Name: function(_id) {
        return GetStringValue(_id, 'Name');
    },
    LongName: function(_id) {
        return GetStringValue(_id, 'LongName');
    },
    DisplayName: function(_id) {
        return GetStringValue(_id, 'DisplayName');
    },
    Path: function(_id) {
        return GetString(function(_len) {
            if (!lib.Path(_id, true, false, _len))
                Fail(`Path failed on ${_id}`);
        });
    },
    LongPath: function(_id) {
        return GetString(function(_len) {
            if (!lib.Path(_id, false, false, _len))
                Fail(`Path failed on ${_id}`);
        });
    },
    LocalPath: function(_id) {
        return GetString(function(_len) {
            if (!lib.Path(_id, false, true, _len))
                Fail(`Path failed on ${_id}`);
        });
    },
    Signature: function(_id) {
        return GetStringValue(_id, 'Signature');
    },
    SortKey: function(_id) {
        return GetStringValue(_id, 'SortKey');
    },
    GetValue: function(_id, path = '') {
        return GetString((_len) => lib.GetValue(_id, wcb(path), _len));
    },
    GetValueEx: function(_id, path = '') {
        return GetString(function(_len) {
            if (!lib.GetValue(_id, wcb(path), _len))
                Fail(`Failed to get element value at: ${elementContext(_id, path)}`);
        });
    },
    SetValue: function(_id, path, value) {
        if (value === undefined) {
            value = path;
            path = '';
        }
        if (!lib.SetValue(_id, wcb(path), wcb(value)))
            Fail(`Failed to set element value at: ${elementContext(_id, path)}`);
    },
    GetIntValue: function(_id, path) {
        return GetNativeValue(_id, path, 'GetIntValue', PInteger).readInt32LE();
    },
    SetIntValue: function(_id, path, value) {
        SetNativeValue(_id, path, 'SetIntValue', value);
    },
    GetUIntValue: function(_id, path) {
        return GetNativeValue(_id, path, 'GetUIntValue', PCardinal).readUInt32LE();
    },
    SetUIntValue: function(_id, path, value) {
        SetNativeValue(_id, path, 'SetUIntValue', value);
    },
    GetFloatValue: function(_id, path) {
        return GetNativeValue(_id, path, 'GetFloatValue', PDouble).readDoubleLE();
    },
    SetFloatValue: function(_id, path, value) {
        SetNativeValue(_id, path, 'SetFloatValue', value);
    },
    SetFlag: function(_id, path, name, enabled) {
        if (!lib.SetFlag(_id, wcb(path), wcb(name), enabled))
            Fail(`Failed to set flag value at: ${flagContext(_id, path, name)} to ${enabled}`);
    },
    GetFlag: function(_id, path, name) {
        return GetBool(function(_bool) {
            if (!lib.GetFlag(_id, wcb(path), wcb(name), _bool))
                Fail(`Failed to get flag value at: ${flagContext(_id, path, name)}`);
        });
    },
    GetEnabledFlags: function(_id, path = '') {
        return GetString(function(_len) {
            if (!lib.GetEnabledFlags(_id, wcb(path), _len))
                Fail(`Failed to get enabled flags at: ${elementContext(_id, path)}`);
        }).split(',');
    },
    SetEnabledFlags: function(_id, path, flags) {
        if (!lib.SetEnabledFlags(_id, wcb(path), wcb(flags.join(','))))
            Fail(`Failed to set enabled flags at: ${elementContext(_id, path)}`);
    },
    GetAllFlags: function(_id, path = '') {
        return GetString(function(_len) {
            if (!lib.GetAllFlags(_id, wcb(path), _len))
                Fail(`Failed to get all flags at: ${elementContext(_id, path)}`);
        }).split(',');
    },
    GetEnumOptions: function(_id, path = '') {
        return GetString(function(_len) {
            if (!lib.GetEnumOptions(_id, wcb(path), _len))
                Fail(`Failed to get all enum options at: ${elementContext(_id, path)}`);
        }).split(',');
    },
});
<commit_msg>added SignatureFromName, NameFromSignature, and GetSignatureNameMap to xelib<commit_after>import { lib, xelib } from './lib';
import { elementContext, Fail, flagContext, GetNativeValue, GetString,
         GetDictionary, GetStringValue, SetNativeValue, wcb } from './helpers';
import { PCardinal, PInteger, PDouble } from './types';

// ELEMENT VALUE METHODS
Object.assign(xelib, {
    Name: function(_id) {
        return GetStringValue(_id, 'Name');
    },
    LongName: function(_id) {
        return GetStringValue(_id, 'LongName');
    },
    DisplayName: function(_id) {
        return GetStringValue(_id, 'DisplayName');
    },
    Path: function(_id) {
        return GetString(function(_len) {
            if (!lib.Path(_id, true, false, _len))
                Fail(`Path failed on ${_id}`);
        });
    },
    LongPath: function(_id) {
        return GetString(function(_len) {
            if (!lib.Path(_id, false, false, _len))
                Fail(`Path failed on ${_id}`);
        });
    },
    LocalPath: function(_id) {
        return GetString(function(_len) {
            if (!lib.Path(_id, false, true, _len))
                Fail(`Path failed on ${_id}`);
        });
    },
    Signature: function(_id) {
        return GetStringValue(_id, 'Signature');
    },
    SortKey: function(_id) {
        return GetStringValue(_id, 'SortKey');
    },
    GetValue: function(_id, path = '') {
        return GetString((_len) => lib.GetValue(_id, wcb(path), _len));
    },
    GetValueEx: function(_id, path = '') {
        return GetString(function(_len) {
            if (!lib.GetValue(_id, wcb(path), _len))
                Fail(`Failed to get element value at: ${elementContext(_id, path)}`);
        });
    },
    SetValue: function(_id, path, value) {
        if (value === undefined) {
            value = path;
            path = '';
        }
        if (!lib.SetValue(_id, wcb(path), wcb(value)))
            Fail(`Failed to set element value at: ${elementContext(_id, path)}`);
    },
    GetIntValue: function(_id, path) {
        return GetNativeValue(_id, path, 'GetIntValue', PInteger).readInt32LE();
    },
    SetIntValue: function(_id, path, value) {
        SetNativeValue(_id, path, 'SetIntValue', value);
    },
    GetUIntValue: function(_id, path) {
        return GetNativeValue(_id, path, 'GetUIntValue', PCardinal).readUInt32LE();
    },
    SetUIntValue: function(_id, path, value) {
        SetNativeValue(_id, path, 'SetUIntValue', value);
    },
    GetFloatValue: function(_id, path) {
        return GetNativeValue(_id, path, 'GetFloatValue', PDouble).readDoubleLE();
    },
    SetFloatValue: function(_id, path, value) {
        SetNativeValue(_id, path, 'SetFloatValue', value);
    },
    SetFlag: function(_id, path, name, enabled) {
        if (!lib.SetFlag(_id, wcb(path), wcb(name), enabled))
            Fail(`Failed to set flag value at: ${flagContext(_id, path, name)} to ${enabled}`);
    },
    GetFlag: function(_id, path, name) {
        return GetBool(function(_bool) {
            if (!lib.GetFlag(_id, wcb(path), wcb(name), _bool))
                Fail(`Failed to get flag value at: ${flagContext(_id, path, name)}`);
        });
    },
    GetEnabledFlags: function(_id, path = '') {
        return GetString(function(_len) {
            if (!lib.GetEnabledFlags(_id, wcb(path), _len))
                Fail(`Failed to get enabled flags at: ${elementContext(_id, path)}`);
        }).split(',');
    },
    SetEnabledFlags: function(_id, path, flags) {
        if (!lib.SetEnabledFlags(_id, wcb(path), wcb(flags.join(','))))
            Fail(`Failed to set enabled flags at: ${elementContext(_id, path)}`);
    },
    GetAllFlags: function(_id, path = '') {
        return GetString(function(_len) {
            if (!lib.GetAllFlags(_id, wcb(path), _len))
                Fail(`Failed to get all flags at: ${elementContext(_id, path)}`);
        }).split(',');
    },
    GetEnumOptions: function(_id, path = '') {
        return GetString(function(_len) {
            if (!lib.GetEnumOptions(_id, wcb(path), _len))
                Fail(`Failed to get all enum options at: ${elementContext(_id, path)}`);
        }).split(',');
    },
    SignatureFromName: function(name) {
        return GetString(function(_len) {
            if (!lib.SignatureFromName(wcb(name), _len))
                Fail(`Failed to get signature from name: ${name}`);
        });
    },
    NameFromSignature: function(sig) {
        return GetString(function(_len) {
            if (!lib.NameFromSignature(wcb(sig), _len))
                Fail(`Failed to get name from signature: ${sig}`);
        });
    },
    GetSignatureNameMap: function() {
        return GetDictionary(function(_len) {
            if (!lib.GetSignatureNameMap(_len))
                Fail(`Failed to get signature name map`);
        });
    }
});
<|endoftext|>


<commit_before>const assert = require('assert')

const Fracture = require('fracture')

const find = require('./find')

class Cursor {
    constructor (sheaf, descent, key) {
        this.page = descent.entry.value
        this.sought = key
        this.index = descent.index
        this.found = descent.found
        this._entry = descent.entry
        this._sheaf = sheaf
        this._promises = {}
    }

    // You must never use `indexOf` to scan backward for insert points, only to
    // scan backward for reading. Actually, let's assume that scanning will
    // operate directly on the `items` array and we're only going to use
    // `indexOf` to search forward for insertion points, and only forward.

    //
    indexOf (key, offset = 0) {
        if (this.page.deleted) {
            return { index: null, found: false }
        }
        const comparator = this._sheaf.comparator
        let index = find(comparator, this.page.items, key, offset, Number.MAX_SAFE_INTEGER)
        // Unambiguous if we actually found it.
        if (-1 < index) {
            return { index: index, found: true }
        }
        // We only insert before the key on the left most page.
        if (~index == 0) {
            return this.page.id == '0.1' || comparator(this.page.key, key) <= 0
                ? { index: ~index, found: false }
                : { index: null, found: false }
        }
        // No problem if the index is within the exiting set of items, or if
        // this is the right most page.
        if (~index < this.page.items.length || this.page.right == null) {
            return { index: ~index, found: false }
        }
        // Otherwise we should ensure that the key is less than the key of the
        // right to the right.
        return comparator(key, this.page.right) < 0
            ? { index: ~index, found: false }
            : { index: null, found: false }
    }

    // A way to get a heft prior to insert, but we won't know the index. We
    // could get a partial heft, though, just the heft of the parts. Does this
    // do any good, though? In Memento we add a part ourselves, and it changes
    // when we insert into the tree. Maybe we somehow pre-serialize then insert
    // into the tree a buffer and the tree doesn't do serialization? But in
    // Strata we need to serialize when we balance, so we can't have
    // deserialization that doesn't match serialization, not unless we specify
    // separate serializers for insert and rewrite. Oh, and `insert` does need
    // both the serialized and deserialized parts anyway.

    //
    serialize (parts) {
        return this._sheaf.storage.serializer.parts.serialize(parts)
    }

    /* Maybe this instead.
    record (key, parts) {
        return { key: key, parts: parts, buffers = this.serialize(parts) }
    }
    */

    // Insert a record into the b-tree. Parts is an array of objects in their
    // deserialized form that will be serialized using the parts serializer. The
    // key for the record will be obtained using the key extractor.
    //
    // The index should be either the index returned from the initial descent of
    // the tree for the value used to desecend the tree or for subsequent
    // inserts using `Cursor.indexOf` if `Cursor.indexOf` does not return
    // `null`.

    //
    insert (stack, index, key, parts, buffers = this.serialize(parts)) {
        assert(Array.isArray(key))
        assert(stack instanceof Fracture.Stack)
        const header = { method: 'insert', index: index }
        const buffer = this._sheaf.storage.recordify(header, buffers)
        const record = { key: key, parts: parts, heft: buffer.length }

        this._entry.heft += record.heft

        this.page.items.splice(index, 0, record)

        return this._sheaf.append(stack, this.page.id, buffer)
    }

    remove (stack, index) {
        assert(stack instanceof Fracture.Stack)
        const header = { method: 'delete', index: index }
        const buffer = this._sheaf.storage.recordify(header, [])

        const [ spliced ] = this.page.items.splice(index, 1)
        this._entry.heft -= spliced.heft

        this.page.deletes++

        return this._sheaf.append(stack, this.page.id, buffer)
    }

    // **TODO** The user no longer releases the cursor.
    release () {
        this._entry.release()
    }
}

module.exports = Cursor
<commit_msg>Fix comparator call in `Cursor.indexOf`.<commit_after>const assert = require('assert')

const Fracture = require('fracture')

const find = require('./find')

class Cursor {
    constructor (sheaf, descent, key) {
        this.page = descent.entry.value
        this.sought = key
        this.index = descent.index
        this.found = descent.found
        this._entry = descent.entry
        this._sheaf = sheaf
        this._promises = {}
    }

    // You must never use `indexOf` to scan backward for insert points, only to
    // scan backward for reading. Actually, let's assume that scanning will
    // operate directly on the `items` array and we're only going to use
    // `indexOf` to search forward for insertion points, and only forward.

    //
    indexOf (key, offset = 0) {
        if (this.page.deleted) {
            return { index: null, found: false }
        }
        const comparator = this._sheaf.comparator
        let index = find(comparator, this.page.items, key, offset, 1)
        // Unambiguous if we actually found it.
        if (-1 < index) {
            return { index: index, found: true }
        }
        // We only insert before the key on the left most page.
        if (~index == 0) {
            return this.page.id == '0.1' || comparator(this.page.key, key) <= 0
                ? { index: ~index, found: false }
                : { index: null, found: false }
        }
        // No problem if the index is within the exiting set of items, or if
        // this is the right most page.
        if (~index < this.page.items.length || this.page.right == null) {
            return { index: ~index, found: false }
        }
        // Otherwise we should ensure that the key is less than the key of the
        // right to the right.
        return comparator(key, this.page.right) < 0
            ? { index: ~index, found: false }
            : { index: null, found: false }
    }

    // A way to get a heft prior to insert, but we won't know the index. We
    // could get a partial heft, though, just the heft of the parts. Does this
    // do any good, though? In Memento we add a part ourselves, and it changes
    // when we insert into the tree. Maybe we somehow pre-serialize then insert
    // into the tree a buffer and the tree doesn't do serialization? But in
    // Strata we need to serialize when we balance, so we can't have
    // deserialization that doesn't match serialization, not unless we specify
    // separate serializers for insert and rewrite. Oh, and `insert` does need
    // both the serialized and deserialized parts anyway.

    //
    serialize (parts) {
        return this._sheaf.storage.serializer.parts.serialize(parts)
    }

    /* Maybe this instead.
    record (key, parts) {
        return { key: key, parts: parts, buffers = this.serialize(parts) }
    }
    */

    // Insert a record into the b-tree. Parts is an array of objects in their
    // deserialized form that will be serialized using the parts serializer. The
    // key for the record will be obtained using the key extractor.
    //
    // The index should be either the index returned from the initial descent of
    // the tree for the value used to desecend the tree or for subsequent
    // inserts using `Cursor.indexOf` if `Cursor.indexOf` does not return
    // `null`.

    //
    insert (stack, index, key, parts, buffers = this.serialize(parts)) {
        assert(Array.isArray(key))
        assert(stack instanceof Fracture.Stack)
        const header = { method: 'insert', index: index }
        const buffer = this._sheaf.storage.recordify(header, buffers)
        const record = { key: key, parts: parts, heft: buffer.length }

        this._entry.heft += record.heft

        this.page.items.splice(index, 0, record)

        return this._sheaf.append(stack, this.page.id, buffer)
    }

    remove (stack, index) {
        assert(stack instanceof Fracture.Stack)
        const header = { method: 'delete', index: index }
        const buffer = this._sheaf.storage.recordify(header, [])

        const [ spliced ] = this.page.items.splice(index, 1)
        this._entry.heft -= spliced.heft

        this.page.deletes++

        return this._sheaf.append(stack, this.page.id, buffer)
    }

    // **TODO** The user no longer releases the cursor.
    release () {
        this._entry.release()
    }
}

module.exports = Cursor
<|endoftext|>


<commit_before>/*global
 define, require
 */
/*jslint
 browser: true,
 white: true
 */
define([
    'jquery',
    'kb_dashboard_widget_base',
    'kb/service/serviceApi',
    'kb/widget/widgets/buttonBar',
    'bluebird',
    'bootstrap'
],
    function ($, DashboardWidget, ServiceApi, Buttonbar, Promise) {
        "use strict";
        var widget = Object.create(DashboardWidget, {
            init: {
                value: function (cfg) {
                    cfg.name = 'PublicNarrativesWidget';
                    cfg.title = 'Public Narratives';
                    this.DashboardWidget_init(cfg);

                    // TODO: get this from somewhere, allow user to configure this.
                    this.params.limit = 10;

                    this.view = 'slider';
                    this.templates.env.addFilter('appName', function (x) {
                        return this.getState(['appsMap', x, 'name'], x);
                    }.bind(this));
                    this.templates.env.addFilter('methodName', function (x) {
                        return this.getState(['methodsMap', x, 'name'], x);
                    }.bind(this));
                    return this;
                }
            },
            getAppName: {
                value: function (name) {
                    return this.getState(['appsMap', name, 'name'], name);
                }
            },
            getMethodName: {
                value: function (name) {
                    return this.getState(['methodsMap', name, 'name'], name);
                }
            },
            setup: {
                value: function () {
                    this.kbservice = ServiceApi.make({runtime: this.runtime});
                }
            },
            renderLayout: {
                value: function () {
                    this.container.html(this.renderTemplate('layout'));
                    this.places = {
                        title: this.container.find('[data-placeholder="title"]'),
                        alert: this.container.find('[data-placeholder="alert"]'),
                        content: this.container.find('[data-placeholder="content"]')
                    };

                }
            },
            setupUI: {
                value: function () {
                    if (this.hasState('narratives') && this.getState('narratives').length > 0) {
                        this.buttonbar = Object.create(Buttonbar).init({
                            container: this.container.find('[data-placeholder="buttonbar"]')
                        });
                        this.buttonbar
                            .clear()

                            /*.addRadioToggle({
                             buttons: [
                             {
                             label: 'Slider',
                             active: true,
                             class: 'btn-kbase',
                             callback: function (e) {
                             this.view = 'slider';
                             this.refresh();
                             }.bind(this)
                             },
                             {
                             label: 'Table',
                             class: 'btn-kbase',
                             callback: function (e) {
                             this.view = 'table';
                             this.refresh();
                             }.bind(this)
                             }]
                             })
                             */
                            .addInput({
                                placeholder: 'Search',
                                place: 'end',
                                onkeyup: function (e) {
                                    // little hack to make sure the public narratives is opened up.
                                    var collapse = this.places.title, id;
                                    if (collapse.hasClass('collapsed')) {
                                        id = collapse.attr('data-target');
                                        $(id).collapse('show');
                                    }

                                    this.filterState({
                                        search: $(e.target).val()
                                    });
                                }.bind(this)
                            });
                    }
                }
            },
            render: {
                value: function () {
                    // Generate initial view based on the current state of this widget.
                    // Head off at the pass -- if not logged in, can't show profile.
                    if (this.error) {
                        this.renderError();
                    } else if (this.runtime.getService('session').isLoggedIn()) {
                        this.places.title.html(this.widgetTitle);
                        this.places.content.html(this.renderTemplate(this.view));
                    } else {
                        // no profile, no basic aaccount info
                        this.places.title.html(this.widgetTitle);
                        this.places.content.html(this.renderTemplate('unauthorized'));
                    }
                    var that = this;
                    that.container.find('[data-toggle="popover"]').popover();
                    that.container.find('[data-toggle="tooltip"]').tooltip();
                    //this.container.find('[data-toggle="popover"]').popover();
                    //this.container.find('[data-toggle="tooltip"]').tooltip();
                    return this;
                }
            },
            filterState: {
                value: function (options) {
                    if (!options.search || options.search.length === 0) {
                        this.setState('narrativesFiltered', this.getState('narratives'));
                        return;
                    }
                    var searchRe = new RegExp(options.search, 'i'),
                        nar = this.getState('narratives').filter(function (x) {
                        if (x.workspace.metadata.narrative_nice_name.match(searchRe) ||
                            (x.object.metadata.cellInfo &&
                                (function (apps) {
                                    for (var i in apps) {
                                        var app = apps[i];
                                        if (app.match(searchRe) || this.getAppName(app).match(searchRe)) {
                                            return true;
                                        }
                                    }
                                }.bind(this))(Object.keys(x.object.metadata.cellInfo.app))) ||
                            (x.object.metadata.cellInfo &&
                                (function (methods) {
                                    for (var i in methods) {
                                        var method = methods[i];
                                        if (method.match(searchRe) || this.getMethodName(method).match(searchRe)) {
                                            return true;
                                        }
                                    }
                                }.bind(this))(Object.keys(x.object.metadata.cellInfo.method)))) {
                            return true;
                        } else {
                            return false;
                        }
                    }.bind(this));
                    this.setState('narrativesFiltered', nar);
                }
            },
            onStateChange: {
                value: function () {
                    var count = this.doState('narratives', function (x) {
                        return x.length;
                    }, null);
                    var filtered = this.doState('narrativesFiltered', function (x) {
                        return x.length;
                    }, null);

                    this.viewState.setItem('publicNarratives', {
                        count: count,
                        filtered: filtered
                    });
                    /*Postal
                     .channel('dashboard.metrics')
                     .publish('update.sharedNarratives', {
                     count: count
                     }
                     );
                     */
                }
            },
            setInitialState: {
                value: function (options) {
                    return Promise.try(function () {
                        // Get all workspaces, filter out those owned by the user,
                        // and those that are public
                        if (!this.runtime.getService('session').isLoggedIn()) {
                            return;
                        }
                        return Promise.all([this.kbservice.getNarratives({
                                params: {
                                    showDeleted: 0,
                                    excludeGlobal: 0
                                }
                            }),
                            this.kbservice.getApps(),
                            this.kbservice.getMethods()])
                            .then(function (result) {
                                var narratives = result[0];
                                var apps = result[1];
                                var methods = result[2];

                                this.setState('apps', apps);
                                var appsMap = {};
                                apps.forEach(function (app) {
                                    appsMap[app.id] = app;
                                });
                                this.setState('appsMap', appsMap);

                                this.setState('methods', methods);
                                var methodsMap = {};
                                methods.forEach(function (method) {
                                    methodsMap[method.id] = method;
                                });
                                this.setState('methodsMap', methodsMap);

                                if (narratives.length === 0) {
                                    this.setState('narratives', []);
                                    return;
                                }

                                // TODO: move this into getNarratives (the hook is there, just not implemented)
                                // filter out those owned by the user, and those which also have some sharing
                                // permission ('n' in this case means "no sharing permission" not "no permission"
                                // because clearly globally shared narratives carrry that permission to everyone!)
                                narratives = narratives.filter(function (x) {
                                    if (x.workspace.owner === this.runtime.getService('session').getUsername() ||
                                        x.workspace.user_permission !== 'n') {
                                        return false;
                                    } else {
                                        return true;
                                    }
                                }.bind(this));

                                return this.kbservice.getPermissions(narratives)
                                    .then(function (narratives) {
                                        narratives = narratives.sort(function (a, b) {
                                            return b.object.saveDate.getTime() - a.object.saveDate.getTime();
                                        });
                                        this.setState('narratives', narratives);
                                        this.setState('narrativesFiltered', narratives);

                                        resolve();
                                    });
                            }.bind(this));
                    }.bind(this));
                }
            }
        });
        return widget;
    });<commit_msg>fix promises usage to avoid bluebird warning <commit_after>/*global
 define, require
 */
/*jslint
 browser: true,
 white: true
 */
define([
    'jquery',
    'kb_dashboard_widget_base',
    'kb/service/serviceApi',
    'kb/widget/widgets/buttonBar',
    'bluebird',
    'bootstrap'
],
    function ($, DashboardWidget, ServiceApi, Buttonbar, Promise) {
        "use strict";
        var widget = Object.create(DashboardWidget, {
            init: {
                value: function (cfg) {
                    cfg.name = 'PublicNarrativesWidget';
                    cfg.title = 'Public Narratives';
                    this.DashboardWidget_init(cfg);

                    // TODO: get this from somewhere, allow user to configure this.
                    this.params.limit = 10;

                    this.view = 'slider';
                    this.templates.env.addFilter('appName', function (x) {
                        return this.getState(['appsMap', x, 'name'], x);
                    }.bind(this));
                    this.templates.env.addFilter('methodName', function (x) {
                        return this.getState(['methodsMap', x, 'name'], x);
                    }.bind(this));
                    return this;
                }
            },
            getAppName: {
                value: function (name) {
                    return this.getState(['appsMap', name, 'name'], name);
                }
            },
            getMethodName: {
                value: function (name) {
                    return this.getState(['methodsMap', name, 'name'], name);
                }
            },
            setup: {
                value: function () {
                    this.kbservice = ServiceApi.make({runtime: this.runtime});
                }
            },
            renderLayout: {
                value: function () {
                    this.container.html(this.renderTemplate('layout'));
                    this.places = {
                        title: this.container.find('[data-placeholder="title"]'),
                        alert: this.container.find('[data-placeholder="alert"]'),
                        content: this.container.find('[data-placeholder="content"]')
                    };

                }
            },
            setupUI: {
                value: function () {
                    if (this.hasState('narratives') && this.getState('narratives').length > 0) {
                        this.buttonbar = Object.create(Buttonbar).init({
                            container: this.container.find('[data-placeholder="buttonbar"]')
                        });
                        this.buttonbar
                            .clear()

                            /*.addRadioToggle({
                             buttons: [
                             {
                             label: 'Slider',
                             active: true,
                             class: 'btn-kbase',
                             callback: function (e) {
                             this.view = 'slider';
                             this.refresh();
                             }.bind(this)
                             },
                             {
                             label: 'Table',
                             class: 'btn-kbase',
                             callback: function (e) {
                             this.view = 'table';
                             this.refresh();
                             }.bind(this)
                             }]
                             })
                             */
                            .addInput({
                                placeholder: 'Search',
                                place: 'end',
                                onkeyup: function (e) {
                                    // little hack to make sure the public narratives is opened up.
                                    var collapse = this.places.title, id;
                                    if (collapse.hasClass('collapsed')) {
                                        id = collapse.attr('data-target');
                                        $(id).collapse('show');
                                    }

                                    this.filterState({
                                        search: $(e.target).val()
                                    });
                                }.bind(this)
                            });
                    }
                }
            },
            render: {
                value: function () {
                    // Generate initial view based on the current state of this widget.
                    // Head off at the pass -- if not logged in, can't show profile.
                    if (this.error) {
                        this.renderError();
                    } else if (this.runtime.getService('session').isLoggedIn()) {
                        this.places.title.html(this.widgetTitle);
                        this.places.content.html(this.renderTemplate(this.view));
                    } else {
                        // no profile, no basic aaccount info
                        this.places.title.html(this.widgetTitle);
                        this.places.content.html(this.renderTemplate('unauthorized'));
                    }
                    var that = this;
                    that.container.find('[data-toggle="popover"]').popover();
                    that.container.find('[data-toggle="tooltip"]').tooltip();
                    //this.container.find('[data-toggle="popover"]').popover();
                    //this.container.find('[data-toggle="tooltip"]').tooltip();
                    return this;
                }
            },
            filterState: {
                value: function (options) {
                    if (!options.search || options.search.length === 0) {
                        this.setState('narrativesFiltered', this.getState('narratives'));
                        return;
                    }
                    var searchRe = new RegExp(options.search, 'i'),
                        nar = this.getState('narratives').filter(function (x) {
                        if (x.workspace.metadata.narrative_nice_name.match(searchRe) ||
                            (x.object.metadata.cellInfo &&
                                (function (apps) {
                                    for (var i in apps) {
                                        var app = apps[i];
                                        if (app.match(searchRe) || this.getAppName(app).match(searchRe)) {
                                            return true;
                                        }
                                    }
                                }.bind(this))(Object.keys(x.object.metadata.cellInfo.app))) ||
                            (x.object.metadata.cellInfo &&
                                (function (methods) {
                                    for (var i in methods) {
                                        var method = methods[i];
                                        if (method.match(searchRe) || this.getMethodName(method).match(searchRe)) {
                                            return true;
                                        }
                                    }
                                }.bind(this))(Object.keys(x.object.metadata.cellInfo.method)))) {
                            return true;
                        } else {
                            return false;
                        }
                    }.bind(this));
                    this.setState('narrativesFiltered', nar);
                }
            },
            onStateChange: {
                value: function () {
                    var count = this.doState('narratives', function (x) {
                        return x.length;
                    }, null);
                    var filtered = this.doState('narrativesFiltered', function (x) {
                        return x.length;
                    }, null);

                    this.viewState.setItem('publicNarratives', {
                        count: count,
                        filtered: filtered
                    });
                    /*Postal
                     .channel('dashboard.metrics')
                     .publish('update.sharedNarratives', {
                     count: count
                     }
                     );
                     */
                }
            },
            setInitialState: {
                value: function (options) {
                    return Promise.try(function () {
                        // Get all workspaces, filter out those owned by the user,
                        // and those that are public
                        if (!this.runtime.getService('session').isLoggedIn()) {
                            return;
                        }
                        return Promise.all([this.kbservice.getNarratives({
                                params: {
                                    showDeleted: 0,
                                    excludeGlobal: 0
                                }
                            }),
                            this.kbservice.getApps(),
                            this.kbservice.getMethods()])
                            .then(function (result) {
                                var narratives = result[0];
                                var apps = result[1];
                                var methods = result[2];

                                this.setState('apps', apps);
                                var appsMap = {};
                                apps.forEach(function (app) {
                                    appsMap[app.id] = app;
                                });
                                this.setState('appsMap', appsMap);

                                this.setState('methods', methods);
                                var methodsMap = {};
                                methods.forEach(function (method) {
                                    methodsMap[method.id] = method;
                                });
                                this.setState('methodsMap', methodsMap);

                                if (narratives.length === 0) {
                                    this.setState('narratives', []);
                                    return;
                                }

                                // TODO: move this into getNarratives (the hook is there, just not implemented)
                                // filter out those owned by the user, and those which also have some sharing
                                // permission ('n' in this case means "no sharing permission" not "no permission"
                                // because clearly globally shared narratives carrry that permission to everyone!)
                                narratives = narratives.filter(function (x) {
                                    if (x.workspace.owner === this.runtime.getService('session').getUsername() ||
                                        x.workspace.user_permission !== 'n') {
                                        return false;
                                    } else {
                                        return true;
                                    }
                                }.bind(this));

                                return this.kbservice.getPermissions(narratives)
                                    .then(function (narratives) {
                                        narratives = narratives.sort(function (a, b) {
                                            return b.object.saveDate.getTime() - a.object.saveDate.getTime();
                                        });
                                        this.setState('narratives', narratives);
                                        this.setState('narrativesFiltered', narratives);

                                        resolve();
                                    }.bind(this));
                            }.bind(this));
                    }.bind(this));
                }
            }
        });
        return widget;
    });<|endoftext|>


<commit_before>angular.module('cesium.es.subscription.services', ['cesium.services', 'cesium.es.http.services'])
.config(function(PluginServiceProvider, csConfig) {
    'ngInject';

    var enable = csConfig.plugins && csConfig.plugins.es;
    if (enable) {
      // Will force to load this service
      PluginServiceProvider.registerEagerLoadingService('esSubscription');
    }

  })

.factory('esSubscription', function($rootScope, $q, $timeout, esHttp, $state, $sce, $sanitize,
                            esSettings, CryptoUtils, UIUtils, csWallet, csWot, BMA, Device, esWallet) {
  'ngInject';
  var
    constants = {
    },
    that = this,
    listeners;

  that.raw = {
    getAll: esHttp.get('/subscription/record/_search?_source_excludes=recipientContent&q=issuer::issuer'),
    count: esHttp.get('/subscription/record/_search?size=0&q=issuer::pubkey'),
    add: esHttp.record.post('/subscription/record'),
    update: esHttp.record.post('/subscription/record/:id/_update'),
    category: {
      get: esHttp.get('/subscription/category/:id'),
      all: esHttp.get('/subscription/category/_search?sort=order&from=0&size=1000&_source=name,parent,key')
    }
  };

  function onWalletReset(data) {
    data.subscriptions = null;
  }

  function onWalletLogin(data, deferred) {
    deferred = deferred || $q.defer();
    if (!data || !data.pubkey || !data.keypair) {
      deferred.resolve();
      return deferred.promise;
    }

    console.debug('[ES] [subscription] Loading subscriptions count...');

    // Load subscriptions count
    that.raw.count({pubkey: data.pubkey})
      .then(function(res) {
        data.subscriptions = data.subscriptions || {};
        data.subscriptions.count = res && res.hits && res.hits.total;
        console.debug('[ES] [subscription] Loaded count (' + data.subscriptions.count  + ')');
        deferred.resolve(data);
      });

    return deferred.promise;
  }

  function loadRecordsByPubkey(issuer, keypair) {
    return that.raw.getAll({issuer: issuer})
      .then(function(res) {
        var records = res && res.hits && res.hits.total &&
          res.hits.hits.reduce(function(res, hit) {
            var record = hit._source;
            record.id = hit._id;
            return res.concat(record);
          }, []) || [];

        return esWallet.box.record.open(records, keypair, 'issuer', 'issuerContent')
          .then(function(records) {
            _.forEach(records, function(record) {
              record.content = JSON.parse(record.issuerContent || '{}');
              delete record.issuerContent;
              delete record.recipientContent;
            });
            return records;
          });
      });
  };

  function addRecord(record) {
    if (!record || !record.type || !record.content || !record.recipient) {
      return $q.reject("Missing arguments 'record' or 'record.type' or 'record.content' or 'record.recipient'");
    }

    var issuer = csWallet.data.pubkey;

    var contentStr = JSON.stringify(record.content);

    // Get a unique nonce
    return CryptoUtils.util.random_nonce()
      // Encrypt contents
      .then(function(nonce) {
        return $q.all([
          esWallet.box.record.pack({issuer: issuer, issuerContent: contentStr}, csWallet.data.keypair, 'issuer', 'issuerContent', nonce),
          esWallet.box.record.pack({recipient: record.recipient, recipientContent: contentStr}, csWallet.data.keypair, 'recipient', 'recipientContent', nonce)
        ]);
      })
      // Merge encrypted record
      .then(function(res){
        var encryptedRecord = angular.merge(res[0], res[1]);
        encryptedRecord.type = record.type;

        // Post subscription
        return that.raw.add(encryptedRecord)
          .then(function(id) {
            record.id = id;
            return record;
          });
      })
      ;
  }

  function updateRecord(record) {
    if (!record || !record.content || !record.recipient) {
      return $q.reject("Missing arguments 'record' or 'record.content', or 'record.recipient'");
    }

    var issuer = csWallet.data.pubkey;
    var contentStr = JSON.stringify(record.content);

    // Get a unique nonce
    return CryptoUtils.util.random_nonce()
    // Encrypt contents
      .then(function(nonce) {
        return $q.all([
          esWallet.box.record.pack({issuer: issuer, issuerContent: contentStr}, csWallet.data.keypair, 'issuer', 'issuerContent', nonce),
          esWallet.box.record.pack({recipient: record.recipient, recipientContent: contentStr}, csWallet.data.keypair, 'recipient', 'recipientContent', nonce)
        ]);
      })
      // Merge encrypted record
      .then(function(res){
        var encryptedRecord = angular.merge(res[0], res[1]);
        encryptedRecord.type = record.type;

        // Post subscription
        return that.raw.update(encryptedRecord, {id:record.id})
          .then(function() {
            return record; // return original record
          });
      })
      ;
  }

  function getCategories() {
    if (that.raw.categories && that.raw.categories.length) {
      var deferred = $q.defer();
      deferred.resolve(that.raw.categories);
      return deferred.promise;
    }

    return that.raw.category.all()
      .then(function(res) {
        if (res.hits.total === 0) {
          that.raw.categories = [];
        }
        else {
          var categories = res.hits.hits.reduce(function(result, hit) {
            var cat = hit._source;
            cat.id = hit._id;
            return result.concat(cat);
          }, []);
          // add as map also
          _.forEach(categories, function(cat) {
            categories[cat.id] = cat;
          });
          that.raw.categories = categories;
        }
        return that.raw.categories;
      });
  }

  function getCategory(params) {
    return that.raw.category.get(params)
      .then(function(hit) {
        var res = hit._source;
        res.id = hit._id;
        return res;
      });
  }

  function removeListeners() {
    _.forEach(listeners, function(remove){
      remove();
    });
    listeners = [];
  }

  function addListeners() {
    // Extend
    listeners = [
      csWallet.api.data.on.login($rootScope, onWalletLogin, this),
      csWallet.api.data.on.init($rootScope, onWalletReset, this),
      csWallet.api.data.on.reset($rootScope, onWalletReset, this)
    ];
  }

  function refreshState() {
    var enable = esHttp.alive;
    if (!enable && listeners && listeners.length > 0) {
      console.debug("[ES] [subscription] Disable");
      removeListeners();
      if (csWallet.isLogin()) {
        return onWalletReset(csWallet.data);
      }
    }
    else if (enable && (!listeners || listeners.length === 0)) {
      console.debug("[ES] [subscription] Enable");
      addListeners();
      if (csWallet.isLogin()) {
        return onWalletLogin(csWallet.data);
      }
    }
  }

  // Default actions
  Device.ready().then(function() {
    esHttp.api.node.on.start($rootScope, refreshState, this);
    esHttp.api.node.on.stop($rootScope, refreshState, this);
    return refreshState();
  });

  // Exports
  that.record = {
    load: loadRecordsByPubkey,
    add: addRecord,
    update: updateRecord,
    remove: esHttp.record.remove('subscription', 'record')
  };
  that.category = {
    all: getCategories,
    get: getCategory
  };
  that.constants = constants;

  return that;
})
;
<commit_msg>JSHint<commit_after>angular.module('cesium.es.subscription.services', ['cesium.services', 'cesium.es.http.services'])
.config(function(PluginServiceProvider, csConfig) {
    'ngInject';

    var enable = csConfig.plugins && csConfig.plugins.es;
    if (enable) {
      // Will force to load this service
      PluginServiceProvider.registerEagerLoadingService('esSubscription');
    }

  })

.factory('esSubscription', function($rootScope, $q, $timeout, esHttp, $state, $sce, $sanitize,
                            esSettings, CryptoUtils, UIUtils, csWallet, csWot, BMA, Device, esWallet) {
  'ngInject';
  var
    constants = {
    },
    that = this,
    listeners;

  that.raw = {
    getAll: esHttp.get('/subscription/record/_search?_source_excludes=recipientContent&q=issuer::issuer'),
    count: esHttp.get('/subscription/record/_search?size=0&q=issuer::pubkey'),
    add: esHttp.record.post('/subscription/record'),
    update: esHttp.record.post('/subscription/record/:id/_update'),
    category: {
      get: esHttp.get('/subscription/category/:id'),
      all: esHttp.get('/subscription/category/_search?sort=order&from=0&size=1000&_source=name,parent,key')
    }
  };

  function onWalletReset(data) {
    data.subscriptions = null;
  }

  function onWalletLogin(data, deferred) {
    deferred = deferred || $q.defer();
    if (!data || !data.pubkey || !data.keypair) {
      deferred.resolve();
      return deferred.promise;
    }

    console.debug('[ES] [subscription] Loading subscriptions count...');

    // Load subscriptions count
    that.raw.count({pubkey: data.pubkey})
      .then(function(res) {
        data.subscriptions = data.subscriptions || {};
        data.subscriptions.count = res && res.hits && res.hits.total;
        console.debug('[ES] [subscription] Loaded count (' + data.subscriptions.count  + ')');
        deferred.resolve(data);
      });

    return deferred.promise;
  }

  function loadRecordsByPubkey(issuer, keypair) {
    return that.raw.getAll({issuer: issuer})
      .then(function(res) {
        var records = res && res.hits && res.hits.total &&
          res.hits.hits.reduce(function(res, hit) {
            var record = hit._source;
            record.id = hit._id;
            return res.concat(record);
          }, []) || [];

        return esWallet.box.record.open(records, keypair, 'issuer', 'issuerContent')
          .then(function(records) {
            _.forEach(records, function(record) {
              record.content = JSON.parse(record.issuerContent || '{}');
              delete record.issuerContent;
              delete record.recipientContent;
            });
            return records;
          });
      });
  }

  function addRecord(record) {
    if (!record || !record.type || !record.content || !record.recipient) {
      return $q.reject("Missing arguments 'record' or 'record.type' or 'record.content' or 'record.recipient'");
    }

    var issuer = csWallet.data.pubkey;

    var contentStr = JSON.stringify(record.content);

    // Get a unique nonce
    return CryptoUtils.util.random_nonce()
      // Encrypt contents
      .then(function(nonce) {
        return $q.all([
          esWallet.box.record.pack({issuer: issuer, issuerContent: contentStr}, csWallet.data.keypair, 'issuer', 'issuerContent', nonce),
          esWallet.box.record.pack({recipient: record.recipient, recipientContent: contentStr}, csWallet.data.keypair, 'recipient', 'recipientContent', nonce)
        ]);
      })
      // Merge encrypted record
      .then(function(res){
        var encryptedRecord = angular.merge(res[0], res[1]);
        encryptedRecord.type = record.type;

        // Post subscription
        return that.raw.add(encryptedRecord)
          .then(function(id) {
            record.id = id;
            return record;
          });
      })
      ;
  }

  function updateRecord(record) {
    if (!record || !record.content || !record.recipient) {
      return $q.reject("Missing arguments 'record' or 'record.content', or 'record.recipient'");
    }

    var issuer = csWallet.data.pubkey;
    var contentStr = JSON.stringify(record.content);

    // Get a unique nonce
    return CryptoUtils.util.random_nonce()
    // Encrypt contents
      .then(function(nonce) {
        return $q.all([
          esWallet.box.record.pack({issuer: issuer, issuerContent: contentStr}, csWallet.data.keypair, 'issuer', 'issuerContent', nonce),
          esWallet.box.record.pack({recipient: record.recipient, recipientContent: contentStr}, csWallet.data.keypair, 'recipient', 'recipientContent', nonce)
        ]);
      })
      // Merge encrypted record
      .then(function(res){
        var encryptedRecord = angular.merge(res[0], res[1]);
        encryptedRecord.type = record.type;

        // Post subscription
        return that.raw.update(encryptedRecord, {id:record.id})
          .then(function() {
            return record; // return original record
          });
      })
      ;
  }

  function getCategories() {
    if (that.raw.categories && that.raw.categories.length) {
      var deferred = $q.defer();
      deferred.resolve(that.raw.categories);
      return deferred.promise;
    }

    return that.raw.category.all()
      .then(function(res) {
        if (res.hits.total === 0) {
          that.raw.categories = [];
        }
        else {
          var categories = res.hits.hits.reduce(function(result, hit) {
            var cat = hit._source;
            cat.id = hit._id;
            return result.concat(cat);
          }, []);
          // add as map also
          _.forEach(categories, function(cat) {
            categories[cat.id] = cat;
          });
          that.raw.categories = categories;
        }
        return that.raw.categories;
      });
  }

  function getCategory(params) {
    return that.raw.category.get(params)
      .then(function(hit) {
        var res = hit._source;
        res.id = hit._id;
        return res;
      });
  }

  function removeListeners() {
    _.forEach(listeners, function(remove){
      remove();
    });
    listeners = [];
  }

  function addListeners() {
    // Extend
    listeners = [
      csWallet.api.data.on.login($rootScope, onWalletLogin, this),
      csWallet.api.data.on.init($rootScope, onWalletReset, this),
      csWallet.api.data.on.reset($rootScope, onWalletReset, this)
    ];
  }

  function refreshState() {
    var enable = esHttp.alive;
    if (!enable && listeners && listeners.length > 0) {
      console.debug("[ES] [subscription] Disable");
      removeListeners();
      if (csWallet.isLogin()) {
        return onWalletReset(csWallet.data);
      }
    }
    else if (enable && (!listeners || listeners.length === 0)) {
      console.debug("[ES] [subscription] Enable");
      addListeners();
      if (csWallet.isLogin()) {
        return onWalletLogin(csWallet.data);
      }
    }
  }

  // Default actions
  Device.ready().then(function() {
    esHttp.api.node.on.start($rootScope, refreshState, this);
    esHttp.api.node.on.stop($rootScope, refreshState, this);
    return refreshState();
  });

  // Exports
  that.record = {
    load: loadRecordsByPubkey,
    add: addRecord,
    update: updateRecord,
    remove: esHttp.record.remove('subscription', 'record')
  };
  that.category = {
    all: getCategories,
    get: getCategory
  };
  that.constants = constants;

  return that;
})
;
<|endoftext|>