<commit_before>/*!
 *  howler.js v1.1.12
 *  howlerjs.com
 *
 *  (c) 2013, James Simpson of GoldFire Studios
 *  goldfirestudios.com
 *
 *  MIT License
 */
!function(){var e={},t=null,n=!0,r=!1;if("undefined"!=typeof AudioContext)t=new AudioContext;else if("undefined"!=typeof webkitAudioContext)t=new webkitAudioContext;else if("undefined"!=typeof Audio){n=!1;try{new Audio}catch(i){r=!0}}else n=!1,r=!0;if(n){var s=void 0===t.createGain?t.createGainNode():t.createGain();s.gain.value=1,s.connect(t.destination)}var o=function(){this._volume=1,this._muted=!1,this.usingWebAudio=n,this._howls=[]};o.prototype={volume:function(e){var t=this;if(e=parseFloat(e),e&&e>=0&&1>=e){t._volume=e,n&&(s.gain.value=e);for(var r in t._howls)if(t._howls.hasOwnProperty(r)&&t._howls[r]._webAudio===!1)for(var i=0;i<t._howls[r]._audioNode.length;i++)t._howls[r]._audioNode[i].volume=t._howls[r]._volume*t._volume;return t}return n?s.gain.value:t._volume},mute:function(){return this._setMuted(!0),this},unmute:function(){return this._setMuted(!1),this},_setMuted:function(e){var t=this;t._muted=e,n&&(s.gain.value=e?0:t._volume);for(var r in t._howls)if(t._howls.hasOwnProperty(r)&&t._howls[r]._webAudio===!1)for(var i=0;i<t._howls[r]._audioNode.length;i++)t._howls[r]._audioNode[i].muted=e}};var u=new o,a=null;if(!r){a=new Audio;var f={mp3:!!a.canPlayType("audio/mpeg;").replace(/^no$/,""),opus:!!a.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/,""),ogg:!!a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),wav:!!a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),m4a:!!(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,""),webm:!!a.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,"")}}var l=function(e){var t=this;t._autoplay=e.autoplay||!1,t._buffer=e.buffer||!1,t._duration=e.duration||0,t._format=e.format||null,t._loop=e.loop||!1,t._loaded=!1,t._sprite=e.sprite||{},t._src=e.src||"",t._pos3d=e.pos3d||[0,0,-.5],t._volume=e.volume||1,t._urls=e.urls||[],t._rate=e.rate||1,t._onload=[e.onload||function(){}],t._onloaderror=[e.onloaderror||function(){}],t._onend=[e.onend||function(){}],t._onpause=[e.onpause||function(){}],t._onplay=[e.onplay||function(){}],t._onendTimer=[],t._webAudio=n&&!t._buffer,t._audioNode=[],t._webAudio&&t._setupAudioNode(),u._howls.push(t)/*,t.load()*/};if(l.prototype={load:function(){var t=this,n=null;if(r)return t.on("loaderror"),void 0;for(var i={mp3:f.mp3,opus:f.opus,ogg:f.ogg,wav:f.wav,m4a:f.m4a,weba:f.webm},s=0;s<t._urls.length;s++){var o;if(t._format?o=t._format:(o=t._urls[s].toLowerCase().match(/.+\.([^?]+)(\?|$)/),o=o&&o.length>=2?o[1]:t._urls[s].toLowerCase().match(/data\:audio\/([^?]+);/)[1]),i[o]){n=t._urls[s];break}}if(!n)return t.on("loaderror"),void 0;if(t._src=n,t._webAudio)c(t,n);else{var a=new Audio;t._audioNode.push(a),a.src=n,a._pos=0,a.preload="auto",a.volume=u._muted?0:t._volume*u.volume(),e[n]=t;var l=function(){t._duration=a.duration,0===Object.getOwnPropertyNames(t._sprite).length&&(t._sprite={_default:[0,1e3*t._duration]}),t._loaded||(t._loaded=!0,t.on("load")),t._autoplay&&t.play(),a.removeEventListener("canplaythrough",l,!1)};a.addEventListener("canplaythrough",l,!1),a.load()}return t},urls:function(e){var t=this;return e?(t.stop(),t._urls="string"==typeof e?[e]:e,t._loaded=!1,t.load(),t):t._urls},play:function(e,n){var r=this;return"function"==typeof e&&(n=e),e&&"function"!=typeof e||(e="_default"),r._loaded?r._sprite[e]?(r._inactiveNode(function(i){i._sprite=e;var s,o=i._pos>0?i._pos:r._sprite[e][0]/1e3,a=r._sprite[e][1]/1e3-i._pos,f=!(!r._loop&&!r._sprite[e][2]),l="string"==typeof n?n:Math.round(Date.now()*Math.random())+"";if(function(){var t={id:l,sprite:e,loop:f};s=setTimeout(function(){!r._webAudio&&f&&r.stop(t.id,t.timer).play(e,t.id),r._webAudio&&!f&&(r._nodeById(t.id).paused=!0),r._webAudio||f||r.stop(t.id,t.timer),r.on("end",l)},1e3*a),r._onendTimer.push(s),t.timer=r._onendTimer[r._onendTimer.length-1]}(),r._webAudio){var c=r._sprite[e][0]/1e3,h=r._sprite[e][1]/1e3;i.id=l,i.paused=!1,p(r,[f,c,h],l),r._playStart=t.currentTime,i.gain.value=r._volume,void 0===i.bufferSource.start?i.bufferSource.noteGrainOn(0,o,a):i.bufferSource.start(0,o,a)}else{if(4!==i.readyState)return r._clearEndTimer(s),function(){var t=r,s=e,o=n,u=i,a=function(){t.play(s,o),u.removeEventListener("canplaythrough",a,!1)};u.addEventListener("canplaythrough",a,!1)}(),r;i.id=l,i.currentTime=o,i.muted=u._muted,i.volume=r._volume*u.volume(),setTimeout(function(){i.play()},0)}return r.on("play"),"function"==typeof n&&n(l),r}),r):("function"==typeof n&&n(),r):(r.on("load",function(){r.play(e,n)}),r)},pause:function(e,t){var n=this;if(!n._loaded)return n.on("play",function(){n.pause(e)}),n;n._clearEndTimer(t||0);var r=e?n._nodeById(e):n._activeNode();if(r)if(r._pos=n.pos(null,e),n._webAudio){if(!r.bufferSource)return n;r.paused=!0,void 0===r.bufferSource.stop?r.bufferSource.noteOff(0):r.bufferSource.stop(0)}else r.pause();return n.on("pause"),n},stop:function(e,t){var n=this;if(!n._loaded)return n.on("play",function(){n.stop(e)}),n;n._clearEndTimer(t||0);var r=e?n._nodeById(e):n._activeNode();if(r)if(r._pos=0,n._webAudio){if(!r.bufferSource)return n;r.paused=!0,void 0===r.bufferSource.stop?r.bufferSource.noteOff(0):r.bufferSource.stop(0)}else r.pause(),r.currentTime=0;return n},mute:function(e){var t=this;if(!t._loaded)return t.on("play",function(){t.mute(e)}),t;var n=e?t._nodeById(e):t._activeNode();return n&&(t._webAudio?n.gain.value=0:n.volume=0),t},unmute:function(e){var t=this;if(!t._loaded)return t.on("play",function(){t.unmute(e)}),t;var n=e?t._nodeById(e):t._activeNode();return n&&(t._webAudio?n.gain.value=t._volume:n.volume=t._volume),t},volume:function(e,t){var n=this;if(e=parseFloat(e),e>=0&&1>=e){if(n._volume=e,!n._loaded)return n.on("play",function(){n.volume(e,t)}),n;var r=t?n._nodeById(t):n._activeNode();return r&&(n._webAudio?r.gain.value=e:r.volume=e*u.volume()),n}return n._volume},loop:function(e){var t=this;return"boolean"==typeof e?(t._loop=e,t):t._loop},sprite:function(e){var t=this;return"object"==typeof e?(t._sprite=e,t):t._sprite},pos:function(e,n){var r=this;if(!r._loaded)return r.on("load",function(){r.pos(e)}),"number"==typeof e?r:r._pos||0;e=parseFloat(e);var i=n?r._nodeById(n):r._activeNode();if(i)return r._webAudio?e>=0?(i._pos=e,r.pause(n).play(i._sprite,n),r):i._pos+(t.currentTime-r._playStart):e>=0?(i.currentTime=e,r):i.currentTime;if(e>=0)return r;for(var s=0;s<r._audioNode.length;s++)if(r._audioNode[s].paused&&4===r._audioNode[s].readyState)return r._webAudio?r._audioNode[s]._pos:r._audioNode[s].currentTime},pos3d:function(e,t,n,r){var i=this;if(t=void 0!==t&&t?t:0,n=void 0!==n&&n?n:-.5,!i._loaded)return i.on("play",function(){i.pos3d(e,t,n,r)}),i;if(!(e>=0||0>e))return i._pos3d;if(i._webAudio){var s=r?i._nodeById(r):i._activeNode();s&&(i._pos3d=[e,t,n],s.panner.setPosition(e,t,n))}return i},fade:function(e,t,n,r,i){var s=this,o=Math.abs(e-t),u=e>t?"down":"up",a=o/.01,f=n/a;if(!s._loaded)return s.on("load",function(){s.fade(e,t,n,r,i)}),s;s.volume(e,i);for(var l=1;a>=l;l++)!function(){var e=s._volume+("up"===u?.01:-.01)*l,n=Math.round(1e3*e)/1e3,o=t;setTimeout(function(){s.volume(n,i),n===o&&r&&r()},f*l)}()},fadeIn:function(e,t,n){return this.volume(0).play().fade(0,e,t,n)},fadeOut:function(e,t,n,r){var i=this;return i.fade(i._volume,e,t,function(){n&&n(),i.pause(r),i.on("end")},r)},_nodeById:function(e){for(var t=this,n=t._audioNode[0],r=0;r<t._audioNode.length;r++)if(t._audioNode[r].id===e){n=t._audioNode[r];break}return n},_activeNode:function(){for(var e=this,t=null,n=0;n<e._audioNode.length;n++)if(!e._audioNode[n].paused){t=e._audioNode[n];break}return e._drainPool(),t},_inactiveNode:function(e){for(var t=this,n=null,r=0;r<t._audioNode.length;r++)if(t._audioNode[r].paused&&4===t._audioNode[r].readyState){e(t._audioNode[r]),n=!0;break}if(t._drainPool(),!n){var i;t._webAudio?(i=t._setupAudioNode(),e(i)):(t.load(),i=t._audioNode[t._audioNode.length-1],i.addEventListener("loadedmetadata",function(){e(i)}))}},_drainPool:function(){var e,t=this,n=0;for(e=0;e<t._audioNode.length;e++)t._audioNode[e].paused&&n++;for(e=t._audioNode.length-1;e>=0&&!(5>=n);e--)t._audioNode[e].paused&&(t._webAudio&&t._audioNode[e].disconnect(0),n--,t._audioNode.splice(e,1))},_clearEndTimer:function(e){var t=this,n=t._onendTimer.indexOf(e);n=n>=0?n:0,t._onendTimer[n]&&(clearTimeout(t._onendTimer[n]),t._onendTimer.splice(n,1))},_setupAudioNode:function(){var e=this,n=e._audioNode,r=e._audioNode.length;return n[r]=void 0===t.createGain?t.createGainNode():t.createGain(),n[r].gain.value=e._volume,n[r].paused=!0,n[r]._pos=0,n[r].readyState=4,n[r].connect(s),n[r].panner=t.createPanner(),n[r].panner.setPosition(e._pos3d[0],e._pos3d[1],e._pos3d[2]),n[r].panner.connect(n[r]),n[r]},on:function(e,t){var n=this,r=n["_on"+e];if("function"==typeof t)r.push(t);else for(var i=0;i<r.length;i++)t?r[i].call(n,t):r[i].call(n);return n},off:function(e,t){for(var n=this,r=n["_on"+e],i=""+t,s=0;s<r.length;s++)if(i===""+r[s]){r.splice(s,1);break}return n},unload:function(){for(var t=this,n=t._audioNode,r=0;r<t._audioNode.length;r++)t.stop(n[r].id),t._webAudio?n[r].disconnect(0):n[r].src="";var i=u._howls.indexOf(t);i&&u._howls.splice(i,1),delete e[t._src],t=null}},n)var c=function(n,r){if(r in e)n._duration=e[r].duration,h(n);else{var i=new XMLHttpRequest;i.open("GET",r,!0),i.responseType="arraybuffer",i.onload=function(){t.decodeAudioData(i.response,function(t){t&&(e[r]=t,h(n,t))})},i.onerror=function(){n._webAudio&&(n._buffer=!0,n._webAudio=!1,n._audioNode=[],delete n._gainNode,n.load())};try{i.send()}catch(s){i.onerror()}}},h=function(e,t){e._duration=t?t.duration:e._duration,0===Object.getOwnPropertyNames(e._sprite).length&&(e._sprite={_default:[0,1e3*e._duration]}),e._loaded||(e._loaded=!0,e.on("load")),e._autoplay&&e.play()},p=function(n,r,i){var s=n._nodeById(i);s.bufferSource=t.createBufferSource(),s.bufferSource.buffer=e[n._src],s.bufferSource.connect(s.panner),s.bufferSource.loop=r[0],r[0]&&(s.bufferSource.loopStart=r[1],s.bufferSource.loopEnd=r[1]+r[2]),s.bufferSource.playbackRate.value=n._rate};"function"==typeof define&&define.amd&&define(function(){return{Howler:u,Howl:l}}),window.Howler=u,window.Howl=l}()<commit_msg>removed duplicate Howler<commit_after><|endoftext|>


