<commit_before>var fs = require('fs')
var nfs = require('node-fs')
var urlparse = require('url').parse
var urlresolve = require('url').resolve
var path = require('path')
var request = require('request')
var CS = require('coffee-script')
CS.register()
var Browser = require('../plain-zombie/zombie/src/zombie/')

var argv = require('minimist')(process.argv.slice(2))
if (argv.h || argv._.length != 2) {
  console.log('USAGE: node client.js <url_file> <output_dir>')
  console.log('-h print this help menu')
  process.exit()
}
url_file = argv._[0]
out_dir = argv._[1]

function parse_url(url) {
  var details = urlparse(url)
  if (path.extname(details.pathname)) {
    details.filename = path.basename(details.pathname)
    details.directory = path.dirname(details.pathname)
  } else {
    details.filename = 'index.html'
    details.directory = details.pathname
  }
  return details
}

function get_directory(details) {
  return path.join(path.join(out_dir,details.host), details.directory)
}

function get_filename(details) {
  return path.join(get_directory(details), details.filename)
}

var pending = 0
var reqs = []
function fetchBrowser(url) {
  console.log('Browsing '+url)
  pending = 0
  var browser = Browser.create()
  browser.waitDuration = '10s'
  browser.on('request', function(req) {
    // Prevent duplicates
    if (reqs.indexOf(req.url) !== -1) {
      return
    }
    reqs.push(req.url)

    fetchObject(req.url)
  })

  browser.on('redirect', function(req, res, red) {
    // Prevent duplicates
    if (reqs.indexOf(red.url) !== -1) {
      return
    }
    reqs.push(red.url)

    fetchObject(red.url)
  })

  browser.visit(url, function () {
    if (pending === 0) {
      nextURL()
    }
  })
}

var dirs = []
function fetchObject(url) {
  console.log('Resource '+url)
  pending += 1
  var details = parse_url(url)

  // If file exists, do not fetch
  fs.stat(get_filename(details), function (err, stats) {
    if (err) {
      createDirectory()
    } else {
      done()
    }
  })

  function createDirectory() {
    // Create domain directory
    if (dirs.indexOf(get_directory(details)) === -1) {
      dirs.push(get_directory(details))

      console.log('Creating directory '+get_directory(details))
      nfs.mkdir(get_directory(details), 0777, true, function (err) {
        if (err) console.log(err)
        onDirectory()
      })
    } else {
      onDirectory()
    }
  }

  function onDirectory() {
    console.log('Fetching '+url)
    try {
      request.get({ uri : url, followRedirect : false, timeout : 5000 }).on('response', onResponse).on('error', function (err) {
        console.log(err)
        done()
      })
    } catch (e) {
      console.log(e)
      done()
    }
  }

  function onResponse(response) {
    // Write response object to file
    var wfile = fs.createWriteStream(get_filename(details))
    wfile.on('error', function(err) { console.log(err) })
    response.pipe(wfile)

    // Store the headers
    var data = {
  	responseCode : 	response.statusCode,
    	headers : 	response.headers
    }
    fs.writeFile(get_filename(details)+'.headers', JSON.stringify(data, null, '\t'), function (err) {
      if (err) console.log(err)
    })
    done()
  }
}

function done() {
  pending -= 1
  if (pending === 0)
    nextURL()
}

// Load the files
var urls = fs.readFileSync(url_file).toString().split('\n')
try {
  fs.mkdirSync(out_dir)
} catch (e) {
  console.log('Error creating output directory.')
}

var i = 0
// Fetch URLs one at a time
function nextURL() {
  if (i < urls.length) {
    fetchBrowser(urls[i])
    i += 1
  } else {
    process.exit()
  }
}

// Go
nextURL()
<commit_msg>remove outdated reference<commit_after>var fs = require('fs')
var nfs = require('node-fs')
var urlparse = require('url').parse
var urlresolve = require('url').resolve
var path = require('path')
var request = require('request')
var CS = require('coffee-script')
CS.register()
var Browser = require('zombie')

var argv = require('minimist')(process.argv.slice(2))
if (argv.h || argv._.length != 2) {
  console.log('USAGE: node client.js <url_file> <output_dir>')
  console.log('-h print this help menu')
  process.exit()
}
url_file = argv._[0]
out_dir = argv._[1]

function parse_url(url) {
  var details = urlparse(url)
  if (path.extname(details.pathname)) {
    details.filename = path.basename(details.pathname)
    details.directory = path.dirname(details.pathname)
  } else {
    details.filename = 'index.html'
    details.directory = details.pathname
  }
  return details
}

function get_directory(details) {
  return path.join(path.join(out_dir,details.host), details.directory)
}

function get_filename(details) {
  return path.join(get_directory(details), details.filename)
}

var pending = 0
var reqs = []
function fetchBrowser(url) {
  console.log('Browsing '+url)
  pending = 0
  var browser = Browser.create()
  browser.waitDuration = '10s'
  browser.features = 'scripts css img iframe'
  browser.on('request', function(req) {
    // Prevent duplicates
    if (reqs.indexOf(req.url) !== -1) {
      return
    }
    reqs.push(req.url)

    fetchObject(req.url)
  })

  browser.on('redirect', function(req, res, red) {
    // Prevent duplicates
    if (reqs.indexOf(red.url) !== -1) {
      return
    }
    reqs.push(red.url)

    fetchObject(red.url)
  })

  browser.visit(url, function () {
    if (pending === 0) {
      nextURL()
    }
  })
}

var dirs = []
function fetchObject(url) {
  console.log('Resource '+url)
  pending += 1
  var details = parse_url(url)

  // If file exists, do not fetch
  fs.stat(get_filename(details), function (err, stats) {
    if (err) {
      createDirectory()
    } else {
      done()
    }
  })

  function createDirectory() {
    // Create domain directory
    if (dirs.indexOf(get_directory(details)) === -1) {
      dirs.push(get_directory(details))

      console.log('Creating directory '+get_directory(details))
      nfs.mkdir(get_directory(details), 0777, true, function (err) {
        if (err) console.log(err)
        onDirectory()
      })
    } else {
      onDirectory()
    }
  }

  function onDirectory() {
    console.log('Fetching '+url)
    try {
      request.get({ uri : url, followRedirect : false, timeout : 5000 }).on('response', onResponse).on('error', function (err) {
        console.log(err)
        done()
      })
    } catch (e) {
      console.log(e)
      done()
    }
  }

  function onResponse(response) {
    // Write response object to file
    var wfile = fs.createWriteStream(get_filename(details))
    wfile.on('error', function(err) { console.log(err) })
    response.pipe(wfile)

    // Store the headers
    var data = {
  	responseCode : 	response.statusCode,
    	headers : 	response.headers
    }
    fs.writeFile(get_filename(details)+'.headers', JSON.stringify(data, null, '\t'), function (err) {
      if (err) console.log(err)
    })
    done()
  }
}

function done() {
  pending -= 1
  if (pending === 0)
    nextURL()
}

// Load the files
var urls = fs.readFileSync(url_file).toString().split('\n')
try {
  fs.mkdirSync(out_dir)
} catch (e) {
  console.log('Error creating output directory.')
}

var i = 0
// Fetch URLs one at a time
function nextURL() {
  if (i < urls.length) {
    fetchBrowser(urls[i])
    i += 1
  } else {
    process.exit()
  }
}

// Go
nextURL()
<|endoftext|>


<commit_before>var PubNub = require('pubnub')
var async = require('async')
var os = require("os");
var config = require('./config.json');

var hostname = os.hostname();

var subscribe = function(callback) {

pubnub = new PubNub({
   publishKey : config.publishKey,
   subscribeKey : config.subscribeKey
})

pubnub.addListener({
  message : function(message) {
    var now = new Date();
    //TODO Awating information into "dirty" json responses
    console.log(message)

  //   message returned is not valid
  //
  //   { channel: 'test',
  // subscription: undefined,
  // actualChannel: null,
  // subscribedChannel: 'test',
  // timetoken: '15028059476527030',
  // publisher: '9B4FD80D-574C-4AB1-9968-FD02F25C0816',
  // message:
  //  { Date: '2017-08-15T14:05:47:000+00:00',
  //    'Content-Length': 3926,
  //    'Cache-Control': 'max-age=6.223095',
  //    'E-Tag': 0,
  //    Status: 404,
  //    Message: 'f8

    console.log("date=" + now +
        ",hostname=" + hostname +
        ",workerid=" + "" +
        ",etag=" + sequenceMessage +
        ",status=" + "" +
        ",elapsed_time_ms=" + "" )
   }

  })

  pubnub.subscribe({
    channels : [ 'test' ]
  });

  callback(null,"Connecting and Subscribing");

};

