<commit_before>var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var mongoose = require('mongoose');
var Iconv  = require('iconv').Iconv;
var kue = require('kue');
var jobs = kue.createQueue();
var parseString = require('xml2js').parseString;

var ObjectId = mongoose.Types.ObjectId;
var Property = require('../models/property.js');
var PP = require('../controllers/property.js');
exports.test = function(req, res) {
  var iconv = new Iconv('UTF-8', 'WINDOWS-874');
  var iconv2 = new Iconv('WINDOWS-874', 'UTF-8');
  var test = iconv.convert('ทดสอบ');
  var test2 = iconv2.convert(test);
  res.send(200, {test1:test.toString(), test2:test2.toString()});
};

exports.getinfo = function(req, res){

            if(req.query.id!=null)
            {
            Property.findOne({_id: req.query.id}).exec(function(err,result){res.send(result);});
              console.log("search for ID"+req.query.id);

}

};
exports.zip = function(req,res){
  var data;
fs.readFile('/home/express/apartmentjs/app/zipcodes.xml', function (err, html) {
if (err){
console.log(err);
if(err.errno==34){
res.end('No such file exist');
}

}else{

 parseString(html, function (err, result) {
    data=result;
    for(var i = 0 ; i< result.test_server.zipcodes.length;i++)
    console.log(result.test_server.zipcodes[i].zipcode[0]);
});
}}

);
//console.log(data.test_server.zipcodes[0].zipcode[0]);
//var conn = mongoose.connection();

}

exports.getpage=function(req,res)
{

            if(req.query.page!=null)
            {
              var pagenum = req.query.page*15;
            Property.find().skip(pagenum).limit(15).exec(function(err,result){res.send(result);});
            }
}

exports.bot = function (req, res) {
  var url = 'http://www.thaihometown.com/apartment/17818';

  request({url: url, encoding:null}, function (err, response, html) {
    //console.log(html);

    var iconv = new Iconv('WINDOWS-874', 'UTF-8//TRANSLIT//IGNORE');

    var body = iconv.convert(new Buffer(html));

    var $ = cheerio.load(body.toString('utf-8'));

    $('.namedesw9').filter(function() {
      var data = $('h1', this);
      res.send( data.html());
    });

    //res.send(html);
  });
};

exports.scrape = function(req, res) {
  //res.charset = 'UTF-8';

  var url = 'http://www.thaihometown.com/apartment/130450';

  var iconv = new Iconv('WINDOWS-874', 'UTF-8//TRANSLIT//IGNORE');

  // The structure of our request call
    // The first parameter is our URL
    // The callback function takes 3 parameters, an error, response status code and the html

  request({url:url, encoding:null}, function (error, response, html){

    // Convert
    var body = iconv.convert(new Buffer(html));
    //console.log(body.toString());
    //var html = iconv.convert(body);

    // First we'll check to make sure no errors occurred when making the request

    if (!error){
      // Next, we'll utilize the cheerio library on the returned html which will essentially give us jQuery functionality

      //var $ = cheerio.load(html);
      var $ = cheerio.load(body.toString('utf-8'));

      // Finally, we'll define the variables we're going to capture

      var newId = new ObjectId();
      var propertyData = {};

      // Iconv
      //var iconv = new Iconv('windows-874', 'utf-8');

      // Get Id
      var regex = /^http:\/\/www.thaihometown.com\/apartment\/(.*)$/g;
      var result = regex.exec(url);
      if (result && result.length > 0) {
        console.log(result[1]);
        var propertyId = result[1];
        propertyData.propertyId = propertyId;
      };

      // Get Title
      $('.namedesw9').filter(function (){
        var data = $('h1', this);
        var buf = iconv.convert(data.text());
        propertyData.title = data.text();

      });

      $('.headtitle2').filter(function () {
        var data = $('h2', this);
        propertyData.detail = data.text();
      });

      $('#divImg').filter(function() {
        var images = $('img', this);
        console.log(data);
        //var images = data.children()
        propertyData.images = [];
        for (var i = images.length - 1; i >= 3; i--) {
         if( images[i]==null)
          {console.log("img undefined");}
        else{
          propertyData.images.push(images[i].parent.attribs.href);
        }
        };
      });

      var linkPrice = $('.linkprice');
      if (linkPrice.length > 0) {
        linkPrice.filter(function() {
          var str = $(this).text();

          // Kinda sucks but it works!
          var regex = /(.*) ([0-9\.\,]+) (.*)\/(.*)/g;
          var result = regex.exec(str);
          if (result && result.length > 0) {

            var rent = parseFloat(result[2].replace(',', ''));
            propertyData.rent = rent;
          };
        })
      };

      if ($('#GMap').length === 0) {
        console.log(propertyData);
        Property.findOne({propertyId: propertyData.propertyId}, function (err, property) {
          if (err) {
            res.send(200, err);
          };

          if (property) {
            Property.findOneAndUpdate({_id: property._id}, propertyData, function (err, property) {
              if (err) {
                res.send(200, err);
                return;
              }
              res.send(200, propertyData);
              return;

            });
          } else {
            propertyData._id = newId;
            var newProperty = new Property(propertyData);
            newProperty.save(function (err) {
              if (err) {
                res.send(200, err);
                return;
              };
              res.send(200, propertyData);
              return;
            });
          };
        });
      } else {

        $('#GMap').filter(function() {
          var data = $(this);

          //console.log(data.attr('src'));
          request(data.attr('src'), function (error, response, html){
            if (!error) {
              //var $ = cheerio.load(html);
              var regex = /google.maps.LatLng\((.*),(.*)\)/g;
              //var regex = '/google/g';
              //var string = $.html();
              //var result = html.match(/google.maps.LatLng\((.*),(.*)\)/gm);
              var result = regex.exec(html);
              if (result && result.length > 0) {
                var location = result.splice(1, 2);
                propertyData.location = [];

                // Store in lng, lat format.
                propertyData.location.push(location[1]);
                propertyData.location.push(location[0]);
                console.log(propertyData);
                Property.findOne({propertyId: propertyData.propertyId}, function (err, property) {
                  if (err) {
                    res.send(200, err);
                    return;
                  };

                  if (property) {
                    Property.findOneAndUpdate({_id: property._id}, propertyData, function (err, property) {
                      if (err) {
                        res.send(200, err);
                        return;
                      }
                      res.send(200, propertyData);
                      return;

                    });
                  } else {
                    propertyData._id = newId;
                    var newProperty = new Property(propertyData);
                    newProperty.save(function (err) {
                      if (err) {
                        res.send(200, err);
                        return;
                      };
                      res.send(200, propertyData);
                      return;
                    });
                  };
                });
              } else {
                console.log('gotcha');
                return;
              }
            } else {
              console.log(error);
              return;
            }
          });
        });
      };

    };
  });
};

exports.getdb = function (req, res1) {

Property.find().limit(20).exec(function (err, result) {

res1.send(result);
});

};

exports.getListing = function (req, res) {
  var url = 'http://www.thaihometown.com/apartment/?page=1';
  request(url, function (error, response, html){
    if (!error) {
      var $ = cheerio.load(html);
      var allUrls = '';
      $('.namedesw_inlist').filter( function () {
        var links = $('a.namelink', this);
        for (var i = links.length - 1; i >= 0; i--) {
          var singleUrl = links[i].attribs.href;
          allUrls += singleUrl + '
';
        };
      });
      console.log(allUrls);
      res.send(200, allUrls);
    };
  });
};

exports.createJobs = function (req, res) {
  var url = 'http://www.thaihometown.com/apartment/';
  var maxPage = 48;

  jobs.create('get list', {
    title: 'get list for ' + url,
    url: url
  }).save();
  for (var i = 0; i < maxPage; i++) {
    var url = 'http://www.thaihometown.com/apartment/?page=' +i;
    jobs.create('get list', {
      title: 'get list for ' + url,
      url: url
    }).save();
    console.log("url : " + url)
  };
  res.send(200, 'OK');
};

jobs.process('get list', function (job, done){

  var url = job.data.url;
  console.log('Get List for ' + url);
  request({url: url, encoding:'utf8'}, function (error, response, html){
    if (!error) {
      var $ = cheerio.load(html);
      var allUrls = '';
      $('.namedesw_inlist').filter( function () {
        var links = $('a.namelink', this);
        for (var i = links.length - 1; i >= 0; i--) {
          var singleUrl = links[i].attribs.href;
          allUrls += singleUrl + '
';
          jobs.create('get detail', {
            title: 'get detail for ' + singleUrl,
            url: singleUrl
          }).save();
          console.log("saveSingleUrl : "+ singleUrl);

        };
      });

      //res.send(200, allUrls);
      done();
    } else {
      done(error);
    };
  });
});