<commit_before>var React = require('react-native');
var precomputeStyle = require('precomputeStyle');
var logError = require('logError');
var LoadingActivityIndicatorIOS = require('./indicators/LoadingActivityIndicatorIOS');
var isPromise = require('is-promise')

var {
  ListView,
  View,
  Text,
  ActivityIndicatorIOS,
  StyleSheet,
  cloneElement
} = React;

let FIXED = 'fixed';
let TOP = 'top';

changeProps = (instance, props) => {
    if (!instance) return;
    Object.keys(props).forEach(function (key) {
        instance.props[key] = props[key];
    });
    instance.forceUpdate()
}

class RefresherListView extends React.Component {
    constructor() {
        super();
        this.state = {
            threshold: 0,
            top: 0,
        }
    }

    onResponderGrant(e) {
        this.props.onResponderGrant && this.props.onResponderGrant(...arguments);
        if (!this.top) {
            this.top = this.top || e.nativeEvent.contentInset.top;
            this.setState({top:this.top});
        }
        this.state.threshold = 0;
        this.scrolling = true;
    }

    onResponderRelease() {
        this.props.onResponderRelease && this.props.onResponderRelease(...arguments);
        this.scrolling = false;
        if (!this.props.refreshOnRelease && !this.scrolling) return;
        this._doLoading();
    }

    getScrollResponder() {
        return this.refs.listview.getScrollResponder();
    }

    setNativeProps(props) {
        this.refs.listview.setNativeProps(props)
    }

    handleRefresh() {
        // Code inspired by
        // react-native-refreshable-listview
        // https://github.com/jsdf/react-native-refreshable-listview/blob/master/lib/RefreshableListView.js#L37

        if (this.willRefresh) return

        this.willRefresh = true

        var loadingPromise = new Promise((resolve) => {
            var refreshReturnValue = this.props.onRefresh(resolve)

            if (isPromise(refreshReturnValue)) {
                loadingPromise = refreshReturnValue
            }

            var delay = (time) => new Promise((resolve) => setTimeout(resolve, time));

            Promise.all([
                loadingPromise,
                new Promise((resolve) => {
                    this.isLoading = true;
                    this.setState(resolve)
                }),
                delay(this.props.minTime),
            ])
            .then(() => {
                this.willRefresh = false;
                this.isLoading = false;
                this._hideLoading();
            })
        })
    }

    onScroll(e) {
        this.props.onScroll && this.props.onScroll();

        let offsetY = e.nativeEvent.contentInset.top + e.nativeEvent.contentOffset.y
        if (this.isLoading || this.lastOffsetY==offsetY) return;

        let listviewscroll = this.getScrollResponder();
        let threshold = Math.max(Math.min(-offsetY/this.getIndicatorHeight(),1),0);
        let status = (threshold>=this.state.threshold&&!listviewscroll.scrollResponderIsAnimating()||this.scrolling)?'pull':null;

        this.state.loadingStatus = status;
        this.state.threshold = threshold;
        changeProps(this.refs.indicator, {threshold, status});

        this.lastOffsetY = offsetY;

        if (!this.scrolling) return;
        if (!this.props.refreshOnRelease && this.state.threshold >=1) {
            this._doLoading();
            return;
        }
    }

    requestAnimationFrame() {
        this.refs.listview.requestAnimationFrame(...arguments);
    }

    _hideLoading() {
        console.log('_hideLoading')
        let listviewscroll = this.getScrollResponder();

        setTimeout(() => {
            this.updateUIThreshold(0);
        },300)

        setTimeout(() => {
            this.requestAnimationFrame(() => {
                if (!this.scrolling && !listviewscroll.scrollResponderIsAnimating() && this.lastOffsetY<this.top) {
                    listviewscroll.scrollTo(-this.top)
                }
            });
        },50)
    }

    updateUIThreshold(threshold) {
        let listview = this.refs.listview;
        let listviewscroll = listview.getScrollResponder();
        this.requestAnimationFrame(() => {
            listviewscroll.setNativeProps(precomputeStyle({contentInset:{top:threshold}}));
            listviewscroll.refs.InnerScrollView.setNativeProps(precomputeStyle({paddingTop:threshold}))
            listview.setNativeProps(precomputeStyle({top:-threshold,bottom:0}))
        });
    }

    _doLoading(){
        if (this.willRefresh || this.isLoading || this.state.threshold<1) return;

        this.updateUIThreshold(this.getIndicatorHeight());

        this.state.loadingStatus = 'loading';
        this.state.threshold = 1;

        changeProps(this.refs.indicator, {status: this.state.loadingStatus, threshold:this.state.threshold});

        this.handleRefresh()
    }

    _getIndicatorPosition() {
        return this.props.indicatorPosition || this.props.indicator.props.position || this.props.indicator.position || FIXED;
    }

    _isIndicatorFixed() {
        return this._getIndicatorPosition() == FIXED;
    }
    getIndicatorHeight() {
        return this.props.threshold == 'auto' ?
        (this.refs.indicator && this.refs.indicator.props.height) || this.props.indicator.props.height
        : parseInt(this.props.threshold);
    }
    renderHeader() {
        if (this._isIndicatorFixed()) {
            // Render the default ListView header if the indicator position is fixed
            return this.props.renderHeader && this.props.renderHeader();
        }
        return (<View style={{height:this.getIndicatorHeight(), flex:1, alignItems:'flex-end', flexDirection:'row', marginTop:-this.getIndicatorHeight()}}>
            <View style={{flex:1}}>
                {this.renderIndicator()}
            </View>
        </View>);
    }

    renderIndicator() {
        let Indicator = this.props.indicator;
        return cloneElement(Indicator, {
            ref: (indicator => {this.refs.indicator = indicator || this.refs.indicator}.bind(this)),
            status: this.state.loadingStatus,
            height: this.getIndicatorHeight(),
            threshold: this.state.threshold
        });
    }

    render() {
        let Component = this.props.component;
        return (<View style={[{flex:1}, this.props.style]}>
                <View style={[styles.fixedLoaderWrapper, {marginTop:this.top||0}]}>
                    {this._isIndicatorFixed()?this.renderIndicator():null}
                </View>
                <Component {...this.props}
                style={this.props.listStyle}
                onResponderRelease={this.onResponderRelease.bind(this)}
                onResponderGrant={this.onResponderGrant.bind(this)}
                renderHeader={this.renderHeader.bind(this)}
                ref="listview"
                onScroll={this.onScroll.bind(this)}
                />
            </View>);
    }
}

var styles = StyleSheet.create({
    fixedLoaderWrapper: {
        position:'absolute',
        flex:1,
        top:0,
        marginTop:0,
        left:0,
        right:0
    },
    list: {
        backgroundColor:'transparent',
        position:'absolute',
        top:0,
        bottom:0,
        left:0,
        right:0
    }
});

RefresherListView.defaultProps = {
    threshold: 'auto',
    component: ListView,
    minTime: 320,
    indicator: <LoadingActivityIndicatorIOS />,
    refreshOnRelease: false,
    listStyle: styles.list,
};

RefresherListView.DataSource = ListView.DataSource;

module.exports = RefresherListView
<commit_msg>Fixed #2 - Not contentInset object in nativeEvent<commit_after>var React = require('react-native');
var precomputeStyle = require('precomputeStyle');
var logError = require('logError');
var LoadingActivityIndicatorIOS = require('./indicators/LoadingActivityIndicatorIOS');
var isPromise = require('is-promise')

var {
  ListView,
  View,
  Text,
  ActivityIndicatorIOS,
  StyleSheet,
  cloneElement
} = React;

let FIXED = 'fixed';
let TOP = 'top';

changeProps = (instance, props) => {
    if (!instance) return;
    Object.keys(props).forEach(function (key) {
        instance.props[key] = props[key];
    });
    instance.forceUpdate()
}

class RefresherListView extends React.Component {
    constructor() {
        super();
        this.state = {
            threshold: 0,
            top: 0,
        }
    }