if (require.main === module) {
  // Number of connections to run on server.
  var connections = 750;
  // Number of seconds to ramp up over.
  var ramp = 600;
  // Concurrent connections attempted per second.
  var rate = Math.ceil((connections / ramp) * 100)/100;;

  var count = 0

  intervalPerConnection = (1/rate)*1000;

  console.log("Rampup commenced " + connections +
   "Connections over " + ramp + " seconds");

  var subscribers = [];

  setTimeout(function request() {
    subscribers.length = 0
    subscribers.push(subscribe);
    async.parallel(subscribers, function(err, result){
      console.log(result)
    });

    if(count == connections){
      console.log("Reached connection count: ", connections);
    }
    else {
      interval = setTimeout(request,intervalPerConnection);
      console.log(count);
      count++;
    }
  }, intervalPerConnection);

} else {
  console.log('please start via node subscribe.js');
}
<commit_msg>WIP: fixed variable not defined error<commit_after>var PubNub = require('pubnub')
var async = require('async')
var os = require("os");
var config = require('./config.json');

var hostname = os.hostname();

var subscribe = function(callback) {

pubnub = new PubNub({
   publishKey : config.publishKey,
   subscribeKey : config.subscribeKey
})

pubnub.addListener({
  message : function(message) {
    var now = new Date();
    //TODO Awating information into "dirty" json responses
    console.log(message)

  //   message returned is not valid
  //
  //   { channel: 'test',
  // subscription: undefined,
  // actualChannel: null,
  // subscribedChannel: 'test',
  // timetoken: '15028059476527030',
  // publisher: '9B4FD80D-574C-4AB1-9968-FD02F25C0816',
  // message:
  //  { Date: '2017-08-15T14:05:47:000+00:00',
  //    'Content-Length': 3926,
  //    'Cache-Control': 'max-age=6.223095',
  //    'E-Tag': 0,
  //    Status: 404,
  //    Message: 'f8

    console.log("date=" + now +
        ",hostname=" + hostname +
        ",workerid=" + "" +
        ",etag=" + "" +
        ",status=" + "" +
        ",elapsed_time_ms=" + "" )
   }

  })

  pubnub.subscribe({
    channels : [ 'test' ]
  });

  callback(null,"Connecting and Subscribing");

};

if (require.main === module) {
  // Number of connections to run on server.
  var connections = 750;
  // Number of seconds to ramp up over.
  var ramp = 600;
  // Concurrent connections attempted per second.
  var rate = Math.ceil((connections / ramp) * 100)/100;;

  var count = 0

  intervalPerConnection = (1/rate)*1000;

  console.log("Rampup commenced " + connections +
   "Connections over " + ramp + " seconds");

  var subscribers = [];

  setTimeout(function request() {
    subscribers.length = 0
    subscribers.push(subscribe);
    async.parallel(subscribers, function(err, result){
      console.log(result)
    });

    if(count == connections){
      console.log("Reached connection count: ", connections);
    }
    else {
      interval = setTimeout(request,intervalPerConnection);
      console.log(count);
      count++;
    }
  }, intervalPerConnection);

} else {
  console.log('please start via node subscribe.js');
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  ToolbarAndroid,
  TextInput,
  TouchableOpacity,
  Alert,
  ListView,
  Image,
  ScrollView,
  ToastAndroid
} from 'react-native'
import Icon from 'react-native-vector-icons/FontAwesome'

import Setting from './About'
import ToolBar from '../common/ToolBar'

import Config from '../Config'

export default class Me extends Component {

  constructor(props) {
    super(props);

    this.state = {
      username:'',
      img:"test",
      token:null,
    };
  }

  componentDidMount() {

    storage.load({
      key: 'loginState',
      // autoSync(默认为true)意味着在没有找到数据或数据过期时自动调用相应的同步方法
      autoSync: true,
      // syncInBackground(默认为true)意味着如果数据过期，
      // 在调用同步方法的同时先返回已经过期的数据。
      // 设置为false的话，则始终强制返回同步方法提供的最新数据(当然会需要更多等待时间)。
      syncInBackground: true
      }).then(ret => {
        //如果找到数据，则在then方法中返回
        console.log(ret.userid);
        this.setState({username:ret.userid,token:ret.token})

        this._fetch();
      }).catch(err => {
        //如果没有找到数据且没有同步方法，
        //或者有其他异常，则在catch中返回
        //console.warn(err);
      })
  }

  _fetch(){
    const {username} = this.state
    fetch(Config.accountUrl + '/' +username,{
        headers: {
          'Auth-Token': this.state.token,
        },
      })
      .then((response) => response.json())
      .then((responseData) => {
           // Alert.alert('',JSON.stringify(responseData));

           if(responseData.status === 401){
              // token过期 重新登录
              ToastAndroid.show('帐号过期，重新登录', ToastAndroid.SHORT)

              // 删除本地的

              this.props.navigator.push(
                {
                  id:'login',
                  title:'登录',
                  params: {
                    username: username
                  }
                }
              )
           }

           if(responseData.code === 0){
              let obj = responseData.data
              // Alert.alert('',JSON.stringify(obj))
              this.setState({
                username: obj.username,
                img: Config.fileUrl + obj.img,
              })

           }else{
              console.log('error');
           }
      })
      .done();
  }

    handler() {
      this.props.navigator.push({
        title:'设置',
        id:'setting',

      })
    }

    _posts() {
      this.props.navigator.push({
        title:'动态',
        id:'posts',

      })
    }

     _post() {
      this.props.navigator.push({
        title:'发布',
        id:'post',
      })
    }

    _favHandler(){
      Alert.alert('','开发中');
    }

    _accountHandler(){
      let _this = this;
      const { navigator } = this.props;
      navigator.push({title:'个人信息',id:'account',
      params: {
              getUser: function(img) {
                  _this.setState({
                      img: img
                  })
              }
        }})
    }

    _login(){
      const { navigator } = this.props;
      navigator.push({title:'登录',id:'login'})
    }

    _renderScene(){
      if(this.state.username !== ''){
        return(
                    <View>

                 <ToolBar navigator={this.props.navigator} route={this.props.route}/>

                  <ScrollView style={styles.container}>

                    <TouchableOpacity style={styles.itemHeader} onPress={()=>this._accountHandler()}>

                        <Image
                            source={{uri: this.state.img}}
                            style={styles.thumbnail}
                          />
                        <View style={styles.item2}>
                            <Text >{this.state.username}</Text>
                        </View>
                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>

                    <TouchableOpacity style={styles.item} onPress={()=>this._post()}>
                        <View style={styles.item1}>
                          <Icon name="picture-o" size={20} color="#238CFE" />
                          <Text style={{marginLeft:5}}>Post</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>

                    <TouchableOpacity style={styles.item} onPress={()=>this._posts()}>
                        <View style={styles.item1}>
                          <Icon name="picture-o" size={20} color="#238CFE" />
                          <Text style={{marginLeft:5}}>动态</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>
                      <View style={{height:1,backgroundColor:'#f4f4f4'}}/>

                      <TouchableOpacity style={styles.item} onPress={()=>this._createDynamic()}>
                          <View style={styles.item1}>
                              <Icon name="picture-o" size={20} color="#238CFE" />
                              <Text style={{marginLeft:5}}>发表动态</Text>
                          </View>

                          <View style={styles.item3}>
                              <Icon name="angle-right" size={25} color="#aaa" />
                          </View>
                      </TouchableOpacity>
                      <View style={{height:1,backgroundColor:'#f4f4f4'}}/>

                    <TouchableOpacity style={styles.item} onPress={()=>this._favHandler()}>
                        <View style={styles.item1}>
                          <Icon name="cube" size={20} color="#238CFE" />
                          <Text style={{marginLeft:5}}>收藏</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>

                    <TouchableOpacity style={styles.item} onPress={()=>this.handler()}>
                        <View style={styles.item1}>
                            <Icon name="gear" size={20} color="#238CFE" />
                            <Text style={{marginLeft:5}}>设置</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>
                </ScrollView>
                </View>
      )
      }else{
                  return(
                    <View>

                 <ToolBar navigator={this.props.navigator} route={this.props.route}/>

                  <ScrollView style={styles.container}>

                    <TouchableOpacity style={styles.itemHeader} onPress={this._login.bind(this)}>

                        <Image
                            source={{uri: 'http://192.16.2.65:8888/v1/file/577606bb8cda23ce7a0369ff'}}
                            style={styles.thumbnail}
                          />
                        <View style={styles.item2}>
                            <Text >登录</Text>
                        </View>
                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>

                    <TouchableOpacity style={styles.item} onPress={()=>this._favHandler()}>
                        <View style={styles.item1}>
                          <Icon name="cube" size={20} color="#238CFE" />
                          <Text style={{marginLeft:5}}>收藏</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>

                    <TouchableOpacity style={styles.item} onPress={()=>this.handler()}>
                        <View style={styles.item1}>
                            <Icon name="gear" size={20} color="#238CFE" />
                            <Text style={{marginLeft:5}}>设置</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>

                    </TouchableOpacity>

                </ScrollView>
                </View>
          )
      }
    }