jobs.process('get detail', function (job, done) {

  // Get url to fetch from job description
  var url = job.data.url;

  // Log to console

  // We need to convert obsolete format!!
  var iconv = new Iconv('WINDOWS-874', 'UTF-8//TRANSLIT//IGNORE');

  // The structure of our request call
  // The first parameter is our URL
  // The callback function takes 3 parameters, an error, response status code and the html

  request({url: url, encoding:null}, function (error, response, html){

    // First we'll check to make sure no errors occurred when making the request

    if (!error){
      // Next, we'll utilize the cheerio library on the returned html which will essentially give us jQuery functionality

      // Let's the iconv magic begin.
      var body = iconv.convert(new Buffer(html));

      // Use converted utf-8 string instead.
      var $ = cheerio.load(body.toString('utf-8'));

      // Finally, we'll define the variables we're going to capture
      //var title, release, rating;
      //var json = { title : "", release : "", rating : ""};
      var newId = new ObjectId();
      var propertyData = {};

      // Get Id
      var regex = /^http:\/\/www.thaihometown.com\/apartment\/(.*)$/g;
      var result = regex.exec(url);
      if (result && result.length > 0) {
        console.log(result[1]);
        var propertyId = result[1];
        propertyData.propertyId = propertyId;
      };

      // Get Title
      $('.namedesw9').filter(function (){
        var data = $('h1', this);

        //console.log(data.text());
        propertyData.title = data.text().toString('utf8');
      });

      $('.headtitle2').filter(function () {
        var data = $('h2', this);
        //console.log(data.text());
        propertyData.detail = data.text();
      });

      $('#divImg').filter(function() {
        var images = $('img', this);
        //console.log(data);
        //var images = data.children()
        propertyData.images = [];
        for (var i = images.length - 1; i >= 3; i--) {
          console.log(images[i].parent.attribs.href);
          if( images[i]==null)
          {console.log("img undefined");}
        else{
          propertyData.images.push(images[i].parent.attribs.href);
        }
        };
      });

      var linkPrice = $('.linkprice');
      if (linkPrice.length > 0) {
        linkPrice.filter(function() {
          var str = $(this).text();

          // Kinda sucks but it works!
          var regex = /(.*) ([0-9\.\,]+) (.*)\/(.*)/g;
          var result = regex.exec(str);
          if (result && result.length > 0) {

            var rent = parseFloat(result[2].replace(',', ''));
            propertyData.rent = rent;
          };
        })
      };

      if ($('#GMap').length === 0) {
        console.log(propertyData);
        Property.findOne({propertyId: propertyData.propertyId}, function (err, property) {
          if (err) {
            done(err);
            return;
          };

          if (property) {
            Property.findOneAndUpdate({_id: property._id}, propertyData, function (err, property) {
              if (err) {
                done(err);
                return;
              }
              done();
              return;

            });
          } else {
            propertyData._id = newId;
            var newProperty = new Property(propertyData);
            newProperty.save(function (err) {
              if (err) {
                done(err);
                return;
              };
              //  console.log(newID + " save with map /******************************************* /n");
              done();
              return;
            });
          };
        });
      } else {

        $('#GMap').filter(function() {
          var data = $(this);

          //console.log(data.attr('src'));
          request(data.attr('src'), function (error, response, html){
            if (!error) {
              //var $ = cheerio.load(html);
              var regex = /google.maps.LatLng\((.*),(.*)\)/g;
              //var regex = '/google/g';
              //var string = $.html();
              //var result = html.match(/google.maps.LatLng\((.*),(.*)\)/gm);
              var result = regex.exec(html);
              if (result && result.length > 0) {
                var location = result.splice(1, 2);
                propertyData.location = [];

                // Store in lng, lat format.
                propertyData.location.push(location[1]);
                propertyData.location.push(location[0]);
                console.log(propertyData);
                Property.findOne({propertyId: propertyData.propertyId}, function (err, property) {
                  if (err) {
                    done(err);
                    return;
                  };

                  if (property) {
                    Property.findOneAndUpdate({_id: property._id}, propertyData, function (err, property) {
                      if (err) {
                        done(err);
                        return;
                      }
                      done();
                      return;

                    });
                  } else {
                    propertyData._id = newId;
                    var newProperty = new Property(propertyData);
                    newProperty.save(function (err) {
                      if (err) {
                        done(err);
                        return;
                      };
                      done();
                      return;
                    });
                  };
                });
              } else {
              	  //console.log(newID + "save with no map/***************************************");
                done('no map');
                return;
              }
            } else {
              done(error);
              return;
            }
          });
        });
      };

    } else {
      console.log("Error detail : "+ error);
      done(error);
    };
  });
});<commit_msg>xml read array5<commit_after>var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var mongoose = require('mongoose');
var Iconv  = require('iconv').Iconv;
var kue = require('kue');
var jobs = kue.createQueue();
var parseString = require('xml2js').parseString;

var ObjectId = mongoose.Types.ObjectId;
var Property = require('../models/property.js');
var PP = require('../controllers/property.js');
exports.test = function(req, res) {
  var iconv = new Iconv('UTF-8', 'WINDOWS-874');
  var iconv2 = new Iconv('WINDOWS-874', 'UTF-8');
  var test = iconv.convert('ทดสอบ');
  var test2 = iconv2.convert(test);
  res.send(200, {test1:test.toString(), test2:test2.toString()});
};

exports.getinfo = function(req, res){

            if(req.query.id!=null)
            {
            Property.findOne({_id: req.query.id}).exec(function(err,result){res.send(result);});
              console.log("search for ID"+req.query.id);

}

};
exports.zip = function(req,res){
  var data;
fs.readFile('/home/express/apartmentjs/app/zipcodes.xml', function (err, html) {
if (err){
console.log(err);
if(err.errno==34){
res.end('No such file exist');
}

}else{
var conn = mongoose.connection();
 parseString(html, function (err, result) {
    data=result;
     console.log(result.test_server.zipcodes);
    for(var i = 0 ; i< result.test_server.zipcodes.length;i++)
    {
      console.log(result.test_server.zipcodes);
    }
});
}}

);
//console.log(data.test_server.zipcodes[0].zipcode[0]);
//

}

exports.getpage=function(req,res)
{

            if(req.query.page!=null)
            {
              var pagenum = req.query.page*15;
            Property.find().skip(pagenum).limit(15).exec(function(err,result){res.send(result);});
            }
}

exports.bot = function (req, res) {
  var url = 'http://www.thaihometown.com/apartment/17818';

  request({url: url, encoding:null}, function (err, response, html) {
    //console.log(html);

    var iconv = new Iconv('WINDOWS-874', 'UTF-8//TRANSLIT//IGNORE');

    var body = iconv.convert(new Buffer(html));

    var $ = cheerio.load(body.toString('utf-8'));

    $('.namedesw9').filter(function() {
      var data = $('h1', this);
      res.send( data.html());
    });

    //res.send(html);
  });
};

exports.scrape = function(req, res) {
  //res.charset = 'UTF-8';

  var url = 'http://www.thaihometown.com/apartment/130450';

  var iconv = new Iconv('WINDOWS-874', 'UTF-8//TRANSLIT//IGNORE');

  // The structure of our request call
    // The first parameter is our URL
    // The callback function takes 3 parameters, an error, response status code and the html

  request({url:url, encoding:null}, function (error, response, html){

    // Convert
    var body = iconv.convert(new Buffer(html));
    //console.log(body.toString());
    //var html = iconv.convert(body);

    // First we'll check to make sure no errors occurred when making the request

    if (!error){
      // Next, we'll utilize the cheerio library on the returned html which will essentially give us jQuery functionality

      //var $ = cheerio.load(html);
      var $ = cheerio.load(body.toString('utf-8'));

      // Finally, we'll define the variables we're going to capture

      var newId = new ObjectId();
      var propertyData = {};

      // Iconv
      //var iconv = new Iconv('windows-874', 'utf-8');

      // Get Id
      var regex = /^http:\/\/www.thaihometown.com\/apartment\/(.*)$/g;
      var result = regex.exec(url);
      if (result && result.length > 0) {
        console.log(result[1]);
        var propertyId = result[1];
        propertyData.propertyId = propertyId;
      };

      // Get Title
      $('.namedesw9').filter(function (){
        var data = $('h1', this);
        var buf = iconv.convert(data.text());
        propertyData.title = data.text();

      });

      $('.headtitle2').filter(function () {
        var data = $('h2', this);
        propertyData.detail = data.text();
      });

      $('#divImg').filter(function() {
        var images = $('img', this);
        console.log(data);
        //var images = data.children()
        propertyData.images = [];
        for (var i = images.length - 1; i >= 3; i--) {
         if( images[i]==null)
          {console.log("img undefined");}
        else{
          propertyData.images.push(images[i].parent.attribs.href);
        }
        };
      });

      var linkPrice = $('.linkprice');
      if (linkPrice.length > 0) {
        linkPrice.filter(function() {
          var str = $(this).text();

          // Kinda sucks but it works!
          var regex = /(.*) ([0-9\.\,]+) (.*)\/(.*)/g;
          var result = regex.exec(str);
          if (result && result.length > 0) {

            var rent = parseFloat(result[2].replace(',', ''));
            propertyData.rent = rent;
          };
        })
      };

      if ($('#GMap').length === 0) {
        console.log(propertyData);
        Property.findOne({propertyId: propertyData.propertyId}, function (err, property) {
          if (err) {
            res.send(200, err);
          };

          if (property) {
            Property.findOneAndUpdate({_id: property._id}, propertyData, function (err, property) {
              if (err) {
                res.send(200, err);
                return;
              }
              res.send(200, propertyData);
              return;

            });
          } else {
            propertyData._id = newId;
            var newProperty = new Property(propertyData);
            newProperty.save(function (err) {
              if (err) {
                res.send(200, err);
                return;
              };
              res.send(200, propertyData);
              return;
            });
          };
        });
      } else {

        $('#GMap').filter(function() {
          var data = $(this);

          //console.log(data.attr('src'));
          request(data.attr('src'), function (error, response, html){
            if (!error) {
              //var $ = cheerio.load(html);
              var regex = /google.maps.LatLng\((.*),(.*)\)/g;
              //var regex = '/google/g';
              //var string = $.html();
              //var result = html.match(/google.maps.LatLng\((.*),(.*)\)/gm);
              var result = regex.exec(html);
              if (result && result.length > 0) {
                var location = result.splice(1, 2);
                propertyData.location = [];

                // Store in lng, lat format.
                propertyData.location.push(location[1]);
                propertyData.location.push(location[0]);
                console.log(propertyData);
                Property.findOne({propertyId: propertyData.propertyId}, function (err, property) {
                  if (err) {
                    res.send(200, err);
                    return;
                  };

                  if (property) {
                    Property.findOneAndUpdate({_id: property._id}, propertyData, function (err, property) {
                      if (err) {
                        res.send(200, err);
                        return;
                      }
                      res.send(200, propertyData);
                      return;

                    });
                  } else {
                    propertyData._id = newId;
                    var newProperty = new Property(propertyData);
                    newProperty.save(function (err) {
                      if (err) {
                        res.send(200, err);
                        return;
                      };
                      res.send(200, propertyData);
                      return;
                    });
                  };
                });
              } else {
                console.log('gotcha');
                return;
              }
            } else {
              console.log(error);
              return;
            }
          });
        });
      };

    };
  });
};

exports.getdb = function (req, res1) {

Property.find().limit(20).exec(function (err, result) {

res1.send(result);
});

};

exports.getListing = function (req, res) {
  var url = 'http://www.thaihometown.com/apartment/?page=1';
  request(url, function (error, response, html){
    if (!error) {
      var $ = cheerio.load(html);
      var allUrls = '';
      $('.namedesw_inlist').filter( function () {
        var links = $('a.namelink', this);
        for (var i = links.length - 1; i >= 0; i--) {
          var singleUrl = links[i].attribs.href;
          allUrls += singleUrl + '
';
        };
      });
      console.log(allUrls);
      res.send(200, allUrls);
    };
  });
};

exports.createJobs = function (req, res) {
  var url = 'http://www.thaihometown.com/apartment/';
  var maxPage = 48;

  jobs.create('get list', {
    title: 'get list for ' + url,
    url: url
  }).save();
  for (var i = 0; i < maxPage; i++) {
    var url = 'http://www.thaihometown.com/apartment/?page=' +i;
    jobs.create('get list', {
      title: 'get list for ' + url,
      url: url
    }).save();
    console.log("url : " + url)
  };
  res.send(200, 'OK');
};

jobs.process('get list', function (job, done){

  var url = job.data.url;
  console.log('Get List for ' + url);
  request({url: url, encoding:'utf8'}, function (error, response, html){
    if (!error) {
      var $ = cheerio.load(html);
      var allUrls = '';
      $('.namedesw_inlist').filter( function () {
        var links = $('a.namelink', this);
        for (var i = links.length - 1; i >= 0; i--) {
          var singleUrl = links[i].attribs.href;
          allUrls += singleUrl + '
';
          jobs.create('get detail', {
            title: 'get detail for ' + singleUrl,
            url: singleUrl
          }).save();
          console.log("saveSingleUrl : "+ singleUrl);

        };
      });

      //res.send(200, allUrls);
      done();
    } else {
      done(error);
    };
  });
});