    onResponderGrant(e) {
        this.props.onResponderGrant && this.props.onResponderGrant(...arguments);
        if (!this.top) {
            this.top = this.top || (e.nativeEvent.contentInset && e.nativeEvent.contentInset.top);
            this.setState({top:this.top});
        }
        this.state.threshold = 0;
        this.scrolling = true;
    }

    onResponderRelease() {
        this.props.onResponderRelease && this.props.onResponderRelease(...arguments);
        this.scrolling = false;
        if (!this.props.refreshOnRelease && !this.scrolling) return;
        this._doLoading();
    }

    getScrollResponder() {
        return this.refs.listview.getScrollResponder();
    }

    setNativeProps(props) {
        this.refs.listview.setNativeProps(props)
    }

    handleRefresh() {
        // Code inspired by
        // react-native-refreshable-listview
        // https://github.com/jsdf/react-native-refreshable-listview/blob/master/lib/RefreshableListView.js#L37

        if (this.willRefresh) return

        this.willRefresh = true

        var loadingPromise = new Promise((resolve) => {
            var refreshReturnValue = this.props.onRefresh(resolve)

            if (isPromise(refreshReturnValue)) {
                loadingPromise = refreshReturnValue
            }

            var delay = (time) => new Promise((resolve) => setTimeout(resolve, time));

            Promise.all([
                loadingPromise,
                new Promise((resolve) => {
                    this.isLoading = true;
                    this.setState(resolve)
                }),
                delay(this.props.minTime),
            ])
            .then(() => {
                this.willRefresh = false;
                this.isLoading = false;
                this._hideLoading();
            })
        })
    }

    onScroll(e) {
        this.props.onScroll && this.props.onScroll();

        let offsetY = e.nativeEvent.contentInset.top + e.nativeEvent.contentOffset.y
        if (this.isLoading || this.lastOffsetY==offsetY) return;

        let listviewscroll = this.getScrollResponder();
        let threshold = Math.max(Math.min(-offsetY/this.getIndicatorHeight(),1),0);
        let status = (threshold>=this.state.threshold&&!listviewscroll.scrollResponderIsAnimating()||this.scrolling)?'pull':null;

        this.state.loadingStatus = status;
        this.state.threshold = threshold;
        changeProps(this.refs.indicator, {threshold, status});

        this.lastOffsetY = offsetY;

        if (!this.scrolling) return;
        if (!this.props.refreshOnRelease && this.state.threshold >=1) {
            this._doLoading();
            return;
        }
    }

    requestAnimationFrame() {
        this.refs.listview.requestAnimationFrame(...arguments);
    }

    _hideLoading() {
        console.log('_hideLoading')
        let listviewscroll = this.getScrollResponder();

        setTimeout(() => {
            this.updateUIThreshold(0);
        },300)

        setTimeout(() => {
            this.requestAnimationFrame(() => {
                if (!this.scrolling && !listviewscroll.scrollResponderIsAnimating() && this.lastOffsetY<this.top) {
                    listviewscroll.scrollTo(-this.top)
                }
            });
        },50)
    }

    updateUIThreshold(threshold) {
        let listview = this.refs.listview;
        let listviewscroll = listview.getScrollResponder();
        this.requestAnimationFrame(() => {
            listviewscroll.setNativeProps(precomputeStyle({contentInset:{top:threshold}}));
            listviewscroll.refs.InnerScrollView.setNativeProps(precomputeStyle({paddingTop:threshold}))
            listview.setNativeProps(precomputeStyle({top:-threshold,bottom:0}))
        });
    }

    _doLoading(){
        if (this.willRefresh || this.isLoading || this.state.threshold<1) return;

        this.updateUIThreshold(this.getIndicatorHeight());

        this.state.loadingStatus = 'loading';
        this.state.threshold = 1;

        changeProps(this.refs.indicator, {status: this.state.loadingStatus, threshold:this.state.threshold});

        this.handleRefresh()
    }

    _getIndicatorPosition() {
        return this.props.indicatorPosition || this.props.indicator.props.position || this.props.indicator.position || FIXED;
    }

    _isIndicatorFixed() {
        return this._getIndicatorPosition() == FIXED;
    }
    getIndicatorHeight() {
        return this.props.threshold == 'auto' ?
        (this.refs.indicator && this.refs.indicator.props.height) || this.props.indicator.props.height
        : parseInt(this.props.threshold);
    }
    renderHeader() {
        if (this._isIndicatorFixed()) {
            // Render the default ListView header if the indicator position is fixed
            return this.props.renderHeader && this.props.renderHeader();
        }
        return (<View style={{height:this.getIndicatorHeight(), flex:1, alignItems:'flex-end', flexDirection:'row', marginTop:-this.getIndicatorHeight()}}>
            <View style={{flex:1}}>
                {this.renderIndicator()}
            </View>
        </View>);
    }

    renderIndicator() {
        let Indicator = this.props.indicator;
        return cloneElement(Indicator, {
            ref: (indicator => {this.refs.indicator = indicator || this.refs.indicator}.bind(this)),
            status: this.state.loadingStatus,
            height: this.getIndicatorHeight(),
            threshold: this.state.threshold
        });
    }

    render() {
        let Component = this.props.component;
        return (<View style={[{flex:1}, this.props.style]}>
                <View style={[styles.fixedLoaderWrapper, {marginTop:this.top||0}]}>
                    {this._isIndicatorFixed()?this.renderIndicator():null}
                </View>
                <Component {...this.props}
                style={this.props.listStyle}
                onResponderRelease={this.onResponderRelease.bind(this)}
                onResponderGrant={this.onResponderGrant.bind(this)}
                renderHeader={this.renderHeader.bind(this)}
                ref="listview"
                onScroll={this.onScroll.bind(this)}
                />
            </View>);
    }
}

var styles = StyleSheet.create({
    fixedLoaderWrapper: {
        position:'absolute',
        flex:1,
        top:0,
        marginTop:0,
        left:0,
        right:0
    },
    list: {
        backgroundColor:'transparent',
        position:'absolute',
        top:0,
        bottom:0,
        left:0,
        right:0
    }
});

RefresherListView.defaultProps = {
    threshold: 'auto',
    component: ListView,
    minTime: 320,
    indicator: <LoadingActivityIndicatorIOS />,
    refreshOnRelease: false,
    listStyle: styles.list,
};

RefresherListView.DataSource = ListView.DataSource;

module.exports = RefresherListView
<|endoftext|>


<commit_before>
(function(window, angular, undefined) {'use strict';
// define ngTouch module
/* global -ngTouch */
var ngTouch = angular.module('ngTouch', []);

/**
 * @ngdoc directive
 * @name ngClick
 *
 * @description
 * A more powerful replacement for the default ngClick designed to be used on touchscreen
 * devices. Most mobile browsers wait about 300ms after a tap-and-release before sending
 * the click event. This version handles them immediately, and then prevents the
 * following click event from propagating.
 *
 * Requires the {@link ngTouch `ngTouch`} module to be installed.
 *
 * This directive can fall back to using an ordinary click event, and so works on desktop
 * browsers as well as mobile.
 *
 * This directive also sets the CSS class `ng-click-active` while the element is being held
 * down (by a mouse click or touch) so you can restyle the depressed element if you wish.
 *
 * @element ANY
 * @param {expression} ngClick {@link guide/expression Expression} to evaluate
 * upon tap. (Event object is available as `$event`)
 *
 * @example
    <example module="ngClickExample" deps="angular-touch.js">
      <file name="index.html">
        <button ng-click="count = count + 1" ng-init="count=0">
          Increment
        </button>
        count: {{ count }}
      </file>
      <file name="script.js">
        angular.module('ngClickExample', ['ngTouch']);
      </file>
    </example>
 */
ngTouch.config(['$provide', function($provide) {
  $provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
    // drop the default ngClick directive
    $delegate.shift();
    return $delegate;
  }]);
}]);

// redefine the ngClick directive
ngTouch.directive('ngClick', ['$parse',
  function($parse) {
    // Actual linking function.
    return function(scope, element, attr) {
      // parse the function to be executed on click
      var fn = $parse(attr.ngClick);
      // attach the modified fastclick handler to this element (needs the real domNode)
      FastClick.attach(element[0]);
      // listen to the click events (fired by Fastclick or per browser default)
      // and execute the action accordingly
      element.on('click', function(event) {
        scope.$apply(function() {
          fn(scope, {$event:event});
        });
      });
    };
  }]
);

})(window, window.angular);
<commit_msg>add class to fastclickable elements (for easier styling)<commit_after>
(function(window, angular, undefined) {'use strict';
// define ngTouch module
/* global -ngTouch */
var ngTouch = angular.module('ngTouch', []);

/**
 * @ngdoc directive
 * @name ngClick
 *
 * @description
 * A more powerful replacement for the default ngClick designed to be used on touchscreen
 * devices. Most mobile browsers wait about 300ms after a tap-and-release before sending
 * the click event. This version handles them immediately, and then prevents the
 * following click event from propagating.
 *
 * Requires the {@link ngTouch `ngTouch`} module to be installed.
 *
 * This directive can fall back to using an ordinary click event, and so works on desktop
 * browsers as well as mobile.
 *
 * This directive also sets the CSS class `ng-click-active` while the element is being held
 * down (by a mouse click or touch) so you can restyle the depressed element if you wish.
 *
 * @element ANY
 * @param {expression} ngClick {@link guide/expression Expression} to evaluate
 * upon tap. (Event object is available as `$event`)
 *
 * @example
    <example module="ngClickExample" deps="angular-touch.js">
      <file name="index.html">
        <button ng-click="count = count + 1" ng-init="count=0">
          Increment
        </button>
        count: {{ count }}
      </file>
      <file name="script.js">
        angular.module('ngClickExample', ['ngTouch']);
      </file>
    </example>
 */
ngTouch.config(['$provide', function($provide) {
  $provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
    // drop the default ngClick directive
    $delegate.shift();
    return $delegate;
  }]);
}]);

// redefine the ngClick directive
ngTouch.directive('ngClick', ['$parse',
  function($parse) {
    // Actual linking function.
    return function(scope, element, attr) {
      // parse the function to be executed on click
      var fn = $parse(attr.ngClick);
      // attach the modified fastclick handler to this element (needs the real domNode)
      FastClick.attach(element[0]);
      // attach a specific class to the clickable element indicating that it is handled via fastclick
      element.addClass('fastclickable');
      // listen to the click events (fired by Fastclick or per browser default)
      // and execute the action accordingly
      element.on('click', function(event) {
        scope.$apply(function() {
          fn(scope, {$event:event});
        });
      });
    };
  }]
);

})(window, window.angular);
<|endoftext|>


<commit_before>var resolver = require('../resolver');
var Deferred = require('jsdeferred').Deferred;