  render() {
    return (
      this._renderScene()
    );
  }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#eee',
    },
    thumbnail :{
        width: 60,
        height: 60,
        marginTop:10,
        marginLeft:10,
    },
    itemHeader: {
        height: 80,
        flex:1,
        flexDirection: 'row',
        backgroundColor: '#fff',
        justifyContent: 'center',
    },
    item: {
        marginTop:10,
        flex:1,
        flexDirection: 'row',
        backgroundColor: '#fff',
        height:45,
        justifyContent: 'center',

    },
    item1: {
        flex: 1,
        alignSelf:'center',
        marginLeft:10,
        flexDirection: 'row',
    },
    item3: {
        flex: 1,
        alignItems:'flex-end',
        justifyContent: 'center',
        marginRight:10,
    },
    item2: {
        flex: 1,
        marginLeft:20,
        justifyContent: 'center',
    },

    toolbar: {
        backgroundColor: '#03A9F4',
        height: 56,
        elevation: 5
    },

    btn: {
        backgroundColor: "#666",
        height: 40,
        borderRadius: 8,
        marginLeft:10,
        marginRight:10,
        marginTop:30,
        justifyContent: 'center',
    },
    btnText: {
        textAlign: 'center',
        color: '#fff'
    },
    options: {
        flex: 1,
        flexDirection: 'row',
        alignItems: 'flex-end',
        marginTop:30
    },
    unlogin: {
        color: '#63B8FF',
        marginLeft: 10
    },
    newUser: {
        flex: 1,
        alignItems: 'flex-end',
        flexDirection: 'row',
        textAlign: 'right',
        marginRight: 10,
        color: '#63B8FF'
    }
});

<commit_msg>我的界面优化。<commit_after>import React, { Component } from 'react'
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  ToolbarAndroid,
  TextInput,
  TouchableOpacity,
  Alert,
  ListView,
  Image,
  ScrollView,
  ToastAndroid
} from 'react-native'
import Icon from 'react-native-vector-icons/FontAwesome'

import Setting from './About'
import ToolBar from '../common/ToolBar'

import Config from '../Config'

export default class Me extends Component {

  constructor(props) {
    super(props);

    this.state = {
      username:'',
      img:"test",
      token:null,
    };
  }

  componentDidMount() {

    storage.load({
      key: 'loginState',
      // autoSync(默认为true)意味着在没有找到数据或数据过期时自动调用相应的同步方法
      autoSync: true,
      // syncInBackground(默认为true)意味着如果数据过期，
      // 在调用同步方法的同时先返回已经过期的数据。
      // 设置为false的话，则始终强制返回同步方法提供的最新数据(当然会需要更多等待时间)。
      syncInBackground: true
      }).then(ret => {
        //如果找到数据，则在then方法中返回
        console.log(ret.userid);
        this.setState({username:ret.userid,token:ret.token})

        this._fetch();
      }).catch(err => {
        //如果没有找到数据且没有同步方法，
        //或者有其他异常，则在catch中返回
        //console.warn(err);
      })
  }

  _fetch(){
    const {username} = this.state
    fetch(Config.accountUrl + '/' +username,{
        headers: {
          'Auth-Token': this.state.token,
        },
      })
      .then((response) => response.json())
      .then((responseData) => {
           // Alert.alert('',JSON.stringify(responseData));

           if(responseData.status === 401){
              // token过期 重新登录
              ToastAndroid.show('帐号过期，重新登录', ToastAndroid.SHORT)

              // 删除本地的

              this.props.navigator.push(
                {
                  id:'login',
                  title:'登录',
                  params: {
                    username: username
                  }
                }
              )
           }

           if(responseData.code === 0){
              let obj = responseData.data
              // Alert.alert('',JSON.stringify(obj))
              this.setState({
                username: obj.username,
                img: Config.fileUrl + obj.img,
              })

           }else{
              console.log('error');
           }
      })
      .done();
  }

    handler() {
      this.props.navigator.push({
        title:'设置',
        id:'setting',

      })
    }

    _posts() {
      this.props.navigator.push({
        title:'动态',
        id:'posts',

      })
    }

     _post() {
      this.props.navigator.push({
        title:'发布',
        id:'post',
      })
    }

    _createDynamic() {
        this.props.navigator.push({
            title: '发表动态',
            id: 'CreateDynamic',
        })
    }

    _favHandler(){
      Alert.alert('','开发中');
    }

    _accountHandler(){
      let _this = this;
      const { navigator } = this.props;
      navigator.push({title:'个人信息',id:'account',
      params: {
              getUser: function(img) {
                  _this.setState({
                      img: img
                  })
              }
        }})
    }

    _login(){
      const { navigator } = this.props;
      navigator.push({title:'登录',id:'login'})
    }

    _renderScene(){
      if(this.state.username !== ''){
        return(
                    <View>

                 <ToolBar navigator={this.props.navigator} route={this.props.route}/>

                  <ScrollView style={styles.container}>

                    <TouchableOpacity style={styles.itemHeader} onPress={()=>this._accountHandler()}>

                        <Image
                            source={{uri: this.state.img}}
                            style={styles.thumbnail}
                          />
                        <View style={styles.item2}>
                            <Text >{this.state.username}</Text>
                        </View>
                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>

                      <View style={{height:1,backgroundColor:'#f4f4f4'}}/>

                    <TouchableOpacity style={styles.item} onPress={()=>this._post()}>
                        <View style={styles.item1}>
                          <Icon name="picture-o" size={20} color="#238CFE" />
                          <Text style={{marginLeft:5}}>Post</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>

                      <View style={{height:1,backgroundColor:'#f4f4f4'}}/>

                    <TouchableOpacity style={styles.item} onPress={()=>this._posts()}>
                        <View style={styles.item1}>
                          <Icon name="picture-o" size={20} color="#238CFE" />
                          <Text style={{marginLeft:5}}>动态</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>
                      <View style={{height:1,backgroundColor:'#f4f4f4'}}/>

                      <TouchableOpacity style={styles.item} onPress={()=>this._createDynamic()}>
                          <View style={styles.item1}>
                              <Icon name="picture-o" size={20} color="#238CFE" />
                              <Text style={{marginLeft:5}}>发表动态</Text>
                          </View>

                          <View style={styles.item3}>
                              <Icon name="angle-right" size={25} color="#aaa" />
                          </View>
                      </TouchableOpacity>
                      <View style={{height:1,backgroundColor:'#f4f4f4'}}/>

                    <TouchableOpacity style={styles.item} onPress={()=>this._favHandler()}>
                        <View style={styles.item1}>
                          <Icon name="cube" size={20} color="#238CFE" />
                          <Text style={{marginLeft:5}}>收藏</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>
                      <View style={{height:1,backgroundColor:'#f4f4f4'}}/>

                    <TouchableOpacity style={styles.item} onPress={()=>this.handler()}>
                        <View style={styles.item1}>
                            <Icon name="gear" size={20} color="#238CFE" />
                            <Text style={{marginLeft:5}}>设置</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>
                      <View style={{height:1,backgroundColor:'#f4f4f4'}}/>
                </ScrollView>
                </View>
      )
      }else{
                  return(
                    <View>

                 <ToolBar navigator={this.props.navigator} route={this.props.route}/>

                  <ScrollView style={styles.container}>

                    <TouchableOpacity style={styles.itemHeader} onPress={this._login.bind(this)}>

                        <Image
                            source={{uri: 'http://192.16.2.65:8888/v1/file/577606bb8cda23ce7a0369ff'}}
                            style={styles.thumbnail}
                          />
                        <View style={styles.item2}>
                            <Text >登录</Text>
                        </View>
                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>
                      <View style={{height:1,backgroundColor:'#f4f4f4'}}/>

                    <TouchableOpacity style={styles.item} onPress={()=>this._favHandler()}>
                        <View style={styles.item1}>
                          <Icon name="cube" size={20} color="#238CFE" />
                          <Text style={{marginLeft:5}}>收藏</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>
                    </TouchableOpacity>
                      <View style={{height:1,backgroundColor:'#f4f4f4'}}/>

                    <TouchableOpacity style={styles.item} onPress={()=>this.handler()}>
                        <View style={styles.item1}>
                            <Icon name="gear" size={20} color="#238CFE" />
                            <Text style={{marginLeft:5}}>设置</Text>
                        </View>

                        <View style={styles.item3}>
                            <Icon name="angle-right" size={25} color="#aaa" />
                        </View>

                    </TouchableOpacity>
                      <View style={{height:1,backgroundColor:'#f4f4f4'}}/>

                </ScrollView>
                </View>
          )
      }
    }

