<commit_before>'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");
var nlp = require("./nlp");
var newBot = require("./newBot");
var push = require("./push");
var logConv = require("./log").logConversation;
//var findSession = require("./sessionsearch");

const scriptRules = require('./script.json');

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Hello!  I\'m A16, the Agile2016 EventBot Concierge.  To find out what I can help you with type MENU for options or KEY for Keywords.')
                .then(() => 'speak');
        }
    },

    speak: {
        receive: (bot, message) => {

            console.log("- bot message ", message);
            console.log("processID", process.pid);

            //exit right away
//            if (message.mediaType) {
//              return bot.say("I'm sorry I don't know how to respond to media yet.  😳   Type MENU or KEY for a list of things I can help you with.")
//                .then(() => 'speak');
//            }

            let upperText = message.text.trim().toUpperCase();

            //This is in case a user uses the bots name in a request
            //console.log("before a16 search ", upperText.indexOf("A16"), upperText.length);
            if ((upperText.indexOf(process.env.BOT_NAME)  > -1)  && (upperText.length > 4)) {
              upperText = upperText.replace(process.env.BOT_NAME, "");
            }

            var msgLog = {
                smoochId: '',
                received: '',
                usermessage: '',
                role: '',
                message_id: '',
                sourcetype: '',
                receivedtime: '',
                responsemessage: '',
                responsetype: '',
                responsetime: ''
              };

            //create message log to pesist in db
            msgLog.smoochId = bot.userId;
            msgLog.received = message.received;
            msgLog.usermessage = message.text;
            msgLog.role = message.role;
            msgLog.message_id = message._id;
            msgLog.receivedtime = new Date();
            if (typeof message.message !== "undefined") {
              //postback
              msgLog.sourcetype = message.action.type;
            } else {
              // This is appUser - which means it is a message typed in by the user
              msgLog.sourcetype = message.source.type;
            }

            //SK_ACCESS is a heroku config var that has the list of user/platform
            //smoochids for users to send ad hoc push conversations
            if (upperText.substr(0,4) == '/SK ') {
              adhocMsg();
            }

            function adhocMsg() {
              var authUsers = process.env.SK_ACCESS;
              //For ad hoc messages - scheduled messages are done differently in checkItems
              //-1 indicates that a user is not authorized to send broadcast messages
              if (authUsers.indexOf(bot.userId) !== -1) {
                upperText = upperText.substr(0,3);
                newBot('adhoc',process.env.ADHOC_PREFIX + message.text.substr(4));
                console.log("- ad hoc msg: ",message.text," authUser:  ",authUsers);
                msgLog.responsemessage = upperText;
                msgLog.responsetype = "adhoc msg";
                //return jResponse();
              } else {
                upperText = "NO_SK";
              }
            }

            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        //console.log('- Special Case: CONNECT ME'); //turns off bot
                        return bot.setProp("silent", true);
                    case "/NOTIFY":
                        //console.log('- Special Case: /NOTIFY'); //turns off bot
                        bot.say("I have notified the Agile2016 human team that you have requested help. They usually respond in less than 5 minutes during conference hours. You are now in live support mode and when you are ready to chat with me again tap the button or type /A16. %[Return](postback:/A16)").then(() => 'speak');
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        //console.log('- Special Case: DISCONNECT'); //turns bot back on
                        return bot.setProp("silent", false);
                    case "/A16":
                        //console.log('- Special Case: /A16'); //turns bot back on
                        bot.say("A16 is back! I hope my human colleagues were able to help you.").then(() => 'speak');
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            function getSilent() {
                return bot.getProp("silent");
            }

            function apiMessage() {
              //prepare to send to API.ai
              console.log("in apiMessage");
              var promises = [];
              var source;
              var fulfillmentSpeech;
              var simplified;
              //To better pass to API.AI does not deal with '/' well
              if (upperText.match(/7\/2[456789]/g)) {
                upperText = upperText.replace("/", " ");
              }

              promises.push(nlp(upperText, bot.userId));

              Q.all(promises).then(function(responses) {
                responses.forEach(function(response) {
                  console.log("- In Q.all");
                  console.log("- Received result from API.ai",response);
                  source = response.result.source;
                  msgLog.responsemessage = response.result.fulfillment.speech;

                  if (source === 'domains') {
                    console.log("apiMessage - domains");
                    console.log("- In domains, switch default");
                    //console.log("what is simplified", response.result.parameters.simplified);
                    //if (response.result.parameters.simplified = "hello") {
                    //  console.log("are you here?");
                    //  upperText = "HELLO"
                    //  return jResponse();
                    //}
                    msgLog.responsetype = 'API.ai domains';
                    msgLog.responsetime = new Date();
                    logConv(msgLog);
                    console.log("- in domains msg logged", msgLog.responsemessage);
                    return bot.say(msgLog.responsemessage).then(() => 'speak');
                  } else if (msgLog.responsemessage) {
                    console.log("- In agent,",simplified);
                    upperText = response.result.action;
                    msgLog.responsetype = 'API.ai agent';
                    return jResponse();
                  } else {
                    msgLog.responsetype = 'No match';
                    msgLog.responsetime = new Date();
                    logConv(msgLog);
                    return bot.say(`I'm sorry that is not something I know.  😳   Type MENU or KEY for a list of things I can help you with.`).then(() => 'speak');
                  }
                });
              }, function(error) {
                  console.log("- Q.all error: ", error);
              });
            }

            function processMessage(isSilent){
                if (isSilent) {
                    return Promise.resolve("speak");
                }
                if (!_.has(scriptRules, upperText))
                {
                  console.log("ProcessMessage no ", upperText);
                  apiMessage();
                } else {
                  console.log("processMessage has rule");
                  msgLog.responsetype = 'JSON';
                  jResponse();
                }
            }

            function jResponse() {
                var response = scriptRules[upperText];
                var lines = response.split('\n');
                console.log("=== msgLog  obj",msgLog);

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log("- p line",line);
                        return wait(50).then(function() {
                            return bot.say(line);
                        });
                    });
                });
                msgLog.responsetime = new Date();
                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(getSilent)
                .then(processMessage)
                .then(logConv(msgLog));
;
        }
    }
});
<commit_msg>work on msgLog<commit_after>'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");
var nlp = require("./nlp");
var newBot = require("./newBot");
var push = require("./push");
var logConv = require("./log").logConversation;
//var findSession = require("./sessionsearch");

const scriptRules = require('./script.json');

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Hello!  I\'m A16, the Agile2016 EventBot Concierge.  To find out what I can help you with type MENU for options or KEY for Keywords.')
                .then(() => 'speak');
        }
    },

    speak: {
        receive: (bot, message) => {

            console.log("- bot message ", message);
            console.log("processID", process.pid);

            //exit right away
//            if (message.mediaType) {
//              return bot.say("I'm sorry I don't know how to respond to media yet.  😳   Type MENU or KEY for a list of things I can help you with.")
//                .then(() => 'speak');
//            }

            let upperText = message.text.trim().toUpperCase();

            //This is in case a user uses the bots name in a request
            //console.log("before a16 search ", upperText.indexOf("A16"), upperText.length);
            if ((upperText.indexOf(process.env.BOT_NAME)  > -1)  && (upperText.length > 4)) {
              upperText = upperText.replace(process.env.BOT_NAME, "");
            }

            var msgLog = {
                smoochId: '',
                received: '',
                usermessage: '',
                role: '',
                message_id: '',
                sourcetype: '',
                receivedtime: '',
                responsemessage: '',
                responsetype: '',
                responsetime: ''
              };

            //create message log to pesist in db
            msgLog.smoochId = bot.userId;
            msgLog.received = message.received;
            msgLog.usermessage = message.text;
            msgLog.role = message.role;
            msgLog.message_id = message._id;
            msgLog.receivedtime = new Date();
            if (typeof message.message !== "undefined") {
              //postback
              msgLog.sourcetype = message.action.type;
            } else {
              // This is appUser - which means it is a message typed in by the user
              msgLog.sourcetype = message.source.type;
            }

            //SK_ACCESS is a heroku config var that has the list of user/platform
            //smoochids for users to send ad hoc push conversations
            if (upperText.substr(0,4) == '/SK ') {
              adhocMsg();
            }

            function adhocMsg() {
              var authUsers = process.env.SK_ACCESS;
              //For ad hoc messages - scheduled messages are done differently in checkItems
              //-1 indicates that a user is not authorized to send broadcast messages
              if (authUsers.indexOf(bot.userId) !== -1) {
                upperText = upperText.substr(0,3);
                newBot('adhoc',process.env.ADHOC_PREFIX + message.text.substr(4));
                console.log("- ad hoc msg: ",message.text," authUser:  ",authUsers);
                msgLog.responsemessage = upperText;
                msgLog.responsetype = "adhoc msg";
                //return jResponse();
              } else {
                upperText = "NO_SK";
              }
            }

            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        //console.log('- Special Case: CONNECT ME'); //turns off bot
                        return bot.setProp("silent", true);
                    case "/NOTIFY":
                        //console.log('- Special Case: /NOTIFY'); //turns off bot
                        bot.say("I have notified the Agile2016 human team that you have requested help. They usually respond in less than 5 minutes during conference hours. You are now in live support mode and when you are ready to chat with me again tap the button or type /A16. %[Return](postback:/A16)").then(() => 'speak');
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        //console.log('- Special Case: DISCONNECT'); //turns bot back on
                        return bot.setProp("silent", false);
                    case "/A16":
                        //console.log('- Special Case: /A16'); //turns bot back on
                        bot.say("A16 is back! I hope my human colleagues were able to help you.").then(() => 'speak');
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            function getSilent() {
                return bot.getProp("silent");
            }

            function apiMessage() {
              //prepare to send to API.ai
              console.log("in apiMessage");
              var promises = [];
              var source;
              var fulfillmentSpeech;
              var simplified;
              //To better pass to API.AI does not deal with '/' well
              if (upperText.match(/7\/2[456789]/g)) {
                upperText = upperText.replace("/", " ");
              }

              promises.push(nlp(upperText, bot.userId));

              Q.all(promises).then(function(responses) {
                responses.forEach(function(response) {
                  console.log("- In Q.all");
                  console.log("- Received result from API.ai",response);
                  source = response.result.source;
                  msgLog.responsemessage = response.result.fulfillment.speech;

                  if (source === 'domains') {
                    console.log("apiMessage - domains");
                    console.log("- In domains, switch default");
                    //console.log("what is simplified", response.result.parameters.simplified);
                    //if (response.result.parameters.simplified = "hello") {
                    //  console.log("are you here?");
                    //  upperText = "HELLO"
                    //  return jResponse();
                    //}
                    msgLog.responsetype = 'API.ai domains';
                    msgLog.responsetime = new Date();
                    logConv(msgLog);
                    console.log("- in domains msg logged", msgLog.responsemessage);
                    return bot.say(msgLog.responsemessage).then(() => 'speak');
                  } else if (msgLog.responsemessage) {
                    console.log("- In agent,",simplified);
                    upperText = response.result.action;
                    msgLog.responsetype = 'API.ai agent';
                    return jResponse();
                  } else {
                    msgLog.responsetype = 'No match';
                    msgLog.responsetime = new Date();
                    logConv(msgLog);
                    return bot.say(`I'm sorry that is not something I know.  😳   Type MENU or KEY for a list of things I can help you with.`).then(() => 'speak');
                  }
                });
              }, function(error) {
                  console.log("- Q.all error: ", error);
              });
            }

            function processMessage(isSilent){
                if (isSilent) {
                    return Promise.resolve("speak");
                }
                if (!_.has(scriptRules, upperText))
                {
                  console.log("ProcessMessage no ", upperText);
                  apiMessage();
                } else {
                  console.log("processMessage has rule");
                  msgLog.responsetype = 'JSON';
                  jResponse();
                }
            }

            function jResponse() {
                var response = scriptRules[upperText];
                msgLog.response = response;
                msgLog.responsetime = new Date();
                var lines = response.split('\n');
                console.log("=== msgLog  obj",msgLog);

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log("- p line",line);
                        return wait(50).then(function() {
                            return bot.say(line);
                        });
                    });
                });
                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(getSilent)
                .then(processMessage)
                .then(logConv(msgLog));