var VERSION_2011_02_01 = exports.VERSION_2011_02_01 = '2011-02-01';

var handlers = Object.create(null);
handlers[VERSION_2011_02_01] = Object.create(null);

handlers[VERSION_2011_02_01].CreateDomain = function(database, request, response) {
  // FIXME just an example
  var domain = request.query.DomainName || '';
  var tableName = resolver.getTableNameFromDomain(domain);
  var options = {
        name: tableName,
        flags: 'TABLE_HASH_KEY',
        key_type: 'ShortText'
      };
  database.commandDeferred('table_create', options)
    .next(function(data) {
      var termsOptions = {
            name: resolver.getTermsTableNameFromDomain(domain),
            flags: 'TABLE_PAT_KEY|KEY_NORMALIZE',
            key_type: 'ShortText',
            default_tokenizer: 'TokenBigram'
          };
      return database.commandDeferred('table_create', termsOptions)
               .next(function() {
                 response.send('created ' + domain);
               });
    })
    .error(function(error) {
      return response.send(error.message, 400);
    });
};

handlers[VERSION_2011_02_01].DefineIndexField = function(database, request, response) {
  var domain = request.query.DomainName || '';
  var tableName = resolver.getTableNameFromDomain(domain);

  var field = request.query['IndexField.IndexFieldName'] || '';
  var columnName = resolver.getColumnNameFromField(field);

  var options = {
        table: tableName,
        name: columnName,
        flags: 'COLUMN_SCALAR',
        type: 'ShortText'
      };
  database.commandDeferred('column_create', options)
    .next(function(data) {
      var termsOptions = {
            table: resolver.getTermsTableNameFromDomain(domain),
            name: tableName + '_' + columnName,
            flags: 'COLUMN_INDEX|WITH_POSITION',
            type: tableName,
            source: columnName
          };
      return database.commandDeferred('column_create', termsOptions)
               .next(function() {
                 response.send('created index field "' + field + '" ' +
                               'for the domain "' + domain + '"');
               });
    })
    .error(function(error) {
      return response.send(error.message, 400);
    });
};

exports.createHandler = function(database) {
  return function(request, response) {
    var version = request.query.Version;
    if (!version)
      return response.send('API version must be given as the parameter "Version".', 400);

    if (!(version in handlers))
      return response.send('API version "' + version + '" is not supported.', 400);

    var action = request.query.Action || '';
    if (!action)
      return response.send('Action must be given as the parameter "Action".', 400);

    if (!(action in handlers[version]))
      return response.send('Action "' + action + '" is not supported.', 400);

    var handler = handlers[version][action];
    handler(database, request, response);
  };
};
<commit_msg>Remove whitespaces<commit_after>var resolver = require('../resolver');
var Deferred = require('jsdeferred').Deferred;

var VERSION_2011_02_01 = exports.VERSION_2011_02_01 = '2011-02-01';

var handlers = Object.create(null);
handlers[VERSION_2011_02_01] = Object.create(null);

handlers[VERSION_2011_02_01].CreateDomain = function(database, request, response) {
  // FIXME just an example
  var domain = request.query.DomainName || '';
  var tableName = resolver.getTableNameFromDomain(domain);
  var options = {
        name: tableName,
        flags: 'TABLE_HASH_KEY',
        key_type: 'ShortText'
      };
  database.commandDeferred('table_create', options)
    .next(function(data) {
      var termsOptions = {
            name: resolver.getTermsTableNameFromDomain(domain),
            flags: 'TABLE_PAT_KEY|KEY_NORMALIZE',
            key_type: 'ShortText',
            default_tokenizer: 'TokenBigram'
          };
      return database.commandDeferred('table_create', termsOptions)
               .next(function() {
                 response.send('created ' + domain);
               });
    })
    .error(function(error) {
      return response.send(error.message, 400);
    });
};

handlers[VERSION_2011_02_01].DefineIndexField = function(database, request, response) {
  var domain = request.query.DomainName || '';
  var tableName = resolver.getTableNameFromDomain(domain);

  var field = request.query['IndexField.IndexFieldName'] || '';
  var columnName = resolver.getColumnNameFromField(field);

  var options = {
        table: tableName,
        name: columnName,
        flags: 'COLUMN_SCALAR',
        type: 'ShortText'
      };
  database.commandDeferred('column_create', options)
    .next(function(data) {
      var termsOptions = {
            table: resolver.getTermsTableNameFromDomain(domain),
            name: tableName + '_' + columnName,
            flags: 'COLUMN_INDEX|WITH_POSITION',
            type: tableName,
            source: columnName
          };
      return database.commandDeferred('column_create', termsOptions)
               .next(function() {
                 response.send('created index field "' + field + '" ' +
                               'for the domain "' + domain + '"');
               });
    })
    .error(function(error) {
      return response.send(error.message, 400);
    });
};

exports.createHandler = function(database) {
  return function(request, response) {
    var version = request.query.Version;
    if (!version)
      return response.send('API version must be given as the parameter "Version".', 400);

    if (!(version in handlers))
      return response.send('API version "' + version + '" is not supported.', 400);

    var action = request.query.Action || '';
    if (!action)
      return response.send('Action must be given as the parameter "Action".', 400);

    if (!(action in handlers[version]))
      return response.send('Action "' + action + '" is not supported.', 400);

    var handler = handlers[version][action];
    handler(database, request, response);
  };
};
<|endoftext|>


<commit_before>var fs = require('fs');
var zlib = require('zlib');
var UglifyJS = require('uglify-js');

function wrapScript(module, scriptPath, callback) {

    var relPath = module.getVersionPath() + scriptPath;
    var absPath = M.config.MODULE_ROOT + relPath;

    fs.readFile(absPath, function(err, data) {

        if (err) { return callback(err); }

        var content =
            'M.wrap(\'' + relPath + '\', function (require, module, exports) {\n' +
            data.toString() + '\n' +
            'return module; });';

        if (M.config.compressFiles) {

            zlib.gzip(UglifyJS.minify(content, {fromString: true}).code, function (err, content) {

                fs.writeFile(absPath, content, callback);
            });

        } else {
            fs.writeFile(absPath, content, callback);
        }
    });
}

function minify (path, rename, callback) {

    callback = callback || (typeof rename === 'function' ? rename : function () {});

    fs.readFile(path, 'utf8', function(err, data) {

        if (err) { return callback(err); }

        zlib.gzip(UglifyJS.minify(data, {fromString: true}).code, function (err, data) {

            if (rename === true) {
                path = path.split('.')[0] + '.min.gz';
            }

            fs.writeFile(path, data, callback);
        });
    });
}

exports.wrapScript = wrapScript;
exports.minify = minify;
<commit_msg>Minor string concat change<commit_after>var fs = require('fs');
var zlib = require('zlib');
var UglifyJS = require('uglify-js');

function wrapScript(module, scriptPath, callback) {

    var relPath = module.getVersionPath() + scriptPath;
    var absPath = M.config.MODULE_ROOT + relPath;

    fs.readFile(absPath, function(err, data) {

        if (err) { return callback(err); }

        var content =
            'M.wrap(\'' + relPath + '\', function (require, module, exports) {\n' +
            data.toString() +
            '\nreturn module; });';

        if (M.config.compressFiles) {

            zlib.gzip(UglifyJS.minify(content, {fromString: true}).code, function (err, content) {

                fs.writeFile(absPath, content, callback);
            });

        } else {
            fs.writeFile(absPath, content, callback);
        }
    });
}

function minify (path, rename, callback) {

    callback = callback || (typeof rename === 'function' ? rename : function () {});

    fs.readFile(path, 'utf8', function(err, data) {

        if (err) { return callback(err); }

        zlib.gzip(UglifyJS.minify(data, {fromString: true}).code, function (err, data) {

            if (rename === true) {
                path = path.split('.')[0] + '.min.gz';
            }

            fs.writeFile(path, data, callback);
        });
    });
}

exports.wrapScript = wrapScript;
exports.minify = minify;
<|endoftext|>


<commit_before>// React
import React, {PropTypes} from 'react';
import ReactDOM from 'react-dom';
import {Component, Provider, ApplicationComponent} from 'tide/components';
import {Router, Route, browserHistory, Link} from 'react-router';
import {Button} from 'orion/ui/helpers';
import {Tooltip} from 'orion/ui/tooltip';
import {StyleGuidePage} from 'orion/base/layout';

export class BaseComponents extends StyleGuidePage {
    sidebar() {
        return (

 ← Home

Avatars

Spinners

Cards

Tabs

Tooltips

Modals

        )
    }

    avatars(){
        return(

Avatars

Username

Username

        )
    }

    spinners(){
        return (

Loading...

Loading...

        )
    }

    cards() {
        return (

Cards

Lorem Ipsum is simply dummy text of the printing and
                          typesetting industry.

                      Tag
                      Long Tag
                      Tag
                      Tag
                      Tag
                      Tag

Lorem Ipsum is simply dummy text of the printing and
                          typesetting industry.

                      Tag
                      Tag
                      TagTag

Lorem Ipsum is simply dummy text of the printing and
                          typesetting industry.

                      Tag
                      Tag
                      Tag
                      Tag

Lorem Ipsum is simply dummy text of the
                              printing and typesetting industry.

Lorem Ipsum is simply dummy text of

Lorem Ipsum is simply dummy text of

                         <button className="l-btn-ghost l-btn-ghost--small">Follow</button>

Username

June 17, 2015

Lorem Ipsum is simply dummy text of the printing
                              and typesetting industry. Lorem Ipsum has been the industry standard dummy text ever since the 1500s, when an unknown printer took a
                              galley of type and scrambled it to make a type specimen book.

                          Read more

        )
    }

    tabs(){
        return (

Tabs

Tab Active

Tab Hover

Tab Default

Tab Default

        )
    }

    tooltips() {
        return (

Tooltips

                  A tooltip can be placed upon a text item.

                  <Tooltip text="top" position="top">

                          Lorem Ipsum is simply dummy text of the printing and typesetting industry.
                           Learn More

                  </Tooltip>
                  ...
                  <Tooltip text="left" position="left">
Lorem Ipsum.
</Tooltip>
                  ...
                  <Tooltip text="bottom" position="bottom">
Lorem Ipsum.
</Tooltip>
                  ...
                  <Tooltip text="right" position="right">
Lorem Ipsum.
</Tooltip>

                  It can also be generated with custom HTML async its contents.
                  <Tooltip containerWidth="100px" html={
HTML
} position="right">

Lorem Ipsum. pew pew brap brap

                  </Tooltip>

                  <Tooltip  html={<Button>A tooltip on a button</Button>} position="bottom">

Lorem Ipsum.

                  </Tooltip>

        )
    }

    modals() {
        return (

Modals

 Open this modal

        )
    }