  render() {
    return (
      this._renderScene()
    );
  }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#eee',
    },
    thumbnail :{
        width: 60,
        height: 60,
        marginTop:10,
        marginLeft:10,
    },
    itemHeader: {
        height: 80,
        flex:1,
        flexDirection: 'row',
        backgroundColor: '#fff',
        justifyContent: 'center',
    },
    item: {
        flex:1,
        flexDirection: 'row',
        backgroundColor: '#fff',
        height:45,
        justifyContent: 'center',

    },
    item1: {
        flex: 1,
        alignSelf:'center',
        marginLeft:10,
        flexDirection: 'row',
    },
    item3: {
        flex: 1,
        alignItems:'flex-end',
        justifyContent: 'center',
        marginRight:10,
    },
    item2: {
        flex: 1,
        marginLeft:20,
        justifyContent: 'center',
    },

    toolbar: {
        backgroundColor: '#03A9F4',
        height: 56,
        elevation: 5
    },

    btn: {
        backgroundColor: "#666",
        height: 40,
        borderRadius: 8,
        marginLeft:10,
        marginRight:10,
        marginTop:30,
        justifyContent: 'center',
    },
    btnText: {
        textAlign: 'center',
        color: '#fff'
    },
    options: {
        flex: 1,
        flexDirection: 'row',
        alignItems: 'flex-end',
        marginTop:30
    },
    unlogin: {
        color: '#63B8FF',
        marginLeft: 10
    },
    newUser: {
        flex: 1,
        alignItems: 'flex-end',
        flexDirection: 'row',
        textAlign: 'right',
        marginRight: 10,
        color: '#63B8FF'
    }
});

<|endoftext|>


<commit_before>import _curry2 from './internal/_curry2'

var merge = _curry2(function merge (a, b) {
  var y = {}
    , prop

  for (prop in a) {
    if (a.hasOwnProperty(prop)) {
      y[prop] = a[prop]
    }
  }
  for (prop in b) {
    if (b.hasOwnProperty(prop)) {
      y[prop] = b[prop]
    }
  }
  return y
})

export default merge
<commit_msg>refactor(merge): merge from L -> R<commit_after>import _curry2 from './internal/_curry2'

/**
 * Merges all own properties of the first object into the second.
 */
var merge = _curry2(function merge (a, b) {
  var y = {}
    , prop

  for (prop in b) {
    if (b.hasOwnProperty(prop)) {
      y[prop] = b[prop]
    }
  }
  for (prop in a) {
    if (a.hasOwnProperty(prop)) {
      y[prop] = a[prop]
    }
  }
  return y
})

export default merge
<|endoftext|>


<commit_before>/**
 * Hack init lifecycle of the Vm.
 *
 * @param  {object} options
 * @return {object}
 */
export function x (options) {
  const oriInit = options.init
  const hasInit = typeof oriInit === 'function'

  // set new init lifecycle
  options.init = function () {
    const opt = this._options
    const parent = this._parentVm || {}

    // set $store from option or parent
    if (opt.store) {
      this.$store = opt.store
    }
    else if (parent.$store) {
      this.$store = parent.$store
    }

    // run original init lifecycle if existed
    if (hasInit) {
      oriInit.call(this)
    }
  }

  return options
}
<commit_msg>fixed parent store bug<commit_after>/**
 * Hack init lifecycle of the Vm.
 *
 * @param  {object} options
 * @return {object}
 */
export function x (options) {
  const oriInit = options.init
  const hasInit = typeof oriInit === 'function'

  // set new init lifecycle
  options.init = function () {
    const opt = this._options
    const parent = this._parent || {}

    // set $store from option or parent
    if (opt.store) {
      this.$store = opt.store
    }
    else if (parent.$store) {
      this.$store = parent.$store
    }

    // run original init lifecycle if existed
    if (hasInit) {
      oriInit.call(this)
    }
  }

  return options
}
<|endoftext|>


<commit_before>function Mixin(proto, properties) {
  for (const property in properties) {
    const value = properties[property];
    if (proto[property] && typeof value == "function") {
      inherit(proto, property, value);
    } else {
      proto[property] = value;
    }
  }
}

function inherit(proto, property, func) {
  var parentFunc = proto[property];
  proto[property] = function () {
    var old = this.callParent;
    this.callParent = parentFunc;
    var ret = func.apply(this, arguments);
    if (old) {
      this.callParent = old;
    }
    return ret;
  };
}

module.exports = Mixin;
<commit_msg>Prefer `const`<commit_after>function Mixin(proto, properties) {
  for (const property in properties) {
    const value = properties[property];
    if (proto[property] && typeof value == "function") {
      inherit(proto, property, value);
    } else {
      proto[property] = value;
    }
  }
}

function inherit(proto, property, func) {
  const parentFunc = proto[property];
  proto[property] = function () {
    const old = this.callParent;
    this.callParent = parentFunc;
    const ret = func.apply(this, arguments);
    if (old) {
      this.callParent = old;
    }
    return ret;
  };
}

module.exports = Mixin;
<|endoftext|>


<commit_before>import constants from './constants'
import utils from './utils'

/**
 * Represents the riot-view-router mixin.
 * @constructor
 * @param (object) options - Router options.
 * @param (array) states - States for router to read from.
 */
class Router {

  constructor(options, states) {

    let self = this.$router = {  }

    Object.defineProperty(self, 'location', {
      get: function() {
        return window.location.hash
      },
      set: function(location) {
        window.location.hash = location
      }
    })

    self.$utils = utils

    /**
     * Used to navigate with hash pattern.
     * @param (string) route - Route to relocate to.
     */
    self.navigate = function(route) {
      self.location = '#!' + route
    }

    /**
     * Used to change states.
     * @param (string) name - Name of state to transition to.
     */
    self.pushState = function(name) {
      let state = self.$utils.stateByName(name)
      let location = self.location.split('#!')[1]

      if (location !== state.route.route) {
        if (!state.route.variables.length) {
          self.navigate(state.route.route)
          return // # assume function will be retriggered
        }
        else {
          if (self.debugging) {
            console.warn(`State "${name}" does not match current route.`)
            console.warn('Could not re-route due to route variables.')
          }
        }
      }

      if (self.onBeforeStateChange) {
        self.onBeforeStateChange(state)
      }
      if (self.$state && self.$state.onLeave) {
        self.$state.onLeave(state)
      } // # call onLeave, pass old state
      self.transition(state)
      if (self.onStateChange) {
        self.onStateChange(state)
      }
      if (state.onEnter) {
        state.onEnter(state)
      } // # call onEnter, pass new state
      self.$state = state
    }

    /**
     * Used to mount state.
     * @param (object) state - State object for mounting.
     */
    self.transition = function(state) {
      let variables = self.$utils.extractRouteVars(state)
      if (self.$state) {
        let tag = riot.util.vdom.find((tag) => tag.root.localName == self.$state.tag)
        if (!tag) throw Error('Could not find a matching tag to unmount')
        tag.unmount()
      }
      let node = document.createElement(state.tag)
      let opts = { }
      variables.forEach((variable) => {
        opts[variable.name] = variable.value
      }) // # add props
      self.context.appendChild(node)
      riot.mount(state.tag, opts)
      let title = state.title
      variables.forEach((variable) => title = title.replace(`<${variable.name}>`, variable.value))
      document.title = title
    }

    /**
     * Used to initialize the router and listeners.
     */
    self.start = function() {
      if (!self.location) {
        window.location.hash = `#!${ self.$utils.stateByName(self.defaultState).route.route }`
      } // # route to default state
      self.context_id = '$' + new Date().getTime().toString()
      window[self.context_id] = window.setInterval(function() {
        let context = document.querySelector(self.marker) || document.querySelector(`[${self.marker}]`)
        if (context) {
          self.context = context
          self.pushState(self.$utils.stateByRoute().name) // # route to initial state
          window.onhashchange = function() {
            self.pushState(self.$utils.stateByRoute().name) // # update state
          } // # create listener for route changes
          window.clearInterval(window[self.context_id])
        }
      }, 250) // # search for view context
    }

    let requiredOptions = ['defaultState']
    let optionalDefaultOptions = ['debugging', 'fallbackState', 'onBeforeStateChange', 'onStateChange']
    let acceptedOptions = requiredOptions.concat(optionalDefaultOptions)

    for (let option in options) {
      if (acceptedOptions.indexOf(option) == -1) {
        throw Error(`Unknown option "${option} is not supported`)
      }
    } // # validate router optionsu

    self = Object.assign(self, options)

    self.debugging = self.debugging || false

    let stateProperties = ['name', 'route', 'tag']
    states = !Array.isArray(states) ? [states] : states
    states.forEach((state) => {
      if (!state.name.match(self.regex.stateName)) {
        throw Error(`Invalid state name "${state.name}",\
        state names must be a valid alphanumeric string.`)
      }
    })
    stateProperties.forEach((prop) => {
      states.forEach((state) => {
        if (!state[prop]) {
          throw Error(`Required state option "${prop}" not specified`)
        }
      })
    }) // # validate state options
    states.forEach(function(item) {
      item.route = self.$utils.splitRoute(item.route)
    }) // # get route pattern
    self.states = states

    if (!self.defaultState) {
      throw Error('Default state must be specified')
    } else {
      if (self.defaultState.indexOf(':') > -1) {
        throw Error(`Default state route cannot take variable parameters`)
      }
      if (!self.$utils.stateByName(self.defaultState)) {
        throw Error(`State "${self.defaultState}" not found in specified states`)
      }
    }

    if (self.fallbackState) {
      if (!self.$utils.stateByName(self.fallbackState)) {
        throw Error(`Fallback state "${self.fallbackState}" not found in specified states`)
      }
    }
    else {
      if (self.debugging) {
        console.warn(`Fallback state not specified, dfaulting to "${self.defaultState}"`)
      }
      self.fallbackState = self.defaultState
    }

    self.marker = self.marker || constants.defaults.marker
    self.start()
  }

}
<commit_msg>Updated config references<commit_after>import constants from './constants'
import utils from './utils'