;
        }
    }
});
<|endoftext|>


<commit_before>//general problem : when vendors are managed in vendor folder, asset path throws err :(
var React = require('react');
var L = require('leaflet');
var $ = require('jquery');
var polyline = require('polyline');
var RouteHandler = require('react-router').RouteHandler;
var ReactSpinner = require('./Spin.js');
require('react-leaflet');
require('leafletCss');
require('ratchet');
require('./css/main.css');

//require('tangram');

var SearchBox = require('./SearchBox')

//should replace to tangram later

var SearchWhileRoute = React.createClass({

  render: function(){
    return (

      <SearchBox
      value = {this.props.startPoint.name}
      addMarker = {this.props.setStartPoint} />
      <SearchBox
          value = {this.props.destPoint.name}
          addMarker = {this.props.addMarker}/>

    );
  }

})

var CurrentLocation = React.createClass({
  getInitialState: function(){
    return{
      config : {
        lines: 9 // The number of lines to draw
        , length: 0 // The length of each line
        , width: 6 // The line thickness
        , radius: 10 // The radius of the inner circle
        , color: '#666' // #rgb or #rrggbb or array of colors
        , speed: 1 // Rounds per second
        , className: 'spinner' // The CSS class to assign to the spinner
        , top: '50%' // Top position relative to parent
        , left: '50%' // Left position relative to parent
        , shadow: false // Whether to render a shadow
        , hwaccel: true // Whether to use hardware acceleration
      },
      spinning: false
    }
  },
  getCurrentLocation: function(){
    this.mountSpinner();
    var self = this;
     if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position){
          self.props.setCurrentLocation(position);
          self.unmountSpinner();
//          console.log("sam is the prettiest");
        });
    } else {
        //what will it show when browser doesn't support geolocation?
    }
  },
  mountSpinner: function(){
    React.render(<ReactSpinner config={this.state.config}/>, document.getElementById('whatsgoingon'));
    this.setState({
      spinning:true
    });
  },
  unmountSpinner: function(){
    React.unmountComponentAtNode(document.getElementById('whatsgoingon'));
    this.setState({
      spinning:false
    })
  },
  render : function(){
    return(

    );
  }
});

var RouteWindow = React.createClass({

  getInitialState : function(){
    return{
      //startPoint must be replaced current location // search result
      activeTab: ""
    }
  },
  //
  route: function(mode){
    //valhalla call form : https://valhalla.mapzen.com/route?json={%22locations%22:[{%22lat%22:39.42923221970601,%22lon%22:-76.6356897354126},{%22lat%22:39.30727282892593,%22lon%22:-76.77203178405762}],%22costing%22:%22auto%22}&api_key=valhalla-RfDii2g
    var serviceurl = "https://valhalla.mapzen.com/";
    var apikey = '&api_key=valhalla-RfDii2g';

    var transitM = mode || 'auto';
    var locs = [];
    locs.push({
      lat : this.props.startPoint.lat,
      lon : this.props.startPoint.lon
    });
    locs.push({
      lat : this.props.destPoint.lat,
      lon : this.props.destPoint.lon
    });

    var self = this;

    var params = JSON.stringify({
      locations: locs,
      costing: transitM
    });

    var routeUrl = serviceurl +  'route?json=' + params + apikey;
    $.get(routeUrl,function(data){

      var coord = polyline.decode(data.trip.legs[0].shape,6);
      self.props.addRouteLayer(coord);
    });
    //there must be better way to do this
    self.setState({
      activeTab: mode
    })

  },

  cancleRouteMode: function(){
    this.props.setMapMode('search');
    this.props.clearMap();
  },
  render: function(){
      return(

        <SearchWhileRoute
          startPoint = {this.props.startPoint}
          addMarker = {this.props.addMarker}
          destPoint = {this.props.destPoint}
          setStartPoint = {this.props.setStartPoint} />

                auto
                bike
                walk

      )
  }
});

var RouteButton = React.createClass({
  getInitialState : function(){
    return{
      //startPoint must be replaced current location // search result
      destPoint : {},
      destPoint : this.props.destMarker,
      routePrirority : this.props.routePrirority,
      bringRouteWindow: false
    }
  },
  route : function(){
    this.props.setMapMode('route');
  },
  render : function(){
      return(

      );

  }
});

var Main = React.createClass({

  getInitialState: function(){
    return{
      // markerLyaer is being mutated, not the way react recommends
      currentPoint : {
        name : "Current location",
        lat: 0,
        lon: 0
      },
      startPoint : {
        name : "Choose start location.",
        lat :  40.7410605,
        lon : -73.9896986
      },
      destMarker : {
        name : "Choose destination.",
        lat :  40.7410605,
        lon : -73.9896986
      },
      currentLayer : L.layerGroup(),
      markerLayer : L.layerGroup([L.marker([39.61, -105.02]).bindPopup('This is Littleton, CO.')]),
      routeLayer : L.layerGroup(),
      mode : "search"
    }

  },
  setStartPoint: function(mrkr){
    this.setState({startPoint:mrkr});
  },

  setCurrentPoint: function(pos){

    var newCurrentLocation = {
      name : "Current location",
      lat: pos.coords.latitude,
      lon: pos.coords.longitude
    }

    this.setState({
      currentPoint : newCurrentLocation,
      startPoint : newCurrentLocation
    });
    var center = L.latLng(pos.coords.latitude,pos.coords.longitude);
    this.state.currentLayer.clearLayers();
    this.state.currentLayer.addLayer(L.circleMarker(center), 3, {
      color: '#00f',
      opacity:1,
      fillColor: '#00f',
      fillOpacity: 0.8,

    });
    this.map.setView(center,14);
    this.setState({
      bbox : this.map.getBounds().toBBoxString()
    });
  },

  addMarker: function(mrkr){

    this.state.markerLayer.clearLayers();
    var marker = L.marker([mrkr.lat,mrkr.lon]);
    this.state.markerLayer.addLayer(marker);

    this.map.setView(marker.getLatLng(),14);
    this.setState({
      destMarker: mrkr,
      bbox : this.map.getBounds().toBBoxString()
    });
  },
  clearMap : function(){
    this.state.markerLayer.clearLayers();
    this.state.currentLayer.clearLayers();
    this.state.routeLayer.clearLayers();
    this.setState({
      startPoint:{},
      destPoint:{}
    });
  },
  addRouteLayer : function(routes){
    this.state.routeLayer.clearLayers();
    var polylineRoute = L.polyline(routes, {color:'red'});
    this.state.routeLayer.addLayer(polylineRoute);
    this.map.fitBounds(polylineRoute.getBounds());
    this.render();
  },
  setMapMode : function(mapMode){
    this.setState({mode:mapMode});
  },
  createMap: function (element) {
    //React.render(<Map lat="40.758" lon="-73.9174" zoom="4" />,document.body);
    var map = L.map(element,{
      zoomControl:false
    });
    var layer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
      attribution: '© OpenStreetMap contributors'
    }).addTo(map);

    // loading scene yaml
    //Error: Can't load worker because couldn't find base URL that library was loaded from
     // var layer = Tangram.leafletLayer({
     //     scene: 'scene.yaml',//sceneYaml,
     //     attribution: 'Tangram | © OSM contributors | Mapzen'
     // });
    layer.addTo(map);
    return map;
    },

    setupMap: function () {
      this.map.setView([40.758, -73.9174], 10);
      this.setState({
        bbox : this.map.getBounds().toBBoxString()
      });
    },

    componentDidMount: function () {
        if (this.props.createMap) {
            this.map = this.props.createMap(this.getDOMNode());
        } else {
            console.log("map is getting inside of map node");
            this.map = this.createMap(document.getElementById('map'));
        }
        this.setupMap();
        this.state.markerLayer.addTo(this.map);
        this.state.currentLayer.addTo(this.map);
        this.state.routeLayer.addTo(this.map);
    },

    render: function () {
      if(this.state.mode == "search"){
      return (

          <SearchBox
            addMarker = {this.addMarker}
            bbox = {this.bbox}/>

          <RouteButton
          destMarker= {this.state.destMarker}
          addRouteLayer = {this.addRouteLayer}
          setMapMode = {this.setMapMode}
          mode = {this.state.mode}/>
          <CurrentLocation
            setCurrentLocation = {this.setCurrentPoint} />
          <RouteHandler />

      );
    }else{
        return(

          <RouteWindow
            startPoint = {this.state.startPoint}
            destPoint = {this.state.destMarker}
            clearMap = {this.clearMap}
            addMarker = {this.addMarker}
            setStartPoint = {this.setStartPoint}
            addRouteLayer = {this.addRouteLayer}
            setMapMode = {this.setMapMode}/>

        );
      }
    }
});

module.exports = Main;
<commit_msg>class name edited<commit_after>//general problem : when vendors are managed in vendor folder, asset path throws err :(
var React = require('react');
var L = require('leaflet');
var $ = require('jquery');
var polyline = require('polyline');
var RouteHandler = require('react-router').RouteHandler;
var ReactSpinner = require('./Spin.js');
require('react-leaflet');
require('leafletCss');
require('ratchet');
require('./css/main.css');

//require('tangram');

var SearchBox = require('./SearchBox')

//should replace to tangram later

var SearchWhileRoute = React.createClass({

  render: function(){
    return (

      <SearchBox
      value = {this.props.startPoint.name}
      addMarker = {this.props.setStartPoint} />
      <SearchBox
          value = {this.props.destPoint.name}
          addMarker = {this.props.addMarker}/>

    );
  }

})