    main() {
        return [
          this.avatars(),
          this.spinners(),
          this.cards(),
          this.tabs(),
          this.tooltips(),
          this.modals()
        ]
    }
}
<commit_msg>Reformatting + Move Sidebar<commit_after>// React
import React, {PropTypes} from 'react';
import ReactDOM from 'react-dom';
import {Component, Provider, ApplicationComponent} from 'tide/components';
import {Router, Route, browserHistory, Link} from 'react-router';
import {Button} from 'orion/ui/helpers';
import {Tooltip} from 'orion/ui/tooltip';
import {StyleGuidePage} from 'orion/base/layout';

export class BaseComponents extends StyleGuidePage {

    avatars() {
        return (

Avatars

Username

Username

        )
    }

    spinners() {
        return (

Loading...

Loading...

        )
    }

    cards() {
        return (

Cards

Lorem Ipsum is simply dummy text of the
                            printing and
                            typesetting industry.

                        Tag
                        Long Tag
                        Tag
                        Tag
                        Tag
                        Tag

Lorem Ipsum is simply dummy text of the
                            printing and
                            typesetting industry.

                        Tag
                        Tag
                        TagTag

Lorem Ipsum is simply dummy text of the
                            printing and
                            typesetting industry.

                        Tag
                        Tag
                        Tag
                        Tag

Lorem Ipsum is simply dummy text of the
                                printing and typesetting industry.

Lorem Ipsum is simply dummy text of

Lorem Ipsum is simply dummy text of

                            <button className="l-btn-ghost l-btn-ghost--small">Follow</button>

Username

June 17, 2015

Lorem Ipsum is simply dummy text of the printing
                                and typesetting industry. Lorem Ipsum has been the industry standard dummy text ever
                                since the 1500s, when an unknown printer took a
                                galley of type and scrambled it to make a type specimen book.

                            Read more

        )
    }

    tabs() {
        return (

Tabs

Tab Active

Tab Hover

Tab Default

Tab Default

        )
    }

    tooltips() {
        return (

Tooltips

                    A tooltip can be placed upon a text item.

                    <Tooltip text="top" position="top">

                            Lorem Ipsum is simply dummy text of the printing and typesetting industry.
                             Learn More

                    </Tooltip>
                    ...
                    <Tooltip text="left" position="left">
Lorem Ipsum.
</Tooltip>
                    ...
                    <Tooltip text="bottom" position="bottom">
Lorem Ipsum.
</Tooltip>
                    ...
                    <Tooltip text="right" position="right">
Lorem Ipsum.
</Tooltip>

                    It can also be generated with custom HTML async its contents.
                    <Tooltip containerWidth="100px" html={
HTML
} position="right">

Lorem Ipsum. pew pew brap brap

                    </Tooltip>

                    <Tooltip html={<Button>A tooltip on a button</Button>} position="bottom">

Lorem Ipsum.

                    </Tooltip>

        )
    }

    modals() {
        return (

Modals

 Open this modal

        )
    }

    main() {
        return [
            this.modals(),
            this.avatars(),
            this.spinners(),
            this.cards(),
            this.tabs(),
            this.tooltips()
        ]
    }

    sidebar() {
        return (

 ← Home

Avatars

Spinners

Cards

Tabs

Tooltips

Modals

        )
    }
}
<|endoftext|>


<commit_before>var async = require('async');
var _ = require('lodash');
var tokenizer = require('./tokenizer');

/**
 * [checkPermissions description]
 * Format of a permission {
 * role: {'basic-user':{match: false}}
 * permissions: []
 * customValidator: functionName
 *}
 *
 * @param  {[type]}   args [description]
 * @param  {Function} done [description]
 * @return {[type]}        [description]
 */

function checkPermissions (args, cb) {
  var seneca = this;
  var permissions = require('../config/permissions.js')();
  var user = {};
  var cmd = args.act;
  console.log('tested:', args.role, cmd );
  var origin = args.role;
  var rules = seneca.permConfig[origin];
  var validity = false; //Global validity, if at least one rule is considered valid
  var httpErr = {};

  function getProfilesByActName (waterfallCb) {
    var profiles = {};
    if(rules[cmd]) profiles = rules[cmd];
    waterfallCb(null, profiles);
  }

  //  TODO : error msg with multiple profiles
  function checkProfiles(profiles, waterfallCb) {
    if(_.isEmpty(profiles)){
      //  Not define = public call
      console.log('No rule defined for this call');
      cb(null, {'allowed': true});
    }else{
      async.some(profiles, checkValidity, function(err, valid){
        console.log('validity', valid, validity || valid ? true: httpErr, httpErr);
        cb(null, {'allowed': validity || valid ? true: httpErr});
      });

    }
  }

  /**
   * Check different parameters based upon a profile rule to ensure the actual user is allowed to use it
   * The validity is global to every check, while the error is passed as callback of every check
   * @param  {Object} profile    Instance of an act profile containing minimal status to use this act
   */
  function checkValidity(profile, validityCb) {
    var actions = [];
    var allowed = true; // This is a local validity to each rule/profile

    if(profile.role) actions.push(isRoleAllowed);
    if(profile.extendedUserTypes) actions.push(getAssociatedUserTypes);
    if(profile.userType) actions.push(isUserTypeAllowed);
    // if(profile.permissions) actions.push(isHavingPermissions);
    if(profile.customValidator) actions.push(applyCustomValidator);

    user = args.user ? args.user : {roles: ['none']} ;
    // console.log('actions', actions);
    async.waterfall(actions, function(err, validities){
      return validityCb(httpErr, allowed);
    });

    /**
     * Check if the profile role is matching (or lower) than the caller
     * @return {Object}      [description]
     */
    function isRoleAllowed (done) {
      httpErr = {
        status: 403
      };
      var profileDepth = getRoleDepth(permissions.roleHierarchy, profile.role);
      var userRoleDepth = getHighestPrivilegedRole(permissions.roleHierarchy, user.roles);
      //  console.log('depthsRole', permissions.roleHierarchy, profileDepth, user.roles, userRoleDepth);
      if (profileDepth >= userRoleDepth.value) {
        allowed = allowed && true;
        httpErr = null;
      }else {
        allowed = false;
      }
      // console.log('isRoleAllowed()', allowed, profile.role, user.roles);
      //  Out of jail scenario for highest role
      //  We bypass further check to avoid over defining scenarios
      if( userRoleDepth === 0 ){
        return validityCb(allowed);
      }

      return done(httpErr);
    }

    function isUserTypeAllowed (done) {
      httpErr = {
        status: 403
      };
      var profileDepth = getRoleDepth(permissions.userTypeHierarchy, profile.userType);

      if(!_.isObject(user.initUserType)){
        var initType = JSON.parse(user.initUserType);
        if( initType.name ){
          user.initUserType = [initType.name];
        }
      }else{
        user.initUserType = _.keys(user.initUserType);
      }
      var userRoleDepth = getHighestPrivilegedRole(permissions.userTypeHierarchy, _.toArray(user.initUserType));
      // console.log('depthsUserType', profileDepth,
      //   _.toArray(user.initUserType), 'higher:', getHighestPrivilegedRole(permissions.userTypeHierarchy,
      //   _.toArray(user.initUserType)), userRoleDepth);

      if (profileDepth >= userRoleDepth.value) {
        allowed = allowed && true;
        httpErr = null;
      }else {
        allowed = false;
      }

      return done(httpErr);
    }

    function getAssociatedUserTypes (done) {
      seneca.act({role: 'cd-dojos', cmd: 'load_usersdojos', query: { userId: user.id }},
        function(err, associations){
          var userTypes = [];
          userTypes.push(JSON.parse(user.initUserType).name);
          _.map(associations, function(association) {
            _.map(association.userTypes, function(userType) {
              userTypes.push(userType);
            });
          });
          user.userType = userTypes;
          return done(err);
      });
    }

    /**
     * Call a seneca act based upon the msg saved as a config
     * Params are provided by the original call
     * ex : {role: 'cd-dojos', cmd: 'isDojoAdmin'}
     */
    function applyCustomValidator (done) {
      var customValidator = profile.customValidator;
      var httpErr = {
        status: 401
      };
      var omittedFields = [ 'cmd', 'role', 'ungate$', 'transport$', 'tx$', 'default$', 'meta$', 'plugin$', 'fatal$' ];
      //We omit perm on purpose ?
      async.every(customValidator, function(validatorAct, validatorCb) {
        var msg = _.defaults(validatorAct, _.omit(_.clone(args), omittedFields));
        seneca.act(msg, function(err, response){
          return validatorCb(null, response);
        });
      }, function(err, valid){
        if (valid) {
          allowed = valid && true;
          httpErr = null;
        }else {
          allowed = false;
        }
        return done(httpErr);
      });

    }

  }

  /**
   * Flatten a tree of roles to find the value until a maxDepth
   *  As much as possible, avoid recursivness with Js
   * @param  {Object} tree   one of permissions' userTypeHierarchy or roleHierarchy
   * @param  {String} value  one of those tree values
   * @return {Integer}       the depth
   */
  function getRoleDepth(tree, value){
    var found = false;
    var maxDepth = 5;
    var depth = -1;
    var localTree = _.clone(tree);
    do{
      var picked = localTree[value];
      depth += 1;
      if(!_.isUndefined(picked)){
        found = true;
      }
      //  Flatten our object (lodash doesn't support flattening of object, only arrays)
      var tempTree = {};
      _.each(_.keys(localTree), function(key) {
         _.merge(tempTree, localTree[key]);
      });
      localTree = tempTree ;

    }while(!found && depth < maxDepth);
    return depth;
  }

  /**
   * Search for the highest possible value in a tree when multiple options are possible
   * (ex multiple userTypes)
   * @param  {Object} tree   from permissions.js, userTypeHierarchy or roleHierarchy
   * @param  {Array} values  haystack for the highest one
   * @return {String}        one of the userType/Role without the actual index
   */
  function getHighestPrivilegedRole(tree, values){
    var lowerDepth = values[0];
    var indexes = {};
    lowerDepth = _.minBy(values, function(value){
      indexes[value] = getRoleDepth(tree, value);
      return indexes[value];
    });
    return {name: lowerDepth,
            value: indexes[lowerDepth]};
  }

  async.waterfall([
    getProfilesByActName,
    checkProfiles
  ]);

}

module.exports = checkPermissions;
<commit_msg>CheckPerm return value rewrote to ensure boolean  || error<commit_after>var async = require('async');
var _ = require('lodash');
var tokenizer = require('./tokenizer');

/**
 * [checkPermissions description]
 * Format of a permission {
 * role: {'basic-user':{match: false}}
 * permissions: []
 * customValidator: functionName
 *}
 *
 * @param  {[type]}   args [description]
 * @param  {Function} done [description]
 * @return {[type]}        [description]
 */