/**
 * Represents the riot-view-router mixin.
 * @constructor
 * @param (object) options - Router options.
 * @param (array) states - States for router to read from.
 */
class Router {

  constructor(options, states) {

    let self = this.$router = {  }

    Object.defineProperty(self, 'location', {
      get: function() {
        return window.location.hash
      },
      set: function(location) {
        window.location.hash = location
      }
    })

    self.$utils = utils

    /**
     * Used to navigate with hash pattern.
     * @param (string) route - Route to relocate to.
     */
    self.navigate = function(route) {
      self.location = '#!' + route
    }

    /**
     * Used to change states.
     * @param (string) name - Name of state to transition to.
     */
    self.pushState = function(name) {
      let state = self.$utils.stateByName(self, name)
      let location = self.location.split('#!')[1]

      if (location !== state.route.route) {
        if (!state.route.variables.length) {
          self.navigate(state.route.route)
          return // # assume function will be retriggered
        }
        else {
          if (self.debugging) {
            console.warn(`State "${name}" does not match current route.`)
            console.warn('Could not re-route due to route variables.')
          }
        }
      }

      if (self.onBeforeStateChange) {
        self.onBeforeStateChange(state)
      }
      if (self.$state && self.$state.onLeave) {
        self.$state.onLeave(state)
      } // # call onLeave, pass old state
      self.transition(state)
      if (self.onStateChange) {
        self.onStateChange(state)
      }
      if (state.onEnter) {
        state.onEnter(state)
      } // # call onEnter, pass new state
      self.$state = state
    }

    /**
     * Used to mount state.
     * @param (object) state - State object for mounting.
     */
    self.transition = function(state) {
      let variables = self.$utils.extractRouteVars(self, state)
      if (self.$state) {
        let tag = riot.util.vdom.find((tag) => tag.root.localName == self.$state.tag)
        if (!tag) throw Error('Could not find a matching tag to unmount')
        tag.unmount()
      }
      let node = document.createElement(state.tag)
      let opts = { }
      variables.forEach((variable) => {
        opts[variable.name] = variable.value
      }) // # add props
      self.context.appendChild(node)
      riot.mount(state.tag, opts)
      let title = state.title
      variables.forEach((variable) => title = title.replace(`<${variable.name}>`, variable.value))
      document.title = title
    }

    /**
     * Used to initialize the router and listeners.
     */
    self.start = function() {
      if (!self.location) {
        window.location.hash = `#!${ self.$utils.stateByName(self, self.defaultState).route.route }`
      } // # route to default state
      self.context_id = '$' + new Date().getTime().toString()
      window[self.context_id] = window.setInterval(function() {
        let context = document.querySelector(self.marker) || document.querySelector(`[${self.marker}]`)
        if (context) {
          self.context = context
          self.pushState(self.$utils.stateByRoute(self).name) // # route to initial state
          window.onhashchange = function() {
            self.pushState(self.$utils.stateByRoute(self).name) // # update state
          } // # create listener for route changes
          window.clearInterval(window[self.context_id])
        }
      }, 250) // # search for view context
    }

    let requiredOptions = ['defaultState']
    let optionalDefaultOptions = ['debugging', 'fallbackState', 'onBeforeStateChange', 'onStateChange']
    let acceptedOptions = requiredOptions.concat(optionalDefaultOptions)

    for (let option in options) {
      if (acceptedOptions.indexOf(option) == -1) {
        throw Error(`Unknown option "${option} is not supported`)
      }
    } // # validate router optionsu

    self = Object.assign(self, options)

    self.debugging = self.debugging || false

    let stateProperties = ['name', 'route', 'tag']
    states = !Array.isArray(states) ? [states] : states
    states.forEach((state) => {
      if (!state.name.match(self.regex.stateName)) {
        throw Error(`Invalid state name "${state.name}",\
        state names must be a valid alphanumeric string.`)
      }
    })
    stateProperties.forEach((prop) => {
      states.forEach((state) => {
        if (!state[prop]) {
          throw Error(`Required state option "${prop}" not specified`)
        }
      })
    }) // # validate state options
    states.forEach(function(item) {
      item.route = self.$utils.splitRoute(self, item.route)
    }) // # get route pattern
    self.states = states

    if (!self.defaultState) {
      throw Error('Default state must be specified')
    } else {
      if (self.defaultState.indexOf(':') > -1) {
        throw Error(`Default state route cannot take variable parameters`)
      }
      if (!self.$utils.stateByName(self, self.defaultState)) {
        throw Error(`State "${self.defaultState}" not found in specified states`)
      }
    }

    if (self.fallbackState) {
      if (!self.$utils.stateByName(self, self.fallbackState)) {
        throw Error(`Fallback state "${self.fallbackState}" not found in specified states`)
      }
    }
    else {
      if (self.debugging) {
        console.warn(`Fallback state not specified, dfaulting to "${self.defaultState}"`)
      }
      self.fallbackState = self.defaultState
    }

    self.marker = self.marker || constants.defaults.marker
    self.start()
  }

}
<|endoftext|>