var CurrentLocation = React.createClass({
  getInitialState: function(){
    return{
      config : {
        lines: 9 // The number of lines to draw
        , length: 0 // The length of each line
        , width: 6 // The line thickness
        , radius: 10 // The radius of the inner circle
        , color: '#666' // #rgb or #rrggbb or array of colors
        , speed: 1 // Rounds per second
        , className: 'spinner' // The CSS class to assign to the spinner
        , top: '50%' // Top position relative to parent
        , left: '50%' // Left position relative to parent
        , shadow: false // Whether to render a shadow
        , hwaccel: true // Whether to use hardware acceleration
      },
      spinning: false
    }
  },
  getCurrentLocation: function(){
    this.mountSpinner();
    var self = this;
     if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position){
          self.props.setCurrentLocation(position);
          self.unmountSpinner();
//          console.log("sam is the prettiest");
        });
    } else {
        //what will it show when browser doesn't support geolocation?
    }
  },
  mountSpinner: function(){
    React.render(<ReactSpinner config={this.state.config}/>, document.getElementById('whatsgoingon'));
    this.setState({
      spinning:true
    });
  },
  unmountSpinner: function(){
    React.unmountComponentAtNode(document.getElementById('whatsgoingon'));
    this.setState({
      spinning:false
    })
  },
  render : function(){
    return(

    );
  }
});

var RouteWindow = React.createClass({

  getInitialState : function(){
    return{
      //startPoint must be replaced current location // search result
      activeTab: ""
    }
  },
  //
  route: function(mode){
    //valhalla call form : https://valhalla.mapzen.com/route?json={%22locations%22:[{%22lat%22:39.42923221970601,%22lon%22:-76.6356897354126},{%22lat%22:39.30727282892593,%22lon%22:-76.77203178405762}],%22costing%22:%22auto%22}&api_key=valhalla-RfDii2g
    var serviceurl = "https://valhalla.mapzen.com/";
    var apikey = '&api_key=valhalla-RfDii2g';

    var transitM = mode || 'auto';
    var locs = [];
    locs.push({
      lat : this.props.startPoint.lat,
      lon : this.props.startPoint.lon
    });
    locs.push({
      lat : this.props.destPoint.lat,
      lon : this.props.destPoint.lon
    });

    var self = this;

    var params = JSON.stringify({
      locations: locs,
      costing: transitM
    });

    var routeUrl = serviceurl +  'route?json=' + params + apikey;
    $.get(routeUrl,function(data){

      var coord = polyline.decode(data.trip.legs[0].shape,6);
      self.props.addRouteLayer(coord);
    });
    //there must be better way to do this
    self.setState({
      activeTab: mode
    })

  },

  cancleRouteMode: function(){
    this.props.setMapMode('search');
    this.props.clearMap();
  },
  render: function(){
      return(

        <SearchWhileRoute
          startPoint = {this.props.startPoint}
          addMarker = {this.props.addMarker}
          destPoint = {this.props.destPoint}
          setStartPoint = {this.props.setStartPoint} />

                auto
                bike
                walk

      )
  }
});

var RouteButton = React.createClass({
  getInitialState : function(){
    return{
      //startPoint must be replaced current location // search result
      destPoint : this.props.destMarker,
      routePrirority : this.props.routePrirority,
      bringRouteWindow: false
    }
  },
  route : function(){
    this.props.setMapMode('route');
  },
  render : function(){
      return(

      );

  }
});

var Main = React.createClass({

  getInitialState: function(){
    return{
      // markerLyaer is being mutated, not the way react recommends
      currentPoint : {
        name : "Current location",
        lat: 0,
        lon: 0
      },
      startPoint : {
        name : "Choose start location.",
        lat :  40.7410605,
        lon : -73.9896986
      },
      destMarker : {
        name : "Choose destination.",
        lat :  40.7410605,
        lon : -73.9896986
      },
      currentLayer : L.layerGroup(),
      markerLayer : L.layerGroup([L.marker([39.61, -105.02]).bindPopup('This is Littleton, CO.')]),
      routeLayer : L.layerGroup(),
      mode : "search"
    }

  },
  setStartPoint: function(mrkr){
    this.setState({startPoint:mrkr});
  },

  setCurrentPoint: function(pos){

    var newCurrentLocation = {
      name : "Current location",
      lat: pos.coords.latitude,
      lon: pos.coords.longitude
    }

    this.setState({
      currentPoint : newCurrentLocation,
      startPoint : newCurrentLocation
    });
    var center = L.latLng(pos.coords.latitude,pos.coords.longitude);
    this.state.currentLayer.clearLayers();
    this.state.currentLayer.addLayer(L.circleMarker(center), 3, {
      color: '#00f',
      opacity:1,
      fillColor: '#00f',
      fillOpacity: 0.8,

    });
    this.map.setView(center,14);
    this.setState({
      bbox : this.map.getBounds().toBBoxString()
    });
  },

  addMarker: function(mrkr){

    this.state.markerLayer.clearLayers();
    var marker = L.marker([mrkr.lat,mrkr.lon]);
    this.state.markerLayer.addLayer(marker);

    this.map.setView(marker.getLatLng(),14);
    this.setState({
      destMarker: mrkr,
      bbox : this.map.getBounds().toBBoxString()
    });
  },
  clearMap : function(){
    this.state.markerLayer.clearLayers();
    this.state.currentLayer.clearLayers();
    this.state.routeLayer.clearLayers();
    this.setState({
      startPoint:{},
      destPoint:{}
    });
  },
  addRouteLayer : function(routes){
    this.state.routeLayer.clearLayers();
    var polylineRoute = L.polyline(routes, {color:'red'});
    this.state.routeLayer.addLayer(polylineRoute);
    this.map.fitBounds(polylineRoute.getBounds());
    this.render();
  },
  setMapMode : function(mapMode){
    this.setState({mode:mapMode});
  },
  createMap: function (element) {
    //React.render(<Map lat="40.758" lon="-73.9174" zoom="4" />,document.body);
    var map = L.map(element,{
      zoomControl:false
    });
    var layer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
      attribution: '© OpenStreetMap contributors'
    }).addTo(map);

    // loading scene yaml
    //Error: Can't load worker because couldn't find base URL that library was loaded from
     // var layer = Tangram.leafletLayer({
     //     scene: 'scene.yaml',//sceneYaml,
     //     attribution: 'Tangram | © OSM contributors | Mapzen'
     // });
    layer.addTo(map);
    return map;
    },

    setupMap: function () {
      this.map.setView([40.758, -73.9174], 10);
      this.setState({
        bbox : this.map.getBounds().toBBoxString()
      });
    },

    componentDidMount: function () {
        if (this.props.createMap) {
            this.map = this.props.createMap(this.getDOMNode());
        } else {
            console.log("map is getting inside of map node");
            this.map = this.createMap(document.getElementById('map'));
        }
        this.setupMap();
        this.state.markerLayer.addTo(this.map);
        this.state.currentLayer.addTo(this.map);
        this.state.routeLayer.addTo(this.map);
    },

    render: function () {
      if(this.state.mode == "search"){
      return (

          <RouteButton
          destMarker= {this.state.destMarker}
          addRouteLayer = {this.addRouteLayer}
          setMapMode = {this.setMapMode}
          mode = {this.state.mode}/>
          <CurrentLocation
            setCurrentLocation = {this.setCurrentPoint} />
          <SearchBox
            addMarker = {this.addMarker}
            bbox = {this.bbox}/>

          <RouteHandler />

      );
    }else{
        return(

          <RouteWindow
            startPoint = {this.state.startPoint}
            destPoint = {this.state.destMarker}
            clearMap = {this.clearMap}
            addMarker = {this.addMarker}
            setStartPoint = {this.setStartPoint}
            addRouteLayer = {this.addRouteLayer}
            setMapMode = {this.setMapMode}/>

        );
      }
    }
});

module.exports = Main;
<|endoftext|>