jobs.process('get detail', function (job, done) {

  // Get url to fetch from job description
  var url = job.data.url;

  // Log to console

  // We need to convert obsolete format!!
  var iconv = new Iconv('WINDOWS-874', 'UTF-8//TRANSLIT//IGNORE');

  // The structure of our request call
  // The first parameter is our URL
  // The callback function takes 3 parameters, an error, response status code and the html

  request({url: url, encoding:null}, function (error, response, html){

    // First we'll check to make sure no errors occurred when making the request

    if (!error){
      // Next, we'll utilize the cheerio library on the returned html which will essentially give us jQuery functionality

      // Let's the iconv magic begin.
      var body = iconv.convert(new Buffer(html));

      // Use converted utf-8 string instead.
      var $ = cheerio.load(body.toString('utf-8'));

      // Finally, we'll define the variables we're going to capture
      //var title, release, rating;
      //var json = { title : "", release : "", rating : ""};
      var newId = new ObjectId();
      var propertyData = {};

      // Get Id
      var regex = /^http:\/\/www.thaihometown.com\/apartment\/(.*)$/g;
      var result = regex.exec(url);
      if (result && result.length > 0) {
        console.log(result[1]);
        var propertyId = result[1];
        propertyData.propertyId = propertyId;
      };

      // Get Title
      $('.namedesw9').filter(function (){
        var data = $('h1', this);

        //console.log(data.text());
        propertyData.title = data.text().toString('utf8');
      });

      $('.headtitle2').filter(function () {
        var data = $('h2', this);
        //console.log(data.text());
        propertyData.detail = data.text();
      });

      $('#divImg').filter(function() {
        var images = $('img', this);
        //console.log(data);
        //var images = data.children()
        propertyData.images = [];
        for (var i = images.length - 1; i >= 3; i--) {
          console.log(images[i].parent.attribs.href);
          if( images[i]==null)
          {console.log("img undefined");}
        else{
          propertyData.images.push(images[i].parent.attribs.href);
        }
        };
      });

      var linkPrice = $('.linkprice');
      if (linkPrice.length > 0) {
        linkPrice.filter(function() {
          var str = $(this).text();

          // Kinda sucks but it works!
          var regex = /(.*) ([0-9\.\,]+) (.*)\/(.*)/g;
          var result = regex.exec(str);
          if (result && result.length > 0) {

            var rent = parseFloat(result[2].replace(',', ''));
            propertyData.rent = rent;
          };
        })
      };

      if ($('#GMap').length === 0) {
        console.log(propertyData);
        Property.findOne({propertyId: propertyData.propertyId}, function (err, property) {
          if (err) {
            done(err);
            return;
          };

          if (property) {
            Property.findOneAndUpdate({_id: property._id}, propertyData, function (err, property) {
              if (err) {
                done(err);
                return;
              }
              done();
              return;

            });
          } else {
            propertyData._id = newId;
            var newProperty = new Property(propertyData);
            newProperty.save(function (err) {
              if (err) {
                done(err);
                return;
              };
              //  console.log(newID + " save with map /******************************************* /n");
              done();
              return;
            });
          };
        });
      } else {

        $('#GMap').filter(function() {
          var data = $(this);

          //console.log(data.attr('src'));
          request(data.attr('src'), function (error, response, html){
            if (!error) {
              //var $ = cheerio.load(html);
              var regex = /google.maps.LatLng\((.*),(.*)\)/g;
              //var regex = '/google/g';
              //var string = $.html();
              //var result = html.match(/google.maps.LatLng\((.*),(.*)\)/gm);
              var result = regex.exec(html);
              if (result && result.length > 0) {
                var location = result.splice(1, 2);
                propertyData.location = [];

                // Store in lng, lat format.
                propertyData.location.push(location[1]);
                propertyData.location.push(location[0]);
                console.log(propertyData);
                Property.findOne({propertyId: propertyData.propertyId}, function (err, property) {
                  if (err) {
                    done(err);
                    return;
                  };

                  if (property) {
                    Property.findOneAndUpdate({_id: property._id}, propertyData, function (err, property) {
                      if (err) {
                        done(err);
                        return;
                      }
                      done();
                      return;

                    });
                  } else {
                    propertyData._id = newId;
                    var newProperty = new Property(propertyData);
                    newProperty.save(function (err) {
                      if (err) {
                        done(err);
                        return;
                      };
                      done();
                      return;
                    });
                  };
                });
              } else {
              	  //console.log(newID + "save with no map/***************************************");
                done('no map');
                return;
              }
            } else {
              done(error);
              return;
            }
          });
        });
      };

    } else {
      console.log("Error detail : "+ error);
      done(error);
    };
  });
});<|endoftext|>


<commit_before>/**
 * @file webpack.config.base.js
 * @author 刘巍峰 <weifeng3@staff.weibo.com>
 * Created on 2016-02-13 23:53
 */
/**
 * Created by liuweifeng on 16/1/14.
 */
'use strict';
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = function (options) {
    const localConfig = require(process.cwd() + '/package.json')['xianyu'] || {};
    options = Object.assign(options, localConfig);

    const template = path.join(__dirname, 'index.ejs');
    let plugins = [];
    let entry = {};
    if (typeof options.entry === 'string') {
        options.entry = {
            'app': options.entry
        }
    }
    Object.keys(options.entry).forEach(function (e) {
        entry[e] = process.cwd() + '/' + options.entry[e];
        let hwpConfig = {
            title: options.title || '咸鱼 - 前端开发脚手架',
            template: template,
            chunks: [e],
            filename: e + '.html'
        };
        if (options.template) {
            let content = fs.readFileSync(path.resolve(path.join(process.cwd(), options.template)));
            if (content.indexOf('<body>') == -1) {
                hwpConfig.content = content;
            } else {
                hwpConfig.templateContent = content;
            }
        }
        plugins[plugins.length] = new HtmlWebpackPlugin(hwpConfig);
    });
    return {
        entry: entry,
        output: {
            path: path.join(process.cwd(), ''),
            filename: '[name].js',
            publicPath: `${options.devHost || 'http://dev.js.weibo.cn'}/${options.module}/build/`
        },
        plugins: plugins,
        resolve: {
            extensions: ['', '.js', '.vue', '.css', '.jsx'],
            root: [path.join(process.cwd(), 'node_modules'), path.join(__dirname, '../node_modules')]
        },
        resolveLoader: {
            root: [path.join(process.cwd(), 'node_modules'), path.join(__dirname, '../node_modules')]
        },
        module: {
            loaders: [
                {
                    test: /\.jsx?$/,
                    loaders: ['babel'],
                    exclude: [/node_modules/]
                },
                {
                    test: /\.json/,
                    loaders: ['json']
                },
                {
                    test: /\.svg$/,
                    loaders: ['raw']
                }
            ]
        },
        babel: {
            presets: [require('babel-preset-es2015'), require('babel-preset-stage-0')],
            plugins: [require('babel-plugin-transform-runtime')]
        }
    };
};
<commit_msg>支持查找与js同名的模板文件<commit_after>/**
 * @file webpack.config.base.js
 * @author 刘巍峰 <weifeng3@staff.weibo.com>
 * Created on 2016-02-13 23:53
 */
/**
 * Created by liuweifeng on 16/1/14.
 */
'use strict';
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = function (options) {
    const localConfig = require(process.cwd() + '/package.json')['xianyu'] || {};
    options = Object.assign(options, localConfig);

    const template = path.join(__dirname, 'index.ejs');
    let plugins = [];
    let entry = {};
    if (typeof options.entry === 'string') {
        options.entry = {
            'app': options.entry
        }
    }
    Object.keys(options.entry).forEach(function (e) {
        entry[e] = process.cwd() + '/' + options.entry[e];
        let hwpConfig = {
            title: options.title || '咸鱼 - 前端开发脚手架',
            template: template,
            chunks: [e],
            filename: e + '.html'
        };
        let tpl;
        if (options.template) {
            tpl = path.resolve(path.join(process.cwd(), options.template));
        }else {
            tpl = path.resolve(path.join(process.cwd(), `src/html/${e}.html`));
        }
        if(fs.existsSync(tpl)){
            let content =fs.readFileSync(tpl, 'utf-8');
            if (content.indexOf('<body>') == -1) {
                hwpConfig.content = content;
            } else {
                hwpConfig.templateContent = content;
            }
        }
        plugins[plugins.length] = new HtmlWebpackPlugin(hwpConfig);
    });
    return {
        entry: entry,
        output: {
            path: path.join(process.cwd(), ''),
            filename: '[name].js',
            publicPath: `${options.devHost || 'http://dev.js.weibo.cn'}/${options.module}/build/`
        },
        plugins: plugins,
        resolve: {
            extensions: ['', '.js', '.vue', '.css', '.jsx'],
            root: [path.join(process.cwd(), 'node_modules'), path.join(__dirname, '../node_modules')]
        },
        resolveLoader: {
            root: [path.join(process.cwd(), 'node_modules'), path.join(__dirname, '../node_modules')]
        },
        module: {
            loaders: [
                {
                    test: /\.jsx?$/,
                    loaders: ['babel'],
                    exclude: [/node_modules/]
                },
                {
                    test: /\.json/,
                    loaders: ['json']
                },
                {
                    test: /\.svg$/,
                    loaders: ['raw']
                }
            ]
        },
        babel: {
            presets: [require('babel-preset-es2015'), require('babel-preset-stage-0')],
            plugins: [require('babel-plugin-transform-runtime')]
        }
    };
};
<|endoftext|>


<commit_before>'use strict';

// Declare app level module which depends on filters, and services
var cloudscalers = angular.module('cloudscalers', [
  'cloudscalers.services',
  'cloudscalers.controllers',
  'ngRoute',
  'angular-szn-autocomplete',
  'ui.bootstrap'
]);