<commit_before>// A functional reactive model library.
//
// By Curran Kelleher 4/15/2014
define([], function () {

  // Returns a debounced version of the given function.
  // Calling the debounced function one or more times in sequence
  // will schedule the given function to execute only once
  // at the next tick of the JavaScript event loop.
  // Similar to http://underscorejs.org/#debounce
  function debounce(func){
    var queued = false;
    return function () {
      if(!queued){
        queued = true;
        setTimeout(function () {
          queued = false;
          func();
        }, 0);
      }
    };
  }

  // Returns true if all values in the given array
  // are defined and not null, false otherwise.
  function allAreDefined(arr){
    arr.forEach(function (d) {
      if(typeof d === 'undefined' || d === null){
        return false;
      }
    });
    return true;
  }

  // The constructor function.
  return function Model(){

    // An object containing callback functions.
    //  * Keys are property names
    //  * Values are arrays of callback functions
    var callbacks = {},

        // An object containing property values.
        //  * Keys are property names
        //  * Values are values set on the model
        values = {};

    // Adds a callback that will listen for changes
    // to the specified property.
    function on(key, callback){

      // If there is not already a list
      // of callbacks for the given key,
      if(!callbacks[key]) {

        // then create one.
        callbacks[key] = [];
      }

      // Add the callback to the list of callbacks
      // for the given key.
      callbacks[key].push(callback);
    }

    /*
     Removes a callback that listening for changes
     to the specified property.
    TODO test this
    function off(key, callbackToRemove){
      if(callbacks[key]){
        callbacks[key] = callbacks[key].filter(function (callback) {
          return callback !== callbackToRemove;
        });
      }
    }
    */

    // Sets a value on the model.
    function set(key, value){

      // Update the internal value.
      values[key] = value;

      // Call callbacks if there are any.
      if(callbacks[key]){
        callbacks[key].forEach(function (callback) {
          callback();
        });
      }
    }

    /* TODO add documentation here */
    function when(dependencies, fn, thisArg){

      // Support passing a single string as `dependencies`
      if(!(dependencies instanceof Array)) {
        dependencies = [dependencies];
      }

      // `callFn()` will invoke `fn` with values of dependency properties
      // on the next tick of the JavaScript event loop.
      var callFn = debounce(function(){

        // Extract the values for each dependency property from the model.
        var args = dependencies.map(function (dependency) {
          return values[dependency];
        });

        // Only call the function if all values are defined.
        if(allAreDefined(args)) {

          // Call `fn` with the dependency property values.
          computedProperties = fn.apply(thisArg, args);
        }
      });

      // Invoke `fn` once for initialization.
      callFn();

      // Invoke `fn` when dependency properties change.
      //
      // Multiple sequential dependency property changes
      // result in only a single invocation of `fn`
      // because callFn is [debounced](underscorejs.org/#debounce).
      dependencies.forEach(function(property){
        on(property, callFn);
      });
    }

    // Return the public Model API,
    // using the revealing module pattern.
    return {
      set: set,
      when: when
    };
  }
});
<commit_msg>Started using JSHint, added missing semicolon<commit_after>// A functional reactive model library.
//
// By Curran Kelleher 4/15/2014
define([], function () {

  // Returns a debounced version of the given function.
  // Calling the debounced function one or more times in sequence
  // will schedule the given function to execute only once
  // at the next tick of the JavaScript event loop.
  // Similar to http://underscorejs.org/#debounce
  function debounce(func){
    var queued = false;
    return function () {
      if(!queued){
        queued = true;
        setTimeout(function () {
          queued = false;
          func();
        }, 0);
      }
    };
  }

  // Returns true if all values in the given array
  // are defined and not null, false otherwise.
  function allAreDefined(arr){
    arr.forEach(function (d) {
      if(typeof d === 'undefined' || d === null){
        return false;
      }
    });
    return true;
  }

  // The constructor function.
  return function Model(){

    // An object containing callback functions.
    //  * Keys are property names
    //  * Values are arrays of callback functions
    var callbacks = {},

        // An object containing property values.
        //  * Keys are property names
        //  * Values are values set on the model
        values = {};

    // Adds a callback that will listen for changes
    // to the specified property.
    function on(key, callback){

      // If there is not already a list
      // of callbacks for the given key,
      if(!callbacks[key]) {

        // then create one.
        callbacks[key] = [];
      }

      // Add the callback to the list of callbacks
      // for the given key.
      callbacks[key].push(callback);
    }

    /*
     Removes a callback that listening for changes
     to the specified property.
    TODO test this
    function off(key, callbackToRemove){
      if(callbacks[key]){
        callbacks[key] = callbacks[key].filter(function (callback) {
          return callback !== callbackToRemove;
        });
      }
    }
    */

    // Sets a value on the model.
    function set(key, value){

      // Update the internal value.
      values[key] = value;

      // Call callbacks if there are any.
      if(callbacks[key]){
        callbacks[key].forEach(function (callback) {
          callback();
        });
      }
    }

    /* TODO add documentation here */
    function when(dependencies, fn, thisArg){

      // Support passing a single string as `dependencies`
      if(!(dependencies instanceof Array)) {
        dependencies = [dependencies];
      }

      // `callFn()` will invoke `fn` with values of dependency properties
      // on the next tick of the JavaScript event loop.
      var callFn = debounce(function(){

        // Extract the values for each dependency property from the model.
        var args = dependencies.map(function (dependency) {
          return values[dependency];
        });

        // Only call the function if all values are defined.
        if(allAreDefined(args)) {

          // Call `fn` with the dependency property values.
          computedProperties = fn.apply(thisArg, args);
        }
      });

      // Invoke `fn` once for initialization.
      callFn();

      // Invoke `fn` when dependency properties change.
      //
      // Multiple sequential dependency property changes
      // result in only a single invocation of `fn`
      // because callFn is [debounced](underscorejs.org/#debounce).
      dependencies.forEach(function(property){
        on(property, callFn);
      });
    }

    // Return the public Model API,
    // using the revealing module pattern.
    return {
      set: set,
      when: when
    };
  };
});
<|endoftext|>


<commit_before>import EventEmitter from 'events';
import uniqueId from 'lodash.uniqueid';
import isObject from 'lodash.isobject';
import isFunction from 'lodash.isfunction';
import isUndefined from 'lodash.isundefined';
import uuidV4 from 'uuid/v4';

/**
 * Model identities
 */
export const identities = new Map();
/**
 * Flags for controlling mutation.
 * Flag index n must have value 2^n.
 * @example
 * this.set('active', value, UNSET_IF_FALSE);
 * this.set('active', value, UNSET_IF_FALSE + SET_SILENT);
 */
export const SET_SILENT = 1; // Don't dispatch event when setting.
export const UNSET_IF_FALSE = 2; // If value evaluates to Boolean False, unset property.
export const SOFT_UPDATE = 4; // During update, if no setter or model found, use set() silent.
export const RESET_REFERENCE = 8; // Reset this._data or this._items references in reset().
/**
 * Helper for checking flags, e.g. for Model.set().
 * @param {Integer} dec Sum of flags.
 * @param {Integer} flag Flag to check.
 * @return {boolean} True if flag is set.
 */
export function flagIsSet(dec, flag) {
    const binStr = (dec >>> 0).toString(2);
    const flagIndex = binStr.length - (flag >>> 0).toString(2).length;
    return binStr[flagIndex] === '1';
}
/**
 * Model
 */
