<commit_before>import React, {
    Component
} from 'react'

import {
    StyleSheet,
    View,
    Text,
    Image,
    Platform,
    TouchableHighlight,
} from 'react-native'

var GiftedListView = require('react-native-gifted-listview');
import {fetDefaultShots, fetDebutsShots} from './api.js'

export default class HomeView extends Component {
    constructor(props) {
        super(props)
        // this.state = {
        //     infos: []
        // }
    }

    render() {
      // let shot;
      //
      // fetDefaultShots(0).catch((error) => {
      // })
      // .then((responseData) => {
      //   console.log('111111111');
      //   console.log(responseData);
      //   shot = responseData[0];
      //   console.log(shot.user.avatar_url);
      // }).done();
      // let info = {
      //   avatar: "5",
      //   created_at: "1404784104",
      //   id: "48",
      //   nickname: "Nicole Sobon",
      //   original_pic: "",
      //   text: "Sometimes the hardest part isn't letting go, but rather, learning to start over.",
      // };
      //   return (
      //     <View style={styles.container}>
      //       <TouchableHighlight underlayColor='transparent' onPress={this._gotoDetails.bind(this, info)}>
      //           <View style={styles.tweetContainer}>
      //               <View style={styles.topContainer}>
      //                   <Image source={{uri: this._getAvatarUrl(info.avatar)}} style={styles.avatar} />
      //                   <View>
      //                       <View style={styles.userContainer}>
      //                           <Text style={styles.name}>{info.nickname}</Text>
      //                           <Text style={styles.time}>{'#' + info.id + ' '} </Text>
      //                       </View>
      //                   </View>
      //               </View>
      //               <View style={styles.middleContainer}>
      //                   <Text>{info.text}</Text>
      //                   {this._renderMsgImage(info)}
      //               </View>
      //               <View style={styles.bottomContainer}>
      //                   <TouchableHighlight style={styles.bottomTool}>
      //                       <Text style={styles.bottomToolText}>Forward</Text>
      //                   </TouchableHighlight>
      //                   <TouchableHighlight style={styles.bottomTool}>
      //                       <Text style={styles.bottomToolText}>Comment</Text>
      //                   </TouchableHighlight>
      //                   <TouchableHighlight style={styles.bottomTool}>
      //                       <Text style={styles.bottomToolText}>Like</Text>
      //                   </TouchableHighlight>
      //               </View>
      //           </View>
      //       </TouchableHighlight>
      //     </View>
      //   )
      let color = 'gray'
        return (
            <GiftedListView
                enableEmptySections={true}
                customStyles={listStyles}
                rowView={this._renderRowView.bind(this)}
                onFetch={this._onFetch.bind(this)}
                firstLoader={true}
                pagination={true}
                refreshable={true}
                withSections={false}
                spinnerColor={color}
            />
        )
    }

    _onFetch(page = 1, callback, options) {
      let info = {
        avatar: "5",
        created_at: "1404784104",
        id: "48",
        nickname: "Nicole Sobon",
        original_pic: "",
        text: "Sometimes the hardest part isn't letting go, but rather, learning to start over.",
      };
            // if(page === 1 && options.firstLoad) {
            //   callback(info)
            // } else if(page === 1 && !options.firstLoad) {
            //   callback(info)
            // } else {
            //   callback(info)
            // }
      if(page === 1 && options.firstLoad) {
        callback([info, info, info, info, info])
      } else if (page === 1 && !options.firstLoad) {
        callback([info, info, info, info, info])
      } else {
        callback([info, info, info, info, info], {
                        allLoaded: true
                    })
      }
      // if (page === 3) {
      //   callback(info, {allLoaded: true})
      // } else {
      //   console.log('refresh');
      //   fetDebutsShots(page).catch((error) => {
      //   })
      //   .then((responseData) => {
      //     console.log(responseData);
      //     console.log(page);
      //     callback(info, {allLoaded: false});
      //   }).done();
      // }
   }

   _renderRowView(info) {
        return (
                <TouchableHighlight underlayColor='transparent' onPress={this._gotoDetails.bind(this, info)}>
                    <View style={styles.tweetContainer}>
                        <View style={styles.topContainer}>
                            <Image source={{uri: this._getAvatarUrl(info.avatar)}} style={styles.avatar} />
                            <View>
                                <View style={styles.userContainer}>
                                    <Text style={styles.name}>{info.nickname}</Text>
                                    <Text style={styles.time}>{'#' + info.id + ' '} </Text>
                                </View>
                            </View>
                        </View>
                        <View style={styles.middleContainer}>
                            <Text>{info.text}</Text>
                            {this._renderMsgImage(info)}
                        </View>
                        <View style={styles.bottomContainer}>
                            <TouchableHighlight style={styles.bottomTool}>
                                <Text style={styles.bottomToolText}>Forward</Text>
                            </TouchableHighlight>
                            <TouchableHighlight style={styles.bottomTool}>
                                <Text style={styles.bottomToolText}>Comment</Text>
                            </TouchableHighlight>
                            <TouchableHighlight style={styles.bottomTool}>
                                <Text style={styles.bottomToolText}>Like</Text>
                            </TouchableHighlight>
                        </View>
                    </View>
                </TouchableHighlight>
        )
    }

    _renderMsgImage(info) {
            if(info.original_pic) {
                return (
                    <Image source={{uri: info.original_pic}} style={[styles.msgImage, { resizeMode: Image.resizeMode.cover }]} />
                )
            }
        }

    _getAvatarUrl(ID) {
        return 'http://lorempixel.com/68/68/people/' + ID
    }

    _gotoDetails(tweet) {
      console.log('goto detail');
    }
}

const listStyles = {
  paginationView: {
    backgroundColor: '#eee',
  },
  url: {
    color: '#007aff'
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
  tweetContainer: {
    backgroundColor: 'white',
    margin: 10,
    marginBottom: 0,
    borderRadius: 2,
    shadowColor: '#000000',
    shadowOpacity: 0.1,
    shadowRadius: 0,
    shadowOffset: {
    height: 2,
    width: 1
    }
  },
  topContainer: {
      flex: 1,
      flexDirection: 'row',
      padding: 10,
      borderColor: '#e1e1e1',
      borderBottomWidth: 1
  },
  avatar: {
      backgroundColor: 'gray',
      width: 35,
      height: 35,
      borderRadius: 4,
      marginRight: 6
  },
  time: {
      fontSize: 13,
      color: '#8999a5',
      marginTop: 2
  },
  name: {
      color: '#ff9630',
      fontWeight: '600',
      fontSize: 14
  },
  middleContainer: {
      padding: 10,
      borderColor: '#e1e1e1',
      borderBottomWidth: 1
  },
  msgImage: {
      flex: 1,
      marginTop: 10,
      height: 200,
      backgroundColor: '#e1e1e1'
  },
  bottomContainer: {
      flexDirection: 'row',
      height: 40,
      backgroundColor: '#fafafa'
  },
  bottomTool: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center'
  },
  bottomToolText: {
      color: '#6D6D78',
      fontWeight: '500',
      alignItems: 'center'
  },
});
<commit_msg>Add json data<commit_after>import React, {
    Component
} from 'react'

import {
    StyleSheet,
    View,
    Text,
    Image,
    Platform,
    TouchableHighlight,
} from 'react-native'

var GiftedListView = require('react-native-gifted-listview');
import {fetDefaultShots, fetDebutsShots} from './api.js'

export default class HomeView extends Component {
    constructor(props) {
        super(props)
        // this.state = {
        //     infos: []
        // }
    }

    render() {
      // let shot;
      //
      // fetDefaultShots(0).catch((error) => {
      // })
      // .then((responseData) => {
      //   console.log('111111111');
      //   console.log(responseData);
      //   shot = responseData[0];
      //   console.log(shot.user.avatar_url);
      // }).done();
      // let info = {
      //   avatar: "5",
      //   created_at: "1404784104",
      //   id: "48",
      //   nickname: "Nicole Sobon",
      //   original_pic: "",
      //   text: "Sometimes the hardest part isn't letting go, but rather, learning to start over.",
      // };
      //   return (
      //     <View style={styles.container}>
      //       <TouchableHighlight underlayColor='transparent' onPress={this._gotoDetails.bind(this, info)}>
      //           <View style={styles.tweetContainer}>
      //               <View style={styles.topContainer}>
      //                   <Image source={{uri: this._getAvatarUrl(info.avatar)}} style={styles.avatar} />
      //                   <View>
      //                       <View style={styles.userContainer}>
      //                           <Text style={styles.name}>{info.nickname}</Text>
      //                           <Text style={styles.time}>{'#' + info.id + ' '} </Text>
      //                       </View>
      //                   </View>
      //               </View>
      //               <View style={styles.middleContainer}>
      //                   <Text>{info.text}</Text>
      //                   {this._renderMsgImage(info)}
      //               </View>
      //               <View style={styles.bottomContainer}>
      //                   <TouchableHighlight style={styles.bottomTool}>
      //                       <Text style={styles.bottomToolText}>Forward</Text>
      //                   </TouchableHighlight>
      //                   <TouchableHighlight style={styles.bottomTool}>
      //                       <Text style={styles.bottomToolText}>Comment</Text>
      //                   </TouchableHighlight>
      //                   <TouchableHighlight style={styles.bottomTool}>
      //                       <Text style={styles.bottomToolText}>Like</Text>
      //                   </TouchableHighlight>
      //               </View>
      //           </View>
      //       </TouchableHighlight>
      //     </View>
      //   )
      let color = 'gray'
        return (
            <GiftedListView
                enableEmptySections={true}
                customStyles={listStyles}
                rowView={this._renderRowView.bind(this)}
                onFetch={this._onFetch.bind(this)}
                firstLoader={true}
                pagination={true}
                refreshable={true}
                withSections={false}
                spinnerColor={color}
            />
        )
    }