cloudscalers
  .config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/decks', {
        templateUrl: 'Portal/Decks/Decks.html',
        title: 'Decks'
    });
    $routeProvider.when('/list', {
        templateUrl: 'shared/list.html',
        controller: 'MachineController',
        title: 'List'
    });
    $routeProvider.when('/new', {
        templateUrl: 'Portal/Decks/MachineDeck/pages/new.html',
        title: 'New'
    });
    $routeProvider.when('/edit/:machineId/:activeTab?', {
        templateUrl: 'shared/details.html',
        controller: 'MachineEditController'
    });
    $routeProvider.when('/CloudSpaceSettings', {
        templateUrl: 'Portal/Admin/CloudSpaceSettings/CloudSpaceSettings.html',
        controller: 'CloudSpaceManagementController',
        title: 'CloudSpace Settings'
    });
    $routeProvider.when('/AccountSettings', {
        templateUrl: 'Portal/Admin/AccountSettings/AccountSettings.html',
        controller: 'AccountSettingsController',
        title: 'Account Settings'
    });
    $routeProvider.when('/GettingStarted', {
        templateUrl: 'Portal/Support/getting-started/getting-started.html',
        title: 'Getting Started'
    });
    $routeProvider.when('/ApiDocs', {
        templateUrl: 'Portal/Support/ApiDocs/ApiDocs.html',
        title: 'Api Docs'
    });
    $routeProvider.when('/Support', {
        templateUrl: 'Portal/Support/Support.html',
        title: 'Support'
    });
    $routeProvider.when('/MachineDeck', {
        templateUrl: 'shared/list.html',
        controller: 'MachineController',
        title: 'Machine Deck'
    });
    $routeProvider.when('/Portforwarding', {
        templateUrl: 'Portal/Decks/NetworkDeck/Portforwarding.html',
        controller: 'PortforwardingController',
        title: 'Portforwarding'
    });
    $routeProvider.when('/NetworkDeck', {
        templateUrl: 'Portal/Decks/NetworkDeck/NetworkDeck.html',
        controller: 'NetworkController',
        title: 'Network Deck'
    });
    $routeProvider.when('/Consumption', {
        templateUrl: 'Portal/Admin/Consumption/Consumption.html',
        controller: 'AccountController',
        title: 'Consumption'
    });
    $routeProvider.when('/Billing', {
        templateUrl: 'Portal/Admin/AccountSettings/Billing.html',
        controller: 'BillingController',
        title: 'Billing'
    });
    $routeProvider.when('/Profile', {
        templateUrl: 'Portal/Admin/Profile/Profile.html',
        controller: 'UsersController',
        title: 'Profile'
    });
    $routeProvider.when('/ResetPassword', {
        templateUrl: 'Public/Authentication/Login/ResetPassword.html',
        controller: 'ResetPasswordController',
        title: 'Reset Password'
    });
    // Docs
    $routeProvider.when('/Docs', {
        templateUrl: 'Portal/Docs/Docs.html',
        title: 'Docs'
    });
    $routeProvider.when('/Docs/access-your-cloud-space-using-openvpn', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/access-your-cloud-space-using-openvpn.html',
        title: 'Access your Cloud Space using OpenVPN'
    });
    $routeProvider.when('/Docs/enable-root-access-on-ubuntu-over-ssh', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/enable-root-access-on-ubuntu-over-ssh.html',
        title: 'Enable Root Access on ubuntu over SSH'
    });
    $routeProvider.when('/Docs/getting-started-with-jumpscale', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/getting-started-with-jumpscale.html',
        title: 'Getting Started with JumpScale'
    });
    $routeProvider.when('/Docs/how-to-configure-ubuntu-to-connect-to-openvpn', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/how-to-configure-ubuntu-to-connect-to-openvpn/tutorial.html',
        title: 'How to configure Ubuntu to connect to OpenVPN'
    });
    $routeProvider.when('/Docs/my-first-machine-linux', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/my-first-machine-linux/tutorial.html',
        title: 'My First Machine Linux'
    });
    $routeProvider.when('/Docs/my-first-machine-windows', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/my-first-machine-windows/tutorial.html',
        title: 'My First Machine Windows'
    });
    $routeProvider.when('/Docs/pptp-connection-to-space-from-windows10', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/pptp-connection-to-space-from-windows10/tutorial.html',
        title: 'Setup a PPTP connection to Space from Windows10'
    });

    $routeProvider.otherwise({redirectTo: '/list'});
  }])
  .config(['$interpolateProvider','$compileProvider', function($interpolateProvider, $compileProvider) {
    // Angular uses {{}} for data-binding. This operator will conflict with JumpScale macro syntax.
    // Use {[]} instead.
    $interpolateProvider.startSymbol('{[').endSymbol(']}');
    //Accept bitcoin and litecoin urls
    $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|bitcoin|litecoin):/);
  }]);

angular.module('cloudscalers.services',['ng'])
  .config(['$httpProvider',function($httpProvider) {
    $httpProvider.interceptors.push('authenticationInterceptor');
    //initialize get if not there
    if (!$httpProvider.defaults.headers.get) {
      $httpProvider.defaults.headers.get = {};
    }
    //disable IE ajax request caching
    $httpProvider.defaults.headers.get['If-Modified-Since'] = '0';
    $httpProvider.defaults.headers.post['Accept'] = 'application/json';
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/json';
  }]);

var cloudscalersControllers = angular.module('cloudscalers.controllers', [
  'ui.slider',
  'cloudscalers.services',
  'cloudscalers.directives',
  'angular-tour',
  'ipCookie'
]);

if (cloudspaceconfig.apibaseurl === '') {
  cloudscalersControllers.config(function($provide) {
    $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
  });
  cloudscalersControllers.run(defineApiStub);
}

// So we can inject our own functions instead of the builtin functions
cloudscalers.value('confirm', window.confirm);
cloudscalers.factory('$alert', function($modal) {
  return function(message) {
    var ModalInstanceCtrl = function($scope, $modalInstance) {
      $scope.message = message.replace('\n', '
');
      $scope.ok = function() {
        $modalInstance.close();
      };
      $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
      };
    };

    $modal.open({
      templateUrl: 'myModalContent.html',
      controller: ModalInstanceCtrl,
      resolve: {}
    });
  };
});
cloudscalers.factory('$ErrorResponseAlert',function($alert) {
  return function(reason) {
    if (reason.status === 500 || reason.status === 502 || reason.status === 504 || reason.data === null) {
      $alert('An unexpected error has occurred');
    } else if (reason.status === 401) {
      $alert('Please login to access full functionality');
    } else {
      var message = '';
      try {
        message = JSON.parse(reason.data);
        if (typeof message !== 'string') {
          message = reason.data;
        }
      } catch (e) {
        message = reason.data;
        //data is not JSON
      }
      $alert(message);
    }
  };
});

cloudscalers.run(function($templateCache, $rootScope) {
  $templateCache.put('autocomplete-result-template.html',
        '
 ' +
          '
 ' +
              '
 ' +
                  ' ' +
                  ' ' +
                  'Invite: {[result.value]} ' +
              '
 ' +
          '
 ' +
      '
'
  );
  $rootScope.$on("$routeChangeSuccess", function(event, currentRoute, previousRoute) {
    $rootScope.title = currentRoute.title;
  });
});
<commit_msg>update titles formatting<commit_after>'use strict';

// Declare app level module which depends on filters, and services
var cloudscalers = angular.module('cloudscalers', [
  'cloudscalers.services',
  'cloudscalers.controllers',
  'ngRoute',
  'angular-szn-autocomplete',
  'ui.bootstrap'
]);

cloudscalers
  .config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/decks', {
        templateUrl: 'Portal/Decks/Decks.html',
        title: 'Decks'
    });
    $routeProvider.when('/list', {
        templateUrl: 'shared/list.html',
        controller: 'MachineController',
        title: 'List'
    });
    $routeProvider.when('/new', {
        templateUrl: 'Portal/Decks/MachineDeck/pages/new.html',
        title: 'New'
    });
    $routeProvider.when('/edit/:machineId/:activeTab?', {
        templateUrl: 'shared/details.html',
        controller: 'MachineEditController',
        title: 'MachineDeck'
    });
    $routeProvider.when('/CloudSpaceSettings', {
        templateUrl: 'Portal/Admin/CloudSpaceSettings/CloudSpaceSettings.html',
        controller: 'CloudSpaceManagementController',
        title: 'CloudSpaceSettings'
    });
    $routeProvider.when('/AccountSettings', {
        templateUrl: 'Portal/Admin/AccountSettings/AccountSettings.html',
        controller: 'AccountSettingsController',
        title: 'AccountSettings'
    });
    $routeProvider.when('/GettingStarted', {
        templateUrl: 'Portal/Support/getting-started/getting-started.html',
        title: 'GettingStarted'
    });
    $routeProvider.when('/ApiDocs', {
        templateUrl: 'Portal/Support/ApiDocs/ApiDocs.html',
        title: 'ApiDocs'
    });
    $routeProvider.when('/Support', {
        templateUrl: 'Portal/Support/Support.html',
        title: 'Support'
    });
    $routeProvider.when('/MachineDeck', {
        templateUrl: 'shared/list.html',
        controller: 'MachineController',
        title: 'MachineDeck'
    });
    $routeProvider.when('/Portforwarding', {
        templateUrl: 'Portal/Decks/NetworkDeck/Portforwarding.html',
        controller: 'PortforwardingController',
        title: 'Portforwarding'
    });
    $routeProvider.when('/NetworkDeck', {
        templateUrl: 'Portal/Decks/NetworkDeck/NetworkDeck.html',
        controller: 'NetworkController',
        title: 'NetworkDeck'
    });
    $routeProvider.when('/Consumption', {
        templateUrl: 'Portal/Admin/Consumption/Consumption.html',
        controller: 'AccountController',
        title: 'Consumption'
    });
    $routeProvider.when('/Billing', {
        templateUrl: 'Portal/Admin/AccountSettings/Billing.html',
        controller: 'BillingController',
        title: 'Billing'
    });
    $routeProvider.when('/Profile', {
        templateUrl: 'Portal/Admin/Profile/Profile.html',
        controller: 'UsersController',
        title: 'Profile'
    });
    $routeProvider.when('/ResetPassword', {
        templateUrl: 'Public/Authentication/Login/ResetPassword.html',
        controller: 'ResetPasswordController',
        title: 'ResetPassword'
    });
    // Docs
    $routeProvider.when('/Docs', {
        templateUrl: 'Portal/Docs/Docs.html',
        title: 'Docs'
    });
    $routeProvider.when('/Docs/access-your-cloud-space-using-openvpn', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/access-your-cloud-space-using-openvpn.html',
        title: 'Access your Cloud Space using OpenVPN'
    });
    $routeProvider.when('/Docs/enable-root-access-on-ubuntu-over-ssh', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/enable-root-access-on-ubuntu-over-ssh.html',
        title: 'Enable Root Access on ubuntu over SSH'
    });
    $routeProvider.when('/Docs/getting-started-with-jumpscale', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/getting-started-with-jumpscale.html',
        title: 'Getting Started with JumpScale'
    });
    $routeProvider.when('/Docs/how-to-configure-ubuntu-to-connect-to-openvpn', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/how-to-configure-ubuntu-to-connect-to-openvpn/tutorial.html',
        title: 'How to configure Ubuntu to connect to OpenVPN'
    });
    $routeProvider.when('/Docs/my-first-machine-linux', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/my-first-machine-linux/tutorial.html',
        title: 'My First Machine Linux'
    });
    $routeProvider.when('/Docs/my-first-machine-windows', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/my-first-machine-windows/tutorial.html',
        title: 'My First Machine Windows'
    });
    $routeProvider.when('/Docs/pptp-connection-to-space-from-windows10', {
        templateUrl: 'Portal/Docs/TechnicalTutorials/pptp-connection-to-space-from-windows10/tutorial.html',
        title: 'Setup a PPTP connection to Space from Windows10'
    });

    $routeProvider.otherwise({redirectTo: '/list'});
  }])
  .config(['$interpolateProvider','$compileProvider', function($interpolateProvider, $compileProvider) {
    // Angular uses {{}} for data-binding. This operator will conflict with JumpScale macro syntax.
    // Use {[]} instead.
    $interpolateProvider.startSymbol('{[').endSymbol(']}');
    //Accept bitcoin and litecoin urls
    $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|bitcoin|litecoin):/);
  }]);