function checkPermissions (args, cb) {
  var seneca = this;
  var permissions = require('../config/permissions.js')();
  var user = {};
  var cmd = args.act;
  console.log('tested:', args.role, cmd );
  var origin = args.role;
  var rules = seneca.permConfig[origin];
  var httpErr = {};

  function getProfilesByActName (waterfallCb) {
    var profiles = {};
    if(rules[cmd]) profiles = rules[cmd];
    waterfallCb(null, profiles);
  }

  //  TODO : error msg with multiple profiles
  function checkProfiles(profiles, waterfallCb) {
    if(_.isEmpty(profiles)){
      //  Not define = public call
      console.log('No rule defined for this call');
      cb(null, {'allowed': true});
    }else{
      async.some(profiles, checkValidity, function(err, valid){
        console.log('validity', valid === true || httpErr, httpErr);
        cb(null, {'allowed': valid === true || httpErr});
      });

    }
  }

  /**
   * Check different parameters based upon a profile rule to ensure the actual user is allowed to use it
   * The validity is global to every check, while the error is passed as callback of every check
   * @param  {Object} profile    Instance of an act profile containing minimal status to use this act
   */
  function checkValidity(profile, validityCb) {
    var actions = [];
    var allowed = true; // This is a local validity to each rule/profile

    if(profile.role) actions.push(isRoleAllowed);
    if(profile.extendedUserTypes) actions.push(getAssociatedUserTypes);
    if(profile.userType) actions.push(isUserTypeAllowed);
    // if(profile.permissions) actions.push(isHavingPermissions);
    if(profile.customValidator) actions.push(applyCustomValidator);

    user = args.user ? args.user : {roles: ['none']} ;
    // console.log('actions', actions);
    async.waterfall(actions, function(err, validities){
      return validityCb(httpErr, allowed);
    });

    /**
     * Check if the profile role is matching (or lower) than the caller
     * @return {Object}      [description]
     */
    function isRoleAllowed (done) {
      httpErr = {
        status: 403
      };
      var profileDepth = getRoleDepth(permissions.roleHierarchy, profile.role);
      var userRoleDepth = getHighestPrivilegedRole(permissions.roleHierarchy, user.roles);
      //  console.log('depthsRole', permissions.roleHierarchy, profileDepth, user.roles, userRoleDepth);
      if (profileDepth >= userRoleDepth.value) {
        allowed = allowed && true;
        httpErr = null;
      }else {
        allowed = false;
      }
      // console.log('isRoleAllowed()', allowed, profile.role, user.roles);
      //  Out of jail scenario for highest role
      //  We bypass further check to avoid over defining scenarios
      if( userRoleDepth === 0 ){
        return validityCb(allowed);
      }

      return done(httpErr);
    }

    function isUserTypeAllowed (done) {
      httpErr = {
        status: 403
      };
      var profileDepth = getRoleDepth(permissions.userTypeHierarchy, profile.userType);

      if(!_.isObject(user.initUserType)){
        var initType = JSON.parse(user.initUserType);
        if( initType.name ){
          user.initUserType = [initType.name];
        }
      }else{
        user.initUserType = _.keys(user.initUserType);
      }
      var userRoleDepth = getHighestPrivilegedRole(permissions.userTypeHierarchy, _.toArray(user.initUserType));
      // console.log('depthsUserType', profileDepth,
      //   _.toArray(user.initUserType), 'higher:', getHighestPrivilegedRole(permissions.userTypeHierarchy,
      //   _.toArray(user.initUserType)), userRoleDepth);

      if (profileDepth >= userRoleDepth.value) {
        allowed = allowed && true;
        httpErr = null;
      }else {
        allowed = false;
      }

      return done(httpErr);
    }

    function getAssociatedUserTypes (done) {
      seneca.act({role: 'cd-dojos', cmd: 'load_usersdojos', query: { userId: user.id }},
        function(err, associations){
          var userTypes = [];
          userTypes.push(JSON.parse(user.initUserType).name);
          _.map(associations, function(association) {
            _.map(association.userTypes, function(userType) {
              userTypes.push(userType);
            });
          });
          user.userType = userTypes;
          return done(err);
      });
    }

    /**
     * Call a seneca act based upon the msg saved as a config
     * Params are provided by the original call
     * ex : {role: 'cd-dojos', cmd: 'isDojoAdmin'}
     */
    function applyCustomValidator (done) {
      var customValidator = profile.customValidator;
      var httpErr = {
        status: 401
      };
      var omittedFields = [ 'cmd', 'role', 'ungate$', 'transport$', 'tx$', 'default$', 'meta$', 'plugin$', 'fatal$' ];
      //We omit perm on purpose ?
      async.every(customValidator, function(validatorAct, validatorCb) {
        var msg = _.defaults(validatorAct, _.omit(_.clone(args), omittedFields));
        seneca.act(msg, function(err, response){
          return validatorCb(null, response);
        });
      }, function(err, valid){
        if (valid) {
          allowed = valid && true;
          httpErr = null;
        }else {
          allowed = false;
        }
        return done(httpErr);
      });

    }

  }

  /**
   * Flatten a tree of roles to find the value until a maxDepth
   *  As much as possible, avoid recursivness with Js
   * @param  {Object} tree   one of permissions' userTypeHierarchy or roleHierarchy
   * @param  {String} value  one of those tree values
   * @return {Integer}       the depth
   */
  function getRoleDepth(tree, value){
    var found = false;
    var maxDepth = 5;
    var depth = -1;
    var localTree = _.clone(tree);
    do{
      var picked = localTree[value];
      depth += 1;
      if(!_.isUndefined(picked)){
        found = true;
      }
      //  Flatten our object (lodash doesn't support flattening of object, only arrays)
      var tempTree = {};
      _.each(_.keys(localTree), function(key) {
         _.merge(tempTree, localTree[key]);
      });
      localTree = tempTree ;

    }while(!found && depth < maxDepth);
    return depth;
  }

  /**
   * Search for the highest possible value in a tree when multiple options are possible
   * (ex multiple userTypes)
   * @param  {Object} tree   from permissions.js, userTypeHierarchy or roleHierarchy
   * @param  {Array} values  haystack for the highest one
   * @return {String}        one of the userType/Role without the actual index
   */
  function getHighestPrivilegedRole(tree, values){
    var lowerDepth = values[0];
    var indexes = {};
    lowerDepth = _.minBy(values, function(value){
      indexes[value] = getRoleDepth(tree, value);
      return indexes[value];
    });
    return {name: lowerDepth,
            value: indexes[lowerDepth]};
  }

  async.waterfall([
    getProfilesByActName,
    checkProfiles
  ]);

}

module.exports = checkPermissions;
<|endoftext|>


<commit_before>'use strict';

const PromiseHelper = require('./promisehelper');
const HttpExecutor = require('./httpexecutor');
const qs = require('querystring');
const errors = require('./errors');

/**
 * CollectionManager allows the management of collections within a Bucket.
 *
 * @category Management
 */
class CollectionManager {
  /**
   * @hideconstructor
   */
  constructor(bucket) {
    this._bucket = bucket;
  }

  get _http() {
    return new HttpExecutor(this._bucket._conn);
  }

  /**
   * @typedef {function(Error)} CreateCollectionCallback
   */
  /**
   * createCollection creates a collection within a scope in a bucket.
   *
   * @param {string} collectionName The name of the collection to create.
   * @param {string} scopeName The name of the scope to contain the new collection.
   * @param {*} [options]
   * @param {Number} [options.timeout] Timeout for the operation in milliseconds.
   * @param {CreateCollectionCallback} [callback]
   * @returns {Promise<boolean>}
   *
   * @throws {ScopeNotFoundError}
   * @throws {CollectionExistsError}
   * @throws {CouchbaseError}
   */
  async createCollection(collectionName, scopeName, options, callback) {
    if (options instanceof Function) {
      callback = arguments[2];
      options = undefined;
    }
    if (!options) {
      options = {};
    }

    return PromiseHelper.wrapAsync(async () => {
      var bucketName = this._bucket.name;

      var res = await this._http.request({
        type: 'MGMT',
        method: 'POST',
        path: `/pools/default/buckets/${bucketName}/collections/${scopeName}`,
        contentType: 'application/x-www-form-urlencoded',
        body: qs.stringify({
          name: collectionName,
        }),
        timeout: options.timeout,
      });

      if (res.statusCode !== 200) {
        var baseerr = errors.makeHttpError(res);
        var errtext = res.body.toString().toLowerCase();

        if (
          errtext.includes('already exists') &&
          errtext.includes('collection')
        ) {
          throw new errors.CollectionExistsError(baseerr);
        }

        if (errtext.includes('not found') && errtext.includes('scope')) {
          throw new errors.ScopeNotFoundError(baseerr);
        }

        throw new errors.CouchbaseError('failed to create collection', baseerr);
      }

      return true;
    }, callback);
  }

  /**
   * @typedef {function(Error)} DropCollectionCallback
   */
  /**
   * dropCollection drops a collection from a scope in a bucket.
   *
   * @param {string} collectionName The name of the collection to drop.
   * @param {string} scopeName The name of the scope containing the collection to drop.
   * @param {*} [options]
   * @param {Number} [options.timeout] Timeout for the operation in milliseconds.
   * @param {DropCollectionCallback} [callback]
   * @returns {Promise<boolean>}
   *
   * @throws {CollectionNotFoundError}
   * @throws {CouchbaseError}
   */
  async dropCollection(collectionName, scopeName, options, callback) {
    if (options instanceof Function) {
      callback = arguments[2];
      options = undefined;
    }
    if (!options) {
      options = {};
    }

    return PromiseHelper.wrapAsync(async () => {
      var bucketName = this._bucket.name;

      var res = await this._http.request({
        type: 'MGMT',
        method: 'DELETE',
        path: `/pools/default/buckets/${bucketName}/collections/${scopeName}/${collectionName}`,
        timeout: options.timeout,
      });

      if (res.statusCode !== 200) {
        var baseerr = errors.makeHttpError(res);
        var errtext = res.body.toString().toLowerCase();

        if (errtext.includes('not found') && errtext.includes('collection')) {
          throw new errors.CollectionNotFoundError(baseerr);
        }

        throw new errors.CouchbaseError('failed to drop collection', baseerr);
      }

      return true;
    }, callback);
  }