    _onFetch(page = 1, callback, options) {
      let info = {
        avatar: "5",
        created_at: "1404784104",
        id: "48",
        nickname: "Nicole Sobon",
        original_pic: "",
        text: "Sometimes the hardest part isn't letting go, but rather, learning to start over.",
      };
            // if(page === 1 && options.firstLoad) {
            //   callback(info)
            // } else if(page === 1 && !options.firstLoad) {
            //   callback(info)
            // } else {
            //   callback(info)
            // }
      fetDefaultShots(page).catch((error) => {
      })
      .then((responseData) => {
        console.log(responseData);
        console.log('name == ' + responseData[0].user.name);
        console.log('avatar_url == ' + responseData[0].user.avatar_url);
        console.log("title == " + responseData[0].title);
        console.log('description == ' + responseData[0].description);
        console.log('animated == ' + responseData[0].animated);
        console.log('normal == ' + responseData[0].images.normal);
        console.log('teaser == ' + responseData[0].images.teaser);
        console.log('views_count == ' + responseData[0].views_count);
        console.log('comment_count == ' + responseData[0].comment_count);
        console.log('likes_count == ' + responseData[0].likes_count);
      }).done();

      if(page === 1 && options.firstLoad) {
        callback([info, info, info, info, info])
      } else if (page === 1 && !options.firstLoad) {
        callback([info, info, info, info, info])
      } else {
        callback([info, info, info, info, info], {
                        allLoaded: true
                    })
      }
      // if (page === 3) {
      //   callback(info, {allLoaded: true})
      // } else {
      //   console.log('refresh');
      //   fetDebutsShots(page).catch((error) => {
      //   })
      //   .then((responseData) => {
      //     console.log(responseData);
      //     console.log(page);
      //     callback(info, {allLoaded: false});
      //   }).done();
      // }
   }

   _renderRowView(info) {
        return (
                <TouchableHighlight underlayColor='transparent' onPress={this._gotoDetails.bind(this, info)}>
                    <View style={styles.tweetContainer}>
                        <View style={styles.topContainer}>
                            <Image source={{uri: this._getAvatarUrl(info.avatar)}} style={styles.avatar} />
                            <View>
                                <View style={styles.userContainer}>
                                    <Text style={styles.name}>{info.nickname}</Text>
                                    <Text style={styles.time}>{'#' + info.id + ' '} </Text>
                                </View>
                            </View>
                        </View>
                        <View style={styles.middleContainer}>
                            <Text>{info.text}</Text>
                            {this._renderMsgImage(info)}
                        </View>
                        <View style={styles.bottomContainer}>
                            <TouchableHighlight style={styles.bottomTool}>
                                <Text style={styles.bottomToolText}>Forward</Text>
                            </TouchableHighlight>
                            <TouchableHighlight style={styles.bottomTool}>
                                <Text style={styles.bottomToolText}>Comment</Text>
                            </TouchableHighlight>
                            <TouchableHighlight style={styles.bottomTool}>
                                <Text style={styles.bottomToolText}>Like</Text>
                            </TouchableHighlight>
                        </View>
                    </View>
                </TouchableHighlight>
        )
    }

    _renderMsgImage(info) {
            if(info.original_pic) {
                return (
                    <Image source={{uri: info.original_pic}} style={[styles.msgImage, { resizeMode: Image.resizeMode.cover }]} />
                )
            }
        }

    _getAvatarUrl(ID) {
        return 'http://lorempixel.com/68/68/people/' + ID
    }

    _gotoDetails(tweet) {
      console.log('goto detail');
    }
}

const listStyles = {
  paginationView: {
    backgroundColor: '#eee',
  },
  url: {
    color: '#007aff'
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
  tweetContainer: {
    backgroundColor: 'white',
    margin: 10,
    marginBottom: 0,
    borderRadius: 2,
    shadowColor: '#000000',
    shadowOpacity: 0.1,
    shadowRadius: 0,
    shadowOffset: {
    height: 2,
    width: 1
    }
  },
  topContainer: {
      flex: 1,
      flexDirection: 'row',
      padding: 10,
      borderColor: '#e1e1e1',
      borderBottomWidth: 1
  },
  avatar: {
      backgroundColor: 'gray',
      width: 35,
      height: 35,
      borderRadius: 4,
      marginRight: 6
  },
  time: {
      fontSize: 13,
      color: '#8999a5',
      marginTop: 2
  },
  name: {
      color: '#ff9630',
      fontWeight: '600',
      fontSize: 14
  },
  middleContainer: {
      padding: 10,
      borderColor: '#e1e1e1',
      borderBottomWidth: 1
  },
  msgImage: {
      flex: 1,
      marginTop: 10,
      height: 200,
      backgroundColor: '#e1e1e1'
  },
  bottomContainer: {
      flexDirection: 'row',
      height: 40,
      backgroundColor: '#fafafa'
  },
  bottomTool: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center'
  },
  bottomToolText: {
      color: '#6D6D78',
      fontWeight: '500',
      alignItems: 'center'
  },
});
<|endoftext|>


<commit_before>"use strict";

/**
 *
 * @param {Object} obj={session: {}, req: {}, tenant:{id: xxx, key: xxx}, product: {product: xxx, package: xxx, appId: xxx}, request: {service: xxx, api: xxx}, device: {}, geo: {}}
 */
function MultiTenantSession(obj) {
    this.session = obj.session;
    this.req = obj.req;
    this.assure({"tenantId": obj.tenant.id, "key": obj.tenant.key});
    this.setPersistSessionHOLDER({"tenant": obj.tenant, "product": obj.product, "request": obj.request});
    this.preserveTenantSession();
    this.setCLIENTINFO({"device": obj.device, "geo": obj.geo, "extKey": obj.tenant.extKey});

}

/**
 *
 * @param {Object} obj={tenantId: xxx, key: xxx}
 */
MultiTenantSession.prototype.assure = function (obj) {
    if (!this.session.persistSession) {
        this.session.persistSession = {};
    }
    if (!this.session.persistSession.state) {
        this.session.persistSession.state = {};
    }
    if (!this.session.persistSession.holder) {
        this.session.persistSession.holder = {};
    }

    if (!this.session.sessions) {
        this.session.sessions = {};
        this.setPersistSessionSTATE("ALL");
    }
    if (!this.session.sessions[obj.tenantId]) {
        this.session.sessions[obj.tenantId] = {};
        this.setPersistSessionSTATE("TENANT");
    }
    if (!this.session.sessions[obj.tenantId].urac) {
        this.session.sessions[obj.tenantId].urac = null;
    }
    if (!this.session.sessions[obj.tenantId].clientInfo) {
        this.session.sessions[obj.tenantId].clientInfo = {'device': {}, 'geo': {}};
    }
    if (!this.session.sessions[obj.tenantId].keys) {
        this.session.sessions[obj.tenantId].keys = {};
    }
    if (!this.session.sessions[obj.tenantId].keys[obj.key]) {
        this.session.sessions[obj.tenantId].keys[obj.key] = {
            "services": {}
        };
        this.setPersistSessionSTATE("KEY");
    }
};

/**
 *
 */
MultiTenantSession.prototype.preserveTenantSession = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;

    for (var tenant in this.session.sessions) {
        if (tenant !== tId) {
            delete this.session.sessions[tenant];
        } else {
            if (this.session.sessions[tId] && this.session.sessions[tId].keys) {
                for (var k in this.session.sessions[tId].keys) {
                    if (k !== key) {
                        delete this.session.sessions[tId].keys[k];
                    }
                }
            }
        }
    }
};

/**
 *
 * @param state
 */
MultiTenantSession.prototype.setPersistSessionSTATE = function (state) {
    if (!this.session.persistSession) {
        this.session.persistSession = {};
    }
    if (!this.session.persistSession.state) {
        this.session.persistSession.state = {};
    }

    if (this.session.persistSession.state.DONE)
        delete this.session.persistSession.state.DONE;

    this.session.persistSession.state[state] = true;
};

/**
 *
 * @param holder
 */
MultiTenantSession.prototype.setPersistSessionHOLDER = function (holder) {
    if (!this.session.persistSession) {
        this.session.persistSession = {};
    }
    this.session.persistSession.holder = holder;
};

/**
 *
 * @param clientInfo
 */
MultiTenantSession.prototype.setCLIENTINFO = function (clientInfo) {
    var tId = this.session.persistSession.holder.tenant.id;

    //TODO: check if clientInfo is still the same

    this.session.sessions[tId].clientInfo = clientInfo;
    //TODO: discuss with team if this is needed
    //this.setPersistSessionSTATE("CLIENTINFO");
};

/**
 *
 */
MultiTenantSession.prototype.setURACKEY = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    if (!this.session.sessions[tId].urac)
        return;
    if (this.session.sessions[tId].urac.config.keys[key])
        return;
    else {
        this.session.sessions[tId].urac.config.keys[key] = {};
        this.setPersistSessionSTATE("URACKEY");
        return;
    }
};

/**
 *
 */
MultiTenantSession.prototype.setURACPACKAGE = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var packageCode = this.session.persistSession.holder.product.package;
    if (!this.session.sessions[tId].urac)
        return;
    if (this.session.sessions[tId].urac.config.packages[packageCode])
        return;
    else {
        this.session.sessions[tId].urac.config.packages[packageCode] = {};
        this.setPersistSessionSTATE("URACPACKAGE");
        return;
    }
};

/**
 *
 * @param acl
 * @param cb
 * @returns {*}
 */