angular.module('cloudscalers.services',['ng'])
  .config(['$httpProvider',function($httpProvider) {
    $httpProvider.interceptors.push('authenticationInterceptor');
    //initialize get if not there
    if (!$httpProvider.defaults.headers.get) {
      $httpProvider.defaults.headers.get = {};
    }
    //disable IE ajax request caching
    $httpProvider.defaults.headers.get['If-Modified-Since'] = '0';
    $httpProvider.defaults.headers.post['Accept'] = 'application/json';
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/json';
  }]);

var cloudscalersControllers = angular.module('cloudscalers.controllers', [
  'ui.slider',
  'cloudscalers.services',
  'cloudscalers.directives',
  'angular-tour',
  'ipCookie'
]);

if (cloudspaceconfig.apibaseurl === '') {
  cloudscalersControllers.config(function($provide) {
    $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
  });
  cloudscalersControllers.run(defineApiStub);
}

// So we can inject our own functions instead of the builtin functions
cloudscalers.value('confirm', window.confirm);
cloudscalers.factory('$alert', function($modal) {
  return function(message) {
    var ModalInstanceCtrl = function($scope, $modalInstance) {
      $scope.message = message.replace('\n', '
');
      $scope.ok = function() {
        $modalInstance.close();
      };
      $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
      };
    };

    $modal.open({
      templateUrl: 'myModalContent.html',
      controller: ModalInstanceCtrl,
      resolve: {}
    });
  };
});
cloudscalers.factory('$ErrorResponseAlert',function($alert) {
  return function(reason) {
    if (reason.status === 500 || reason.status === 502 || reason.status === 504 || reason.data === null) {
      $alert('An unexpected error has occurred');
    } else if (reason.status === 401) {
      $alert('Please login to access full functionality');
    } else {
      var message = '';
      try {
        message = JSON.parse(reason.data);
        if (typeof message !== 'string') {
          message = reason.data;
        }
      } catch (e) {
        message = reason.data;
        //data is not JSON
      }
      $alert(message);
    }
  };
});

cloudscalers.run(function($templateCache, $rootScope) {
  $templateCache.put('autocomplete-result-template.html',
        '
 ' +
          '
 ' +
              '
 ' +
                  ' ' +
                  ' ' +
                  'Invite: {[result.value]} ' +
              '
 ' +
          '
 ' +
      '
'
  );
  $rootScope.$on("$routeChangeSuccess", function(event, currentRoute, previousRoute) {
    $rootScope.title = currentRoute.title;
  });
});
<|endoftext|>


<commit_before>var express = require('express');
var app = express();
var router  = express.Router();

var gender  = require("../models/gender");
var kinks   = require("../models/kinks");
var role    = require("../models/role");
var species = require("../models/species");

/* GET index */
router.get('/', function(req, res) {
  res.render('home', {
    title: 'Yiff Spot | Yiff With Random Furries!',
    breeds: species.getAll(),
    genders: gender.getAll(),
    kinks: kinks.getAll(),
    roles: role.getAll()
  });
});

module.exports = router;<commit_msg>Fix to page title.<commit_after>var express = require('express');
var app = express();
var router  = express.Router();

var gender  = require("../models/gender");
var kinks   = require("../models/kinks");
var role    = require("../models/role");
var species = require("../models/species");

/* GET index */
router.get('/', function(req, res) {
  res.render('home', {
    pageTitle: 'Yiff Spot | Yiff With Random Furries!',
    breeds: species.getAll(),
    genders: gender.getAll(),
    kinks: kinks.getAll(),
    roles: role.getAll()
  });
});

module.exports = router;<|endoftext|>


<commit_before>'use strict';

const httpStatus = require('http-status-codes');
const Quest = require('../models/quest');
const Stage = require('../models/stage');
const constants = require('../constants/controllers');
const {NotFoundError, BadRequestError} = require('../libs/customErrors/errors');
const cloudinary = require('../libs/cloudinary');

function getStageData(req, cloudinaryFile) {
    return {
        src: cloudinaryFile.url,
        cloudinaryId: cloudinaryFile.public_id,
        title: req.body.title,
        description: req.body.description || '',
        location: req.body.location || ''
    };
}

function getStageObject(stage) {
    stage = stage.toObject();
    delete stage._id;

    return stage;
}