export default class Model extends EventEmitter {
    /**
     * Model.constructor
     * @param {Object} data JSON serializable object.
     * @param {...} args Arguments passed to _getDefaults().
     */
    constructor(data = {}, ...args) {
        super();
        // Update with defaults
        this._withDefaults(data, ...args);
        // Validate data
        this._validate(data);
        // Valid, set
        this._data = data;
        // Store previous
        this._previousData = {};
        // Store modified
        this._modified = undefined;
        // Client id
        this._cid = this._getUniqueClientId();
    }
    /**
     * Get client id. Not persisted.
     * @return {String}
     */
    get cid() {
        return this._cid;
    }
    /**
     * Get uuid.
     * @return {String}
     */
    get uuid() {
        return this.get('uuid');
    }
    /**
     * Underlying data object for model.
     * @return {String} Model polymorphic identity.
     */
    getModelIdentity() {
        return this.get('identity');
    }
    /**
     * Underlying data object for model.
     * @return {Object} JSON serializable object.
     */
    getModelData() {
        return this._data;
    }
    /**
     * Get value of data.property.
     * @param {String} property Name of property.
     * @param {*} defaultValue Default value to return if property is undefined.
     * @return {*}
     */
    get(property, defaultValue) {
        return this.has(property) ? this._data[property] : defaultValue;
    }
    /**
     * Return previous value of property.
     * @param {String} property Name of property.
     * @return {*}
     */
    getPrevious(property) {
        return this._previousData[property];
    }
    /**
     * Check if property is set in data.
     * @param {String} property Name of property.
     * @return {boolean} True if set.
     */
    has(property) {
        return this._data.hasOwnProperty(property);
    }
    /**
     * Check if previous value of property is same
     * as current.
     * @param {list of strings} properties Names of properties.
     * @return {boolean} True if any of them has changed.
     */
    hasChanged(...properties) {
        for (let prop of properties) {
            if (this._previousData[prop] !== this._data[prop]) {
                return true;
            }
        }
        return false;
    }
    /**
     * Set value of data.property.
     * @param {String} property Name of property.
     * @param {*} value Anything JSON serializable.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    set(property, value, flags = 0) {
        // Unset?
        if (flagIsSet(flags, UNSET_IF_FALSE) && Boolean(value) === false) {
            this.unset(property, flags);
            return;
        }
        // Previous value
        this._previousData[property] = this._data[property];
        // If property not set or value different
        if (!this.has(property) || this._data[property] !== value) {
            // Set new value
            this._data[property] = value;
            // Set modified
            this.updateModified();
        }
        // Dispatch change event, if not silent
        if (this.hasChanged(property) && !flagIsSet(flags, SET_SILENT)) {
            this.dispatchChange(property, value, this._previousData[property]);
        }
        // Return
        return this;
    }
    /**
     * Toggle boolean property.
     * @param {String} property Name of property.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    toggle(property, flags = 0) {
        const current = this.get(property, false); // False if not set
        return this.set(property, !current, flags); // Set to !current
    }
    /**
     * Unset value of data.property.
     * @param {String} property Name of property.
     * @param {Integer} flags (@see constants).
     * @return {boolean} True if property found and unset.
     */
    unset(property, flags = 0) {
        // Previous value
        this._previousData[property] = this._data[property];
        // Present in _data
        const present = this._data.hasOwnProperty(property);
        // Delete from data
        delete this._data[property];
        // Has changed?
        if (this.hasChanged(property)) {
            // Set modified
            this.updateModified();
            // Dispatch change event, if not silent
            if (!flagIsSet(flags, SET_SILENT)) {
                this.dispatchChange(property, undefined, this._previousData[property]);
            }
        }
        // True if present and deleted.
        return present;
    }
    /**
     * Delete multiple properties from data.
     * @param {list of strings} properties
     * @return {Model} The Model object.
     */
    unsetMultiple(...properties) {
        for (let prop of properties) {
            this._previousData[prop] = this._data[prop];
            delete this._data[prop];
        }
        if (this.hasChanged(...properties)) {
            this.updateModified();
        }
        // Return
        return this;
    }
    /**
     * Reset underlying data object for model.
     * @param {Object}  data JSON serializable object.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    reset(data, flags = 0) {
        data = data || {};
        // Keep identity and uuid
        const {uuid, identity} = this._data;
        Object.assign(data, {uuid, identity});
        // Update new data with defaults
        this._withDefaults(data);
        // If reset reference flag
        if (flagIsSet(flags, RESET_REFERENCE)) {
            // Reset data reference
            this._data = data;
            // Dispatch change event, if not silent
            if (!flagIsSet(flags, SET_SILENT)) {
                this.dispatchChange();
            }
        // else, reset properties but keep this reference (not recursive)
        } else {
            // Unset properties not in data
            Object.keys(this._data).forEach(property => {
                if (isUndefined(data[property])) {
                    this.unset(property, flags);
                }
            });
            // Recursive reset or updateProperty
            Object.keys(this._data).forEach(property => {
                // Check recursiveness
                let currentVal = this[property];
                if (currentVal && isFunction(currentVal.reset)) {
                    currentVal.reset(data[property], flags);
                // Just update
                } else {
                    this.updateProperty(property, data[property], flags);
                }
            });
        }
        // Validate
        this._validate(this._data);
        // Return
        return this;
    }
    /**
     * Recursively update model properties.
     * @param {Object} data JSON serializable object.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    update(data, flags = 0) {
        // Iterate data dict
        Object.keys(data).forEach(prop => {
            this.updateProperty(prop, data[prop], flags);
        });
        // Set modified
        this.updateModified();
        // Notify if not silent. Dispatch for each property?
        if (!flagIsSet(flags, SET_SILENT)) {
            this.dispatchChange();
        }
        // Return
        return this;
    }
    /**
     * Update single property.
     * @param {String} property Name of property.
     * @param {*} value Anything JSON serializable.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    updateProperty(property, value, flags = 0) {
        // Check if setter exists
        if (typeof this.__lookupSetter__(property) !== 'undefined') {
            this[property] = value;
            return this;
        }
        // No setter, check if getter returns model
        const currentVal = this[property];
        if (currentVal && isFunction(currentVal.update)) {
            // If yes, update recursively.
            currentVal.update(value, flags);
            return this;
        }
        // Soft update
        if (flagIsSet(flags, SOFT_UPDATE)) {
            return this.set(property, value, flags);
        }
        // If no setter or sub model, throw error.
        throw new Error('Could not update property "' + property + '" on ' + this.constructor.name + '.');
    }
    /**
     * Update modified timestamp.
     * @param {timestamp} modified Time of modification or undefined if now.
     * @return {Model} The Model object.
     */
    updateModified(modified) {
        this._modified = modified || Date.now();
        // Return
        return this;
    }
    /**
     * Return a copy of this model, with new uuids.
     * FIX: Better way to do this?
     * @return {Model} New instance of Model (or Model subclass).
     */
    copy() {
        // stringify data dict
        const jsonStr = JSON.stringify(this._data);
        // replace all uuids with new one's.
        const uuidRegexp = /"uuid":"........-....-....-....-............"/g;
        const newJsonStr = jsonStr.replace(uuidRegexp, () => {
            return '"uuid":"' + uuidV4() + '"';
        });
        // return instance of this
        const Constructor = this.constructor;
        return new Constructor(JSON.parse(newJsonStr));
    }
    /**
     * Interface for dispatching events.
     * Currently alias for EventEmitter.emit. May change.
     * @param {String} eventType Event type key.
     * @param {...} args Arguments passed to listeners.
     * @return {Model} The Model object.
     */
    dispatchEvent(eventType, ...args) {
        this.emit(eventType, [this].concat(args));
        // Return
        return this;
    }
    /**
     * Dispatch change events.
     * @param {String} property Name of property.
     * @param {*} newValue Anything JSON serializable.
     * @param {*} oldValue Anything JSON serializable.
     * @return {Model} The Model object.
     */
    dispatchChange(property, newValue, oldValue) {
        if (property) {
            this.dispatchEvent('change ' + property, newValue, oldValue);
        }
        return this.dispatchEvent('change');
    }
    /**
     * Alias for EventEmitter.addListener
     */
    addEventListener(event, listener) {
        this.addListener(event, listener);
        // Return
        return this;
    }
    /**
     * Alias for EventEmitter.removeListener
     */
    removeEventListener(event, listener) {
        this.removeListener(event, listener);
        // Return
        return this;
    }
    /**
     * Dispose model and sub models recursively.
     * Remove event listeners and delete references.
     * @return {Model} The Model object.
     */
    dispose() {
        // Remove event listeners
        this.removeAllListeners();
        // Check sub models on this, recursively
        Object.keys(this).forEach(attr => {
            if (isObject(this[attr]) && isFunction(this[attr].dispose)) {
                this[attr].dispose();
            }
        });
        // delete refs
        this._deleteReferences();
        // Return
        return this;
    }
    /**
     * Delete references set on model.
     */
    _deleteReferences() {
        delete this._data;
        delete this._previousData;
        delete this._modified;
    }
    /**
     * Check validity of data. Throw error if not valid.
     * @param {Object} data JSON serializable object.
     */
    _validate(data) {
        // Abstract
    }
    /**
     * Return default data object for new instance.
     * @param {...} constructorArgs List of arguments passed in constructor.
     * @return {Object} Default data (JSON serializable object) for Model.
     */
    _getDefaults(...constructorArgs) {
        return {
            // Model polymorphic identity
            identity: Model.identity,
            // model uuid
            uuid: uuidV4()
        };
    }
    /**
     * Update data object with defaults.
     * @param {Object} data JSON serializable object.
     * @param {...} constructorArgs List of arguments passed in constructor.
     * @return {Model} The Model object.
     */
    _withDefaults(data, ...constructorArgs) {
        // defaults
        const defaultData = this._getDefaults(...constructorArgs);
        // Update undefined props from defaults
        Object.keys(defaultData).forEach(prop => {
            if (isUndefined(data[prop])) {
                data[prop] = defaultData[prop];
            }
        });
        return this;
    }
    /**
     * Return unique client id.
     * @return {String} Unique string.
     */
    _getUniqueClientId() {
        return uniqueId(this.getModelIdentity());
    }

}
// Polymorphic identity
Model.identity = 'mozy.Model';
// Register Model
identities.set(Model.identity, Model);
<commit_msg>Model.dispatchEvent fix<commit_after>import EventEmitter from 'events';
import uniqueId from 'lodash.uniqueid';
import isObject from 'lodash.isobject';
import isFunction from 'lodash.isfunction';
import isUndefined from 'lodash.isundefined';
import uuidV4 from 'uuid/v4';

/**
 * Model identities
 */
export const identities = new Map();
/**
 * Flags for controlling mutation.
 * Flag index n must have value 2^n.
 * @example
 * this.set('active', value, UNSET_IF_FALSE);
 * this.set('active', value, UNSET_IF_FALSE + SET_SILENT);
 */
export const SET_SILENT = 1; // Don't dispatch event when setting.
export const UNSET_IF_FALSE = 2; // If value evaluates to Boolean False, unset property.
export const SOFT_UPDATE = 4; // During update, if no setter or model found, use set() silent.
export const RESET_REFERENCE = 8; // Reset this._data or this._items references in reset().
/**
 * Helper for checking flags, e.g. for Model.set().
 * @param {Integer} dec Sum of flags.
 * @param {Integer} flag Flag to check.
 * @return {boolean} True if flag is set.
 */
export function flagIsSet(dec, flag) {
    const binStr = (dec >>> 0).toString(2);
    const flagIndex = binStr.length - (flag >>> 0).toString(2).length;
    return binStr[flagIndex] === '1';
}
/**
 * Model
 */