  /**
   * @typedef {function(Error)} CreateScopeCallback
   */
  /**
   * createScope creates a scope within a bucket.
   *
   * @param {string} scopeName The name of the scope to create.
   * @param {*} [options]
   * @param {Number} [options.timeout] Timeout for the operation in milliseconds.
   * @param {CreateScopeCallback} [callback]
   * @returns {Promise<boolean>}
   *
   * @throws {CouchbaseError}
   */
  async createScope(scopeName, options, callback) {
    if (options instanceof Function) {
      callback = arguments[1];
      options = undefined;
    }
    if (!options) {
      options = {};
    }

    return PromiseHelper.wrapAsync(async () => {
      var bucketName = this._bucket.name;

      var res = await this._http.request({
        type: 'MGMT',
        method: 'POST',
        path: `/pools/default/buckets/${bucketName}/collections`,
        contentType: 'application/x-www-form-urlencoded',
        body: qs.stringify({
          name: scopeName,
        }),
        timeout: options.timeout,
      });

      if (res.statusCode !== 200) {
        var baseerr = errors.makeHttpError(res);
        var errtext = res.body.toString().toLowerCase();

        if (errtext.includes('already exists') && errtext.includes('scope')) {
          throw new errors.ScopeExistsError(baseerr);
        }

        throw new errors.CouchbaseError('failed to create scope', baseerr);
      }

      return true;
    }, callback);
  }

  /**
   * @typedef {function(Error)} DropScopeCallback
   */
  /**
   * dropScope drops a scope from a bucket.
   *
   * @param {string} scopeName The name of the scope to drop.
   * @param {*} [options]
   * @param {Number} [options.timeout] Timeout for the operation in milliseconds.
   * @param {DropScopeCallback} [callback]
   * @returns {Promise<boolean>}
   *
   * @throws {ScopeNotFoundError}
   * @throws {CouchbaseError}
   */
  async dropScope(scopeName, options, callback) {
    if (options instanceof Function) {
      callback = arguments[2];
      options = undefined;
    }
    if (!options) {
      options = {};
    }

    return PromiseHelper.wrapAsync(async () => {
      var bucketName = this._bucket.name;

      var res = await this._http.request({
        type: 'MGMT',
        method: 'DELETE',
        path: `/pools/default/buckets/${bucketName}/collections/${scopeName}`,
        timeout: options.timeout,
      });

      if (res.statusCode !== 200) {
        var baseerr = errors.makeHttpError(res);
        var errtext = res.body.toString().toLowerCase();

        if (errtext.includes('not found') && errtext.includes('scope')) {
          throw new errors.ScopeNotFoundError(baseerr);
        }

        throw new errors.CouchbaseError('failed to drop scope', baseerr);
      }

      return true;
    }, callback);
  }
}
module.exports = CollectionManager;
<commit_msg>JSCBC-757: Fixed CreateCollection method definition.<commit_after>'use strict';

const PromiseHelper = require('./promisehelper');
const HttpExecutor = require('./httpexecutor');
const qs = require('querystring');
const errors = require('./errors');

/**
 * CollectionManager allows the management of collections within a Bucket.
 *
 * @category Management
 */
class CollectionManager {
  /**
   * @hideconstructor
   */
  constructor(bucket) {
    this._bucket = bucket;
  }

  get _http() {
    return new HttpExecutor(this._bucket._conn);
  }

  /**
   * @typedef {function(Error)} CreateCollectionCallback
   */
  /**
   * createCollection creates a collection within a scope in a bucket.
   *
   * @param {*} collectionSpec The details of the collection to create.
   * @param {string} collectionSpec.name The name of the collection to create.
   * @param {string} collectionSpec.scopeName The name of the scope to create the collection in.
   * @param {*} [options]
   * @param {Number} [options.timeout] Timeout for the operation in milliseconds.
   * @param {CreateCollectionCallback} [callback]
   * @returns {Promise<boolean>}
   *
   * @throws {ScopeNotFoundError}
   * @throws {CollectionExistsError}
   * @throws {CouchbaseError}
   */
  async createCollection(collectionSpec, options, callback) {
    // Deprecated usage conversion for (name, scopeName, options, callback)
    if (typeof collectionSpec === 'string') {
      collectionSpec = {
        name: arguments[0],
        scopeName: arguments[1],
      };
      options = arguments[2];
      callback = arguments[3];
    }

    if (options instanceof Function) {
      callback = arguments[2];
      options = undefined;
    }
    if (!options) {
      options = {};
    }

    return PromiseHelper.wrapAsync(async () => {
      var bucketName = this._bucket.name;

      var res = await this._http.request({
        type: 'MGMT',
        method: 'POST',
        path: `/pools/default/buckets/${bucketName}/collections/${collectionSpec.scopeName}`,
        contentType: 'application/x-www-form-urlencoded',
        body: qs.stringify({
          name: collectionSpec.name,
        }),
        timeout: options.timeout,
      });

      if (res.statusCode !== 200) {
        var baseerr = errors.makeHttpError(res);
        var errtext = res.body.toString().toLowerCase();

        if (
          errtext.includes('already exists') &&
          errtext.includes('collection')
        ) {
          throw new errors.CollectionExistsError(baseerr);
        }

        if (errtext.includes('not found') && errtext.includes('scope')) {
          throw new errors.ScopeNotFoundError(baseerr);
        }

        throw new errors.CouchbaseError('failed to create collection', baseerr);
      }

      return true;
    }, callback);
  }

  /**
   * @typedef {function(Error)} DropCollectionCallback
   */
  /**
   * dropCollection drops a collection from a scope in a bucket.
   *
   * @param {string} collectionName The name of the collection to drop.
   * @param {string} scopeName The name of the scope containing the collection to drop.
   * @param {*} [options]
   * @param {Number} [options.timeout] Timeout for the operation in milliseconds.
   * @param {DropCollectionCallback} [callback]
   * @returns {Promise<boolean>}
   *
   * @throws {CollectionNotFoundError}
   * @throws {CouchbaseError}
   */
  async dropCollection(collectionName, scopeName, options, callback) {
    if (options instanceof Function) {
      callback = arguments[2];
      options = undefined;
    }
    if (!options) {
      options = {};
    }

    return PromiseHelper.wrapAsync(async () => {
      var bucketName = this._bucket.name;

      var res = await this._http.request({
        type: 'MGMT',
        method: 'DELETE',
        path: `/pools/default/buckets/${bucketName}/collections/${scopeName}/${collectionName}`,
        timeout: options.timeout,
      });

      if (res.statusCode !== 200) {
        var baseerr = errors.makeHttpError(res);
        var errtext = res.body.toString().toLowerCase();

        if (errtext.includes('not found') && errtext.includes('collection')) {
          throw new errors.CollectionNotFoundError(baseerr);
        }

        throw new errors.CouchbaseError('failed to drop collection', baseerr);
      }

      return true;
    }, callback);
  }

  /**
   * @typedef {function(Error)} CreateScopeCallback
   */
  /**
   * createScope creates a scope within a bucket.
   *
   * @param {string} scopeName The name of the scope to create.
   * @param {*} [options]
   * @param {Number} [options.timeout] Timeout for the operation in milliseconds.
   * @param {CreateScopeCallback} [callback]
   * @returns {Promise<boolean>}
   *
   * @throws {CouchbaseError}
   */
  async createScope(scopeName, options, callback) {
    if (options instanceof Function) {
      callback = arguments[1];
      options = undefined;
    }
    if (!options) {
      options = {};
    }

    return PromiseHelper.wrapAsync(async () => {
      var bucketName = this._bucket.name;

      var res = await this._http.request({
        type: 'MGMT',
        method: 'POST',
        path: `/pools/default/buckets/${bucketName}/collections`,
        contentType: 'application/x-www-form-urlencoded',
        body: qs.stringify({
          name: scopeName,
        }),
        timeout: options.timeout,
      });

      if (res.statusCode !== 200) {
        var baseerr = errors.makeHttpError(res);
        var errtext = res.body.toString().toLowerCase();

        if (errtext.includes('already exists') && errtext.includes('scope')) {
          throw new errors.ScopeExistsError(baseerr);
        }

        throw new errors.CouchbaseError('failed to create scope', baseerr);
      }

      return true;
    }, callback);
  }

  /**
   * @typedef {function(Error)} DropScopeCallback
   */
  /**
   * dropScope drops a scope from a bucket.
   *
   * @param {string} scopeName The name of the scope to drop.
   * @param {*} [options]
   * @param {Number} [options.timeout] Timeout for the operation in milliseconds.
   * @param {DropScopeCallback} [callback]
   * @returns {Promise<boolean>}
   *
   * @throws {ScopeNotFoundError}
   * @throws {CouchbaseError}
   */
  async dropScope(scopeName, options, callback) {
    if (options instanceof Function) {
      callback = arguments[2];
      options = undefined;
    }
    if (!options) {
      options = {};
    }

    return PromiseHelper.wrapAsync(async () => {
      var bucketName = this._bucket.name;

      var res = await this._http.request({
        type: 'MGMT',
        method: 'DELETE',
        path: `/pools/default/buckets/${bucketName}/collections/${scopeName}`,
        timeout: options.timeout,
      });

      if (res.statusCode !== 200) {
        var baseerr = errors.makeHttpError(res);
        var errtext = res.body.toString().toLowerCase();

        if (errtext.includes('not found') && errtext.includes('scope')) {
          throw new errors.ScopeNotFoundError(baseerr);
        }

        throw new errors.CouchbaseError('failed to drop scope', baseerr);
      }

      return true;
    }, callback);
  }
}
module.exports = CollectionManager;
<|endoftext|>