module.exports = {
    async add(req, res) {
        const quest = await Quest.getBySlug(req.params.slug);
        const file = req.file;

        if (!quest) {
            throw new NotFoundError(constants.quest.questNotFoundErrorMessage);
        }

        if (file) {
            const cloudinaryFile = await cloudinary.upload(file);
            const stageData = getStageData(req, cloudinaryFile);
            try {
                const stage = await quest.addStage(stageData);

                return res.status(httpStatus.OK).send({data: stage});
            } catch (err) {
                await cloudinary.remove(cloudinaryFile.public_id);

                throw new BadRequestError(err.message);
            }
        }

        throw new BadRequestError(constants.file.notFoundMessage);
    },

    async getAllByQuest(req, res) {
        try {
            const quest = await Quest.getBySlug(req.params.slug);
            const stages = (await quest.getStages()).map(getStageObject);

            res.status(httpStatus.OK).send({data: stages});
        } catch (err) {
            throw new NotFoundError(constants.quest.questNotFoundErrorMessage);
        }
    },

    async update(req, res) {
        const stageId = req.params.stageId;
        let stage = await Stage.getByShortId(stageId);
        const file = req.file;
        const stageData = {
            title: req.body.title,
            description: req.body.description,
            location: req.body.location
        };

        if (!stage) {
            throw new NotFoundError(constants.stage.notFoundMessage);
        }

        if (file) {
            if (stage.cloudinaryId) {
                await cloudinary.remove(stage.cloudinaryId);
            }
            const cloudinaryFile = await cloudinary.upload(file);
            stageData.src = cloudinaryFile.url;
            stageData.cloudinaryId = cloudinaryFile.public_id;
        }

        try {
            stage = await Stage.update(stageId, stageData);

            res.status(httpStatus.OK).send({data: stage});
        } catch (err) {
            throw new BadRequestError(err.message);
        }
    },

    async remove(req, res) {
        const quest = await Quest.getBySlug(req.params.slug);
        const stageId = req.params.stageId;
        const cloudinaryId = await Stage.getByShortId(stageId);
        const stage = await quest.removeStage(stageId);

        if (!stage) {
            throw new NotFoundError(constants.stage.notFoundMessage);
        }

        cloudinary.remove(cloudinaryId);

        res.status(httpStatus.OK).send();
    },

    async getById(req, res) {
        const stageId = req.params.stageId;
        const stage = await Stage.getByShortId(stageId);
        if (!stage) {
            throw new NotFoundError(constants.stage.notFoundMessage);
        }

        res.status(httpStatus.OK).send({data: stage});
    }
};
<commit_msg>Secure url из Cloudinary (#238)<commit_after>'use strict';

const httpStatus = require('http-status-codes');
const Quest = require('../models/quest');
const Stage = require('../models/stage');
const config = require('config');
const constants = require('../constants/controllers');
const {NotFoundError, BadRequestError} = require('../libs/customErrors/errors');
const cloudinary = require('../libs/cloudinary');

function getStageData(req, cloudinaryFile) {
    return {
        src: config.mode === 'production' ? cloudinaryFile.secure_url : cloudinaryFile.url,
        cloudinaryId: cloudinaryFile.public_id,
        title: req.body.title,
        description: req.body.description || '',
        location: req.body.location || ''
    };
}

function getStageObject(stage) {
    stage = stage.toObject();
    delete stage._id;

    return stage;
}

module.exports = {
    async add(req, res) {
        const quest = await Quest.getBySlug(req.params.slug);
        const file = req.file;

        if (!quest) {
            throw new NotFoundError(constants.quest.questNotFoundErrorMessage);
        }

        if (file) {
            const cloudinaryFile = await cloudinary.upload(file);
            const stageData = getStageData(req, cloudinaryFile);
            try {
                const stage = await quest.addStage(stageData);

                return res.status(httpStatus.OK).send({data: stage});
            } catch (err) {
                await cloudinary.remove(cloudinaryFile.public_id);

                throw new BadRequestError(err.message);
            }
        }

        throw new BadRequestError(constants.file.notFoundMessage);
    },

    async getAllByQuest(req, res) {
        try {
            const quest = await Quest.getBySlug(req.params.slug);
            const stages = (await quest.getStages()).map(getStageObject);

            res.status(httpStatus.OK).send({data: stages});
        } catch (err) {
            throw new NotFoundError(constants.quest.questNotFoundErrorMessage);
        }
    },

    async update(req, res) {
        const stageId = req.params.stageId;
        let stage = await Stage.getByShortId(stageId);
        const file = req.file;
        const stageData = {
            title: req.body.title,
            description: req.body.description,
            location: req.body.location
        };

        if (!stage) {
            throw new NotFoundError(constants.stage.notFoundMessage);
        }

        if (file) {
            if (stage.cloudinaryId) {
                await cloudinary.remove(stage.cloudinaryId);
            }
            const cloudinaryFile = await cloudinary.upload(file);
            stageData.src = cloudinaryFile.url;
            stageData.cloudinaryId = cloudinaryFile.public_id;
        }

        try {
            stage = await Stage.update(stageId, stageData);

            res.status(httpStatus.OK).send({data: stage});
        } catch (err) {
            throw new BadRequestError(err.message);
        }
    },

    async remove(req, res) {
        const quest = await Quest.getBySlug(req.params.slug);
        const stageId = req.params.stageId;
        const cloudinaryId = await Stage.getByShortId(stageId);
        const stage = await quest.removeStage(stageId);

        if (!stage) {
            throw new NotFoundError(constants.stage.notFoundMessage);
        }

        cloudinary.remove(cloudinaryId);

        res.status(httpStatus.OK).send();
    },

    async getById(req, res) {
        const stageId = req.params.stageId;
        const stage = await Stage.getByShortId(stageId);
        if (!stage) {
            throw new NotFoundError(constants.stage.notFoundMessage);
        }

        res.status(httpStatus.OK).send({data: stage});
    }
};
<|endoftext|>


<commit_before>const moment = require('moment');
const express = require('express');
const shortId = require('shortid');
const router = express.Router({ mergeParams: true });
const Nexboard = require("nexboard-api-js");
const api = require('../api');
const authHelper = require('../helpers/authentication');

const etherpadBaseUrl = process.env.ETHERPAD_BASE_URL || 'https://etherpad.schul-cloud.org/etherpad/p/';

const editTopicHandler = (req, res, next) => {
    let lessonPromise, action, method;
    if (req.params.topicId) {
        action = '/courses/' + req.params.courseId + '/topics/' + req.params.topicId +
            (req.query.courseGroup ? '?courseGroup=' + req.query.courseGroup : '');
        method = 'patch';
        lessonPromise = api(req).get('/lessons/' + req.params.topicId);
    } else {
        action = '/courses/' + req.params.courseId + '/topics' +
            (req.query.courseGroup ? '?courseGroup=' + req.query.courseGroup : '');
        method = 'post';
        lessonPromise = Promise.resolve({});
    }

    lessonPromise.then(lesson => {
        if (lesson.contents) {
            // so we can share the content through data-value to the react component
            lesson.contents = JSON.stringify(lesson.contents);
        }

        res.render('topic/edit-topic', {
            action,
            method,
            title: req.params.topicId ? 'Thema bearbeiten' : 'Thema anlegen',
            submitLabel: req.params.topicId ? 'Änderungen speichern' : 'Thema anlegen',
            closeLabel: 'Abbrechen',
            lesson,
            courseId: req.params.courseId,
            courseGroupId: req.query.courseGroup,
            etherpadBaseUrl: etherpadBaseUrl
        });
    });
};

// secure routes
router.use(authHelper.authChecker);

router.get('/', (req, res, next) => {
    res.redirect('/courses/' + req.params.courseId);
});

router.get('/add', editTopicHandler);

router.post('/', function(req, res, next) {

    const data = req.body;

    // Check for neXboard compontent
    data.contents = createNewNexBoards(req, res, data.contents);

    data.time = moment(data.time || 0, 'HH:mm').toString();
    data.date = moment(data.date || 0, 'YYYY-MM-DD').toString();

    req.query.courseGroup ? delete data.courseId : delete data.courseGroupId;

    api(req).post('/lessons/', {
        json: data // TODO: sanitize
    }).then(_ => {
        res.redirect('/courses/' + req.params.courseId +
            (req.query.courseGroup ? '/groups/' + req.query.courseGroup : ''));
    }).catch(_ => {
        res.sendStatus(500);
    });
});

router.post('/:id/share', function(req, res, next) {
    // if lesson already has shareToken, do not generate a new one
    api(req).get('/lessons/' + req.params.id).then(topic => {
        topic.shareToken = topic.shareToken || shortId.generate();
        api(req).patch("/lessons/" + req.params.id, { json: topic })
            .then(result => res.json(result))
            .catch(err => { res.err(err); });
    });
});

router.get('/:topicId', function(req, res, next) {

    Promise.all([
        api(req).get('/courses/' + req.params.courseId),
        api(req).get('/lessons/' + req.params.topicId, {
            qs: {
                $populate: ['materialIds']
            }
        }),
        api(req).get('/homework/', {
            qs: {
                courseId: req.params.courseId,
                lessonId: req.params.topicId,
                $populate: ['courseId'],
                archived: { $ne: res.locals.currentUser._id }
            }
        }),
        req.query.courseGroup ?
        api(req).get('/courseGroups/' + req.query.courseGroup) :
        Promise.resolve({})
    ]).then(([course, lesson, homeworks, courseGroup]) => {
        // decorate contents
        lesson.contents = (lesson.contents || []).map(block => {
            block.component = 'topic/components/content-' + block.component;
            return block;
        });
        homeworks = (homeworks.data || []).map(assignment => {
            assignment.url = '/homework/' + assignment._id;
            return assignment;
        });
        homeworks.sort((a, b) => {
            if (a.dueDate > b.dueDate) {
                return 1;
            } else {
                return -1;
            }
        });
        res.render('topic/topic', Object.assign({}, lesson, {
            title: lesson.name,
            homeworks: homeworks.filter(function(task) { return !task.private; }),
            myhomeworks: homeworks.filter(function(task) { return task.private; }),
            courseId: req.params.courseId,
            isCourseGroupTopic: courseGroup._id !== undefined,
            breadcrumb: [{
                    title: 'Meine Kurse',
                    url: '/courses'
                },
                {
                    title: course.name,
                    url: '/courses/' + course._id
                },
                courseGroup._id ? {
                    title: courseGroup.name,
                    url: '/courses/' + course._id + '/groups/' + courseGroup._id
                } : {}
            ]
        }), (error, html) => {
            if (error) {
                throw 'error in GET /:topicId - res.render: ' + error;
            }
            res.send(html);
        });
    });
});

router.patch('/:topicId', function(req, res, next) {
    const data = req.body;
    data.time = moment(data.time || 0, 'HH:mm').toString();
    data.date = moment(data.date || 0, 'YYYY-MM-DD').toString();

    // if not a simple hidden or position patch, set contents to empty array
    if (!data.contents && !req.query.json) {
        data.contents = [];
    }

    req.query.courseGroup ? delete data.courseId : delete data.courseGroupId;

    // create new Nexboard when necessary
    data.contents = createNewNexBoards(req, res, data.contents);
    api(req).patch('/lessons/' + req.params.topicId, {
        json: data // TODO: sanitize
    }).then(_ => {
        if (req.query.json) {
            res.json(_);
        } else {
            //sends a GET request, not a PATCH
            res.redirect('/courses/' + req.params.courseId + '/topics/' + req.params.topicId +
                (req.query.courseGroup ? '?courseGroup=' + req.query.courseGroup : ''));
        }
    }).catch(_ => {
        res.sendStatus(500);
    });
});

router.delete('/:topicId', function(req, res, next) {
    api(req).delete('/lessons/' + req.params.topicId).then(_ => {
        res.sendStatus(200);
    }).catch(err => {
        next(err);
    });
});

router.delete('/:topicId/materials/:materialId', function(req, res, next) {
    api(req).patch('/lessons/' + req.params.topicId, {
        json: {
            $pull: {
                materialIds: req.params.materialId
            }
        }
    }).then(_ => {
        api(req).delete('/materials/' + req.params.materialId).then(_ => {
            res.sendStatus(200);
        });
    });
});

router.get('/:topicId/edit', editTopicHandler);

const createNewNexBoards = (req, res, contents = []) => {
    contents.forEach(content => {
        if (content.component === "neXboard" && content.content.board === '0') {
            const board = getNexBoardAPI().createBoard(
                content.content.title,
                content.content.description,
                getNexBoardProjectFromUser(req, res.locals.currentUser));
            content.content.title = board.title;
            content.content.board = board.boardId;
            content.content.url = "https://" + board.public_link;
            content.content.description = board.description;
        }
    });
    return contents;
};

const getNexBoardAPI = () => {
    if (!process.env.NEXBOARD_USER_ID && !process.env.NEXBOARD_API_KEY) {
        //TODO handle error properly

    }
    return new Nexboard(process.env.NEXBOARD_API_KEY, process.env.NEXBOARD_USER_ID);
};

const getNexBoardProjectFromUser = (req, user) => {
    const preferences = user.preferences || {};
    if (typeof preferences.nexBoardProjectID === 'undefined') {
        const project = getNexBoardAPI().createProject(user._id, user._id);
        preferences.nexBoardProjectID = project.id;
        api(req).patch('/users/' + user._id, { json: { preferences } });
    }
    return preferences.nexBoardProjectID;
};

const getNexBoards = (req, res, next) => {
    api(req).get('/lessons/contents/neXboard', {
            qs: {
                type: 'neXboard',
                user: res.locals.currentUser._id
            }
        })
        .then(boards => {
            res.json(boards);
        });
};

router.get('/:topicId/nexboard/boards', getNexBoards);

router.get('/nexboard/boards', getNexBoards);

module.exports = router;<commit_msg>fix topic moving bug (#572)<commit_after>const moment = require('moment');
const express = require('express');
const shortId = require('shortid');
const router = express.Router({ mergeParams: true });
const Nexboard = require("nexboard-api-js");
const api = require('../api');
const authHelper = require('../helpers/authentication');

const etherpadBaseUrl = process.env.ETHERPAD_BASE_URL || 'https://etherpad.schul-cloud.org/etherpad/p/';

const editTopicHandler = (req, res, next) => {
    let lessonPromise, action, method;
    if (req.params.topicId) {
        action = '/courses/' + req.params.courseId + '/topics/' + req.params.topicId +
            (req.query.courseGroup ? '?courseGroup=' + req.query.courseGroup : '');
        method = 'patch';
        lessonPromise = api(req).get('/lessons/' + req.params.topicId);
    } else {
        action = '/courses/' + req.params.courseId + '/topics' +
            (req.query.courseGroup ? '?courseGroup=' + req.query.courseGroup : '');
        method = 'post';
        lessonPromise = Promise.resolve({});
    }

    lessonPromise.then(lesson => {
        if (lesson.contents) {
            // so we can share the content through data-value to the react component
            lesson.contents = JSON.stringify(lesson.contents);
        }

        res.render('topic/edit-topic', {
            action,
            method,
            title: req.params.topicId ? 'Thema bearbeiten' : 'Thema anlegen',
            submitLabel: req.params.topicId ? 'Änderungen speichern' : 'Thema anlegen',
            closeLabel: 'Abbrechen',
            lesson,
            courseId: req.params.courseId,
            courseGroupId: req.query.courseGroup,
            etherpadBaseUrl: etherpadBaseUrl
        });
    });
};

// secure routes
router.use(authHelper.authChecker);

router.get('/', (req, res, next) => {
    res.redirect('/courses/' + req.params.courseId);
});

router.get('/add', editTopicHandler);

router.post('/', function(req, res, next) {

    const data = req.body;

    // Check for neXboard compontent
    data.contents = createNewNexBoards(req, res, data.contents);

    data.time = moment(data.time || 0, 'HH:mm').toString();
    data.date = moment(data.date || 0, 'YYYY-MM-DD').toString();

    req.query.courseGroup ? delete data.courseId : delete data.courseGroupId;

    api(req).post('/lessons/', {
        json: data // TODO: sanitize
    }).then(_ => {
        res.redirect('/courses/' + req.params.courseId +
            (req.query.courseGroup ? '/groups/' + req.query.courseGroup : ''));
    }).catch(_ => {
        res.sendStatus(500);
    });
});

router.post('/:id/share', function(req, res, next) {
    // if lesson already has shareToken, do not generate a new one
    api(req).get('/lessons/' + req.params.id).then(topic => {
        topic.shareToken = topic.shareToken || shortId.generate();
        api(req).patch("/lessons/" + req.params.id, { json: topic })
            .then(result => res.json(result))
            .catch(err => { res.err(err); });
    });
});

router.get('/:topicId', function(req, res, next) {

    Promise.all([
        api(req).get('/courses/' + req.params.courseId),
        api(req).get('/lessons/' + req.params.topicId, {
            qs: {
                $populate: ['materialIds']
            }
        }),
        api(req).get('/homework/', {
            qs: {
                courseId: req.params.courseId,
                lessonId: req.params.topicId,
                $populate: ['courseId'],
                archived: { $ne: res.locals.currentUser._id }
            }
        }),
        req.query.courseGroup ?
        api(req).get('/courseGroups/' + req.query.courseGroup) :
        Promise.resolve({})
    ]).then(([course, lesson, homeworks, courseGroup]) => {
        // decorate contents
        lesson.contents = (lesson.contents || []).map(block => {
            block.component = 'topic/components/content-' + block.component;
            return block;
        });
        homeworks = (homeworks.data || []).map(assignment => {
            assignment.url = '/homework/' + assignment._id;
            return assignment;
        });
        homeworks.sort((a, b) => {
            if (a.dueDate > b.dueDate) {
                return 1;
            } else {
                return -1;
            }
        });
        res.render('topic/topic', Object.assign({}, lesson, {
            title: lesson.name,
            homeworks: homeworks.filter(function(task) { return !task.private; }),
            myhomeworks: homeworks.filter(function(task) { return task.private; }),
            courseId: req.params.courseId,
            isCourseGroupTopic: courseGroup._id !== undefined,
            breadcrumb: [{
                    title: 'Meine Kurse',
                    url: '/courses'
                },
                {
                    title: course.name,
                    url: '/courses/' + course._id
                },
                courseGroup._id ? {
                    title: courseGroup.name,
                    url: '/courses/' + course._id + '/groups/' + courseGroup._id
                } : {}
            ]
        }), (error, html) => {
            if (error) {
                throw 'error in GET /:topicId - res.render: ' + error;
            }
            res.send(html);
        });
    });
});

router.patch('/:topicId', function(req, res, next) {
    const data = req.body;
    data.time = moment(data.time || 0, 'HH:mm').toString();
    data.date = moment(data.date || 0, 'YYYY-MM-DD').toString();

    // if not a simple hidden or position patch, set contents to empty array
    if (!data.contents && !req.query.json) {
        data.contents = [];
    }

    req.query.courseGroup ? delete data.courseId : delete data.courseGroupId;

    // create new Nexboard when necessary, if not simple hidden or position patch
    data.contents ? data.contents = createNewNexBoards(req, res, data.contents) : '';
    api(req).patch('/lessons/' + req.params.topicId, {
        json: data // TODO: sanitize
    }).then(_ => {
        if (req.query.json) {
            res.json(_);
        } else {
            //sends a GET request, not a PATCH
            res.redirect('/courses/' + req.params.courseId + '/topics/' + req.params.topicId +
                (req.query.courseGroup ? '?courseGroup=' + req.query.courseGroup : ''));
        }
    }).catch(_ => {
        res.sendStatus(500);
    });
});

router.delete('/:topicId', function(req, res, next) {
    api(req).delete('/lessons/' + req.params.topicId).then(_ => {
        res.sendStatus(200);
    }).catch(err => {
        next(err);
    });
});

router.delete('/:topicId/materials/:materialId', function(req, res, next) {
    api(req).patch('/lessons/' + req.params.topicId, {
        json: {
            $pull: {
                materialIds: req.params.materialId
            }
        }
    }).then(_ => {
        api(req).delete('/materials/' + req.params.materialId).then(_ => {
            res.sendStatus(200);
        });
    });
});

router.get('/:topicId/edit', editTopicHandler);

const createNewNexBoards = (req, res, contents = []) => {
    contents.forEach(content => {
        if (content.component === "neXboard" && content.content.board === '0') {
            const board = getNexBoardAPI().createBoard(
                content.content.title,
                content.content.description,
                getNexBoardProjectFromUser(req, res.locals.currentUser));
            content.content.title = board.title;
            content.content.board = board.boardId;
            content.content.url = "https://" + board.public_link;
            content.content.description = board.description;
        }
    });
    return contents;
};

const getNexBoardAPI = () => {
    if (!process.env.NEXBOARD_USER_ID && !process.env.NEXBOARD_API_KEY) {
        //TODO handle error properly

    }
    return new Nexboard(process.env.NEXBOARD_API_KEY, process.env.NEXBOARD_USER_ID);
};

const getNexBoardProjectFromUser = (req, user) => {
    const preferences = user.preferences || {};
    if (typeof preferences.nexBoardProjectID === 'undefined') {
        const project = getNexBoardAPI().createProject(user._id, user._id);
        preferences.nexBoardProjectID = project.id;
        api(req).patch('/users/' + user._id, { json: { preferences } });
    }
    return preferences.nexBoardProjectID;
};

const getNexBoards = (req, res, next) => {
    api(req).get('/lessons/contents/neXboard', {
            qs: {
                type: 'neXboard',
                user: res.locals.currentUser._id
            }
        })
        .then(boards => {
            res.json(boards);
        });
};

router.get('/:topicId/nexboard/boards', getNexBoards);

router.get('/nexboard/boards', getNexBoards);

module.exports = router;<|endoftext|>


<commit_before>var args = _.extend({
	duration: 2000,
	animationDuration: 250,
	message: '',
	title: Ti.App.name,
	elasticity: 0.5,
	pushForce: 30,
	usePhysicsEngine: true
}, arguments[0] || {});

var That = null;

exports.show = function(opt) {
	if (_.isObject(opt)) _.extend(args, opt);
	if (_.isString(opt)) _.extend(args, { message: opt });

	if (OS_ANDROID && args.view == null) {

		Ti.API.error("In Android you have to set a view that contain the sliding view. Fallbacking to Ti.UI.Notification.");

		That = Ti.UI.createNotification({
			message: args.message,
			duration: args.duration
		});

		That.show();

	} else {

		That = Widget.createController('window', args);

	}
};

exports.hide = function() {
	if (That != null) {
		That.hide();
	}
};

exports.setMessage = function(message) {
	That.setMessage(message);
};<commit_msg>Added setIcon function<commit_after>var args = _.extend({
	duration: 2000,
	animationDuration: 250,
	message: '',
	title: Ti.App.name,
	elasticity: 0.5,
	pushForce: 30,
	usePhysicsEngine: true
}, arguments[0] || {});

var That = null;

exports.show = function(opt) {
	if (_.isObject(opt)) _.extend(args, opt);
	if (_.isString(opt)) _.extend(args, { message: opt });

	if (OS_ANDROID && args.view == null) {

		Ti.API.error("In Android you have to set a view that contain the sliding view. Fallbacking to Ti.UI.Notification.");

		That = Ti.UI.createNotification({
			message: args.message,
			duration: args.duration
		});

		That.show();

	} else {

		That = Widget.createController('window', args);

	}
};

exports.hide = function() {
	if (That != null) {
		That.hide();
	}
};

exports.setMessage = function(message) {
	That.setMessage(message);
};

exports.setIcon = function(icon) {
	That.setIcon(icon);
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

/*
       Licensed to the Apache Software Foundation (ASF) under one
       or more contributor license agreements.  See the NOTICE file
       distributed with this work for additional information
       regarding copyright ownership.  The ASF licenses this file
       to you under the Apache License, Version 2.0 (the
       "License"); you may not use this file except in compliance
       with the License.  You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

       Unless required by applicable law or agreed to in writing,
       software distributed under the License is distributed on an
       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
       KIND, either express or implied.  See the License for the
       specific language governing permissions and limitations
       under the License.
*/

var exec  = require('./exec'),
    Q     = require('q'),
    os    = require('os'),
    build = require('./build'),
    appinfo = require('./appinfo');

/**
 * Returns a promise for the list of the device ID's found
 * @param lookHarder When true, try restarting adb if no devices are found.
 */
module.exports.list = function(lookHarder) {
    function helper() {
        return exec('adb devices', os.tmpdir())
        .then(function(output) {
            var response = output.split('\n');
            var device_list = [];
            for (var i = 1; i < response.length; i++) {
                if (response[i].match(/\w+\tdevice/) && !response[i].match(/emulator/)) {
                    device_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
                }
            }
            return device_list;
        });
    }
    return helper()
    .then(function(list) {
        if (list.length === 0 && lookHarder) {
            // adb kill-server doesn't seem to do the trick.
            // Could probably find a x-platform version of killall, but I'm not actually
            // sure that this scenario even happens on non-OSX machines.
            return exec('killall adb')
            .then(function() {
                console.log('Restarting adb to see if more devices are detected.');
                return helper();
            }, function() {
                // For non-killall OS's.
                return list;
            });
        }
        return list;
    });
};

module.exports.resolveTarget = function(target) {
    return this.list(true)
    .then(function(device_list) {
        if (!device_list || !device_list.length) {
            return Q.reject('ERROR: Failed to deploy to device, no devices found.');
        }
        // default device
        target = target || device_list[0];

        if (device_list.indexOf(target) < 0) {
            return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
        }

        return build.detectArchitecture(target)
        .then(function(arch) {
            return { target: target, arch: arch, isEmulator: false };
        });
    });
};

/*
 * Installs a previously built application on the device
 * and launches it.
 * Returns a promise.
 */
module.exports.install = function(target, buildResults) {
    return Q().then(function() {
        if (target && typeof target == 'object') {
            return target;
        }
        return module.exports.resolveTarget(target);
    }).then(function(resolvedTarget) {
        var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
        var launchName = appinfo.getActivityName();
        console.log('Using apk: ' + apk_path);
        console.log('Installing app on device...');
        var cmd = 'adb -s ' + resolvedTarget.target + ' install -r -d "' + apk_path + '"';
        return exec(cmd, os.tmpdir())
        .then(function(output) {
            if (output.match(/Failure/)) return Q.reject('ERROR: Failed to install apk to device: ' + output);

            //unlock screen
            var cmd = 'adb -s ' + resolvedTarget.target + ' shell input keyevent 82';
            return exec(cmd, os.tmpdir());
        }, function(err) { return Q.reject('ERROR: Failed to install apk to device: ' + err); })
        .then(function() {
            // launch the application
            console.log('Launching application...');
            var cmd = 'adb -s ' + resolvedTarget.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
            return exec(cmd, os.tmpdir());
        }).then(function() {
            console.log('LAUNCH SUCCESS');
        }, function(err) {
            return Q.reject('ERROR: Failed to launch application on device: ' + err);
        });
    });
};
<commit_msg>CB-9080: -d option is not supported on Android 4.1.1 and lower, removing<commit_after>#!/usr/bin/env node

/*
       Licensed to the Apache Software Foundation (ASF) under one
       or more contributor license agreements.  See the NOTICE file
       distributed with this work for additional information
       regarding copyright ownership.  The ASF licenses this file
       to you under the Apache License, Version 2.0 (the
       "License"); you may not use this file except in compliance
       with the License.  You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

       Unless required by applicable law or agreed to in writing,
       software distributed under the License is distributed on an
       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
       KIND, either express or implied.  See the License for the
       specific language governing permissions and limitations
       under the License.
*/

var exec  = require('./exec'),
    Q     = require('q'),
    os    = require('os'),
    build = require('./build'),
    appinfo = require('./appinfo');

/**
 * Returns a promise for the list of the device ID's found
 * @param lookHarder When true, try restarting adb if no devices are found.
 */
module.exports.list = function(lookHarder) {
    function helper() {
        return exec('adb devices', os.tmpdir())
        .then(function(output) {
            var response = output.split('\n');
            var device_list = [];
            for (var i = 1; i < response.length; i++) {
                if (response[i].match(/\w+\tdevice/) && !response[i].match(/emulator/)) {
                    device_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
                }
            }
            return device_list;
        });
    }
    return helper()
    .then(function(list) {
        if (list.length === 0 && lookHarder) {
            // adb kill-server doesn't seem to do the trick.
            // Could probably find a x-platform version of killall, but I'm not actually
            // sure that this scenario even happens on non-OSX machines.
            return exec('killall adb')
            .then(function() {
                console.log('Restarting adb to see if more devices are detected.');
                return helper();
            }, function() {
                // For non-killall OS's.
                return list;
            });
        }
        return list;
    });
};

module.exports.resolveTarget = function(target) {
    return this.list(true)
    .then(function(device_list) {
        if (!device_list || !device_list.length) {
            return Q.reject('ERROR: Failed to deploy to device, no devices found.');
        }
        // default device
        target = target || device_list[0];

        if (device_list.indexOf(target) < 0) {
            return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
        }

        return build.detectArchitecture(target)
        .then(function(arch) {
            return { target: target, arch: arch, isEmulator: false };
        });
    });
};

/*
 * Installs a previously built application on the device
 * and launches it.
 * Returns a promise.
 */
module.exports.install = function(target, buildResults) {
    return Q().then(function() {
        if (target && typeof target == 'object') {
            return target;
        }
        return module.exports.resolveTarget(target);
    }).then(function(resolvedTarget) {
        var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
        var launchName = appinfo.getActivityName();
        console.log('Using apk: ' + apk_path);
        console.log('Installing app on device...');
        var cmd = 'adb -s ' + resolvedTarget.target + ' install -r "' + apk_path + '"';
        return exec(cmd, os.tmpdir())
        .then(function(output) {
            if (output.match(/Failure/)) return Q.reject('ERROR: Failed to install apk to device: ' + output);

            //unlock screen
            var cmd = 'adb -s ' + resolvedTarget.target + ' shell input keyevent 82';
            return exec(cmd, os.tmpdir());
        }, function(err) { return Q.reject('ERROR: Failed to install apk to device: ' + err); })
        .then(function() {
            // launch the application
            console.log('Launching application...');
            var cmd = 'adb -s ' + resolvedTarget.target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
            return exec(cmd, os.tmpdir());
        }).then(function() {
            console.log('LAUNCH SUCCESS');
        }, function(err) {
            return Q.reject('ERROR: Failed to launch application on device: ' + err);
        });
    });
};
<|endoftext|>


<commit_before>/*eslint-env browser */
const ASCII_ENTER = 13;

var english = null;
var japanese = null;

var count = -1;
var remaining = -1;
var idx = -1;

var files = null;
var fileCounter = 0;
var wordCounter = 0;

var front = true;

function handleFileSelect(e) {
	wordCounter = 0;
	fileCounter = 0;
	english = [];
	japanese = [];
	files = e.target.files;
	var reader = new FileReader();

	reader.onload = function(e) {
		var text = reader.result;
		var strings = text.split("\r");
		for (var i = 0; i < strings.length / 2; i++) {
			english[wordCounter] = strings[i * 2].trim();
			japanese[wordCounter] = strings[(i * 2) + 1].trim();
			wordCounter++;
		}
		count = english.length;
		remaining = count;

		fileCounter++;

		if (fileCounter !== files.length) {
			reader.readAsText(files[fileCounter], "UTF-8");
		} else {
			document.getElementById("nextBtn").disabled = false;
			show();
		}
	};

	reader.readAsText(files[fileCounter], "UTF-8");
}

var enableKeyboard = true;

function showKeyboard() {
	enableKeyboard = !enableKeyboard;

	if (enableKeyboard) {
		document.getElementById("canvas").style.display = "inline";
	} else {
		document.getElementById("canvas").style.display = "none";
	}
}

document.getElementById('files').addEventListener('change', handleFileSelect, false);

function updateFlashCard() {
	var canvasFront = document.getElementById('canvasFront');
	var canvasBack = document.getElementById('canvasBack');
	var contextFront = canvasFront.getContext('2d');
	var contextBack = canvasBack.getContext('2d');

	if (front) {
		contextBack.clearRect(0, 0, canvasBack.width, canvasBack.height);

		var x = canvasFront.width / 2;
		var y = canvasFront.height / 2;

		contextFront.font = "30pt Calibri";
		contextFront.textAlign = "center";
		contextFront.textBaseline = "middle";
		contextFront.fillStyle = "white";
		contextFront.fillRect(0, 0, canvasFront.width, canvasFront.height);
		contextFront.fillStyle = "black";
		contextFront.fillText(japanese[idx], x, y);
	} else {
		contextFront.clearRect(0, 0, canvasFront.width, canvasFront.height);

		var x = canvasBack.width / 2;
		var y = canvasBack.height / 2;

		contextBack.font = "30pt Calibri";
		contextBack.textAlign = "center";
		contextBack.textBaseline = "middle";
		contextBack.fillStyle = "white";
		contextBack.fillRect(0, 0, canvasBack.width, canvasBack.height);
		contextBack.fillStyle = "black";
		contextBack.fillText(japanese[idx], x, y);
	}
}

function show() {
	idx = Math.floor(Math.random() * remaining);
	updateFlashCard();
	document.getElementById("remaining").innerHTML = "残り： " + remaining;
	document.getElementById("input").value = "";
}

function onClick() {
	if (document.getElementById("input").value === english[idx]) {
		remaining--;
		english[idx] = english[remaining];
		japanese[idx] = japanese[remaining];

		document.getElementById("mistake").innerHTML = "";

		if (remaining === 0) {
			alert("終わりました！");
			document.getElementById("front").innerHTML = "";
			document.getElementById("back").innerHTML = "";
			document.getElementById("remaining").innerHTML = "残り： 0";
			document.getElementById("nextBtn").disabled = true;
		} else {
			front = !front;
			show();

			var card = document.getElementById("card");
			if (card.className === "card") {
				card.className = "card flipped";
			} else {
				card.className = "card";
			}
		}
	} else {
		document.getElementById("mistake").innerHTML = "間違った！";
	}
}

function keyDownHandler(e) {
	if (e.keyCode === ASCII_ENTER && remaining !== 0) {
		onClick();
	}
}

document.addEventListener("keydown", keyDownHandler, false);<commit_msg>Clear the canvas instead of removing it when finished<commit_after>/*eslint-env browser */
const ASCII_ENTER = 13;

var english = null;
var japanese = null;

var count = -1;
var remaining = -1;
var idx = -1;

var files = null;
var fileCounter = 0;
var wordCounter = 0;

var front = true;

function handleFileSelect(e) {
	wordCounter = 0;
	fileCounter = 0;
	english = [];
	japanese = [];
	files = e.target.files;
	var reader = new FileReader();

	reader.onload = function(e) {
		var text = reader.result;
		var strings = text.split("\r");
		for (var i = 0; i < strings.length / 2; i++) {
			english[wordCounter] = strings[i * 2].trim();
			japanese[wordCounter] = strings[(i * 2) + 1].trim();
			wordCounter++;
		}
		count = english.length;
		remaining = count;

		fileCounter++;

		if (fileCounter !== files.length) {
			reader.readAsText(files[fileCounter], "UTF-8");
		} else {
			document.getElementById("nextBtn").disabled = false;
			show();
		}
	};

	reader.readAsText(files[fileCounter], "UTF-8");
}

var enableKeyboard = true;

function showKeyboard() {
	enableKeyboard = !enableKeyboard;

	if (enableKeyboard) {
		document.getElementById("canvas").style.display = "inline";
	} else {
		document.getElementById("canvas").style.display = "none";
	}
}

document.getElementById('files').addEventListener('change', handleFileSelect, false);

function updateFlashCard() {
	var canvasFront = document.getElementById('canvasFront');
	var canvasBack = document.getElementById('canvasBack');
	var contextFront = canvasFront.getContext('2d');
	var contextBack = canvasBack.getContext('2d');

	if (front) {
		contextBack.clearRect(0, 0, canvasBack.width, canvasBack.height);

		var x = canvasFront.width / 2;
		var y = canvasFront.height / 2;

		contextFront.font = "30pt Calibri";
		contextFront.textAlign = "center";
		contextFront.textBaseline = "middle";
		contextFront.fillStyle = "white";
		contextFront.fillRect(0, 0, canvasFront.width, canvasFront.height);
		contextFront.fillStyle = "black";
		contextFront.fillText(japanese[idx], x, y);
	} else {
		contextFront.clearRect(0, 0, canvasFront.width, canvasFront.height);

		var x = canvasBack.width / 2;
		var y = canvasBack.height / 2;

		contextBack.font = "30pt Calibri";
		contextBack.textAlign = "center";
		contextBack.textBaseline = "middle";
		contextBack.fillStyle = "white";
		contextBack.fillRect(0, 0, canvasBack.width, canvasBack.height);
		contextBack.fillStyle = "black";
		contextBack.fillText(japanese[idx], x, y);
	}
}

function show() {
	idx = Math.floor(Math.random() * remaining);
	updateFlashCard();
	document.getElementById("remaining").innerHTML = "残り： " + remaining;
	document.getElementById("input").value = "";
}

function onClick() {
	if (document.getElementById("input").value === english[idx]) {
		remaining--;
		english[idx] = english[remaining];
		japanese[idx] = japanese[remaining];

		document.getElementById("mistake").innerHTML = "";

		if (remaining === 0) {
			var canvas = document.getElementById("canvasFront");
			var ctx = canvas.getContext("2d");
			ctx.fillStyle = "white";
			ctx.fillRect(0, 0, canvas.width, canvas.height);

			canvas = document.getElementById("canvasBack");
			ctx = canvas.getContext("2d");
			ctx.fillStyle = "white";
			ctx.fillRect(0, 0, canvas.width, canvas.height);

			alert("終わりました！");
			document.getElementById("remaining").innerHTML = "残り： 0";
			document.getElementById("nextBtn").disabled = true;
		} else {
			front = !front;
			show();

			var card = document.getElementById("card");
			if (card.className === "card") {
				card.className = "card flipped";
			} else {
				card.className = "card";
			}
		}
	} else {
		document.getElementById("mistake").innerHTML = "間違った！";
	}
}

function keyDownHandler(e) {
	if (e.keyCode === ASCII_ENTER && remaining !== 0) {
		onClick();
	}
}

document.addEventListener("keydown", keyDownHandler, false);<|endoftext|>