export default class Model extends EventEmitter {
    /**
     * Model.constructor
     * @param {Object} data JSON serializable object.
     * @param {...} args Arguments passed to _getDefaults().
     */
    constructor(data = {}, ...args) {
        super();
        // Update with defaults
        this._withDefaults(data, ...args);
        // Validate data
        this._validate(data);
        // Valid, set
        this._data = data;
        // Store previous
        this._previousData = {};
        // Store modified
        this._modified = undefined;
        // Client id
        this._cid = this._getUniqueClientId();
    }
    /**
     * Get client id. Not persisted.
     * @return {String}
     */
    get cid() {
        return this._cid;
    }
    /**
     * Get uuid.
     * @return {String}
     */
    get uuid() {
        return this.get('uuid');
    }
    /**
     * Underlying data object for model.
     * @return {String} Model polymorphic identity.
     */
    getModelIdentity() {
        return this.get('identity');
    }
    /**
     * Underlying data object for model.
     * @return {Object} JSON serializable object.
     */
    getModelData() {
        return this._data;
    }
    /**
     * Get value of data.property.
     * @param {String} property Name of property.
     * @param {*} defaultValue Default value to return if property is undefined.
     * @return {*}
     */
    get(property, defaultValue) {
        return this.has(property) ? this._data[property] : defaultValue;
    }
    /**
     * Return previous value of property.
     * @param {String} property Name of property.
     * @return {*}
     */
    getPrevious(property) {
        return this._previousData[property];
    }
    /**
     * Check if property is set in data.
     * @param {String} property Name of property.
     * @return {boolean} True if set.
     */
    has(property) {
        return this._data.hasOwnProperty(property);
    }
    /**
     * Check if previous value of property is same
     * as current.
     * @param {list of strings} properties Names of properties.
     * @return {boolean} True if any of them has changed.
     */
    hasChanged(...properties) {
        for (let prop of properties) {
            if (this._previousData[prop] !== this._data[prop]) {
                return true;
            }
        }
        return false;
    }
    /**
     * Set value of data.property.
     * @param {String} property Name of property.
     * @param {*} value Anything JSON serializable.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    set(property, value, flags = 0) {
        // Unset?
        if (flagIsSet(flags, UNSET_IF_FALSE) && Boolean(value) === false) {
            this.unset(property, flags);
            return;
        }
        // Previous value
        this._previousData[property] = this._data[property];
        // If property not set or value different
        if (!this.has(property) || this._data[property] !== value) {
            // Set new value
            this._data[property] = value;
            // Set modified
            this.updateModified();
        }
        // Dispatch change event, if not silent
        if (this.hasChanged(property) && !flagIsSet(flags, SET_SILENT)) {
            this.dispatchChange(property, value, this._previousData[property]);
        }
        // Return
        return this;
    }
    /**
     * Toggle boolean property.
     * @param {String} property Name of property.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    toggle(property, flags = 0) {
        const current = this.get(property, false); // False if not set
        return this.set(property, !current, flags); // Set to !current
    }
    /**
     * Unset value of data.property.
     * @param {String} property Name of property.
     * @param {Integer} flags (@see constants).
     * @return {boolean} True if property found and unset.
     */
    unset(property, flags = 0) {
        // Previous value
        this._previousData[property] = this._data[property];
        // Present in _data
        const present = this._data.hasOwnProperty(property);
        // Delete from data
        delete this._data[property];
        // Has changed?
        if (this.hasChanged(property)) {
            // Set modified
            this.updateModified();
            // Dispatch change event, if not silent
            if (!flagIsSet(flags, SET_SILENT)) {
                this.dispatchChange(property, undefined, this._previousData[property]);
            }
        }
        // True if present and deleted.
        return present;
    }
    /**
     * Delete multiple properties from data.
     * @param {list of strings} properties
     * @return {Model} The Model object.
     */
    unsetMultiple(...properties) {
        for (let prop of properties) {
            this._previousData[prop] = this._data[prop];
            delete this._data[prop];
        }
        if (this.hasChanged(...properties)) {
            this.updateModified();
        }
        // Return
        return this;
    }
    /**
     * Reset underlying data object for model.
     * @param {Object}  data JSON serializable object.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    reset(data, flags = 0) {
        data = data || {};
        // Keep identity and uuid
        const {uuid, identity} = this._data;
        Object.assign(data, {uuid, identity});
        // Update new data with defaults
        this._withDefaults(data);
        // If reset reference flag
        if (flagIsSet(flags, RESET_REFERENCE)) {
            // Reset data reference
            this._data = data;
            // Dispatch change event, if not silent
            if (!flagIsSet(flags, SET_SILENT)) {
                this.dispatchChange();
            }
        // else, reset properties but keep this reference (not recursive)
        } else {
            // Unset properties not in data
            Object.keys(this._data).forEach(property => {
                if (isUndefined(data[property])) {
                    this.unset(property, flags);
                }
            });
            // Recursive reset or updateProperty
            Object.keys(this._data).forEach(property => {
                // Check recursiveness
                let currentVal = this[property];
                if (currentVal && isFunction(currentVal.reset)) {
                    currentVal.reset(data[property], flags);
                // Just update
                } else {
                    this.updateProperty(property, data[property], flags);
                }
            });
        }
        // Validate
        this._validate(this._data);
        // Return
        return this;
    }
    /**
     * Recursively update model properties.
     * @param {Object} data JSON serializable object.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    update(data, flags = 0) {
        // Iterate data dict
        Object.keys(data).forEach(prop => {
            this.updateProperty(prop, data[prop], flags);
        });
        // Set modified
        this.updateModified();
        // Notify if not silent. Dispatch for each property?
        if (!flagIsSet(flags, SET_SILENT)) {
            this.dispatchChange();
        }
        // Return
        return this;
    }
    /**
     * Update single property.
     * @param {String} property Name of property.
     * @param {*} value Anything JSON serializable.
     * @param {Integer} flags (@see constants).
     * @return {Model} The Model object.
     */
    updateProperty(property, value, flags = 0) {
        // Check if setter exists
        if (typeof this.__lookupSetter__(property) !== 'undefined') {
            this[property] = value;
            return this;
        }
        // No setter, check if getter returns model
        const currentVal = this[property];
        if (currentVal && isFunction(currentVal.update)) {
            // If yes, update recursively.
            currentVal.update(value, flags);
            return this;
        }
        // Soft update
        if (flagIsSet(flags, SOFT_UPDATE)) {
            return this.set(property, value, flags);
        }
        // If no setter or sub model, throw error.
        throw new Error('Could not update property "' + property + '" on ' + this.constructor.name + '.');
    }
    /**
     * Update modified timestamp.
     * @param {timestamp} modified Time of modification or undefined if now.
     * @return {Model} The Model object.
     */
    updateModified(modified) {
        this._modified = modified || Date.now();
        // Return
        return this;
    }
    /**
     * Return a copy of this model, with new uuids.
     * FIX: Better way to do this?
     * @return {Model} New instance of Model (or Model subclass).
     */
    copy() {
        // stringify data dict
        const jsonStr = JSON.stringify(this._data);
        // replace all uuids with new one's.
        const uuidRegexp = /"uuid":"........-....-....-....-............"/g;
        const newJsonStr = jsonStr.replace(uuidRegexp, () => {
            return '"uuid":"' + uuidV4() + '"';
        });
        // return instance of this
        const Constructor = this.constructor;
        return new Constructor(JSON.parse(newJsonStr));
    }
    /**
     * Interface for dispatching events.
     * Currently alias for EventEmitter.emit. May change.
     * @param {String} eventType Event type key.
     * @param {...} args Arguments passed to listeners.
     * @return {Model} The Model object.
     */
    dispatchEvent(eventType, ...args) {
        this.emit(eventType, ...[eventType, this].concat(args));
        // Return
        return this;
    }
    /**
     * Dispatch change events.
     * @param {String} property Name of property.
     * @param {*} newValue Anything JSON serializable.
     * @param {*} oldValue Anything JSON serializable.
     * @return {Model} The Model object.
     */
    dispatchChange(property, newValue, oldValue) {
        if (property) {
            this.dispatchEvent('change ' + property, newValue, oldValue);
        }
        return this.dispatchEvent('change');
    }
    /**
     * Alias for EventEmitter.addListener
     */
    addEventListener(event, listener) {
        this.addListener(event, listener);
        // Return
        return this;
    }
    /**
     * Alias for EventEmitter.removeListener
     */
    removeEventListener(event, listener) {
        this.removeListener(event, listener);
        // Return
        return this;
    }
    /**
     * Dispose model and sub models recursively.
     * Remove event listeners and delete references.
     * @return {Model} The Model object.
     */
    dispose() {
        // Remove event listeners
        this.removeAllListeners();
        // Check sub models on this, recursively
        Object.keys(this).forEach(attr => {
            if (isObject(this[attr]) && isFunction(this[attr].dispose)) {
                this[attr].dispose();
            }
        });
        // delete refs
        this._deleteReferences();
        // Return
        return this;
    }
    /**
     * Delete references set on model.
     */
    _deleteReferences() {
        delete this._data;
        delete this._previousData;
        delete this._modified;
    }
    /**
     * Check validity of data. Throw error if not valid.
     * @param {Object} data JSON serializable object.
     */
    _validate(data) {
        // Abstract
    }
    /**
     * Return default data object for new instance.
     * @param {...} constructorArgs List of arguments passed in constructor.
     * @return {Object} Default data (JSON serializable object) for Model.
     */
    _getDefaults(...constructorArgs) {
        return {
            // Model polymorphic identity
            identity: Model.identity,
            // model uuid
            uuid: uuidV4()
        };
    }
    /**
     * Update data object with defaults.
     * @param {Object} data JSON serializable object.
     * @param {...} constructorArgs List of arguments passed in constructor.
     * @return {Model} The Model object.
     */
    _withDefaults(data, ...constructorArgs) {
        // defaults
        const defaultData = this._getDefaults(...constructorArgs);
        // Update undefined props from defaults
        Object.keys(defaultData).forEach(prop => {
            if (isUndefined(data[prop])) {
                data[prop] = defaultData[prop];
            }
        });
        return this;
    }
    /**
     * Return unique client id.
     * @return {String} Unique string.
     */
    _getUniqueClientId() {
        return uniqueId(this.getModelIdentity());
    }

}
// Polymorphic identity
Model.identity = 'mozy.Model';
// Register Model
identities.set(Model.identity, Model);
<|endoftext|>