MultiTenantSession.prototype.setURACKEYACL = function (acl, cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    if (!this.session.sessions[tId].urac) {
        if (cb && (typeof cb === "function")) {
            return cb();
        }
        else
            return;
    }
    this.setURACKEY();
    this.session.sessions[tId].urac.config.keys[key].acl = acl;
    this.setPersistSessionSTATE("URACKEYACL");
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @param config
 * @param cb
 * @returns {*}
 */
MultiTenantSession.prototype.setURACKEYCONFIG = function (config, cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    if (!this.session.sessions[tId].urac) {
        if (cb && (typeof cb === "function")) {
            return cb();
        }
        else
            return;
    }
    this.setURACKEY();
    this.session.sessions[tId].urac.config.keys[key].config = config;
    this.setPersistSessionSTATE("URACKEYCONFIG");
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @param cb
 */
MultiTenantSession.prototype.clearURAC = function (cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    if (this.session.sessions[tId].urac) {
        this.session.sessions[tId].urac = null;
        this.setPersistSessionSTATE("URAC");
        if (cb && (typeof cb === "function")) {
            this.req.sessionStore.set(this.req.sessionID, this.session, cb);
        }
    }
    else
        cb();
};

/**
 *
 * @param urac
 * @param cb
 * @returns {*}
 */
MultiTenantSession.prototype.setURAC = function (urac, cb) {
    var tId = this.session.persistSession.holder.tenant.id;

    if (!urac) {
        if (cb && (typeof cb === "function")) {
            return cb();
        }
        else
            return;
    }

    //NOTE: we need to assure config = {packages: {}, keys : {}}
    if (!urac.config)
        urac.config = {};
    if (!urac.config.packages)
        urac.config.packages = {};
    if (!urac.config.keys)
        urac.config.keys = {};
    this.session.sessions[tId].urac = urac;

    this.setPersistSessionSTATE("URAC");
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @param acl
 * @param cb
 * @returns {*}
 */
MultiTenantSession.prototype.setURACPACKAGEACL = function (acl, cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    var packageCode = this.session.persistSession.holder.product.package;
    if (!this.session.sessions[tId].urac) {
        if (cb && (typeof cb === "function")) {
            return cb();
        }
        else
            return;
    }
    this.setURACPACKAGE();
    this.session.sessions[tId].urac.config.packages[packageCode].acl = acl;
    this.setPersistSessionSTATE("URACPACKAGEACL");
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @param obj
 * @param cb
 */
MultiTenantSession.prototype.setSERVICE = function (obj, cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    var service = this.session.persistSession.holder.request.service;
    this.session.sessions[tId].keys[key].services[service] = obj;
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @returns {*}
 */
MultiTenantSession.prototype.getSERVICE = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    var service = this.session.persistSession.holder.request.service;
    var obj = this.session.sessions[tId].keys[key].services[service];

    return obj;
};

/**
 *
 * @param cb
 */
MultiTenantSession.prototype.deleteTenantSession = function (cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    this.session.sessions[tId] = null;
    this.setPersistSessionSTATE("TENANT");
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @returns {*}
 */
MultiTenantSession.prototype.getAcl = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    var packageCode = this.session.persistSession.holder.product.package;
    if (!this.session.sessions[tId].urac) {
        return null;
    }
    var acl = null;
    if (this.session.sessions[tId].urac.config.keys[key] && this.session.sessions[tId].urac.config.keys[key].acl)
        acl = this.session.sessions[tId].urac.config.keys[key].acl;
    if(!acl && this.session.sessions[tId].urac.config.packages[packageCode] && this.session.sessions[tId].urac.config.packages[packageCode].acl)
        acl = this.session.sessions[tId].urac.config.packages[packageCode].acl;

    return acl;
};

/**
 *
 * @returns {*}
 */
MultiTenantSession.prototype.getConfig = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    if (!this.session.sessions[tId].urac) {
        return null;
    }
    var config = null;
    if (this.session.sessions[tId].urac.config.keys[key] && this.session.sessions[tId].urac.config.keys[key].config)
        config = this.session.sessions[tId].urac.config.keys[key].config;

    return config;
};

/**
 *
 * @returns {*}
 */
MultiTenantSession.prototype.getUrac = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    if (!this.session.sessions[tId].urac) {
        return null;
    }
    var urac = null;
    if (this.session.sessions[tId].urac.username){
        urac = {
            "_id": this.session.sessions[tId].urac._id,
            "username": this.session.sessions[tId].urac.username,
            "firstName": this.session.sessions[tId].urac.firstName,
            "lastName": this.session.sessions[tId].urac.lastName,
            "email": this.session.sessions[tId].urac.email,
            "groups" : this.session.sessions[tId].urac.groups,
            "profile": this.session.sessions[tId].urac.profile,
            "tenant" : this.session.sessions[tId].urac.tenant,
            "oauthRefreshToken" : this.session.sessions[tId].urac.oauthRefreshToken,
            "oauthAccessToken" : this.session.sessions[tId].urac.oauthAccessToken
        };
    }
    return urac;
};

/**
 *
 * @returns {*}
 */
MultiTenantSession.prototype.getGroups = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    if (!this.session.sessions[tId].urac) {
        return null;
    }
    var groups = null;
    if (this.session.sessions[tId].urac.groups){
        groups = this.session.sessions[tId].urac.groups;
    }
    return groups;
};

module.exports = MultiTenantSession;

<commit_msg>added getPackageAcl to multiTenantSession class<commit_after>"use strict";

/**
 *
 * @param {Object} obj={session: {}, req: {}, tenant:{id: xxx, key: xxx}, product: {product: xxx, package: xxx, appId: xxx}, request: {service: xxx, api: xxx}, device: {}, geo: {}}
 */
function MultiTenantSession(obj) {
    this.session = obj.session;
    this.req = obj.req;
    this.assure({"tenantId": obj.tenant.id, "key": obj.tenant.key});
    this.setPersistSessionHOLDER({"tenant": obj.tenant, "product": obj.product, "request": obj.request});
    this.preserveTenantSession();
    this.setCLIENTINFO({"device": obj.device, "geo": obj.geo, "extKey": obj.tenant.extKey});

}

/**
 *
 * @param {Object} obj={tenantId: xxx, key: xxx}
 */
MultiTenantSession.prototype.assure = function (obj) {
    if (!this.session.persistSession) {
        this.session.persistSession = {};
    }
    if (!this.session.persistSession.state) {
        this.session.persistSession.state = {};
    }
    if (!this.session.persistSession.holder) {
        this.session.persistSession.holder = {};
    }

    if (!this.session.sessions) {
        this.session.sessions = {};
        this.setPersistSessionSTATE("ALL");
    }
    if (!this.session.sessions[obj.tenantId]) {
        this.session.sessions[obj.tenantId] = {};
        this.setPersistSessionSTATE("TENANT");
    }
    if (!this.session.sessions[obj.tenantId].urac) {
        this.session.sessions[obj.tenantId].urac = null;
    }
    if (!this.session.sessions[obj.tenantId].clientInfo) {
        this.session.sessions[obj.tenantId].clientInfo = {'device': {}, 'geo': {}};
    }
    if (!this.session.sessions[obj.tenantId].keys) {
        this.session.sessions[obj.tenantId].keys = {};
    }
    if (!this.session.sessions[obj.tenantId].keys[obj.key]) {
        this.session.sessions[obj.tenantId].keys[obj.key] = {
            "services": {}
        };
        this.setPersistSessionSTATE("KEY");
    }
};

/**
 *
 */
MultiTenantSession.prototype.preserveTenantSession = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;

    for (var tenant in this.session.sessions) {
        if (tenant !== tId) {
            delete this.session.sessions[tenant];
        } else {
            if (this.session.sessions[tId] && this.session.sessions[tId].keys) {
                for (var k in this.session.sessions[tId].keys) {
                    if (k !== key) {
                        delete this.session.sessions[tId].keys[k];
                    }
                }
            }
        }
    }
};

/**
 *
 * @param state
 */
MultiTenantSession.prototype.setPersistSessionSTATE = function (state) {
    if (!this.session.persistSession) {
        this.session.persistSession = {};
    }
    if (!this.session.persistSession.state) {
        this.session.persistSession.state = {};
    }

    if (this.session.persistSession.state.DONE)
        delete this.session.persistSession.state.DONE;

    this.session.persistSession.state[state] = true;
};

/**
 *
 * @param holder
 */
MultiTenantSession.prototype.setPersistSessionHOLDER = function (holder) {
    if (!this.session.persistSession) {
        this.session.persistSession = {};
    }
    this.session.persistSession.holder = holder;
};

/**
 *
 * @param clientInfo
 */
MultiTenantSession.prototype.setCLIENTINFO = function (clientInfo) {
    var tId = this.session.persistSession.holder.tenant.id;

    //TODO: check if clientInfo is still the same

    this.session.sessions[tId].clientInfo = clientInfo;
    //TODO: discuss with team if this is needed
    //this.setPersistSessionSTATE("CLIENTINFO");
};

/**
 *
 */
MultiTenantSession.prototype.setURACKEY = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    if (!this.session.sessions[tId].urac)
        return;
    if (this.session.sessions[tId].urac.config.keys[key])
        return;
    else {
        this.session.sessions[tId].urac.config.keys[key] = {};
        this.setPersistSessionSTATE("URACKEY");
        return;
    }
};

/**
 *
 */
MultiTenantSession.prototype.setURACPACKAGE = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var packageCode = this.session.persistSession.holder.product.package;
    if (!this.session.sessions[tId].urac)
        return;
    if (this.session.sessions[tId].urac.config.packages[packageCode])
        return;
    else {
        this.session.sessions[tId].urac.config.packages[packageCode] = {};
        this.setPersistSessionSTATE("URACPACKAGE");
        return;
    }
};

/**
 *
 * @param acl
 * @param cb
 * @returns {*}
 */