<commit_before>var streamer={};
$.getJSON('/getsongs',function(data){
	if (!data.length) {return;}
	//ultility
	function getRandomInt(min, max) {
  		return Math.floor(Math.random() * (max - min)) + min;
	}
	var player=document.getElementById('player');
	//Song,Library MVC
	var Song=Backbone.Model.extend({
		play:function(){
			var span=$('#play .play span')
			span.removeClass('glyphicon-play').addClass('glyphicon-pause');
			if (player.getAttribute('src')!==this.get('file')) {
				player.src=this.get('file')
			}
			player.play();
		},
		pause:function(){
			var span=$('#play .play span')
			span.addClass('glyphicon-play').removeClass('glyphicon-pause');
			player.pause();
		},
		updateInfo:function(){
			var artist=$('#song-info .artist span');
			var title=$('#song-info .title span');
			var album=$('#song-info .album span');
			artist.text(this.get('artist'));
			title.text(this.get('title'));
			album.text(this.get('album'));
		}
	});
	var Library = Backbone.Collection.extend({
  		model: Song,
	});
	var lib=new Library(data);
	var oldLib=_.clone(lib);
	var SongView = Backbone.View.extend({
		tagName: "li",
		className:'list',
	  	template: _.template('
<%= title %>

<%= artist %> - <%= album %>

'),
	  	render: function() {
	    	this.$el.html(this.template(this.model.attributes));
	    	return this;
	  	}
	});
	var musicLibrary=function(collection,wrapper){
		var ul=document.createElement('ul');
		ul.className='playlist';
		var html='';
		collection.each(function(model){
			var songView=new SongView({model:model});
			ul.appendChild(songView.render().el);
		});
		wrapper.html('').append(ul);
		wrapper.find('.playlist .list').each(function(index){
			$(this).click(function(){
				currentSong.set({'list':collection.models,'current':index})
			})
		});
	}
	musicLibrary(lib,$('#songlist'));
	$('#songlist .list').each(function(index){
		$(this).click(function(){
			currentSong.set({'list':oldLib.models,'current':index})
		})
	});
	//song playing model
	var CurrentSong=Backbone.Model.extend({
		defaults:{
			current:0,
			random:false,
			playing:true,
			list:lib.models
		},
		initialize:function(){
			this.play();
		},
		prev:function(){
			var current=this.get('current');
			var target=current-1;
			if (target<0){
				target=this.get('list').length-1;
			}
			return target;
		},
		next:function(){
			var current=this.get('current');
			var target=current+1;
			if (target>=this.get('list').length){
				target=0
			}
			return target;
		},
		play:function(){
			var model=this.get('list')[this.get('current')];
			this.set('playing',true);
			model.play();
			model.updateInfo();
		},
		pause:function(){
			var model=this.get('list')[this.get('current')];
			this.set('playing',false);
			model.pause();
		}
	});
	var currentSong=new CurrentSong();
	currentSong.on('change:current',function(){
		this.play();
	},currentSong);
	currentSong.on('change:playing',function(){
		var playing=this.get('playing');
		if (playing) {
			this.play()
		} else {
			this.pause()
		}
	},currentSong);
	currentSong.on('change:list',function(){
		this.play();
	},currentSong);
	var controlSong=function(type){
		var number;
		if (type==='next') {
			number=currentSong.next();
		}
		if (type==='prev') {
			number=currentSong.prev();
		}
		if (currentSong.get('random')) {
			number=getRandomInt(0,currentSong.get('list').length-1);
		}
		currentSong.set('current',number);
	}
	//shuffle the song list
	var playModel=function(model){
		if (model==='random') {
			currentSong.set('random',true);
		}
		else if (model==='one') {
			currentSong.set('singleRepeat',true);
		}
		else {
			currentSong.set({'singleRepeat':false,'random':false});
		}
	}
	//artist MVC
	var ArtistModel=Backbone.Model.extend();
	var ArtistView=Backbone.View.extend({
		tagName:'li',
		className:'list',
		events:{
			'click':'showAlbum'
		},
		showAlbum:function(){
			var name=this.model.get('name');
			var songs=lib.filter(function(model){
				return model.get('artist')===name
			});
			var list=new Backbone.Collection();
			list.add(songs);
			allAlbum(list,$('#artist'));
		},
		render:function(){
			this.$el.text(this.model.get('name'));
			return this;
		}
	});
	var allArtist=function(collection,wrapper) {
		var all=_.uniq(collection.pluck('artist'));
		var ul=$('

');
		all=_.sortBy(all,function(num){return num});
		all.forEach(function(item){
			var artistModel=new ArtistModel({'name':item});
			var artistView=new ArtistView({model:artistModel});
			ul.append(artistView.render().el)
		});
		wrapper.html('').append(ul);
	};
	//allArtist(lib,$('#artist'));
	//album MVC
	var AlbumModel=Backbone.Model.extend();
	var AlbumView=Backbone.View.extend({
		tagName:'li',
		className:'list',
		events:{
			'click':'showSongs'
		},
		showSongs:function(){
			var name=this.model.get('index');
			window.location.hash='#album/'+name;
			//router.navigate('album/'+name);
		},
		render:function(){
			this.$el.text(this.model.get('name')+'-'+this.model.get('artist'));
			return this;
		}
	});
	var allAlbum=function(collection,wrapper) {
		var all=_.uniq(collection.pluck('album'));
		var ul=$('

');
		all=_.sortBy(all,function(num){return num});
		var index=0;
		all.forEach(function(item){
			var albumModel=new AlbumModel({
				'name':item,
				'index':index,
				'artist':collection.findWhere({'album':item}).get('artist'),
				'album':collection.findWhere({'album':item}).get('album')
			});
			var albumView=new AlbumView({model:albumModel});
			ul.append(albumView.render().el);
			index++;
		});
		wrapper.html('').append(ul);
	};
	//allAlbum(lib,$('#album'));
	//router
	var Router=Backbone.Router.extend({
		routes: {
			'album':'album',
			'artist':'artist',
			'album/:index':'renderAlbum'
		},
		artist:function(){
			allArtist(lib,$('#artist'));
		},
		album:function(){
			allAlbum(lib,$('#album'));
		},
		renderAlbum:function(index){
			var album=lib.models[index].get('album');
			console.log(album);
			var songs=lib.find({'album':album})
			//console.log(arr);
			//var songs=lib.find()
			console.log(songs);
			var list=new Backbone.Collection(songs);
			musicLibrary(list,$('#album'));
		}
	});
	var router=new Router();
	Backbone.history.start();

	//export function for debug purpose
	streamer.collection=lib;
	streamer.order=playModel;
	streamer.control=controlSong;
	streamer.current=currentSong;
	streamer.router=router;
});

//Put the player manupulation code outside of MVC logic
(function($){
	var player=document.getElementById('player');
	var progress=$('.progress .progress-bar');
	var totalTime=$('.play-time .duration');
	var currentTime=$('.play-time .current');
	var prev=$('.controller .prev');
	var next=$('.controller .next');
	var play=$('.controller .play');
	var model=$('.play-model');
	var clicks=0;
	var formatTime=function(seconds) {
		var min=Math.floor(seconds/60);
		var sec=Math.floor(seconds%60);
		min>9?min=min:min='0'+min;
		sec>9?sec=sec:sec='0'+sec;
		return min+':'+sec;
	};
	var timer;
	var repeatFlag;
	player.addEventListener('play',function(){
		timer=window.setInterval(function(){
			var percent=Math.ceil(player.currentTime/player.duration*100)+'%';
			progress.css('width',percent);
			currentTime.text(formatTime(player.currentTime));
		},1000)
	});
	player.addEventListener('loadedmetadata',function(){
		totalTime.text(formatTime(player.duration));
	});
	player.addEventListener('ended',function(){
		window.clearInterval(timer);
		if (!repeatFlag) {
			streamer.control('prev');
		} else {
			player.loop=true;
		}
	});
	prev.on('click',function(){
		if (!repeatFlag) {
			streamer.control('prev');
		}
	});
	next.on('click',function(){
		if (!repeatFlag) {
			streamer.control('next');
		}
	});
	play.on('click',function(){
		var $this=$(this);
		$this.toggleClass('paused');
		if ($this.hasClass('paused')){
			streamer.current.set('playing',false);
		} else {
			streamer.current.set('playing',true);
		}
	})
	model.click(function(event){
		var $this=$(this);
		var icon=$this.find('span').eq(0);
		var text=$this.find('span').eq(1);
		switch (clicks) {
			case 0:
			streamer.order('one');
			icon.attr('class','glyphicon glyphicon-repeat');
			player.loop=true;
			repeatFlag=true;
			clicks++;
			break;
			case 1:
			streamer.order('random');
			icon.attr('class','glyphicon glyphicon-random');
			text.text('Shuffle');
			player.loop=false;
			repeatFlag=false;
			clicks++
			break;
			case 2:
			streamer.order();
			icon.attr('class','glyphicon glyphicon-refresh');
			text.text('All')
			clicks=0
			break;
			default:
			return;
		}
	});
	function scrollText(){
		var artist=$('#song-info .artist');
		var title=$('#song-info .title');
		var artText=artist.find('span');
		var titleText=title.find('span');
		if (titleText.width()>title.width()) {
			title.animate({'text-indent':title.width()-titleText.width()},2000,function(){
				title.css('text-indent',0);
			})
		}
		if (artText.width()>artist.width()) {
			artist.animate({'text-indent':artist.width()-artText.width()},2000,function(){
				artist.css('text-indent',0);
			})
		}
	}
	window.setInterval(scrollText,4000)
})(jQuery);

//here goes misc controls for non-essential
(function($){
	//nav
	var nav=$('nav.nav ul li');
	var wrapper=$('.wrapper');
	var width=$(window).width();
	var height=$(window).height();
	var sections=$('.wrapper>section');
	sections.css('width',width).css('height',height-90);
	wrapper.css('height',height-90);
	nav.each(function(index){
		$(this).click(function(){
			wrapper.css({
				'transform':'translateX(-'+width*index+'px)'});
			nav.removeClass('active').eq(index).addClass('active');
		})
	});
})(jQuery)<commit_msg>workaround to avoid string problem<commit_after>var streamer={};
$.getJSON('/getsongs',function(data){
	if (!data.length) {return;}
	//ultility
	function getRandomInt(min, max) {
  		return Math.floor(Math.random() * (max - min)) + min;
	}
	var player=document.getElementById('player');
	//Song,Library MVC
	var Song=Backbone.Model.extend({
		play:function(){
			var span=$('#play .play span')
			span.removeClass('glyphicon-play').addClass('glyphicon-pause');
			if (player.getAttribute('src')!==this.get('file')) {
				player.src=this.get('file')
			}
			player.play();
		},
		pause:function(){
			var span=$('#play .play span')
			span.addClass('glyphicon-play').removeClass('glyphicon-pause');
			player.pause();
		},
		updateInfo:function(){
			var artist=$('#song-info .artist span');
			var title=$('#song-info .title span');
			var album=$('#song-info .album span');
			artist.text(this.get('artist'));
			title.text(this.get('title'));
			album.text(this.get('album'));
		}
	});
	var Library = Backbone.Collection.extend({
  		model: Song,
	});
	var lib=new Library(data);
	var oldLib=_.clone(lib);
	var SongView = Backbone.View.extend({
		tagName: "li",
		className:'list',
	  	template: _.template('
<%= title %>

<%= artist %> - <%= album %>

'),
	  	render: function() {
	    	this.$el.html(this.template(this.model.attributes));
	    	return this;
	  	}
	});
	var musicLibrary=function(collection,wrapper){
		var ul=document.createElement('ul');
		ul.className='playlist';
		var html='';
		collection.each(function(model){
			var songView=new SongView({model:model});
			ul.appendChild(songView.render().el);
		});
		wrapper.html('').append(ul);
		wrapper.find('.playlist .list').each(function(index){
			$(this).click(function(){
				currentSong.set({'list':collection.models,'current':index})
			})
		});
	}
	musicLibrary(lib,$('#songlist'));
	$('#songlist .list').each(function(index){
		$(this).click(function(){
			currentSong.set({'list':oldLib.models,'current':index})
		})
	});
	//song playing model
	var CurrentSong=Backbone.Model.extend({
		defaults:{
			current:0,
			random:false,
			playing:true,
			list:lib.models
		},
		initialize:function(){
			this.play();
		},
		prev:function(){
			var current=this.get('current');
			var target=current-1;
			if (target<0){
				target=this.get('list').length-1;
			}
			return target;
		},
		next:function(){
			var current=this.get('current');
			var target=current+1;
			if (target>=this.get('list').length){
				target=0
			}
			return target;
		},
		play:function(){
			var model=this.get('list')[this.get('current')];
			this.set('playing',true);
			model.play();
			model.updateInfo();
		},
		pause:function(){
			var model=this.get('list')[this.get('current')];
			this.set('playing',false);
			model.pause();
		}
	});
	var currentSong=new CurrentSong();
	currentSong.on('change:current',function(){
		this.play();
	},currentSong);
	currentSong.on('change:playing',function(){
		var playing=this.get('playing');
		if (playing) {
			this.play()
		} else {
			this.pause()
		}
	},currentSong);
	currentSong.on('change:list',function(){
		this.play();
	},currentSong);
	var controlSong=function(type){
		var number;
		if (type==='next') {
			number=currentSong.next();
		}
		if (type==='prev') {
			number=currentSong.prev();
		}
		if (currentSong.get('random')) {
			number=getRandomInt(0,currentSong.get('list').length-1);
		}
		currentSong.set('current',number);
	}
	//shuffle the song list
	var playModel=function(model){
		if (model==='random') {
			currentSong.set('random',true);
		}
		else if (model==='one') {
			currentSong.set('singleRepeat',true);
		}
		else {
			currentSong.set({'singleRepeat':false,'random':false});
		}
	}
	//artist MVC
	var ArtistModel=Backbone.Model.extend();
	var ArtistView=Backbone.View.extend({
		tagName:'li',
		className:'list',
		events:{
			'click':'showAlbum'
		},
		showAlbum:function(){
			var name=this.model.get('name');
			var songs=lib.filter(function(model){
				return model.get('artist')===name
			});
			var list=new Backbone.Collection();
			list.add(songs);
			allAlbum(list,$('#artist'));
		},
		render:function(){
			this.$el.text(this.model.get('name'));
			return this;
		}
	});
	var allArtist=function(collection,wrapper) {
		var all=_.uniq(collection.pluck('artist'));
		var ul=$('

');
		all=_.sortBy(all,function(num){return num});
		all.forEach(function(item){
			var artistModel=new ArtistModel({'name':item});
			var artistView=new ArtistView({model:artistModel});
			ul.append(artistView.render().el)
		});
		wrapper.html('').append(ul);
	};
	//allArtist(lib,$('#artist'));
	//album MVC
	var AlbumModel=Backbone.Model.extend();
	var AlbumView=Backbone.View.extend({
		tagName:'li',
		className:'list',
		events:{
			'click':'showSongs'
		},
		showSongs:function(){
			var name=this.model.get('index');
			window.location.hash='#album/'+name;
			//router.navigate('album/'+name);
		},
		render:function(){
			this.$el.text(this.model.get('name')+'-'+this.model.get('artist'));
			return this;
		}
	});
	var allAlbum=function(collection,wrapper) {
		var all=_.uniq(collection.pluck('album'));
		var ul=$('

');
		all=_.sortBy(all,function(num){return num});
		var index=0;
		all.forEach(function(item){
			var albumModel=new AlbumModel({
				'name':item,
				'index':index,
				'artist':collection.findWhere({'album':item}).get('artist'),
				'album':collection.findWhere({'album':item}).get('album')
			});
			var albumView=new AlbumView({model:albumModel});
			ul.append(albumView.render().el);
			index++;
		});
		wrapper.html('').append(ul);
	};
	//allAlbum(lib,$('#album'));
	//router
	var Router=Backbone.Router.extend({
		routes: {
			'album':'album',
			'artist':'artist',
			'album/:index':'renderAlbum'
		},
		artist:function(){
			allArtist(lib,$('#artist'));
		},
		album:function(){
			allAlbum(lib,$('#album'));
		},
		renderAlbum:function(index){
			var album=lib.models[index].get('album');
			var songs=lib.filter(function(model){
				return model==lib.models[index];
			})
			var list=new Backbone.Collection(songs);
			musicLibrary(list,$('#album'));
		}
	});
	var router=new Router();
	Backbone.history.start();

	//export function for debug purpose
	streamer.collection=lib;
	streamer.order=playModel;
	streamer.control=controlSong;
	streamer.current=currentSong;
	streamer.router=router;
});

//Put the player manupulation code outside of MVC logic
(function($){
	var player=document.getElementById('player');
	var progress=$('.progress .progress-bar');
	var totalTime=$('.play-time .duration');
	var currentTime=$('.play-time .current');
	var prev=$('.controller .prev');
	var next=$('.controller .next');
	var play=$('.controller .play');
	var model=$('.play-model');
	var clicks=0;
	var formatTime=function(seconds) {
		var min=Math.floor(seconds/60);
		var sec=Math.floor(seconds%60);
		min>9?min=min:min='0'+min;
		sec>9?sec=sec:sec='0'+sec;
		return min+':'+sec;
	};
	var timer;
	var repeatFlag;
	player.addEventListener('play',function(){
		timer=window.setInterval(function(){
			var percent=Math.ceil(player.currentTime/player.duration*100)+'%';
			progress.css('width',percent);
			currentTime.text(formatTime(player.currentTime));
		},1000)
	});
	player.addEventListener('loadedmetadata',function(){
		totalTime.text(formatTime(player.duration));
	});
	player.addEventListener('ended',function(){
		window.clearInterval(timer);
		if (!repeatFlag) {
			streamer.control('prev');
		} else {
			player.loop=true;
		}
	});
	prev.on('click',function(){
		if (!repeatFlag) {
			streamer.control('prev');
		}
	});
	next.on('click',function(){
		if (!repeatFlag) {
			streamer.control('next');
		}
	});
	play.on('click',function(){
		var $this=$(this);
		$this.toggleClass('paused');
		if ($this.hasClass('paused')){
			streamer.current.set('playing',false);
		} else {
			streamer.current.set('playing',true);
		}
	})
	model.click(function(event){
		var $this=$(this);
		var icon=$this.find('span').eq(0);
		var text=$this.find('span').eq(1);
		switch (clicks) {
			case 0:
			streamer.order('one');
			icon.attr('class','glyphicon glyphicon-repeat');
			player.loop=true;
			repeatFlag=true;
			clicks++;
			break;
			case 1:
			streamer.order('random');
			icon.attr('class','glyphicon glyphicon-random');
			text.text('Shuffle');
			player.loop=false;
			repeatFlag=false;
			clicks++
			break;
			case 2:
			streamer.order();
			icon.attr('class','glyphicon glyphicon-refresh');
			text.text('All')
			clicks=0
			break;
			default:
			return;
		}
	});
	function scrollText(){
		var artist=$('#song-info .artist');
		var title=$('#song-info .title');
		var artText=artist.find('span');
		var titleText=title.find('span');
		if (titleText.width()>title.width()) {
			title.animate({'text-indent':title.width()-titleText.width()},2000,function(){
				title.css('text-indent',0);
			})
		}
		if (artText.width()>artist.width()) {
			artist.animate({'text-indent':artist.width()-artText.width()},2000,function(){
				artist.css('text-indent',0);
			})
		}
	}
	window.setInterval(scrollText,4000)
})(jQuery);

//here goes misc controls for non-essential
(function($){
	//nav
	var nav=$('nav.nav ul li');
	var wrapper=$('.wrapper');
	var width=$(window).width();
	var height=$(window).height();
	var sections=$('.wrapper>section');
	sections.css('width',width).css('height',height-90);
	wrapper.css('height',height-90);
	nav.each(function(index){
		$(this).click(function(){
			wrapper.css({
				'transform':'translateX(-'+width*index+'px)'});
			nav.removeClass('active').eq(index).addClass('active');
		})
	});
})(jQuery)<|endoftext|>


<commit_before>import { remote } from 'electron';

const mainWindow = remote.getCurrentWindow();
const webContents = mainWindow.webContents;
const MINI_SIZE = 310;

let oldSize;

window.wait(() => {
  if (Settings.get('miniAlwaysShowSongInfo', false)) {
    document.body.setAttribute('controls', 'controls');
  }

  window.GPM.mini.on('enable', () => {
    Emitter.fire('mini', { state: true });
    oldSize = remote.getCurrentWindow().getSize();
    mainWindow.setSize(MINI_SIZE, MINI_SIZE);
    mainWindow.setMaximumSize(MINI_SIZE, MINI_SIZE);
    webContents.executeJavaScript('document.body.setAttribute("mini", "mini")');
    remote.getCurrentWebContents().setZoomFactor(1);
    remote.getCurrentWindow().setAlwaysOnTop(Settings.get('miniAlwaysOnTop', false));
  });

  window.GPM.mini.on('disable', () => {
    Emitter.fire('mini', { state: false });
    // DEV: Set max size to be massive
    //      Same reason as specified in Electron src
    //        --> https://github.com/atom/electron/blob/master/atom/browser/native_window_views.cc
    mainWindow.setMaximumSize(99999999, 999999999);
    mainWindow.setSize(...oldSize);
    webContents.executeJavaScript('document.body.removeAttribute("mini", "mini")');
    remote.getCurrentWebContents().setZoomFactor(1);
    remote.getCurrentWindow().setAlwaysOnTop(false);
  });
});

let nextZoom;
Emitter.on('set:zoom', (event, factor) => {
  if (nextZoom) {
    clearTimeout(nextZoom);
  }
  nextZoom = setTimeout(() => {
    remote.getCurrentWebContents().setZoomFactor(factor);
  }, 5);
});

Emitter.on('miniAlwaysShowSongInfo', (event, state) => {
  if (state.state) {
    document.body.setAttribute('controls', 'controls');
  } else {
    document.body.removeAttribute('controls');
  }
});
Emitter.on('miniAlwaysOnTop', (event, state) => {
  remote.getCurrentWindow().setAlwaysOnTop(state.state);
});
<commit_msg>Fix alwaysOnTop issue<commit_after>import { remote } from 'electron';

const mainWindow = remote.getCurrentWindow();
const webContents = mainWindow.webContents;
const MINI_SIZE = 310;

let mini = false;
let oldSize;

window.wait(() => {
  if (Settings.get('miniAlwaysShowSongInfo', false)) {
    document.body.setAttribute('controls', 'controls');
  }

  window.GPM.mini.on('enable', () => {
    Emitter.fire('mini', { state: true });
    oldSize = remote.getCurrentWindow().getSize();
    mainWindow.setSize(MINI_SIZE, MINI_SIZE);
    mainWindow.setMaximumSize(MINI_SIZE, MINI_SIZE);
    webContents.executeJavaScript('document.body.setAttribute("mini", "mini")');
    remote.getCurrentWebContents().setZoomFactor(1);
    remote.getCurrentWindow().setAlwaysOnTop(Settings.get('miniAlwaysOnTop', false));
    mini = true;
  });

  window.GPM.mini.on('disable', () => {
    Emitter.fire('mini', { state: false });
    // DEV: Set max size to be massive
    //      Same reason as specified in Electron src
    //        --> https://github.com/atom/electron/blob/master/atom/browser/native_window_views.cc
    mainWindow.setMaximumSize(99999999, 999999999);
    mainWindow.setSize(...oldSize);
    webContents.executeJavaScript('document.body.removeAttribute("mini", "mini")');
    remote.getCurrentWebContents().setZoomFactor(1);
    remote.getCurrentWindow().setAlwaysOnTop(false);
    mini = false;
  });
});

let nextZoom;
Emitter.on('set:zoom', (event, factor) => {
  if (nextZoom) {
    clearTimeout(nextZoom);
  }
  nextZoom = setTimeout(() => {
    remote.getCurrentWebContents().setZoomFactor(factor);
  }, 5);
});

Emitter.on('miniAlwaysShowSongInfo', (event, state) => {
  if (state.state) {
    document.body.setAttribute('controls', 'controls');
  } else {
    document.body.removeAttribute('controls');
  }
});
Emitter.on('miniAlwaysOnTop', (event, state) => {
  if (mini) {
    remote.getCurrentWindow().setAlwaysOnTop(state.state);
  }
});
<|endoftext|>


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

export default class Who extends Component {
  constructor(props) {
    super(props);

    this.state = {
      male: "client/styles/images/male_shilouette.png",
      female: "client/styles/images/female_shilouette.png",
      kids: "client/styles/images/kids_shillouette.png",
    }

    this.addMale = this.addMale.bind(this);
    this.addFemale = this.addFemale.bind(this);
    this.addKid = this.addKid.bind(this);
  }

  addMale(){
    let who = {

    }
  }

  render() {
    return(

Who is going?

               this.setState({ male: "client/styles/images/male_shilouette_black.png" })} onMouseOut={(e) => this.setState({ male: "client/styles/images/male_shilouette.png" })} onClick={this.addMale}/>

               this.setState({ female: "client/styles/images/female_shilouette_black copy.png" })} onMouseOut={(e) => this.setState({ female: "client/styles/images/female_shilouette.png" })} onClick={this.addFemale}/>

               this.setState({ kids: "client/styles/images/kids_shillouette_black copy.png" })} onMouseOut={(e) => this.setState({ kids: "client/styles/images/kids_shillouette.png" })} onClicke={this.addKid}/>

              1

              1

              3

    )
  }
}
<commit_msg>added _getComponentState() to Who Component<commit_after>import React, { Component } from 'react';
import ClientStore from '../../stores/ClientStore.js'
import ClientActions from '../../actions/ClientActions.js'

function _getComponentState() {
  return { client: ClientStore.getClient() }
}

export default class Who extends Component {
  constructor(props) {
    super(props);

    this.state = {
      male: "client/styles/images/male_shilouette.png",
      female: "client/styles/images/female_shilouette.png",
      kids: "client/styles/images/kids_shillouette.png",
    }

    this.addMale = this.addMale.bind(this);
    this.addFemale = this.addFemale.bind(this);
    this.addKid = this.addKid.bind(this);
  }

  addMale(){
    let who = {

    }
  }

  render() {
    return(

Who is going?

               this.setState({ male: "client/styles/images/male_shilouette_black.png" })} onMouseOut={(e) => this.setState({ male: "client/styles/images/male_shilouette.png" })} onClick={this.addMale}/>

               this.setState({ female: "client/styles/images/female_shilouette_black copy.png" })} onMouseOut={(e) => this.setState({ female: "client/styles/images/female_shilouette.png" })} onClick={this.addFemale}/>

               this.setState({ kids: "client/styles/images/kids_shillouette_black copy.png" })} onMouseOut={(e) => this.setState({ kids: "client/styles/images/kids_shillouette.png" })} onClicke={this.addKid}/>

              1

              1

              3

    )
  }
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name            rZhihu
// @author          nonoroazoro
// @description     为知乎首页添加类似 Google Reader 的快捷键。
// @description:en  Adding Google-like keyboard shortcuts for Zhihu homepage.
// @homepageURL     https://github.com/nonoroazoro/firefox/tree/master/greasemonkey/rZhihu
// @namespace       https://greasyfork.org/zh-CN/scripts/30036-rzhihu
// @grant           none
// @version         1.1.6
// @run-at          document-end
// @include         https://www.zhihu.com/
// @include         https://www.zhihu.com/#*
// ==/UserScript==

let currentIndex = 0;
let inProgress = false;
let maxIndex = -1;
let currentTopic = null;
let stories = null;
let storyContainer = null;
const ignoreList = [
    {
        nodeName: "DIV",
        className: "public-DraftEditor-content"
    },
    {
        nodeName: "INPUT"
    },
    {
        nodeName: "TEXTAREA"
    }
];

function start()
{
    storyContainer = document.getElementById("TopstoryContent");
    observe(storyContainer, update);
    storyContainer.addEventListener("click", _handleClick);
    document.body.addEventListener("keydown", _handleKeydown);
}

function _handleClick(e)
{
    // highlight the clicked story.
    const index = _getIndexOfStory(_getAncestor(e.target, "TopstoryItem"));
    if (index !== -1)
    {
        _flip(index, false);
    }
}

function _handleKeydown(e)
{
    if (!stories || _isIgnored(e.target) || e.altKey || e.shiftKey || e.ctrlKey || e.metaKey)
    {
        return;
    }

    if (e.keyCode === 74)
    {
        // press "j"
        _next();
    }
    else if (e.keyCode === 75)
    {
        // press "k"
        _prev();
    }
    else if (e.keyCode === 79 || e.keyCode === 13)
    {
        // press "o/enter"
        _toggle();
    }
    else if (e.keyCode === 67)
    {
        // press "c"
        _toggleComment();
    }
    else if (e.keyCode === 85)
    {
        // press "u"
        _unlike();
    }
    else if (e.keyCode === 86)
    {
        // press "v"
        _openInNewTab();
    }
}

/**
 * check if key press should be ignored.
 */
function _isIgnored(target)
{
    let ignored = false;
    const nodeName = target.nodeName;
    const className = target.className;
    for (const item of ignoreList)
    {
        ignored = nodeName === item.nodeName;
        if (item.className)
        {
            ignored = ignored && (className.indexOf(item.className) !== -1);
        }

        if (ignored)
        {
            break;
        }
    }
    return ignored;
}

/**
 * flip to next story.
 */
function _next()
{
    _flip(currentIndex + 1);
}

/**
 * flip to previous story.
 */
function _prev()
{
    _flip(currentIndex - 1);
}

/**
 * flip to story.
 *
 * @param {number} index
 * @param {boolean} [ensureVisible=true]
 */
function _flip(index, ensureVisible = true)
{
    if (!inProgress)
    {
        inProgress = true;

        let targetIndex = index;
        if (targetIndex < 0)
        {
            targetIndex = 0;
        }

        if (targetIndex > maxIndex)
        {
            targetIndex = maxIndex;
        }

        const target = stories[targetIndex];
        if (target)
        {
            if (targetIndex !== currentIndex)
            {
                stories[currentIndex].style.border = "1px solid #E7EAF1";
            }
            currentIndex = targetIndex;
            target.style.border = "1px solid #A4D2F8";

            if (ensureVisible)
            {
                window.scrollTo(0, target.offsetTop);
            }
        }

        inProgress = false;
    }
}

/**
 * toggle story expand/collapse.
 */
function _toggle()
{
    const expand = _query(".is-collapsed .RichContent-inner");
    if (expand)
    {
        expand.click();
    }
    else
    {
        const collapse = _query(".ContentItem-actions > button:last-child");
        if (collapse)
        {
            collapse.click();
        }
    }
}

/**
 * toggle comment expand/collapse.
 */
function _toggleComment()
{
    const close = document.querySelector(".Modal.Modal--fullPage > button");
    if (close)
    {
        // should close the dialog when comment dialog is shown.
        close.click();
    }
    else
    {
        // otherwise expand/collapse the comment.
        const comment = _query(".ContentItem-actions > button:nth-child(2)");
        if (comment)
        {
            comment.click();

            // resume state
            _flip(currentIndex);
        }
    }
}

/**
 * toggle story unlike.
 */
function _unlike()
{
    let element = _query("button:first-child");
    if (element)
    {
        if (element.textContent === "广告")
        {
            element.click();
            element = document.querySelector(".Menu > button:first-child");
        }

        if (element)
        {
            element.click();
            if (element.textContent !== "撤销")
            {
                // auto-next
                _next();
            }
        }
    }
}

/**
 * open current story in a new tab.
 */
function _openInNewTab()
{
    // 1. answer;
    // 2. empty answer;
    // 3. advertisement.
    const element = _query(".ContentItem-title a, .QuestionItem-title > a, .Advert--card > a");
    if (element)
    {
        element.click();
    }
}

/**
 * find the specified element in current story.
 *
 * @param {string} selector
 * @returns {Element}
 */
function _query(selector)
{
    if (selector)
    {
        const story = stories[currentIndex];
        if (story)
        {
            return story.querySelector(selector);
        }
    }
    return null;
}

/**
 * get ancestor of the element with specified class name.
 *
 * @param {Element} element
 * @param {string} className
 * @returns {Element}
 */
function _getAncestor(element, className)
{
    if (element && className)
    {
        let ancestor = element;
        while (ancestor)
        {
            if (ancestor.className.trim().split(/\W+/).indexOf(className) !== -1)
            {
                return ancestor;
            }
            else
            {
                ancestor = ancestor.parentNode;
            }
        }
    }
    return null;
}

/**
 * Gets the index of the story.
 *
 * @param {Element} story
 * @returns {number}
 */
function _getIndexOfStory(story)
{
    if (story && stories)
    {
        return Array.prototype.indexOf.call(stories, story);
    }
    return -1;
}

/**
 * Gets all the stories.
 */
// function _getStories()
// {
//     return document.querySelectorAll("#TopstoryContent .Card.TopstoryItem");
// }

/**
 * Update after the original zhihu story list is loaded.
 */
function update(mutations)
{
    if (mutations.length > 0)
    {
        const topicContainer = storyContainer.children[0];
        if (topicContainer)
        {
            if (topicContainer.className !== currentTopic)
            {
                // Switch topic and reset index.
                currentIndex = 0;
                currentTopic = topicContainer.className;
            }

            const subContainer = topicContainer.children[0];
            if (subContainer)
            {
                maxIndex = subContainer.children.length - 1;
                stories = subContainer.querySelectorAll(".Card.TopstoryItem");
                return;
            }
        }

        // Reset.
        currentIndex = 0;
        maxIndex = -1;
        stories = [];
    }
}

function observe(element, callback)
{
    if (element && typeof callback === "function")
    {
        (new window.MutationObserver(debounce(callback))).observe(element, {
            childList: true,
            subtree: true
        });
    }
}

function debounce(callback, delay = 500)
{
    let timer = null;
    return (...args) =>
    {
        const context = this;
        window.clearTimeout(timer);
        timer = window.setTimeout(() => callback.apply(context, args), delay);
    };
}

/**
 * check if run-at is working correctly.
 */
function isRunAtAvailabe()
{
    let available = false;
    if (typeof GM_info === "undefined")
    {
        available = true;
    }
    else
    {
        available = GM_info.scriptHandler === "Tampermonkey";
    }
    return available;
}

if (isRunAtAvailabe())
{
    start();
}
else
{
    document.addEventListener("DOMContentLoaded", () => start());
}
<commit_msg>fix error<commit_after>// ==UserScript==
// @name            rZhihu
// @author          nonoroazoro
// @description     为知乎首页添加类似 Google Reader 的快捷键。
// @description:en  Adding Google-like keyboard shortcuts for Zhihu homepage.
// @homepageURL     https://github.com/nonoroazoro/firefox/tree/master/greasemonkey/rZhihu
// @namespace       https://greasyfork.org/zh-CN/scripts/30036-rzhihu
// @grant           none
// @version         1.1.6
// @run-at          document-end
// @include         https://www.zhihu.com/
// @include         https://www.zhihu.com/#*
// ==/UserScript==

let currentIndex = -1;
let inProgress = false;
let maxIndex = -1;
let currentTopic = null;
let currentTopicStrip = null;
let stories = null;
let storyContainer = null;
const ignoreList = [
    {
        nodeName: "DIV",
        className: "public-DraftEditor-content"
    },
    {
        nodeName: "INPUT"
    },
    {
        nodeName: "TEXTAREA"
    }
];

function start()
{
    initCurrentTopicStrip();
    storyContainer = document.getElementById("TopstoryContent");
    observe(storyContainer, update);
    storyContainer.addEventListener("click", _handleClick);
    document.body.addEventListener("keydown", _handleKeydown);
}

function initCurrentTopicStrip()
{
    currentTopicStrip = document.createElement("div");
    currentTopicStrip.style.position = "absolute";
    currentTopicStrip.style.right = "0";
    currentTopicStrip.style.top = "0";
    currentTopicStrip.style.bottom = "0";
    currentTopicStrip.style.width = "1px";
    currentTopicStrip.style.backgroundColor = "#6cb8ff";
}

function _handleClick(e)
{
    // highlight the clicked story.
    const index = _getIndexOfStory(_getAncestor(e.target, "TopstoryItem"));
    if (index !== -1)
    {
        _flip(index, false);
    }
}

function _handleKeydown(e)
{
    if (!stories || _isIgnored(e.target) || e.altKey || e.shiftKey || e.ctrlKey || e.metaKey)
    {
        return;
    }

    if (e.keyCode === 74)
    {
        // press "j"
        _next();
    }
    else if (e.keyCode === 75)
    {
        // press "k"
        _prev();
    }
    else if (e.keyCode === 79 || e.keyCode === 13)
    {
        // press "o/enter"
        _toggle();
    }
    else if (e.keyCode === 67)
    {
        // press "c"
        _toggleComment();
    }
    else if (e.keyCode === 85)
    {
        // press "u"
        _unlike();
    }
    else if (e.keyCode === 86)
    {
        // press "v"
        _openInNewTab();
    }
}

/**
 * check if key press should be ignored.
 */
function _isIgnored(target)
{
    let ignored = false;
    const nodeName = target.nodeName;
    const className = target.className;
    for (const item of ignoreList)
    {
        ignored = nodeName === item.nodeName;
        if (item.className)
        {
            ignored = ignored && (className.indexOf(item.className) !== -1);
        }

        if (ignored)
        {
            break;
        }
    }
    return ignored;
}

/**
 * Flip to next story.
 */
function _next()
{
    _flip(currentIndex + 1);
}

/**
 * Flip to previous story.
 */
function _prev()
{
    _flip(currentIndex - 1);
}

/**
 * Flip to story.
 *
 * @param {number} index
 * @param {boolean} [ensureVisible=true]
 */
function _flip(index, ensureVisible = true)
{
    if (!inProgress)
    {
        inProgress = true;

        let targetIndex = index;
        if (targetIndex < 0)
        {
            targetIndex = 0;
        }

        if (targetIndex > maxIndex)
        {
            targetIndex = maxIndex;
        }

        const target = stories[targetIndex];
        if (target)
        {
            currentIndex = targetIndex;
            // Show strip.
            stories[currentIndex].appendChild(currentTopicStrip);
            if (ensureVisible)
            {
                window.scrollTo({
                    left: 0,
                    top: target.offsetTop - target.offsetHeight,
                    behavior: "smooth"
                });
            }
        }

        inProgress = false;
    }
}

/**
 * Toggle story expand/collapse.
 */
function _toggle()
{
    const expand = _query(".is-collapsed .RichContent-inner");
    if (expand)
    {
        expand.click();
    }
    else
    {
        const collapse = _query(".ContentItem-actions > button:last-child");
        if (collapse)
        {
            collapse.click();
        }
    }
}

/**
 * Toggle comment expand/collapse.
 */
function _toggleComment()
{
    const close = document.querySelector(".Modal.Modal--fullPage > button");
    if (close)
    {
        // should close the dialog when comment dialog is shown.
        close.click();
    }
    else
    {
        // otherwise expand/collapse the comment.
        const comment = _query(".ContentItem-actions > button:nth-child(2)");
        if (comment)
        {
            comment.click();

            // resume state
            _flip(currentIndex);
        }
    }
}

/**
 * Toggle story unlike.
 */
function _unlike()
{
    let element = _query("button:first-child");
    if (element)
    {
        if (element.textContent === "广告")
        {
            element.click();
            element = document.querySelector(".Menu > button:first-child");
        }

        if (element)
        {
            element.click();
            if (element.textContent !== "撤销")
            {
                // auto-next
                _next();
            }
        }
    }
}

/**
 * Open current story in a new tab.
 */
function _openInNewTab()
{
    // 1. answer;
    // 2. empty answer;
    // 3. advertisement.
    const element = _query(".ContentItem-title a, .QuestionItem-title > a, .Advert--card > a");
    if (element)
    {
        element.click();
    }
}

/**
 * Finds the specified element in current story.
 *
 * @param {string} selector
 * @returns {Element}
 */
function _query(selector)
{
    if (selector)
    {
        const story = stories[currentIndex];
        if (story)
        {
            return story.querySelector(selector);
        }
    }
    return null;
}

/**
 * Gets the ancestor of the element with specified class name.
 *
 * @param {Element} element
 * @param {string} className
 * @returns {Element}
 */
function _getAncestor(element, className)
{
    if (element && className)
    {
        let ancestor = element;
        while (ancestor)
        {
            if (ancestor.className.trim().split(/\W+/).indexOf(className) !== -1)
            {
                return ancestor;
            }
            else
            {
                ancestor = ancestor.parentNode;
            }
        }
    }
    return null;
}

/**
 * Gets the index of the story.
 *
 * @param {Element} story
 * @returns {number}
 */
function _getIndexOfStory(story)
{
    if (story && stories)
    {
        return Array.prototype.indexOf.call(stories, story);
    }
    return -1;
}

/**
 * Updates after the story list is loaded.
 */
function update(mutations)
{
    if (mutations.length > 0)
    {
        const topicContainer = storyContainer.children[0];
        if (topicContainer)
        {
            if (topicContainer.className !== currentTopic)
            {
                // Switch topic and reset index.
                currentIndex = -1;
                currentTopic = topicContainer.className;
            }

            const subContainer = topicContainer.children[0];
            if (subContainer)
            {
                // Ignore adverts.
                stories = subContainer.querySelectorAll(".Card.TopstoryItem:not(.TopstoryItem--advertCard)");
                maxIndex = stories.length - 1;
                return;
            }
        }

        // Reset.
        currentIndex = -1;
        maxIndex = -1;
        stories = [];
    }
}

function observe(element, callback)
{
    if (element && typeof callback === "function")
    {
        (new window.MutationObserver(callback)).observe(element, {
            childList: true,
            subtree: true
        });
    }
}

function debounce(callback, delay = 500)
{
    let timer = null;
    return (...args) =>
    {
        const context = this;
        window.clearTimeout(timer);
        timer = window.setTimeout(() => callback.apply(context, args), delay);
    };
}

/**
 * Check if run-at is working correctly.
 */
function isRunAtAvailabe()
{
    let available = false;
    if (typeof GM_info === "undefined")
    {
        available = true;
    }
    else
    {
        available = GM_info.scriptHandler === "Tampermonkey";
    }
    return available;
}

if (isRunAtAvailabe())
{
    start();
}
else
{
    document.addEventListener("DOMContentLoaded", () => start());
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name         nHentai Downloader
// @namespace    http://devs.forumvi.com
// @description  Download manga on nHentai.net
// @version      1.6.2
// @icon         http://i.imgur.com/FAsQ4vZ.png
// @author       Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        http://nhentai.net/g/*
// @match        https://nhentai.net/g/*
// @require      https://code.jquery.com/jquery-3.3.1.min.js
// @require      https://unpkg.com/jszip@3.1.5/dist/jszip.min.js
// @require      https://unpkg.com/file-saver@1.3.8/FileSaver.min.js
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?v=a834d46
// @noframes
// @connect      self
// @supportURL   https://github.com/lelinhtinh/Userscript/issues
// @run-at       document-idle
// @grant        GM.xmlHttpRequest
// ==/UserScript==

jQuery(function ($) {
    'use strict';

    /**
     * Output extension
     * @type {String} zip
     *                cbz
     *
     * Tips: Convert .zip to .cbz
     * Windows
     * $ ren *.zip *.cbz
     * Linux
     * $ rename 's/\.zip$/\.cbz/' *.zip
     */
    var outputExt = 'cbz'; // or 'zip'

    /**
     * Multithreading
     * @type {Number} [1 -> 32]
     */
    var threading = 8;

    /**
     * Logging
     * @type {Boolean}
     */
    var debug = false;

    function end() {
        $win.off('beforeunload');

        if (debug) console.timeEnd('nHentai');
    }

    function getInfo() {
        var $info = $('#info'),
            $h1 = $info.find('h1'),
            $h2 = $info.find('h2'),
            $tags = $('#tags').clone(),
            info = '';

        $tags.find('.tag-container.hidden').remove();
        $tags.find('.count').remove();
        $tags.find('.tags a').replaceWith(function () {
            return this.textContent.trim() + ', ';
        });
        $tags.find('.tags').replaceWith(function () {
            return this.textContent.trim().slice(0, -1);
        });
        $tags.find('.tag-container').replaceWith(function () {
            return this.textContent.trim().replace(/[\n\s\t]{2,}/, ' ');
        });

        if ($h1.length) info += $h1.text().trim() + '\r\n';
        if ($h2.length) info += $h2.text().trim() + '\r\n';
        if ($tags.length) info += '\r\n' + $tags.text().trim().replace(/[\n\s\t]{2,}/g, '\r\n');

        if (debug) console.log(info);
        return info;
    }

    function genZip() {
        zip.file('info.txt', getInfo());

        zip.generateAsync({
            type: 'blob'
        }).then(function (blob) {
            var zipName = tit.split(' » ')[0]
                .replace(/\s/g, '_') + '.' + comicId + '.' + outputExt;

            if (prevZip) window.URL.revokeObjectURL(prevZip);
            prevZip = blob;

            $download.html(' Complete')
                .css('backgroundColor', 'green')
                .attr({
                    href: window.URL.createObjectURL(prevZip),
                    download: zipName
                });

            saveAs(blob, zipName);

            doc.title = '[⇓] ' + tit;
            if (debug) console.log('COMPLETE');
            end();
        }, function (reason) {
            $download.html(' Fail')
                .css('backgroundColor', 'red');

            doc.title = '[x] ' + tit;
            if (debug) console.error(reason, 'ERROR');
            end();
        });
    }

    function dlImg(url, success, error) {
        var filename = url.replace(/.*\//g, '');
        filename = filename.split('.');
        filename = ('0000' + filename[0]).slice(-4) + '.' + filename[1];

        if (debug) console.log(filename, 'progress');
        GM.xmlHttpRequest({
            method: 'GET',
            url: url,
            responseType: 'arraybuffer',
            onload: function (response) {
                final++;
                success(response, filename);
            },
            onerror: function (err) {
                final++;
                error(err, filename);
            }
        });
    }

    function next() {
        $download.html(' ' + final + '/' + total);
        if (debug) console.log(final, current);

        if (final < current) return;
        final < total ? addZip() : genZip();
    }

    function addZip() {
        var max = current + threading;
        if (max > total) max = total;

        for (current; current < max; current++) {
            var url = images[current];

            if (debug) console.log(url, 'download');
            dlImg(url, function (response, filename) {
                zip.file(filename, response.response);

                if (debug) console.log(filename, 'success');
                next();
            }, function (err, filename) {
                zip.file(filename + '_' + comicId + '_error.gif', 'R0lGODdhBQAFAIACAAAAAP/eACwAAAAABQAFAAACCIwPkWerClIBADs=', {
                    base64: true
                });
                $download.css('backgroundColor', '#FF7F7F');

                if (debug) console.log(filename, 'error');
                next();
            });
        }
        if (debug) console.log(current, 'current');
    }

    var zip = new JSZip(),
        prevZip = false,
        current = 0,
        final = 0,
        total = 0,
        images = [],
        $images = $('#thumbnail-container img'),
        $download = $('#download-torrent, #download'),
        doc = document,
        tit = doc.title,
        $win = $(window),
        comicId = location.pathname.match(/\d+/)[0];

    if (!$images.length || !$download.length) return;

    window.URL = window.URL || window.webkitURL;

    $download.css('backgroundColor', 'cornflowerblue')
        .one('click', function (e) {
            e.preventDefault();
            if (debug) console.time('nHentai');

            if (threading < 1) threading = 1;
            if (threading > 32) threading = 32;

            $win.on('beforeunload', function () {
                return 'Progress is running...';
            });

            $download.attr('href', '#download')
                .html(' Waiting...')
                .css('backgroundColor', 'orange');

            $images.each(function (i, v) {
                var src = $(v).data('src');

                if (/^\/\/t\./i.test(src)) src = location.protocol + src;
                src = src.replace('t.n', 'i.n')
                    .replace(/\/(\d+)t\./, '/$1.');

                images[i] = src;
            });

            total = images.length;
            addZip();
        });

});
<commit_msg>Update nHentai_downloader.user.js<commit_after>// ==UserScript==
// @name         nHentai Downloader
// @namespace    http://devs.forumvi.com
// @description  Download manga on nHentai.net
// @version      1.6.3
// @icon         http://i.imgur.com/FAsQ4vZ.png
// @author       Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        http://nhentai.net/g/*
// @match        https://nhentai.net/g/*
// @require      https://code.jquery.com/jquery-3.3.1.min.js
// @require      https://unpkg.com/jszip@3.1.5/dist/jszip.min.js
// @require      https://unpkg.com/file-saver@1.3.8/FileSaver.min.js
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?v=a834d46
// @noframes
// @connect      self
// @supportURL   https://github.com/lelinhtinh/Userscript/issues
// @run-at       document-idle
// @grant        GM.xmlHttpRequest
// @grant        GM_xmlhttpRequest
// ==/UserScript==

jQuery(function ($) {
    'use strict';

    /**
     * Output extension
     * @type {String} zip
     *                cbz
     *
     * Tips: Convert .zip to .cbz
     * Windows
     * $ ren *.zip *.cbz
     * Linux
     * $ rename 's/\.zip$/\.cbz/' *.zip
     */
    var outputExt = 'cbz'; // or 'zip'

    /**
     * Multithreading
     * @type {Number} [1 -> 32]
     */
    var threading = 8;

    /**
     * Logging
     * @type {Boolean}
     */
    var debug = false;

    function end() {
        $win.off('beforeunload');

        if (debug) console.timeEnd('nHentai');
    }

    function getInfo() {
        var $info = $('#info'),
            $h1 = $info.find('h1'),
            $h2 = $info.find('h2'),
            $tags = $('#tags').clone(),
            info = '';

        $tags.find('.tag-container.hidden').remove();
        $tags.find('.count').remove();
        $tags.find('.tags a').replaceWith(function () {
            return this.textContent.trim() + ', ';
        });
        $tags.find('.tags').replaceWith(function () {
            return this.textContent.trim().slice(0, -1);
        });
        $tags.find('.tag-container').replaceWith(function () {
            return this.textContent.trim().replace(/[\n\s\t]{2,}/, ' ');
        });

        if ($h1.length) info += $h1.text().trim() + '\r\n';
        if ($h2.length) info += $h2.text().trim() + '\r\n';
        if ($tags.length) info += '\r\n' + $tags.text().trim().replace(/[\n\s\t]{2,}/g, '\r\n');

        if (debug) console.log(info);
        return info;
    }

    function genZip() {
        zip.file('info.txt', getInfo());

        zip.generateAsync({
            type: 'blob'
        }).then(function (blob) {
            var zipName = tit.split(' » ')[0]
                .replace(/\s/g, '_') + '.' + comicId + '.' + outputExt;

            if (prevZip) window.URL.revokeObjectURL(prevZip);
            prevZip = blob;

            $download.html(' Complete')
                .css('backgroundColor', 'green')
                .attr({
                    href: window.URL.createObjectURL(prevZip),
                    download: zipName
                });

            saveAs(blob, zipName);

            doc.title = '[⇓] ' + tit;
            if (debug) console.log('COMPLETE');
            end();
        }, function (reason) {
            $download.html(' Fail')
                .css('backgroundColor', 'red');

            doc.title = '[x] ' + tit;
            if (debug) console.error(reason, 'ERROR');
            end();
        });
    }

    function dlImg(url, success, error) {
        var filename = url.replace(/.*\//g, '');
        filename = filename.split('.');
        filename = ('0000' + filename[0]).slice(-4) + '.' + filename[1];

        if (debug) console.log(filename, 'progress');
        GM.xmlHttpRequest({
            method: 'GET',
            url: url,
            responseType: 'arraybuffer',
            onload: function (response) {
                final++;
                success(response, filename);
            },
            onerror: function (err) {
                final++;
                error(err, filename);
            }
        });
    }

    function next() {
        $download.html(' ' + final + '/' + total);
        if (debug) console.log(final, current);

        if (final < current) return;
        final < total ? addZip() : genZip();
    }

    function addZip() {
        var max = current + threading;
        if (max > total) max = total;

        for (current; current < max; current++) {
            var url = images[current];

            if (debug) console.log(url, 'download');
            dlImg(url, function (response, filename) {
                zip.file(filename, response.response);

                if (debug) console.log(filename, 'success');
                next();
            }, function (err, filename) {
                zip.file(filename + '_' + comicId + '_error.gif', 'R0lGODdhBQAFAIACAAAAAP/eACwAAAAABQAFAAACCIwPkWerClIBADs=', {
                    base64: true
                });
                $download.css('backgroundColor', '#FF7F7F');

                if (debug) console.log(filename, 'error');
                next();
            });
        }
        if (debug) console.log(current, 'current');
    }

    var zip = new JSZip(),
        prevZip = false,
        current = 0,
        final = 0,
        total = 0,
        images = [],
        $images = $('#thumbnail-container img'),
        $download = $('#download-torrent, #download'),
        doc = document,
        tit = doc.title,
        $win = $(window),
        comicId = location.pathname.match(/\d+/)[0];

    if (!$images.length || !$download.length) return;

    window.URL = window.URL || window.webkitURL;

    $download.css('backgroundColor', 'cornflowerblue')
        .one('click', function (e) {
            e.preventDefault();
            if (debug) console.time('nHentai');

            if (threading < 1) threading = 1;
            if (threading > 32) threading = 32;

            $win.on('beforeunload', function () {
                return 'Progress is running...';
            });

            $download.attr('href', '#download')
                .html(' Waiting...')
                .css('backgroundColor', 'orange');

            $images.each(function (i, v) {
                var src = $(v).data('src');

                if (/^\/\/t\./i.test(src)) src = location.protocol + src;
                src = src.replace('t.n', 'i.n')
                    .replace(/\/(\d+)t\./, '/$1.');

                images[i] = src;
            });

            total = images.length;
            addZip();
        });

});
<|endoftext|>


<commit_before>exports.names = ['.reward', '!reward'];
exports.hidden = false;
exports.enabled = true;
exports.matchStart = true;
var tacos = ["a blunt :snoop:", "a leather mask :forsenddk:", "a trimmed mithril armor"];
var cookies = ["a chocolate chip cookie", "a sugar cookie", "an oatmeal raisin cookie", "a 'special' brownie", "an animal cracker", "a scooby snack", "a blueberry muffin", "a cupcake", "Strawberry Sunday", "Chocolate Chip Icecream Cone", "Cookie Dough Triple Scoop ", "Mint Chocolate Chip Icecream Cone", "Chocolate Icecream Sunday", "Banana Split with Whipped Cream", "Vanilla Icecream Cone with Sprinkles ", "Bubblegum Flavored Popcicle", "en bröllopstårta", "kladdkaka"];
exports.cd_all = 15;
exports.cd_user = 30;
exports.cd_manager = 10;
exports.handler = function (data) {
    var params = _.rest(data.message.split(' '), 1);
    var username = '';
    if (params.length < 1) {
        var users = bot.getUsers();
        var randomUserIndex = _.random(1, users.length);
        username = '@' + users[(randomUserIndex - 1)].username;
    } else {
        console.log(params.join(' '));
        username_uf = params.join(' ').trim();
        username = username_uf.replace('@', '');
        console.log(username);
        var user = _.findWhere(bot.getUsers(), {username: username});
        if (user) {
            username = '@' + user.username;
        } else {
            chatMessage(username + ' is not here :biblethump:');
            return;
        }
    }

    var random_sentence = _.random(0, 10);
    var random_cookie = _.random(0, cookies.length - 1);
    var random_taco = _.random(0, tacos.length - 1);
    if (random_sentence <= 9) {
        chatMessage(username + ', ' + data.from.username + ' has rewarded you with ' + cookies[random_cookie] + '. Enjoy! :minik:');
    } else {
        chatMessage(username + ', ' + data.from.username + ' has rewarded you with ' + tacos[random_taco] + '. Enjoy! :minik:');
    }
};
<commit_msg>Reorganized the .reward texts to occupy one row each, to make for simpler editing.<commit_after>var tacos = [ /* Rare (1/10) */
    "a blunt :snoop:",
    "a leather mask :forsenddk:",
    "a trimmed mithril armor"
    ];
var cookies = [ /* Common (9/10) */
    "a chocolate chip cookie",
    "a sugar cookie",
    "an oatmeal raisin cookie :dansgame:",
    "a 'special' brownie",
    "an animal cracker",
    "a scooby snack",
    "a blueberry muffin",
    "a cupcake",
    "Strawberry Sunday",
    "Chocolate Chip Icecream Cone",
    "Cookie Dough Triple Scoop",
    "Mint Chocolate Chip Icecream Cone",
    "Chocolate Icecream Sunday",
    "Banana Split with Whipped Cream",
    "Vanilla Icecream Cone with Sprinkles",
    "Bubblegum Flavored Popcicle",
    "en bröllopstårta",
    "kladdkaka"
    ];

exports.names = ['reward'];
exports.hidden = false;
exports.enabled = true;
exports.matchStart = true;
exports.cd_all = 15;
exports.cd_user = 30;
exports.cd_manager = 10;
exports.handler = function (data) {
    var params = _.rest(data.message.split(' '), 1);
    var username = '';
    if (params.length < 1) {
        var users = bot.getUsers();
        var randomUserIndex = _.random(1, users.length);
        username = '@' + users[(randomUserIndex - 1)].username;
    } else {
        console.log(params.join(' '));
        username_uf = params.join(' ').trim();
        username = username_uf.replace('@', '');
        console.log(username);
        var user = _.findWhere(bot.getUsers(), {username: username});
        if (user) {
            username = '@' + user.username;
        } else {
            chatMessage(username + ' is not here :biblethump:');
            return;
        }
    }

    var random_sentence = _.random(0, 10);
    var random_cookie = _.random(0, cookies.length - 1);
    var random_taco = _.random(0, tacos.length - 1);
    if (random_sentence <= 9) {
        chatMessage(username + ', ' + data.from.username + ' has rewarded you with ' + cookies[random_cookie] + '. Enjoy! :minik:');
    } else {
        chatMessage(username + ', ' + data.from.username + ' has rewarded you with ' + tacos[random_taco] + '. Enjoy! :minik:');
    }
};
<|endoftext|>