<commit_before>(function() {
    var OutfitSvc = ['$http', 'BaseSvc',
        function($http, BaseSvc) {
            var getWorld = function(playerID) {
                return $http.jsonp(BaseSvc.urlBuilder.build('character', [
                        'character_id=' + playerID,
                        'c:resolve=world',
                        'c:join=world^on:world_id^inject_at:world',
                        'c:show=character_id,world',
                        'c:lang=en'
                    ]))
                    .then(function(response) {
                        var data = response.data.character_list[0].world;
                        var world = {
                            'name': data.name.en,
                            'id': parseInt(data.world_id)
                        };
                        return world;
                    });
            };

            var getOutfit = function(alias) {
                alias = typeof alias !== 'undefined' ? alias : 'nuc';
                alias = angular.lowercase(alias.replace(/\s+/g, ''));
                return $http.jsonp(BaseSvc.urlBuilder.build('outfit', [
                        'c:resolve=rank,leader(name,battle_rank,faction_id),member_character(name,battle_rank,member_since_date,rank,title_id,times)',
                        'alias_lower=' + alias
                    ]))
                    .then(function(response) {
                        var data = response.data.outfit_list[0];
                        //TODO Refactor promise tree
                        return BaseSvc.data.getFactions().then(function(factions) {
                            return BaseSvc.data.getTitles().then(function(titles) {
                                return getWorld(data.leader_character_id).then(function(world) {
                                    //TODO Refactor this with PlayerSvc.getPlayerFriends
                                    var findFaction = function() {
                                        if (typeof data.leader.faction_id !== 'undefined') {
                                            for (var x = 0; x < factions.length; x++) {
                                                if (factions[x].id === parseInt(data.leader.faction_id)) {
                                                    return factions[x].name;
                                                }
                                            }
                                        }
                                    };

                                    var findTitle = function(i) {
                                        if (typeof data.members[i].title_id !== 'undefined') {
                                            for (var x = 0; x < titles.length; x++) {
                                                if (titles[x].id === parseInt(data.members[i].title_id)) {
                                                    return titles[x].name;
                                                }
                                            }
                                        }
                                    };

                                    var outfit = {
                                        'name': data.name,
                                        'alias': data.alias,
                                        'created': Date.parse(data.time_created_date),
                                        'leader': data.leader.name.first,
                                        'faction': {
                                            'name': findFaction(),
                                            'id': parseInt(data.leader.faction_id)
                                        },
                                        'world': world
                                    };

                                    outfit.ranks = [];
                                    for (var i = 0; i < data.ranks.length; i++) {
                                        var rank = {
                                            'name': data.ranks[i].name,
                                            'description': data.ranks[i].description,
                                            'id': parseInt(data.ranks[i].ordinal)
                                        };
                                        outfit.ranks.push(rank);
                                    }

                                    outfit.members = [];
                                    for (i = 0; i < data.members.length; i++) {
                                        var member = {
                                            'name': typeof data.members[i].name !== 'undefined' ? data.members[i].name.first : '',
                                            'battle_rank': typeof data.members[i].battle_rank !== 'undefined' ? parseInt(data.members[i].battle_rank.value) : 0,
                                            'joined': new Date(0).setUTCSeconds(data.members[i].member_since),
                                            'lastLogin': typeof data.members[i].times !== 'undefined' ? new Date(0).setUTCSeconds(data.members[i].times.last_login) : new Date(0),
                                            'rank': {
                                                'name': data.members[i].rank,
                                                'id': parseInt(data.members[i].rank_ordinal)
                                            },
                                            'title': findTitle(i)
                                        };
                                        member.isActive = member.lastLogin > new Date(new Date().setDate(new Date().getDate() - 14)),
                                        outfit.members.push(member);
                                    }
                                    outfit.activeMembers = 0;
                                    for (i = 0; i < outfit.members.length; i++) {
                                        if (outfit.members[i].isActive) outfit.activeMembers++;
                                    }
                                    return outfit;
                                });
                            });
                        });
                    });
            };

            return {
                'getOutfit': getOutfit
            };
        }
    ];

    var module = angular.module('PS2Info');
    module.factory('OutfitSvc', OutfitSvc);
}());
<commit_msg>Outfit creation date now uses UTC<commit_after>(function() {
    var OutfitSvc = ['$http', 'BaseSvc',
        function($http, BaseSvc) {
            var getWorld = function(playerID) {
                return $http.jsonp(BaseSvc.urlBuilder.build('character', [
                        'character_id=' + playerID,
                        'c:resolve=world',
                        'c:join=world^on:world_id^inject_at:world',
                        'c:show=character_id,world',
                        'c:lang=en'
                    ]))
                    .then(function(response) {
                        var data = response.data.character_list[0].world;
                        var world = {
                            'name': data.name.en,
                            'id': parseInt(data.world_id)
                        };
                        return world;
                    });
            };

            var getOutfit = function(alias) {
                alias = typeof alias !== 'undefined' ? alias : 'nuc';
                alias = angular.lowercase(alias.replace(/\s+/g, ''));
                return $http.jsonp(BaseSvc.urlBuilder.build('outfit', [
                        'c:resolve=rank,leader(name,battle_rank,faction_id),member_character(name,battle_rank,member_since_date,rank,title_id,times)',
                        'alias_lower=' + alias
                    ]))
                    .then(function(response) {
                        var data = response.data.outfit_list[0];
                        //TODO Refactor promise tree
                        return BaseSvc.data.getFactions().then(function(factions) {
                            return BaseSvc.data.getTitles().then(function(titles) {
                                return getWorld(data.leader_character_id).then(function(world) {
                                    //TODO Refactor this with PlayerSvc.getPlayerFriends
                                    var findFaction = function() {
                                        if (typeof data.leader.faction_id !== 'undefined') {
                                            for (var x = 0; x < factions.length; x++) {
                                                if (factions[x].id === parseInt(data.leader.faction_id)) {
                                                    return factions[x].name;
                                                }
                                            }
                                        }
                                    };

                                    var findTitle = function(i) {
                                        if (typeof data.members[i].title_id !== 'undefined') {
                                            for (var x = 0; x < titles.length; x++) {
                                                if (titles[x].id === parseInt(data.members[i].title_id)) {
                                                    return titles[x].name;
                                                }
                                            }
                                        }
                                    };

                                    var outfit = {
                                        'name': data.name,
                                        'alias': data.alias,
                                        'created': new Date(0).setUTCSeconds(data.time_created),
                                        'leader': data.leader.name.first,
                                        'faction': {
                                            'name': findFaction(),
                                            'id': parseInt(data.leader.faction_id)
                                        },
                                        'world': world
                                    };

                                    outfit.ranks = [];
                                    for (var i = 0; i < data.ranks.length; i++) {
                                        var rank = {
                                            'name': data.ranks[i].name,
                                            'description': data.ranks[i].description,
                                            'id': parseInt(data.ranks[i].ordinal)
                                        };
                                        outfit.ranks.push(rank);
                                    }

                                    outfit.members = [];
                                    for (i = 0; i < data.members.length; i++) {
                                        var member = {
                                            'name': typeof data.members[i].name !== 'undefined' ? data.members[i].name.first : '',
                                            'battle_rank': typeof data.members[i].battle_rank !== 'undefined' ? parseInt(data.members[i].battle_rank.value) : 0,
                                            'joined': new Date(0).setUTCSeconds(data.members[i].member_since),
                                            'lastLogin': typeof data.members[i].times !== 'undefined' ? new Date(0).setUTCSeconds(data.members[i].times.last_login) : new Date(0),
                                            'rank': {
                                                'name': data.members[i].rank,
                                                'id': parseInt(data.members[i].rank_ordinal)
                                            },
                                            'title': findTitle(i)
                                        };
                                        member.isActive = member.lastLogin > new Date(new Date().setDate(new Date().getDate() - 14)),
                                        outfit.members.push(member);
                                    }
                                    outfit.activeMembers = 0;
                                    for (i = 0; i < outfit.members.length; i++) {
                                        if (outfit.members[i].isActive) outfit.activeMembers++;
                                    }
                                    return outfit;
                                });
                            });
                        });
                    });
            };

            return {
                'getOutfit': getOutfit
            };
        }
    ];

    var module = angular.module('PS2Info');
    module.factory('OutfitSvc', OutfitSvc);
}());
<|endoftext|>


<commit_before>import React, {PropTypes, PureComponent} from 'react'
import shallowCompare from 'react-addons-shallow-compare'
import lastValues from 'shared/parsing/lastValues'
import Gauge from 'shared/components/Gauge'

import {DEFAULT_COLORS} from 'src/dashboards/constants/gaugeColors'
import {DASHBOARD_LAYOUT_ROW_HEIGHT} from 'shared/constants'

class GaugeChart extends PureComponent {
  render() {
    const {
      data,
      cellHeight,
      isFetchingInitially,
      colors,
      resizeCoords,
      resizerTopHeight,
    } = this.props

    // If data for this graph is being fetched for the first time, show a graph-wide spinner.
    if (isFetchingInitially) {
      return (

      )
    }

    const lastValue = lastValues(data)[1]
    const precision = 100.0
    const roundedValue = Math.round(+lastValue * precision) / precision

    // When a new height is passed the Gauge component resizes internally
    // Passing in a new often ensures the gauge appears sharp

    const initialCellHeight =
      cellHeight && (cellHeight * DASHBOARD_LAYOUT_ROW_HEIGHT).toString()

    const resizeCoordsHeight =
      resizeCoords && (resizeCoords.h * DASHBOARD_LAYOUT_ROW_HEIGHT).toString()

    const height = (resizeCoordsHeight ||
      initialCellHeight ||
      resizerTopHeight ||
      300)
      .toString()

    return (

 (this.gaugeContainer = r)}>
        <Gauge
          width="900"
          height={height}
          colors={colors}
          gaugePosition={roundedValue}
        />

    )
  }
}

const {arrayOf, bool, number, shape, string} = PropTypes

GaugeChart.defaultProps = {
  colors: DEFAULT_COLORS,
}

GaugeChart.propTypes = {
  data: arrayOf(shape()).isRequired,
  isFetchingInitially: bool,
  cellHeight: number,
  resizerTopHeight: number,
  resizeCoords: shape(),
  colors: arrayOf(
    shape({
      type: string.isRequired,
      hex: string.isRequired,
      id: string.isRequired,
      name: string.isRequired,
      value: string.isRequired,
    }).isRequired
  ),
}

export default GaugeChart
<commit_msg>Remove unused ref<commit_after>import React, {PropTypes, PureComponent} from 'react'
import lastValues from 'shared/parsing/lastValues'
import Gauge from 'shared/components/Gauge'

import {DEFAULT_COLORS} from 'src/dashboards/constants/gaugeColors'
import {DASHBOARD_LAYOUT_ROW_HEIGHT} from 'shared/constants'

class GaugeChart extends PureComponent {
  render() {
    const {
      data,
      cellHeight,
      isFetchingInitially,
      colors,
      resizeCoords,
      resizerTopHeight,
    } = this.props

    // If data for this graph is being fetched for the first time, show a graph-wide spinner.
    if (isFetchingInitially) {
      return (

      )
    }

    const lastValue = lastValues(data)[1]
    const precision = 100.0
    const roundedValue = Math.round(+lastValue * precision) / precision

    // When a new height is passed the Gauge component resizes internally
    // Passing in a new often ensures the gauge appears sharp

    const initialCellHeight =
      cellHeight && (cellHeight * DASHBOARD_LAYOUT_ROW_HEIGHT).toString()

    const resizeCoordsHeight =
      resizeCoords && (resizeCoords.h * DASHBOARD_LAYOUT_ROW_HEIGHT).toString()

    const height = (resizeCoordsHeight ||
      initialCellHeight ||
      resizerTopHeight ||
      300)
      .toString()

    return (

        <Gauge
          width="900"
          height={height}
          colors={colors}
          gaugePosition={roundedValue}
        />

    )
  }
}

const {arrayOf, bool, number, shape, string} = PropTypes

GaugeChart.defaultProps = {
  colors: DEFAULT_COLORS,
}

GaugeChart.propTypes = {
  data: arrayOf(shape()).isRequired,
  isFetchingInitially: bool,
  cellHeight: number,
  resizerTopHeight: number,
  resizeCoords: shape(),
  colors: arrayOf(
    shape({
      type: string.isRequired,
      hex: string.isRequired,
      id: string.isRequired,
      name: string.isRequired,
      value: string.isRequired,
    }).isRequired
  ),
}

export default GaugeChart
<|endoftext|>