MultiTenantSession.prototype.setURACKEYACL = function (acl, cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    if (!this.session.sessions[tId].urac) {
        if (cb && (typeof cb === "function")) {
            return cb();
        }
        else
            return;
    }
    this.setURACKEY();
    this.session.sessions[tId].urac.config.keys[key].acl = acl;
    this.setPersistSessionSTATE("URACKEYACL");
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @param config
 * @param cb
 * @returns {*}
 */
MultiTenantSession.prototype.setURACKEYCONFIG = function (config, cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    if (!this.session.sessions[tId].urac) {
        if (cb && (typeof cb === "function")) {
            return cb();
        }
        else
            return;
    }
    this.setURACKEY();
    this.session.sessions[tId].urac.config.keys[key].config = config;
    this.setPersistSessionSTATE("URACKEYCONFIG");
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @param cb
 */
MultiTenantSession.prototype.clearURAC = function (cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    if (this.session.sessions[tId].urac) {
        this.session.sessions[tId].urac = null;
        this.setPersistSessionSTATE("URAC");
        if (cb && (typeof cb === "function")) {
            this.req.sessionStore.set(this.req.sessionID, this.session, cb);
        }
    }
    else
        cb();
};

/**
 *
 * @param urac
 * @param cb
 * @returns {*}
 */
MultiTenantSession.prototype.setURAC = function (urac, cb) {
    var tId = this.session.persistSession.holder.tenant.id;

    if (!urac) {
        if (cb && (typeof cb === "function")) {
            return cb();
        }
        else
            return;
    }

    //NOTE: we need to assure config = {packages: {}, keys : {}}
    if (!urac.config)
        urac.config = {};
    if (!urac.config.packages)
        urac.config.packages = {};
    if (!urac.config.keys)
        urac.config.keys = {};
    this.session.sessions[tId].urac = urac;

    this.setPersistSessionSTATE("URAC");
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @param acl
 * @param cb
 * @returns {*}
 */
MultiTenantSession.prototype.setURACPACKAGEACL = function (acl, cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    var packageCode = this.session.persistSession.holder.product.package;
    if (!this.session.sessions[tId].urac) {
        if (cb && (typeof cb === "function")) {
            return cb();
        }
        else
            return;
    }
    this.setURACPACKAGE();
    this.session.sessions[tId].urac.config.packages[packageCode].acl = acl;
    this.setPersistSessionSTATE("URACPACKAGEACL");
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @param obj
 * @param cb
 */
MultiTenantSession.prototype.setSERVICE = function (obj, cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    var service = this.session.persistSession.holder.request.service;
    this.session.sessions[tId].keys[key].services[service] = obj;
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @returns {*}
 */
MultiTenantSession.prototype.getSERVICE = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    var service = this.session.persistSession.holder.request.service;
    var obj = this.session.sessions[tId].keys[key].services[service];

    return obj;
};

/**
 *
 * @param cb
 */
MultiTenantSession.prototype.deleteTenantSession = function (cb) {
    var tId = this.session.persistSession.holder.tenant.id;
    this.session.sessions[tId] = null;
    this.setPersistSessionSTATE("TENANT");
    if (cb && (typeof cb === "function")) {
        this.req.sessionStore.set(this.req.sessionID, this.session, cb);
    }
};

/**
 *
 * @returns {*}
 */
MultiTenantSession.prototype.getAcl = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    var packageCode = this.session.persistSession.holder.product.package;
    if (!this.session.sessions[tId].urac) {
        return null;
    }
    var acl = null;
    if (this.session.sessions[tId].urac.config.keys[key] && this.session.sessions[tId].urac.config.keys[key].acl)
        acl = this.session.sessions[tId].urac.config.keys[key].acl;
    if(!acl && this.session.sessions[tId].urac.config.packages[packageCode] && this.session.sessions[tId].urac.config.packages[packageCode].acl)
        acl = this.session.sessions[tId].urac.config.packages[packageCode].acl;

    return acl;
};
/**
 *
 *
 * @returns {*}
 */
MultiTenantSession.prototype.getPackageAcl = function (packageCode) {
    var tId = this.session.persistSession.holder.tenant.id;
    if (!this.session.sessions[tId].urac) {
        return null;
    }
    var acl = null;
    if(!acl && this.session.sessions[tId].urac.config.packages[packageCode] && this.session.sessions[tId].urac.config.packages[packageCode].acl)
        acl = this.session.sessions[tId].urac.config.packages[packageCode].acl;

    return acl;
};

/**
 *
 * @returns {*}
 */
MultiTenantSession.prototype.getConfig = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    var key = this.session.persistSession.holder.tenant.key;
    if (!this.session.sessions[tId].urac) {
        return null;
    }
    var config = null;
    if (this.session.sessions[tId].urac.config.keys[key] && this.session.sessions[tId].urac.config.keys[key].config)
        config = this.session.sessions[tId].urac.config.keys[key].config;

    return config;
};

/**
 *
 * @returns {*}
 */
MultiTenantSession.prototype.getUrac = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    if (!this.session.sessions[tId].urac) {
        return null;
    }
    var urac = null;
    if (this.session.sessions[tId].urac.username){
        urac = {
            "_id": this.session.sessions[tId].urac._id,
            "username": this.session.sessions[tId].urac.username,
            "firstName": this.session.sessions[tId].urac.firstName,
            "lastName": this.session.sessions[tId].urac.lastName,
            "email": this.session.sessions[tId].urac.email,
            "groups" : this.session.sessions[tId].urac.groups,
            "profile": this.session.sessions[tId].urac.profile,
            "tenant" : this.session.sessions[tId].urac.tenant,
            "oauthRefreshToken" : this.session.sessions[tId].urac.oauthRefreshToken,
            "oauthAccessToken" : this.session.sessions[tId].urac.oauthAccessToken
        };
    }
    return urac;
};

/**
 *
 * @returns {*}
 */
MultiTenantSession.prototype.getGroups = function () {
    var tId = this.session.persistSession.holder.tenant.id;
    if (!this.session.sessions[tId].urac) {
        return null;
    }
    var groups = null;
    if (this.session.sessions[tId].urac.groups){
        groups = this.session.sessions[tId].urac.groups;
    }
    return groups;
};

module.exports = MultiTenantSession;

<|endoftext|>


<commit_before>/**
 * Created by jack on 16-4-21.
 */

import Vue from 'vue';
import template from './nav.html';
import './style.scss';

class Navigation {
	constructor() {
		const MinScreenWidth = 768;
		this.previousTop = 0;
		this.isVisible = false;
		this.isFixed = false;
		this._bodyScrollListener = this._bodyScrollListener.bind(this);

		return {
			template,
			data: () => {
				return {
					data: this
				};
			},
			ready: () => {
				MinScreenWidth < document.body.clientWidth && document.addEventListener('scroll', this._bodyScrollListener);
			},
			detached: () => {
				MinScreenWidth < document.body.clientWidth && document.removeEventListener('scroll', this._bodyScrollListener);
			}
		};
	}

	_bodyScrollListener() {
		let currentTop = document.body.scrollTop;
		// in vue ready lifecycle, page not rendered, so can't query the dom element.
		this.headerHeight = document.querySelector('.navbar-custom').clientHeight;

		// check if user is scrolling up
		if (currentTop < this.previousTop) {
			// if scrolling up...
			if (currentTop > 0 && this.isFixed) {
				this.isVisible = true;
			} else {
				this.isVisible = false;
				this.isFixed = false;
			}
		} else if (currentTop > this.previousTop) {
			// if scrolling down...
			this.isVisible = false;
			currentTop > this.headerHeight && (this.isFixed = true);
		}chan
		this.previousTop = currentTop;
	}
}

export default Vue.component('navigation', new Navigation());
<commit_msg>change jquery code into vue components & es6 class<commit_after>/**
 * Created by jack on 16-4-21.
 */

import Vue from 'vue';
import template from './nav.html';
import './style.scss';

class Navigation {
	constructor() {
		const MinScreenWidth = 768;
		this.previousTop = 0;
		this.isVisible = false;
		this.isFixed = false;
		this._bodyScrollListener = this._bodyScrollListener.bind(this);

		return {
			template,
			data: () => {
				return {
					data: this
				};
			},
			ready: () => {
				MinScreenWidth < document.body.clientWidth && document.addEventListener('scroll', this._bodyScrollListener);
			},
			detached: () => {
				MinScreenWidth < document.body.clientWidth && document.removeEventListener('scroll', this._bodyScrollListener);
			}
		};
	}

	_bodyScrollListener() {
		let currentTop = document.body.scrollTop;
		// in vue ready lifecycle, page not rendered, so can't query the dom element.
		this.headerHeight = document.querySelector('.navbar-custom').clientHeight;

		// check if user is scrolling up
		if (currentTop < this.previousTop) {
			// if scrolling up...
			if (currentTop > 0 && this.isFixed) {
				this.isVisible = true;
			} else {
				this.isVisible = false;
				this.isFixed = false;
			}
		} else if (currentTop > this.previousTop) {
			// if scrolling down...
			this.isVisible = false;
			currentTop > this.headerHeight && (this.isFixed = true);
		}
		this.previousTop = currentTop;
	}
}

export default Vue.component('navigation', new Navigation());
<|endoftext|>


<commit_before>import {Top, Bottom} from './constants';
import guideMark from './guide-mark';
import {RuleMark} from '../marks/marktypes';
import {AxisDomainRole} from '../marks/roles';
import {addEncode} from '../encode/encode-util';

export default function(spec, config, userEncode, dataRef) {
  var orient = spec.orient,
      zero = {value: 0},
      encode = {}, enter, update, u, u2, v;

  encode.enter = enter = {
    opacity: zero
  };
  addEncode(enter, 'stroke', config.tickColor);
  addEncode(enter, 'strokeWidth', config.tickWidth);

  encode.exit = {
    opacity: zero
  };

  encode.update = update = {
    opacity: {value: 1}
  };

  (orient === Top || orient === Bottom)
    ? (u = 'x', v = 'y')
    : (u = 'y', v = 'x');
  u2 = u + '2',

  enter[v] = zero;
  update[u] = enter[u] = position(spec, 0);
  update[u2] = enter[u2] = position(spec, 1);

  return guideMark(RuleMark, AxisDomainRole, null, dataRef, encode, userEncode);
}

function position(spec, pos) {
  return {scale: spec.scale, range: pos};
}
<commit_msg>Fix axis domain config lookup.<commit_after>import {Top, Bottom} from './constants';
import guideMark from './guide-mark';
import {RuleMark} from '../marks/marktypes';
import {AxisDomainRole} from '../marks/roles';
import {addEncode} from '../encode/encode-util';

export default function(spec, config, userEncode, dataRef) {
  var orient = spec.orient,
      zero = {value: 0},
      encode = {}, enter, update, u, u2, v;

  encode.enter = enter = {
    opacity: zero
  };
  addEncode(enter, 'stroke', config.domainColor);
  addEncode(enter, 'strokeWidth', config.domainWidth);

  encode.exit = {
    opacity: zero
  };

  encode.update = update = {
    opacity: {value: 1}
  };

  (orient === Top || orient === Bottom)
    ? (u = 'x', v = 'y')
    : (u = 'y', v = 'x');
  u2 = u + '2',

  enter[v] = zero;
  update[u] = enter[u] = position(spec, 0);
  update[u2] = enter[u2] = position(spec, 1);

  return guideMark(RuleMark, AxisDomainRole, null, dataRef, encode, userEncode);
}

function position(spec, pos) {
  return {scale: spec.scale, range: pos};
}
<|endoftext|>


<commit_before>import Complex from "src/math/Complex.js"
import Matrix from "src/math/Matrix.js"
import QuantumShaders from "src/pipeline/QuantumShaders.js"
import Seq from "src/base/Seq.js"
import PipelineNode from "src/pipeline/PipelineNode.js"
import Util from "src/base/Util.js"
import WglDirector from "src/webgl/WglDirector.js"
import WglTexture from "src/webgl/WglTexture.js"

/**
 * Represents a WebGL texture containing amplitudes or probabilities, to be computed when the pipeline is run.
 *
 * Use mergedReadFloats to get pipeline nodes for the pixel data, instead of the not-so-useful textures.
 */
export default class SuperpositionNode {

    /**
     * @param {!(!PipelineNode[])} inputNodes
     * @param {!function(!(!WglTexture[])) : !WglTexture} operation
     * @param {!int} width
     * @param {!int} height
     *
     * @property {!PipelineNode} pipelineNode
     * @property {!int} width
     * @property {!int} height
     */
    constructor(width, height, inputNodes, operation) {
        this.pipelineNode = new PipelineNode(inputNodes, operation, reuseTexture);
        this.width = width;
        this.height = height;
    }

    /**
     * @param {!int} qubitCount
     * @param {!function(!WglTexture)} render
     * @returns {!SuperpositionNode}
     */
    static input(qubitCount, render) {
        let w = 1 << Math.ceil(qubitCount / 2);
        let h = 1 << Math.floor(qubitCount / 2);
        return new SuperpositionNode(w, h, [], () => {
            let result = allocTexture(w, h);
            render(result);
            return result;
        });
    }

    /**
     * Creates a superposition with the given amplitudes for each possible state.
     * @param {!(!Complex[])|!(!number[])} amplitudes
     * @returns {!SuperpositionNode}
     */
    static fromAmplitudes(amplitudes) {
        Util.need(Util.isPowerOf2(amplitudes.length), "isPowerOf2(amplitudes.length)");

        let dataArray = new Float32Array(amplitudes.length * 4);
        for (let i = 0; i < amplitudes.length; i++) {
            dataArray[i*4] = Complex.realPartOf(amplitudes[i]);
            dataArray[i*4 + 1] = Complex.imagPartOf(amplitudes[i]);
        }
        let qubitCount = Util.bitSize(amplitudes.length - 1);
        return SuperpositionNode.input(
            qubitCount,
            t => QuantumShaders.renderPixelColorData(getSharedDirector(), t, dataArray));
    };

    /**
     * Creates a superposition initialized into a classical state.
     * @param {!int} qubitCount
     * @param {!int} stateIndex
     * @returns {!SuperpositionNode}
     */
    static fromClassicalStateInRegisterOfSize(stateIndex, qubitCount) {
        Util.need(qubitCount >= 0, "qubitCount >= 0");
        Util.need(stateIndex >= 0 && stateIndex < (1 << qubitCount), "stateMask >= 0 && stateMask < (1 << qubitCount)");

        return SuperpositionNode.input(qubitCount, t =>
            QuantumShaders.renderClassicalState(getSharedDirector(), t, stateIndex));
    };

    /**
     * Returns a texture holding the result of applying a single-qubit operation to the receiving texture's quantum
     * state.
     * @param {!int} qubitIndex The index of the qubit to apply the operation to.
     * @param {!Matrix} operation A 2x2 matrix.
     * @param {!QuantumControlMask} controlMask
     * @returns {!SuperpositionNode}
     */
    withQubitOperationApplied(qubitIndex, operation, controlMask) {
        Util.need(controlMask.desiredValueFor(qubitIndex) === null, "Controlled with qubit being modified.");

        return new SuperpositionNode(this.width, this.height, [this.pipelineNode], input => {
            let control = QuantumShaders.renderControlMask(
                getSharedDirector(),
                controlMask,
                allocTexture(this.width, this.height),
                allocTexture(this.width, this.height));
            QuantumShaders.renderQubitOperation(
                getSharedDirector(),
                control.available,
                input[0],
                operation,
                qubitIndex,
                control.result);
            reuseTexture(control.result);
            return control.available;
        });
    };

    /**
     * Returns a texture holding the result of applying a swap operation.
     * @param {!int} qubitIndex1 The index of one of the qubits to swap.
     * @param {!int} qubitIndex2 The index of the other qubit to swap.
     * @param {!QuantumControlMask} controlMask
     * @returns {!SuperpositionNode}
     */
    withSwap(qubitIndex1, qubitIndex2, controlMask) {
        Util.need(controlMask.desiredValueFor(qubitIndex1) === null, "Controlled with qubit being modified.");
        Util.need(controlMask.desiredValueFor(qubitIndex2) === null, "Controlled with qubit being modified.");

        return new SuperpositionNode(this.width, this.height, [this.pipelineNode], input => {
            let control = QuantumShaders.renderControlMask(
                getSharedDirector(),
                controlMask,
                allocTexture(this.width, this.height),
                allocTexture(this.width, this.height));
            QuantumShaders.renderSwapOperation(
                getSharedDirector(),
                control.available,
                input[0],
                qubitIndex1,
                qubitIndex2,
                control.result);
            reuseTexture(control.result);
            return control.available;
        });
    }

    /**
     * Returns a texture containing probabilities that the superposition would match various control masks if measured.
     *
     * @param {!QuantumControlMask} controlMask
     * @returns {!SuperpositionNode}
     */
    controlledProbabilities(controlMask) {
        let qubitCount = Util.bitSize(this.width * this.height - 1);
        let qubitCountLg2 = Util.bitSize(qubitCount - 1);
        let w = 1 << Math.ceil(qubitCountLg2 / 2);
        let h = 1 << Math.floor(qubitCountLg2 / 2);

        return new SuperpositionNode(w, h, [this.pipelineNode], inputs => {
            let result = allocTexture(w, h);
            let workspace1 = allocTexture(this.width, this.height);
            let workspace2 = allocTexture(this.width, this.height);
            QuantumShaders.renderControlCombinationProbabilities(
                getSharedDirector(),
                result,
                workspace1,
                workspace2,
                controlMask,
                inputs[0]);
            reuseTexture(workspace1);
            reuseTexture(workspace2);
            return result;
        });
    };

    /**
     * Returns a texture containing probabilities that the superposition would match various control masks if measured.
     *
     * @param {!QuantumControlMask} controlMask
     * @returns {!SuperpositionNode}
     */
    densityMatrixI(i, controlMask) {
        let qubitCount = Util.bitSize(this.width * this.height - 1);
        let w = 2;
        let h = 2;

        return new SuperpositionNode(w, h, [this.pipelineNode], inputs => {
            let result = allocTexture(2, 2);
            QuantumShaders.renderSuperpositionToDensityMatrix(
                getSharedDirector(),
                result,
                inputs[0],
                [i],
                Seq.range(qubitCount).filter(e => e !== i).toArray(),
                controlMask);
            return result;
        });
    };

    /**
     * Returns a node with operations for extending the pipeline after the eventual pixel data read occurs.
     * @returns {!SuperpositionReadNode}
     */
    read() {
        return new SuperpositionReadNode(new PipelineNode(
            [this.pipelineNode],
            inputs => getSharedDirector().readPixelColorFloats(inputs[0])));
    };

    /**
     * Figures out how large of a texture is needed to aggregate all the desired results, and the offset where those
     * results will end up in the output.
     *
     * @param {!Map.<K, !{width: !int, height: !int}>} sizeMap
     * @returns {!{width: !int, height: !int, placeMap: !Map.<K, !int>}}
     * @template K
     */
    static planPackingIntoSingleTexture(sizeMap) {
        let total = 0;

        let placeMap = new Map();
        for (let [key, size] of sizeMap) {
            //noinspection JSUnusedAssignment
            let {width: w, height: h} = size;
            //noinspection JSUnusedAssignment
            placeMap.set(key, total);
            total += w * h;
        }

        let width = Util.ceilingPowerOf2(Math.ceil(Math.sqrt(total)));
        let height = Util.ceilingPowerOf2(Math.ceil(total / width));

        return {width, height, placeMap};
    };

    /**
     * @param {!(!SuperpositionNode[])} superpositionNodes
     * @returns {!(!SuperpositionReadNode[])}
     */
    static mergedReadFloats(superpositionNodes) {
        let sizes = new Seq(superpositionNodes).keyedBy(e => e.pipelineNode.id);
        let plan = SuperpositionNode.planPackingIntoSingleTexture(sizes);

        let seedCombined = new SuperpositionNode(plan.width, plan.height, [], () => {
            let t = allocTexture(plan.width, plan.height);
            QuantumShaders.renderUniformColor(getSharedDirector(), t, 0, 0, 0, 0);
            return t;
        });
        let accumulateCombined = (aNode, eNode) => new SuperpositionNode(
            plan.width,
            plan.height,
            [aNode.pipelineNode, eNode.pipelineNode],
            textures => {
                // Note: this would be more efficient if the merging was done in a balanced way.
                // This will do for now, despite being quadratic instead of n log n.
                let [a, e] = textures;
                let t = allocTexture(plan.width, plan.height);
                let r = plan.placeMap.get(eNode.pipelineNode.id);
                QuantumShaders.renderLinearOverlay(getSharedDirector(), t, r, e, a);
                return t;
            });

        // Hope they're in the right order (as opposed to doing a topological sort)...
        let combined = new Seq(superpositionNodes).aggregate(seedCombined, accumulateCombined).read();

        return new Seq(superpositionNodes).map(
            e => new SuperpositionReadNode(new PipelineNode([combined.floatsNode], inputs => {
                let floats = inputs[0];
                let offset = plan.placeMap.get(e.pipelineNode.id) * 4;
                let length = e.width * e.height * 4;

                if (floats.slice) {
                    return floats.slice(offset, offset + length);
                }

                // The above fails in chrome, so we need this fallback. For now.
                let result = new Float32Array(length);
                for (let i = 0; i < length; i++) {
                    result[i] = floats[i + offset];
                }
                return result;
            }))).toArray();
    }
}

/**
 * Represents an array of amplitudes or probabilities to be computed when the surrounding pipeline is run.
 */
export class SuperpositionReadNode {
    /**
     * @param {!PipelineNode<!Array.<!number>|!Float32Array>} floatsNode
     * @property {!PipelineNode<!Array.<!number>|!Float32Array>} floatsNode
     */
    constructor(floatsNode) {
        this.floatsNode = floatsNode;
    }

    /**
     * Just the read texture's color component float data.
     * @returns {!PipelineNode<!(!Complex[])>}
     */
    raw() {
        return this.floatsNode;
    };

    /**
     * Reads the amplitudes associated with the texture data (red component for reals, blue for imaginaries).
     * @returns {!PipelineNode.<!Array.<!Complex>>}
     */
    asRenormalizedAmplitudes() {
        return new PipelineNode([this.floatsNode], inputs => {
            let floats = inputs[0];

            // Renormalization factor. For better answers when non-unitary gates are used.
            let unity = 0;
            for (let f of floats) {
                unity += f*f;
            }
            unity = Math.sqrt(unity);

            return Seq.range(floats.length/4).map(i => new Complex(floats[i*4]/unity, floats[i*4+1]/unity)).toArray();
        });
    };

    /**
     * Reads the amplitudes associated with the texture data (red component for reals, blue for imaginaries).
     * @returns {!PipelineNode.<!Array.<!Complex>>}
     */
    asDensityMatrix() {
        return new PipelineNode([this.floatsNode], inputs => {
            let floats = inputs[0];

            let n = Math.round(Math.sqrt(floats.length/4));
            if (!Util.isPowerOf2(n) || !n*n*4 === floats.length) {
                throw new Error("Need a square number of entries.")
            }

            let matrix = Matrix.generate(n, n, (r, c) => new Complex(floats[(r*n + c)*4], floats[(r*n + c)*4 + 1]));

            // Renormalization factor. For better answers when non-unitary gates are used.
            let unity = matrix.trace();
            if (unity.isEqualTo(0)) {
                return matrix.scaledBy(NaN);
            }

            return matrix.scaledBy(Complex.ONE.dividedBy(unity));
        });
    };

    /**
     * Reads the probability that each qubit would end up true, if measured, based on the texture data being
     * control combination data.
     * @param {!QuantumControlMask} mask The mask that was used when combining the probabilities.
     * @param {!int} qubitCount
     * @returns {!PipelineNode.<!Array.<!number>>}
     */
    asRenormalizedPerQubitProbabilities(mask, qubitCount) {
        return new PipelineNode([this.floatsNode], inputs => {
            let floats = inputs[0];
            return Seq.range(qubitCount).
                map(i => {
                    let invertedProbability = (mask.desiredValueMask & (1 << i)) === 0;
                    let unity = floats[4 * i];
                    if (unity <= 0) {
                        return NaN;
                    }
                    let p = floats[4 * i + 1] / unity;
                    p = Math.max(0, Math.min(1, p));
                    return invertedProbability ? 1 - p : p;
                }).
                toArray();
        });
    };

    /**
     * Reads the probability that each qubit would end up true, given that the mask's conrols were satisfied,
     * based on the texture data being corresponding control combination data.
     * @param {!QuantumControlMask} mask
     * @param {!int} qubitCount
     * @returns {!PipelineNode.<!Array.<!number>>}
     */
    asRenormalizedConditionalPerQubitProbabilities(mask, qubitCount) {
        return new PipelineNode([this.floatsNode], inputs => {
            let floats = inputs[0];
            let r = Seq.range(qubitCount).
                map(i => {
                    let reversedValues = (mask.inclusionMask & (1 << i)) === 0;
                    let invertedProbability = (mask.desiredValueMask & (1 << i)) === 0;
                    let pMatch = floats[4 * i + 2];
                    let pEither = floats[4 * i + 3];
                    if (reversedValues) {
                        [pEither, pMatch] = [pMatch, pEither]
                    }
                    if (pEither <= 0) {
                        return NaN;
                    }
                    let p = pMatch / pEither;
                    p = Math.max(0, Math.min(1, p));
                    return invertedProbability ? 1 - p : p;
                }).
                toArray();
            return r;
        });
    };
}

/** @type {undefined|!WglDirector} */
let CACHED_SHARED_DIRECTOR = undefined;
/** @returns {!WglDirector} */
let getSharedDirector = () => {
    if (CACHED_SHARED_DIRECTOR === undefined) {
        CACHED_SHARED_DIRECTOR = new WglDirector();
    }
    return CACHED_SHARED_DIRECTOR;
};

/** @type {!Map.<!int, !(!WglTexture[])>} */
let TEXTURE_POOL = new Map();

/**
 * @param {!int} width
 * @param {!int} height
 * @returns {!WglTexture}
 */
let allocTexture = (width, height) => {
    let k = width + ":" + height;

    if (!TEXTURE_POOL.has(k)) {
        TEXTURE_POOL.set(k, []);
    }
    let pool = TEXTURE_POOL.get(k);
    if (pool.length > 0) {
        return pool.pop();
    }

    return new WglTexture(width, height);
};

/**
 * @param {!WglTexture} texture
 */
let reuseTexture = texture => {
    let pool = TEXTURE_POOL.get(texture.width + ":" + texture.height);
    pool.push(texture);
};
<commit_msg>Falling to NaN when denominator gets suspicious<commit_after>import Complex from "src/math/Complex.js"
import Matrix from "src/math/Matrix.js"
import QuantumShaders from "src/pipeline/QuantumShaders.js"
import Seq from "src/base/Seq.js"
import PipelineNode from "src/pipeline/PipelineNode.js"
import Util from "src/base/Util.js"
import WglDirector from "src/webgl/WglDirector.js"
import WglTexture from "src/webgl/WglTexture.js"

/**
 * Represents a WebGL texture containing amplitudes or probabilities, to be computed when the pipeline is run.
 *
 * Use mergedReadFloats to get pipeline nodes for the pixel data, instead of the not-so-useful textures.
 */
export default class SuperpositionNode {

    /**
     * @param {!(!PipelineNode[])} inputNodes
     * @param {!function(!(!WglTexture[])) : !WglTexture} operation
     * @param {!int} width
     * @param {!int} height
     *
     * @property {!PipelineNode} pipelineNode
     * @property {!int} width
     * @property {!int} height
     */
    constructor(width, height, inputNodes, operation) {
        this.pipelineNode = new PipelineNode(inputNodes, operation, reuseTexture);
        this.width = width;
        this.height = height;
    }

    /**
     * @param {!int} qubitCount
     * @param {!function(!WglTexture)} render
     * @returns {!SuperpositionNode}
     */
    static input(qubitCount, render) {
        let w = 1 << Math.ceil(qubitCount / 2);
        let h = 1 << Math.floor(qubitCount / 2);
        return new SuperpositionNode(w, h, [], () => {
            let result = allocTexture(w, h);
            render(result);
            return result;
        });
    }

    /**
     * Creates a superposition with the given amplitudes for each possible state.
     * @param {!(!Complex[])|!(!number[])} amplitudes
     * @returns {!SuperpositionNode}
     */
    static fromAmplitudes(amplitudes) {
        Util.need(Util.isPowerOf2(amplitudes.length), "isPowerOf2(amplitudes.length)");

        let dataArray = new Float32Array(amplitudes.length * 4);
        for (let i = 0; i < amplitudes.length; i++) {
            dataArray[i*4] = Complex.realPartOf(amplitudes[i]);
            dataArray[i*4 + 1] = Complex.imagPartOf(amplitudes[i]);
        }
        let qubitCount = Util.bitSize(amplitudes.length - 1);
        return SuperpositionNode.input(
            qubitCount,
            t => QuantumShaders.renderPixelColorData(getSharedDirector(), t, dataArray));
    };

    /**
     * Creates a superposition initialized into a classical state.
     * @param {!int} qubitCount
     * @param {!int} stateIndex
     * @returns {!SuperpositionNode}
     */
    static fromClassicalStateInRegisterOfSize(stateIndex, qubitCount) {
        Util.need(qubitCount >= 0, "qubitCount >= 0");
        Util.need(stateIndex >= 0 && stateIndex < (1 << qubitCount), "stateMask >= 0 && stateMask < (1 << qubitCount)");

        return SuperpositionNode.input(qubitCount, t =>
            QuantumShaders.renderClassicalState(getSharedDirector(), t, stateIndex));
    };

    /**
     * Returns a texture holding the result of applying a single-qubit operation to the receiving texture's quantum
     * state.
     * @param {!int} qubitIndex The index of the qubit to apply the operation to.
     * @param {!Matrix} operation A 2x2 matrix.
     * @param {!QuantumControlMask} controlMask
     * @returns {!SuperpositionNode}
     */
    withQubitOperationApplied(qubitIndex, operation, controlMask) {
        Util.need(controlMask.desiredValueFor(qubitIndex) === null, "Controlled with qubit being modified.");

        return new SuperpositionNode(this.width, this.height, [this.pipelineNode], input => {
            let control = QuantumShaders.renderControlMask(
                getSharedDirector(),
                controlMask,
                allocTexture(this.width, this.height),
                allocTexture(this.width, this.height));
            QuantumShaders.renderQubitOperation(
                getSharedDirector(),
                control.available,
                input[0],
                operation,
                qubitIndex,
                control.result);
            reuseTexture(control.result);
            return control.available;
        });
    };

    /**
     * Returns a texture holding the result of applying a swap operation.
     * @param {!int} qubitIndex1 The index of one of the qubits to swap.
     * @param {!int} qubitIndex2 The index of the other qubit to swap.
     * @param {!QuantumControlMask} controlMask
     * @returns {!SuperpositionNode}
     */
    withSwap(qubitIndex1, qubitIndex2, controlMask) {
        Util.need(controlMask.desiredValueFor(qubitIndex1) === null, "Controlled with qubit being modified.");
        Util.need(controlMask.desiredValueFor(qubitIndex2) === null, "Controlled with qubit being modified.");

        return new SuperpositionNode(this.width, this.height, [this.pipelineNode], input => {
            let control = QuantumShaders.renderControlMask(
                getSharedDirector(),
                controlMask,
                allocTexture(this.width, this.height),
                allocTexture(this.width, this.height));
            QuantumShaders.renderSwapOperation(
                getSharedDirector(),
                control.available,
                input[0],
                qubitIndex1,
                qubitIndex2,
                control.result);
            reuseTexture(control.result);
            return control.available;
        });
    }

    /**
     * Returns a texture containing probabilities that the superposition would match various control masks if measured.
     *
     * @param {!QuantumControlMask} controlMask
     * @returns {!SuperpositionNode}
     */
    controlledProbabilities(controlMask) {
        let qubitCount = Util.bitSize(this.width * this.height - 1);
        let qubitCountLg2 = Util.bitSize(qubitCount - 1);
        let w = 1 << Math.ceil(qubitCountLg2 / 2);
        let h = 1 << Math.floor(qubitCountLg2 / 2);

        return new SuperpositionNode(w, h, [this.pipelineNode], inputs => {
            let result = allocTexture(w, h);
            let workspace1 = allocTexture(this.width, this.height);
            let workspace2 = allocTexture(this.width, this.height);
            QuantumShaders.renderControlCombinationProbabilities(
                getSharedDirector(),
                result,
                workspace1,
                workspace2,
                controlMask,
                inputs[0]);
            reuseTexture(workspace1);
            reuseTexture(workspace2);
            return result;
        });
    };

    /**
     * Returns a texture containing probabilities that the superposition would match various control masks if measured.
     *
     * @param {!QuantumControlMask} controlMask
     * @returns {!SuperpositionNode}
     */
    densityMatrixI(i, controlMask) {
        let qubitCount = Util.bitSize(this.width * this.height - 1);
        let w = 2;
        let h = 2;

        return new SuperpositionNode(w, h, [this.pipelineNode], inputs => {
            let result = allocTexture(2, 2);
            QuantumShaders.renderSuperpositionToDensityMatrix(
                getSharedDirector(),
                result,
                inputs[0],
                [i],
                Seq.range(qubitCount).filter(e => e !== i).toArray(),
                controlMask);
            return result;
        });
    };

    /**
     * Returns a node with operations for extending the pipeline after the eventual pixel data read occurs.
     * @returns {!SuperpositionReadNode}
     */
    read() {
        return new SuperpositionReadNode(new PipelineNode(
            [this.pipelineNode],
            inputs => getSharedDirector().readPixelColorFloats(inputs[0])));
    };

    /**
     * Figures out how large of a texture is needed to aggregate all the desired results, and the offset where those
     * results will end up in the output.
     *
     * @param {!Map.<K, !{width: !int, height: !int}>} sizeMap
     * @returns {!{width: !int, height: !int, placeMap: !Map.<K, !int>}}
     * @template K
     */
    static planPackingIntoSingleTexture(sizeMap) {
        let total = 0;

        let placeMap = new Map();
        for (let [key, size] of sizeMap) {
            //noinspection JSUnusedAssignment
            let {width: w, height: h} = size;
            //noinspection JSUnusedAssignment
            placeMap.set(key, total);
            total += w * h;
        }

        let width = Util.ceilingPowerOf2(Math.ceil(Math.sqrt(total)));
        let height = Util.ceilingPowerOf2(Math.ceil(total / width));

        return {width, height, placeMap};
    };

    /**
     * @param {!(!SuperpositionNode[])} superpositionNodes
     * @returns {!(!SuperpositionReadNode[])}
     */
    static mergedReadFloats(superpositionNodes) {
        let sizes = new Seq(superpositionNodes).keyedBy(e => e.pipelineNode.id);
        let plan = SuperpositionNode.planPackingIntoSingleTexture(sizes);

        let seedCombined = new SuperpositionNode(plan.width, plan.height, [], () => {
            let t = allocTexture(plan.width, plan.height);
            QuantumShaders.renderUniformColor(getSharedDirector(), t, 0, 0, 0, 0);
            return t;
        });
        let accumulateCombined = (aNode, eNode) => new SuperpositionNode(
            plan.width,
            plan.height,
            [aNode.pipelineNode, eNode.pipelineNode],
            textures => {
                // Note: this would be more efficient if the merging was done in a balanced way.
                // This will do for now, despite being quadratic instead of n log n.
                let [a, e] = textures;
                let t = allocTexture(plan.width, plan.height);
                let r = plan.placeMap.get(eNode.pipelineNode.id);
                QuantumShaders.renderLinearOverlay(getSharedDirector(), t, r, e, a);
                return t;
            });

        // Hope they're in the right order (as opposed to doing a topological sort)...
        let combined = new Seq(superpositionNodes).aggregate(seedCombined, accumulateCombined).read();

        return new Seq(superpositionNodes).map(
            e => new SuperpositionReadNode(new PipelineNode([combined.floatsNode], inputs => {
                let floats = inputs[0];
                let offset = plan.placeMap.get(e.pipelineNode.id) * 4;
                let length = e.width * e.height * 4;

                if (floats.slice) {
                    return floats.slice(offset, offset + length);
                }

                // The above fails in chrome, so we need this fallback. For now.
                let result = new Float32Array(length);
                for (let i = 0; i < length; i++) {
                    result[i] = floats[i + offset];
                }
                return result;
            }))).toArray();
    }
}

/**
 * Represents an array of amplitudes or probabilities to be computed when the surrounding pipeline is run.
 */
export class SuperpositionReadNode {
    /**
     * @param {!PipelineNode<!Array.<!number>|!Float32Array>} floatsNode
     * @property {!PipelineNode<!Array.<!number>|!Float32Array>} floatsNode
     */
    constructor(floatsNode) {
        this.floatsNode = floatsNode;
    }

    /**
     * Just the read texture's color component float data.
     * @returns {!PipelineNode<!(!Complex[])>}
     */
    raw() {
        return this.floatsNode;
    };

    /**
     * Reads the amplitudes associated with the texture data (red component for reals, blue for imaginaries).
     * @returns {!PipelineNode.<!Array.<!Complex>>}
     */
    asRenormalizedAmplitudes() {
        return new PipelineNode([this.floatsNode], inputs => {
            let floats = inputs[0];

            // Renormalization factor. For better answers when non-unitary gates are used.
            let unity = 0;
            for (let f of floats) {
                unity += f*f;
            }
            unity = Math.sqrt(unity);
            if (unity < 0.000001) {
                unity = NaN;
            }

            return Seq.range(floats.length/4).map(i => new Complex(floats[i*4]/unity, floats[i*4+1]/unity)).toArray();
        });
    };

    /**
     * Reads the amplitudes associated with the texture data (red component for reals, blue for imaginaries).
     * @returns {!PipelineNode.<!Array.<!Complex>>}
     */
    asDensityMatrix() {
        return new PipelineNode([this.floatsNode], inputs => {
            let floats = inputs[0];

            let n = Math.round(Math.sqrt(floats.length/4));
            if (!Util.isPowerOf2(n) || !n*n*4 === floats.length) {
                throw new Error("Need a square number of entries.")
            }

            let matrix = Matrix.generate(n, n, (r, c) => new Complex(floats[(r*n + c)*4], floats[(r*n + c)*4 + 1]));

            // Renormalization factor. For better answers when non-unitary gates are used.
            let unity = matrix.trace();
            if (unity.abs() < 0.00001) {
                return matrix.scaledBy(NaN);
            }

            return matrix.scaledBy(Complex.ONE.dividedBy(unity));
        });
    };

    /**
     * Reads the probability that each qubit would end up true, if measured, based on the texture data being
     * control combination data.
     * @param {!QuantumControlMask} mask The mask that was used when combining the probabilities.
     * @param {!int} qubitCount
     * @returns {!PipelineNode.<!Array.<!number>>}
     */
    asRenormalizedPerQubitProbabilities(mask, qubitCount) {
        return new PipelineNode([this.floatsNode], inputs => {
            let floats = inputs[0];
            return Seq.range(qubitCount).
                map(i => {
                    let invertedProbability = (mask.desiredValueMask & (1 << i)) === 0;
                    let unity = floats[4 * i];
                    if (unity < 0.000001) {
                        return NaN;
                    }
                    let p = floats[4 * i + 1] / unity;
                    p = Math.max(0, Math.min(1, p));
                    return invertedProbability ? 1 - p : p;
                }).
                toArray();
        });
    };

    /**
     * Reads the probability that each qubit would end up true, given that the mask's conrols were satisfied,
     * based on the texture data being corresponding control combination data.
     * @param {!QuantumControlMask} mask
     * @param {!int} qubitCount
     * @returns {!PipelineNode.<!Array.<!number>>}
     */
    asRenormalizedConditionalPerQubitProbabilities(mask, qubitCount) {
        return new PipelineNode([this.floatsNode], inputs => {
            let floats = inputs[0];
            let r = Seq.range(qubitCount).
                map(i => {
                    let reversedValues = (mask.inclusionMask & (1 << i)) === 0;
                    let invertedProbability = (mask.desiredValueMask & (1 << i)) === 0;
                    let pMatch = floats[4 * i + 2];
                    let pEither = floats[4 * i + 3];
                    if (reversedValues) {
                        [pEither, pMatch] = [pMatch, pEither]
                    }
                    if (pEither <= 0) {
                        return NaN;
                    }
                    let p = pMatch / pEither;
                    p = Math.max(0, Math.min(1, p));
                    return invertedProbability ? 1 - p : p;
                }).
                toArray();
            return r;
        });
    };
}

/** @type {undefined|!WglDirector} */
let CACHED_SHARED_DIRECTOR = undefined;
/** @returns {!WglDirector} */
let getSharedDirector = () => {
    if (CACHED_SHARED_DIRECTOR === undefined) {
        CACHED_SHARED_DIRECTOR = new WglDirector();
    }
    return CACHED_SHARED_DIRECTOR;
};

/** @type {!Map.<!int, !(!WglTexture[])>} */
let TEXTURE_POOL = new Map();

/**
 * @param {!int} width
 * @param {!int} height
 * @returns {!WglTexture}
 */
let allocTexture = (width, height) => {
    let k = width + ":" + height;

    if (!TEXTURE_POOL.has(k)) {
        TEXTURE_POOL.set(k, []);
    }
    let pool = TEXTURE_POOL.get(k);
    if (pool.length > 0) {
        return pool.pop();
    }

    return new WglTexture(width, height);
};

/**
 * @param {!WglTexture} texture
 */
let reuseTexture = texture => {
    let pool = TEXTURE_POOL.get(texture.width + ":" + texture.height);
    pool.push(texture);
};
<|endoftext|>


<commit_before>import React from 'react';
import cx from 'classnames';

const DEPLOYMENT_SVG = (
  <svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 50 50">
    <path d="M 35.34375 -0.09375 C 31.92175 -0.09375 28.7935 1.82125 27.1875 4.78125 C 26.4305 4.35225 25.55025 4.125 24.65625 4.125 C 22.03025 4.125 19.87075 6.10225 19.59375 8.65625 C 18.79175 8.97525 18.08375 9.46125 17.46875 10.03125 C 17.42775 10.02625 17.38575 10 17.34375 10 L 7.6875 10 C 6.7755 10 5.9525 10.69025 5.8125 11.53125 L 0.875 32.1875 C 1.233 32.0815 1.608 32 2 32 L 48 32 C 48.38 32 48.74575 32.05725 49.09375 32.15625 L 46.5 21.3125 C 47.098 21.0105 47.637 20.613 48.125 20.125 C 49.331 18.918 50 17.30075 50 15.59375 C 50 12.42875 47.677 9.8165 44.625 9.3125 C 44.626 9.2745 44.625 9.2255 44.625 9.1875 C 44.625 4.0635 40.46775 -0.09375 35.34375 -0.09375 z M 35.34375 1.90625 C 39.36475 1.90625 42.625 5.1655 42.625 9.1875 C 42.625 9.4955 42.5995 9.79675 42.5625 10.09375 L 42.46875 11.21875 L 43.59375 11.21875 C 46.01675 11.21875 48 13.17075 48 15.59375 C 48 16.76675 47.54775 17.88975 46.71875 18.71875 C 45.88975 19.54775 44.797 20 43.625 20 L 22.15625 20 C 19.44425 20 17.25 17.80475 17.25 15.09375 C 17.25 12.89275 18.71875 10.93075 20.84375 10.34375 L 21.59375 10.125 L 21.5625 9.21875 C 21.5625 7.50875 22.94625 6.125 24.65625 6.125 C 25.48625 6.125 26.289 6.44425 26.875 7.03125 L 27.96875 8.125 L 28.5 6.65625 C 29.556 3.80425 32.31175 1.90625 35.34375 1.90625 z M 2 34 C 0.897 34 0 34.897 0 36 L 0 48 C 0 49.103 0.897 50 2 50 L 48 50 C 49.103 50 50 49.103 50 48 L 50 36 C 50 34.897 49.103 34 48 34 L 2 34 z M 40 40 C 41.105 40 42 40.896 42 42 C 42 43.104 41.105 44 40 44 C 38.895 44 38 43.104 38 42 C 38 40.896 38.895 40 40 40 z"></path>
  </svg>
);

const Deployment = (props) => {
  let description;

  switch (props.deployment) {
    case 'heroku':
      description = (

          Heroku — Free Tier. 512MB RAM, 1 web/1 worker, sleeps after 30 min of inactivity, must sleep 6 hours in a 24 hour period. No credit card required.

      );
      break;
    case 'azure':
      description = (

          Microsoft Azure — Free one-month trial. Sign up for free and get $200 to spend on all Azure services.

      );
      break;
    case 'bluemix':
      description = (

          IBM Bluemix — Free Tier. 512BM RAM, 2 Public IP Addresses, 20 GB External Storage. No credit card required.

      );
      break;
    case 'digitalOcean':
      description = (

          Digital Ocean — Starts at $5/month. 512MB RAM, 1 Core Processor, 20GB SSD Disk, 1TB Transfer. Referral Link — $10 credit bonus.

      );
      break;
    default:
      description =

;
  }

  return (

{DEPLOYMENT_SVG}{!props.deployment || props.deployment === 'none' ? 'Deployment' : props.deployment}

        {description}

            <input type="radio" name="deploymentRadios" value="none" onChange={props.handleChange} checked={props.deployment === 'none'} />
            None

            <input type="radio" name="deploymentRadios" value="heroku" onChange={props.handleChange} checked={props.deployment === 'heroku'} />
            Heroku

            <input type="radio" name="deploymentRadios" value="azure" onChange={props.handleChange} checked={props.deployment === 'azure'} />
            Microsoft Azure

            <input type="radio" name="deploymentRadios" value="bluemix" onChange={props.handleChange} checked={props.deployment === 'bluemix'} />
            IBM Bluemix

            <input type="radio" name="deploymentRadios" value="digitalOcean" onChange={props.handleChange} checked={props.deployment === 'digitalOcean'} />
            Digital Ocean

  );
};

export default Deployment;
<commit_msg>Shortened deployment label names<commit_after>import React from 'react';
import cx from 'classnames';

const DEPLOYMENT_SVG = (
  <svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 50 50">
    <path d="M 35.34375 -0.09375 C 31.92175 -0.09375 28.7935 1.82125 27.1875 4.78125 C 26.4305 4.35225 25.55025 4.125 24.65625 4.125 C 22.03025 4.125 19.87075 6.10225 19.59375 8.65625 C 18.79175 8.97525 18.08375 9.46125 17.46875 10.03125 C 17.42775 10.02625 17.38575 10 17.34375 10 L 7.6875 10 C 6.7755 10 5.9525 10.69025 5.8125 11.53125 L 0.875 32.1875 C 1.233 32.0815 1.608 32 2 32 L 48 32 C 48.38 32 48.74575 32.05725 49.09375 32.15625 L 46.5 21.3125 C 47.098 21.0105 47.637 20.613 48.125 20.125 C 49.331 18.918 50 17.30075 50 15.59375 C 50 12.42875 47.677 9.8165 44.625 9.3125 C 44.626 9.2745 44.625 9.2255 44.625 9.1875 C 44.625 4.0635 40.46775 -0.09375 35.34375 -0.09375 z M 35.34375 1.90625 C 39.36475 1.90625 42.625 5.1655 42.625 9.1875 C 42.625 9.4955 42.5995 9.79675 42.5625 10.09375 L 42.46875 11.21875 L 43.59375 11.21875 C 46.01675 11.21875 48 13.17075 48 15.59375 C 48 16.76675 47.54775 17.88975 46.71875 18.71875 C 45.88975 19.54775 44.797 20 43.625 20 L 22.15625 20 C 19.44425 20 17.25 17.80475 17.25 15.09375 C 17.25 12.89275 18.71875 10.93075 20.84375 10.34375 L 21.59375 10.125 L 21.5625 9.21875 C 21.5625 7.50875 22.94625 6.125 24.65625 6.125 C 25.48625 6.125 26.289 6.44425 26.875 7.03125 L 27.96875 8.125 L 28.5 6.65625 C 29.556 3.80425 32.31175 1.90625 35.34375 1.90625 z M 2 34 C 0.897 34 0 34.897 0 36 L 0 48 C 0 49.103 0.897 50 2 50 L 48 50 C 49.103 50 50 49.103 50 48 L 50 36 C 50 34.897 49.103 34 48 34 L 2 34 z M 40 40 C 41.105 40 42 40.896 42 42 C 42 43.104 41.105 44 40 44 C 38.895 44 38 43.104 38 42 C 38 40.896 38.895 40 40 40 z"></path>
  </svg>
);

const Deployment = (props) => {
  let description;

  switch (props.deployment) {
    case 'heroku':
      description = (

          Heroku — Free Tier. 512MB RAM, 1 web/1 worker, sleeps after 30 min of inactivity, must sleep 6 hours in a 24 hour period. No credit card required.

      );
      break;
    case 'azure':
      description = (

          Microsoft Azure — Free one-month trial. Sign up for free and get $200 to spend on all Azure services.

      );
      break;
    case 'bluemix':
      description = (

          IBM Bluemix — Free Tier. 512BM RAM, 2 Public IP Addresses, 20 GB External Storage. No credit card required.

      );
      break;
    case 'digitalOcean':
      description = (

          Digital Ocean — Starts at $5/month. 512MB RAM, 1 Core Processor, 20GB SSD Disk, 1TB Transfer. Referral Link — $10 credit bonus.

      );
      break;
    default:
      description =

;
  }

  return (

{DEPLOYMENT_SVG}{!props.deployment || props.deployment === 'none' ? 'Deployment' : props.deployment}

        {description}

            <input type="radio" name="deploymentRadios" value="none" onChange={props.handleChange} checked={props.deployment === 'none'} />
            None

            <input type="radio" name="deploymentRadios" value="heroku" onChange={props.handleChange} checked={props.deployment === 'heroku'} />
            Heroku

            <input type="radio" name="deploymentRadios" value="azure" onChange={props.handleChange} checked={props.deployment === 'azure'} />
            Azure

            <input type="radio" name="deploymentRadios" value="bluemix" onChange={props.handleChange} checked={props.deployment === 'bluemix'} />
            Bluemix

            <input type="radio" name="deploymentRadios" value="digitalOcean" onChange={props.handleChange} checked={props.deployment === 'digitalOcean'} />
            Digital Ocean

  );
};

export default Deployment;
<|endoftext|>