<commit_before>/**
 Copyright 2014 Gordon Williams (gw@pur3.co.uk)

 This Source Code is subject to the terms of the Mozilla Public
 License, v2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.

 ------------------------------------------------------------------
  Utilities
 ------------------------------------------------------------------
**/
"use strict";
(function(){

  function init() {

  }

  function isWindows() {
    return navigator.userAgent.indexOf("Windows")>=0;
  }

  function getChromeVersion(){
    return parseInt(window.navigator.appVersion.match(/Chrome\/(.*?) /)[1].split(".")[0]);
  }

  function escapeHTML(text, escapeSpaces)
  {
    escapeSpaces = typeof escapeSpaces !== 'undefined' ? escapeSpaces : true;

    var chr = { '"': '"', '&': '&', '<': '<', '>': '>', ' ' : (escapeSpaces ? ' ' : ' ') };

    return text.toString().replace(/[\"&<> ]/g, function (a) { return chr[a]; });
  }

  /* Google Docs, forums, etc tend to break code by replacing characters with
  fancy unicode versions. Un-break the code by undoing these changes */
  function fixBrokenCode(text)
  {
    // make sure we ignore `` - which gets inserted
    // by the forum's code formatter
    text = text.replace(/\u00AD/g,'');
    // replace quotes that get auto-replaced by Google Docs and other editors
    text = text.replace(/[\u201c\u201d]/g,'"');
    text = text.replace(/[\u2018\u2019]/g,'\'');

    return text;
  }

  function getSubString(str, from, len) {
    if (len == undefined) {
      return str.substr(from, len);
    } else {
      var s = str.substr(from, len);
      while (s.length < len) s+=" ";
      return s;
    }
  };

  /** Get a Lexer to parse JavaScript - this is really very nasty right now and it doesn't lex even remotely properly.
   * It'll return {type:"type", str:"chars that were parsed", value:"string", startIdx: Index in string of the start, endIdx: Index in string of the end}, until EOF when it returns undefined */
  function getLexer(str) {
    // Nasty lexer - no comments/etc
    var chAlpha="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
    var chNum="0123456789";
    var chAlphaNum = chAlpha+chNum;
    var chWhiteSpace=" \t\n\r";
    var chQuotes = "\"'";
    var ch;
    var idx = 0;
    var lineNumber = 1;
    var nextCh = function() {
      ch = str[idx++];
      if (ch=="\n") lineNumber++;
    };
    nextCh();
    var isIn = function(s,c) { return s.indexOf(c)>=0; } ;
    var nextToken = function() {
      while (isIn(chWhiteSpace,ch)) {
        nextCh();
      }
      if (ch==undefined) return undefined;
      if (ch=="/") {
        nextCh();
        if (ch=="/") {
          // single line comment
          while (ch!==undefined && ch!="\n") nextCh();
          return nextToken();
        } else if (ch=="*") {
          nextCh();
          var last = ch;
          nextCh();
          // multiline comment
          while (ch!==undefined && !(last=="*" && ch=="/")) {
            last = ch;
            nextCh();
          }
          nextCh();
          return nextToken();
        }
        return {type:"CHAR", str:"/", value:"/", startIdx:idx-2, endIdx:idx-1, lineNumber:lineNumber};
      }
      var s = "";
      var type, value;
      var startIdx = idx-1;
      if (isIn(chAlpha,ch)) { // ID
        type = "ID";
        do {
          s+=ch;
          nextCh();
        } while (isIn(chAlphaNum,ch));
      } else if (isIn(chNum,ch)) { // NUMBER
        type = "NUMBER";
        do {
          s+=ch;
          nextCh();
        } while (isIn(chNum,ch) || ch==".")
      } else if (isIn(chQuotes,ch)) { // STRING
        type = "STRING";
        var q = ch;
        value = "";
        s+=ch;
        nextCh();
        while (ch!==undefined && ch!=q) {
          s+=ch;
          if (ch=="\\") {
            nextCh();
            // FIXME: handle hex/etc correctly here
          }
          value += ch;
          nextCh();
        };
        if (ch!==undefined) s+=ch;
        nextCh();
      } else {
        type = "CHAR";
        s+=ch;
        nextCh();
      }
      if (value===undefined) value=s;
      return {type:type, str:s, value:value, startIdx:startIdx, endIdx:idx-1, lineNumber:lineNumber};
    };

    return {
      next : nextToken
    };
  };

  /** Count brackets in a string - will be 0 if all are closed */
  function countBrackets(str) {
    var lex = getLexer(str);
    var brackets = 0;
    var tok = lex.next();
    while (tok!==undefined) {
      if (tok.str=="(" || tok.str=="{" || tok.str=="[") brackets++;
      if (tok.str==")" || tok.str=="}" || tok.str=="]") brackets--;
      tok = lex.next();
    }
    return brackets;
  }

  /** Try and get a prompt from Espruino - if we don't see one, issue Ctrl-C
   * and hope it comes back. Calls callback with first argument true if it
     had to Ctrl-C out */
  function getEspruinoPrompt(callback) {
    if (Espruino.Core.Terminal!==undefined &&
        Espruino.Core.Terminal.getTerminalLine()==">") {
      console.log("Found a prompt... great!");
      return callback();
    }

    var  receivedData = "";
    var prevReader = Espruino.Core.Serial.startListening(function (readData) {
      var bufView = new Uint8Array(readData);
      for(var i = 0; i < bufView.length; i++) {
        receivedData += String.fromCharCode(bufView[i]);
      }
      if (receivedData[receivedData.length-1] == ">") {
        console.log("Received a prompt after sending newline... good!");
        clearTimeout(timeout);
        nextStep();
      }
    });
    // timeout in case something goes wrong...
    var hadToBreak = false;
    var timeout = setTimeout(function() {
      console.log("Got "+JSON.stringify(receivedData));
      // if we haven't had the prompt displayed for us, Ctrl-C to break out of what we had
      console.log("No Prompt found, got "+JSON.stringify(receivedData[receivedData.length-1])+" - issuing Ctrl-C to try and break out");
      Espruino.Core.Serial.write('\x03');
      hadToBreak = true;
      nextStep();
    },500);
    // when we're done...
    var nextStep = function() {
      // send data to console anyway...
      prevReader(receivedData);
      receivedData = "";
      // start the previous reader listening again
      Espruino.Core.Serial.startListening(prevReader);
      // call our callback
      if (callback) callback(hadToBreak);
    };
    // send a newline, and we hope we'll see '=undefined\r\n>'
    Espruino.Core.Serial.write('\n');
  };

  /** Return the value of executing an expression on the board */
  function executeExpression(expressionToExecute, callback) {
    var receivedData = "";
    var hadDataSinceTimeout = false;

    function getProcessInfo(expressionToExecute, callback) {
      var prevReader = Espruino.Core.Serial.startListening(function (readData) {
        var bufView = new Uint8Array(readData);
        for(var i = 0; i < bufView.length; i++) {
          receivedData += String.fromCharCode(bufView[i]);
        }
        // check if we got what we wanted
        var startProcess = receivedData.indexOf("< <<");
        var endProcess = receivedData.indexOf(">> >", startProcess);
        if(startProcess >= 0 && endProcess > 0){
          // All good - get the data!
          var result = receivedData.substring(startProcess + 4,endProcess);
          console.log("Got "+JSON.stringify(receivedData));
          // strip out the text we found
          receivedData = receivedData.substr(0,startProcess) + receivedData.substr(endProcess+4);
          // Now stop time timeout
          clearInterval(timeout);
          // Do the next stuff
          nextStep(result);
        } else if (startProcess >= 0) {
          // we got some data - so keep waiting...
          hadDataSinceTimeout = true;
        }
      });

      // when we're done...
      var nextStep = function(result) {
        // start the previous reader listing again
        Espruino.Core.Serial.startListening(prevReader);
        // forward the original text to the previous reader
        prevReader(receivedData);
        // run the callback
        callback(result);
      };

      // Don't Ctrl-C, as we've already got ourselves a prompt with Espruino.Core.Utils.getEspruinoPrompt
      Espruino.Core.Serial.write('\x10console.log("<","<<",JSON.stringify('+expressionToExecute+'),">>",">")\n');

      var maxTimeout = 20; // 10 secs
      var timeoutCnt = 0;
      var timeout = setInterval(function onTimeout(){
        timeoutCnt++;
        // if we're still getting data, keep waiting for up to 10 secs
        if (hadDataSinceTimeout && timeoutCnt<maxTimeout) {
          hadDataSinceTimeout = false;
        } else if (timeoutCnt>2) {
          // No data in 1 second
          // OR we keep getting data for > maxTimeout seconds
          clearInterval(timeout);
          console.warn("No result found - just got "+JSON.stringify(receivedData));
          nextStep(undefined);
        }
      }, 500);
    }

    if(Espruino.Core.Serial.isConnected()){
      Espruino.Core.Utils.getEspruinoPrompt(function() {
        getProcessInfo(expressionToExecute, callback);
      });
    } else console.error("executeExpression called when not connected!");
  };

  function versionToFloat(version) {
    return parseFloat(version.trim().replace("v","."));
  };

  /** Make an HTML table out of a simple key/value object */
  function htmlTable(obj) {
    var html = '
';
    for (var key in obj) {
      html += '
'+Espruino.Core.Utils.escapeHTML(key)+'	'+Espruino.Core.Utils.escapeHTML(obj[key])+'
';
    }
    return html + '
';
  }

  function markdownToHTML(markdown) {
    var html = markdown;
    //console.log(JSON.stringify(html));
    html = html.replace(/\n\s*\n/g, "\n

\n"); // newlines
    html = html.replace(/\*\*(.*)\*\*/g, "$1"); // bold
    html = html.replace(/```(.*)```/g, "$1"); // code
    //console.log(JSON.stringify(html));
    return html;
  };

  /// Gets a URL, and returns callback(data) or callback(undefined) on error
  function getURL(url, callback) {
    Espruino.callProcessor("getURL", { url : url, data : undefined }, function(result) {
      if (result.data!==undefined) {
        callback(result.data);
      } else {
        if (typeof process === 'undefined') {
          // Web browser
          $.get( url, function(d) {
            callback(d);
          }, "text").error(function(xhr,status,err) {
            console.error(err);
            callback(undefined);
          });
        } else {
          // Node.js
          if (url.substr(0,4)=="http") {
            require("http").get(url, function(res) {
              if (res.statusCode != 200) {
                console.error("Espruino.Core.Utils.getURL: got HTTP status code "+res.statusCode+" for "+url);
                return callback(undefined);
              }
              var data = "";
              res.on("data", function(d) { data += d; });
              res.on("end", function() {
                callback(data);
              });
            }).on('error', function(err) {
              console.error(err);
              callback(undefined);
            });
          } else {
            require("fs").readFile(url, function(err, d) {
              if (err) {
                console.error(err);
                callback(undefined);
              } else
                callback(d.toString());
            });
          }
        }
      }
    });
  }

  /// Gets a URL as JSON, and returns callback(data) or callback(undefined) on error
  function getJSONURL(url, callback) {
    getURL(url, function(d) {
      if (!d) return callback(d);
      var j;
      try { j=JSON.parse(d); } catch (e) { console.error("Unable to parse JSON",d); }
      callback(j);
    });
  }

  function isURL(text) {
    return (new RegExp( '(http|https)://' )).test(text);
  }

  /* Are we served from a secure location so we're
   forced to use a secure get? */
  function needsHTTPS() {
    if (typeof window==="undefined" || !window.location) return false;
    return window.location.protocol=="https:";
  }

  Espruino.Core.Utils = {
      init : init,
      isWindows : isWindows,
      getChromeVersion : getChromeVersion,
      escapeHTML : escapeHTML,
      fixBrokenCode : fixBrokenCode,
      getSubString : getSubString,
      getLexer : getLexer,
      countBrackets : countBrackets,
      getEspruinoPrompt : getEspruinoPrompt,
      executeExpression : executeExpression,
      versionToFloat : versionToFloat,
      htmlTable : htmlTable,
      markdownToHTML : markdownToHTML,
      getURL : getURL,
      getJSONURL : getJSONURL,
      isURL : isURL,
      needsHTTPS : needsHTTPS
  };
}());
<commit_msg>handle ES6 tenplate literals<commit_after>/**
 Copyright 2014 Gordon Williams (gw@pur3.co.uk)

 This Source Code is subject to the terms of the Mozilla Public
 License, v2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.

 ------------------------------------------------------------------
  Utilities
 ------------------------------------------------------------------
**/
"use strict";
(function(){

  function init() {

  }

  function isWindows() {
    return navigator.userAgent.indexOf("Windows")>=0;
  }

  function getChromeVersion(){
    return parseInt(window.navigator.appVersion.match(/Chrome\/(.*?) /)[1].split(".")[0]);
  }

  function escapeHTML(text, escapeSpaces)
  {
    escapeSpaces = typeof escapeSpaces !== 'undefined' ? escapeSpaces : true;

    var chr = { '"': '"', '&': '&', '<': '<', '>': '>', ' ' : (escapeSpaces ? ' ' : ' ') };

    return text.toString().replace(/[\"&<> ]/g, function (a) { return chr[a]; });
  }

  /* Google Docs, forums, etc tend to break code by replacing characters with
  fancy unicode versions. Un-break the code by undoing these changes */
  function fixBrokenCode(text)
  {
    // make sure we ignore `` - which gets inserted
    // by the forum's code formatter
    text = text.replace(/\u00AD/g,'');
    // replace quotes that get auto-replaced by Google Docs and other editors
    text = text.replace(/[\u201c\u201d]/g,'"');
    text = text.replace(/[\u2018\u2019]/g,'\'');

    return text;
  }

  function getSubString(str, from, len) {
    if (len == undefined) {
      return str.substr(from, len);
    } else {
      var s = str.substr(from, len);
      while (s.length < len) s+=" ";
      return s;
    }
  };

  /** Get a Lexer to parse JavaScript - this is really very nasty right now and it doesn't lex even remotely properly.
   * It'll return {type:"type", str:"chars that were parsed", value:"string", startIdx: Index in string of the start, endIdx: Index in string of the end}, until EOF when it returns undefined */
  function getLexer(str) {
    // Nasty lexer - no comments/etc
    var chAlpha="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
    var chNum="0123456789";
    var chAlphaNum = chAlpha+chNum;
    var chWhiteSpace=" \t\n\r";
    var chQuotes = "\"'`";
    var ch;
    var idx = 0;
    var lineNumber = 1;
    var nextCh = function() {
      ch = str[idx++];
      if (ch=="\n") lineNumber++;
    };
    nextCh();
    var isIn = function(s,c) { return s.indexOf(c)>=0; } ;
    var nextToken = function() {
      while (isIn(chWhiteSpace,ch)) {
        nextCh();
      }
      if (ch==undefined) return undefined;
      if (ch=="/") {
        nextCh();
        if (ch=="/") {
          // single line comment
          while (ch!==undefined && ch!="\n") nextCh();
          return nextToken();
        } else if (ch=="*") {
          nextCh();
          var last = ch;
          nextCh();
          // multiline comment
          while (ch!==undefined && !(last=="*" && ch=="/")) {
            last = ch;
            nextCh();
          }
          nextCh();
          return nextToken();
        }
        return {type:"CHAR", str:"/", value:"/", startIdx:idx-2, endIdx:idx-1, lineNumber:lineNumber};
      }
      var s = "";
      var type, value;
      var startIdx = idx-1;
      if (isIn(chAlpha,ch)) { // ID
        type = "ID";
        do {
          s+=ch;
          nextCh();
        } while (isIn(chAlphaNum,ch));
      } else if (isIn(chNum,ch)) { // NUMBER
        type = "NUMBER";
        do {
          s+=ch;
          nextCh();
        } while (isIn(chNum,ch) || ch==".")
      } else if (isIn(chQuotes,ch)) { // STRING
        type = "STRING";
        var q = ch;
        value = "";
        s+=ch;
        nextCh();
        while (ch!==undefined && ch!=q) {
          s+=ch;
          if (ch=="\\") {
            nextCh();
            // FIXME: handle hex/etc correctly here
          }
          value += ch;
          nextCh();
        };
        if (ch!==undefined) s+=ch;
        nextCh();
      } else {
        type = "CHAR";
        s+=ch;
        nextCh();
      }
      if (value===undefined) value=s;
      return {type:type, str:s, value:value, startIdx:startIdx, endIdx:idx-1, lineNumber:lineNumber};
    };

    return {
      next : nextToken
    };
  };

  /** Count brackets in a string - will be 0 if all are closed */
  function countBrackets(str) {
    var lex = getLexer(str);
    var brackets = 0;
    var tok = lex.next();
    while (tok!==undefined) {
      if (tok.str=="(" || tok.str=="{" || tok.str=="[") brackets++;
      if (tok.str==")" || tok.str=="}" || tok.str=="]") brackets--;
      tok = lex.next();
    }
    return brackets;
  }

  /** Try and get a prompt from Espruino - if we don't see one, issue Ctrl-C
   * and hope it comes back. Calls callback with first argument true if it
     had to Ctrl-C out */
  function getEspruinoPrompt(callback) {
    if (Espruino.Core.Terminal!==undefined &&
        Espruino.Core.Terminal.getTerminalLine()==">") {
      console.log("Found a prompt... great!");
      return callback();
    }

    var  receivedData = "";
    var prevReader = Espruino.Core.Serial.startListening(function (readData) {
      var bufView = new Uint8Array(readData);
      for(var i = 0; i < bufView.length; i++) {
        receivedData += String.fromCharCode(bufView[i]);
      }
      if (receivedData[receivedData.length-1] == ">") {
        console.log("Received a prompt after sending newline... good!");
        clearTimeout(timeout);
        nextStep();
      }
    });
    // timeout in case something goes wrong...
    var hadToBreak = false;
    var timeout = setTimeout(function() {
      console.log("Got "+JSON.stringify(receivedData));
      // if we haven't had the prompt displayed for us, Ctrl-C to break out of what we had
      console.log("No Prompt found, got "+JSON.stringify(receivedData[receivedData.length-1])+" - issuing Ctrl-C to try and break out");
      Espruino.Core.Serial.write('\x03');
      hadToBreak = true;
      nextStep();
    },500);
    // when we're done...
    var nextStep = function() {
      // send data to console anyway...
      prevReader(receivedData);
      receivedData = "";
      // start the previous reader listening again
      Espruino.Core.Serial.startListening(prevReader);
      // call our callback
      if (callback) callback(hadToBreak);
    };
    // send a newline, and we hope we'll see '=undefined\r\n>'
    Espruino.Core.Serial.write('\n');
  };

  /** Return the value of executing an expression on the board */
  function executeExpression(expressionToExecute, callback) {
    var receivedData = "";
    var hadDataSinceTimeout = false;

    function getProcessInfo(expressionToExecute, callback) {
      var prevReader = Espruino.Core.Serial.startListening(function (readData) {
        var bufView = new Uint8Array(readData);
        for(var i = 0; i < bufView.length; i++) {
          receivedData += String.fromCharCode(bufView[i]);
        }
        // check if we got what we wanted
        var startProcess = receivedData.indexOf("< <<");
        var endProcess = receivedData.indexOf(">> >", startProcess);
        if(startProcess >= 0 && endProcess > 0){
          // All good - get the data!
          var result = receivedData.substring(startProcess + 4,endProcess);
          console.log("Got "+JSON.stringify(receivedData));
          // strip out the text we found
          receivedData = receivedData.substr(0,startProcess) + receivedData.substr(endProcess+4);
          // Now stop time timeout
          clearInterval(timeout);
          // Do the next stuff
          nextStep(result);
        } else if (startProcess >= 0) {
          // we got some data - so keep waiting...
          hadDataSinceTimeout = true;
        }
      });

      // when we're done...
      var nextStep = function(result) {
        // start the previous reader listing again
        Espruino.Core.Serial.startListening(prevReader);
        // forward the original text to the previous reader
        prevReader(receivedData);
        // run the callback
        callback(result);
      };

      // Don't Ctrl-C, as we've already got ourselves a prompt with Espruino.Core.Utils.getEspruinoPrompt
      Espruino.Core.Serial.write('\x10console.log("<","<<",JSON.stringify('+expressionToExecute+'),">>",">")\n');

      var maxTimeout = 20; // 10 secs
      var timeoutCnt = 0;
      var timeout = setInterval(function onTimeout(){
        timeoutCnt++;
        // if we're still getting data, keep waiting for up to 10 secs
        if (hadDataSinceTimeout && timeoutCnt<maxTimeout) {
          hadDataSinceTimeout = false;
        } else if (timeoutCnt>2) {
          // No data in 1 second
          // OR we keep getting data for > maxTimeout seconds
          clearInterval(timeout);
          console.warn("No result found - just got "+JSON.stringify(receivedData));
          nextStep(undefined);
        }
      }, 500);
    }

    if(Espruino.Core.Serial.isConnected()){
      Espruino.Core.Utils.getEspruinoPrompt(function() {
        getProcessInfo(expressionToExecute, callback);
      });
    } else console.error("executeExpression called when not connected!");
  };

  function versionToFloat(version) {
    return parseFloat(version.trim().replace("v","."));
  };

  /** Make an HTML table out of a simple key/value object */
  function htmlTable(obj) {
    var html = '
';
    for (var key in obj) {
      html += '
'+Espruino.Core.Utils.escapeHTML(key)+'	'+Espruino.Core.Utils.escapeHTML(obj[key])+'
';
    }
    return html + '
';
  }

  function markdownToHTML(markdown) {
    var html = markdown;
    //console.log(JSON.stringify(html));
    html = html.replace(/\n\s*\n/g, "\n

\n"); // newlines
    html = html.replace(/\*\*(.*)\*\*/g, "$1"); // bold
    html = html.replace(/```(.*)```/g, "$1"); // code
    //console.log(JSON.stringify(html));
    return html;
  };

  /// Gets a URL, and returns callback(data) or callback(undefined) on error
  function getURL(url, callback) {
    Espruino.callProcessor("getURL", { url : url, data : undefined }, function(result) {
      if (result.data!==undefined) {
        callback(result.data);
      } else {
        if (typeof process === 'undefined') {
          // Web browser
          $.get( url, function(d) {
            callback(d);
          }, "text").error(function(xhr,status,err) {
            console.error(err);
            callback(undefined);
          });
        } else {
          // Node.js
          if (url.substr(0,4)=="http") {
            require("http").get(url, function(res) {
              if (res.statusCode != 200) {
                console.error("Espruino.Core.Utils.getURL: got HTTP status code "+res.statusCode+" for "+url);
                return callback(undefined);
              }
              var data = "";
              res.on("data", function(d) { data += d; });
              res.on("end", function() {
                callback(data);
              });
            }).on('error', function(err) {
              console.error(err);
              callback(undefined);
            });
          } else {
            require("fs").readFile(url, function(err, d) {
              if (err) {
                console.error(err);
                callback(undefined);
              } else
                callback(d.toString());
            });
          }
        }
      }
    });
  }

  /// Gets a URL as JSON, and returns callback(data) or callback(undefined) on error
  function getJSONURL(url, callback) {
    getURL(url, function(d) {
      if (!d) return callback(d);
      var j;
      try { j=JSON.parse(d); } catch (e) { console.error("Unable to parse JSON",d); }
      callback(j);
    });
  }

  function isURL(text) {
    return (new RegExp( '(http|https)://' )).test(text);
  }

  /* Are we served from a secure location so we're
   forced to use a secure get? */
  function needsHTTPS() {
    if (typeof window==="undefined" || !window.location) return false;
    return window.location.protocol=="https:";
  }

  Espruino.Core.Utils = {
      init : init,
      isWindows : isWindows,
      getChromeVersion : getChromeVersion,
      escapeHTML : escapeHTML,
      fixBrokenCode : fixBrokenCode,
      getSubString : getSubString,
      getLexer : getLexer,
      countBrackets : countBrackets,
      getEspruinoPrompt : getEspruinoPrompt,
      executeExpression : executeExpression,
      versionToFloat : versionToFloat,
      htmlTable : htmlTable,
      markdownToHTML : markdownToHTML,
      getURL : getURL,
      getJSONURL : getJSONURL,
      isURL : isURL,
      needsHTTPS : needsHTTPS
  };
}());
<|endoftext|>


<commit_before>/*jshint esversion: 6 */
(function() {
  'use strict';

  const util = require('util');
  const moment = require('moment');
  const _ = require('lodash');
  const cheerio = require('cheerio');

  const EVENT_COUNT = 9;
  const JOB_COUNT = 5;
  const ANNOUNCEMENT_COUNT = 5;
  const ANNOUNCEMENT_COUNT_PAGE = 10;
  const SOCIAL_MEDIA_POSTS = 4 * 3;
  const CONTENT_FOLDER = '/sisalto';
  const NEWS_FOLDER = '/uutiset';
  const ANNOUNCEMENTS_FOLDER = '/kuulutukset';

  function resolveLinkType(link) {
    if (!link || link.startsWith('#')) {
      return 'NONE';
    }

    if (link.startsWith('/')) {
      return 'PATH';
    } else if (link.match(/[a-zA-Z]*:\/\/.*/)) {
      return 'ABSOLUTE';
    }

    return 'RELATIVE';
  }

  function processLink(currentPage, text) {
    if (!text) {
      return null;
    }

    var link = text.trim();
    if (!link) {
      return null;
    }

    switch (resolveLinkType(link)) {
      case 'PATH':
        return util.format('%s%s', CONTENT_FOLDER, link);
      case 'RELATIVE':
        return util.format('%s/%s', currentPage.split('/').splice(-1), link);
      default:
    }

    return link;
  }

  function processPageContent(currentPage, content) {
    if (!content) {
      return '';
    }

    const $ = cheerio.load(content);

    $('a[href]').each(function(index, link) {
      var href = $(link).attr('href');
      $(link).attr('href', processLink(currentPage, href));
    });

    $('aside').remove();

    return $.html();
  }

  function getSidebarContent(content) {
    if (!content) {
      return '';
    }

    const $ = cheerio.load(content);
    return $('aside').html();
  }

  module.exports = function(app, config, ModulesClass) {

    function loadChildPages(pages, preferLanguages, callback) {
      var module = new ModulesClass(config);

      pages.forEach((page) => {
        if (!page.meta || !page.meta.hideMenuChildren) {
          module.pages.listMetaByParentId(page.id, preferLanguages);
        }
      });

      module.callback(function (data) {
        var index = 0;
        pages.forEach((page) => {
          if (!page.meta || !page.meta.hideMenuChildren) {
            pages[index].hasChildren = data[index] && data[index].length > 0;
            index++;
          }
        });

        callback(pages);
      });
    }

    app.use(function(req, res, next) {
      var modules = new ModulesClass(config);

      modules.menus.list()
        .callback(function(data) {
          var menus = data[0];

          _.keys(menus).forEach(menuKey => {
            var menu = menus[menuKey];

            menu.items = menu.items.map(item => {
              if (item.url) {
                item.url = processLink(null, item.url);
              }

              return item;
            });
          });

          req.kuntaApi = {
            data: {
              menus: menus
            }
          };

          next();
        }, function(err) {
       	  console.error(err);
          res.status(500).send(err);
        });
    });

    app.get('/', function(req, res) {
      new ModulesClass(config)
        .events.latest(EVENT_COUNT)
        .news.latest(0, 9)
        .banners.list()
        .tiles.list()
        .socialMedia.latest(SOCIAL_MEDIA_POSTS)
        .jobs.list(JOB_COUNT, 'PUBLICATION_END', 'ASCENDING')
        .announcements.list(ANNOUNCEMENT_COUNT, 'PUBLICATION_DATE', 'DESCENDING')
        .callback(function(data) {
          var events = _.clone(data[0] || []).map(event => {
            return Object.assign(event, {
              "shortDate": moment(event.start).format("D/M")
            });
          });

          var news = _.clone(data[1]).map(newsArticle => {
            return Object.assign(newsArticle, {
              "shortDate": moment(newsArticle.published).format("D.M.YYYY")
            });
          });

          var banners = _.clone(data[2] || []).map(banner => {
            return Object.assign(banner, {
              imageSrc: banner.imageSrc ? banner.imageSrc : '/gfx/layout/mikkeli-banner-default.jpg'
            });
          });

          var tiles = _.clone(data[3] || []).map(tile => {
            return Object.assign(tile, {
              imageSrc: tile.imageSrc ? tile.imageSrc : '/gfx/layout/mikkeli-tile-default.jpg'
            });
          });

          var socialMediaItems = _.clone(data[4] || []).map(socialMediaItem => {
            return Object.assign(socialMediaItem, {
              "shortDate": moment(socialMediaItem.created).format("D.M.YYYY hh:mm")
            });
          });

          var jobs = _.clone(data[5] || []);
          var announcements = _.clone(data[6] || []).map(announcement => {
            return Object.assign(announcement, {
              "shortDate": moment(announcement.published).format("D.M.YYYY")
            });
          });

          res.render('pages/index.pug', {
            events: events,
            banners: banners,
            tiles: tiles,
            socialMediaItems: socialMediaItems,
            jobs: jobs,
            announcements: announcements,
            news: {
              top: news.splice(0, 1)[0],
              thumbs: news.splice(0, 4),
              texts: news
            },
            menus: req.kuntaApi.data.menus
          });

        }, function(err) {
          console.error(err);
          res.status(500).send(err);
        });
    });

    app.get('/redirect/:type/:id', function (req, res) {
      var type = req.params.type;
      var id = req.params.id;

      if (type !== 'page') {
        res.status(400).send('Invalid type');
      }

      new ModulesClass(config)
        .pages.resolvePath(id)
        .callback((data) => {
          if (data) {
            res.redirect(util.format("%s/%s", CONTENT_FOLDER, data));
          } else {
            res.redirect('/');
          }
        });
    });

    app.get('/ajax/pagenav', function (req, res) {
      var pageId = req.query.pageId;
      var preferLanguages = req.headers['accept-language'];

      new ModulesClass(config)
        .pages.listMetaByParentId(pageId, preferLanguages)
        .callback(function(data) {
          loadChildPages(data[0], preferLanguages, (children) => {
            res.render('ajax/pagenav.pug', {
              childPages: children,
              activeIds: []
            });
          });
        });
    });

    app.get('/ajax/search', function (req, res) {
      var search = req.query.search;
      var preferLanguages = req.headers['accept-language'];

      new ModulesClass(config)
        .pages.search(search, preferLanguages)
        .files.search(search, preferLanguages)
        .callback(function(data) {
          var pages = data[0];
          var files = data[1];

          console.log(files);

          res.render('ajax/search.pug', {
            pages: pages,
            files: files
          });
        });
    });

    function mapOpenChildren(children, activeIds, openTreeNodes) {
      if (openTreeNodes.length > 0) {
        for (var i = 0; i < children.length; i++) {
          if (activeIds.indexOf(children[i].id) != -1) {
            children[i].children = openTreeNodes.shift();
            mapOpenChildren(children[i].children, activeIds, openTreeNodes);
            break;
          }
        }
      }

      return children;
    }

    app.get(util.format('%s*', CONTENT_FOLDER), function(req, res) {
      var path = req.path.substring(9);
      var rootPath = path.split('/')[0];
      var preferLanguages = req.headers['accept-language'];

      new ModulesClass(config)
        .pages.findByPath(path, preferLanguages)
        .pages.findByPath(rootPath, preferLanguages)
        .callback(function(data) {
          var page = data[0];
          var rootPage = data[1];
          if (!page || !rootPage) {
            res.status(404).send("Not Found");
            return;
          }

          new ModulesClass(config)
            .pages.getContent(page.id, preferLanguages)
            .pages.resolveBreadcrumbs(CONTENT_FOLDER, page, preferLanguages)
            .pages.listMetaByParentId(rootPage.id, preferLanguages)
            .pages.readMenuTree(rootPage.id, page.parentId, preferLanguages)
            .callback(function(pageData) {
              var contents = pageData[0];
              var breadcrumbs = pageData[1];
              var rootFolderTitle = rootPage.title;
              var featuredImageSrc = page.featuredImageSrc ? page.featuredImageSrc : '/gfx/layout/mikkeli-page-image-default.jpg';
              // TODO: Banner should come from API
              var bannerSrc = '/gfx/layout/mikkeli-page-banner-default.jpg';
              var openTreeNodes = pageData[3];
              var activeIds = _.map(breadcrumbs, (breadcrumb) => {
                return breadcrumb.id;
              });

              loadChildPages(pageData[2], preferLanguages, (children) => {
                res.render('pages/contents.pug', {
                  id: page.id,
                  slug: page.slug,
                  rootPath: util.format("%s/%s", CONTENT_FOLDER, rootPath),
                  title: page.title,
                  rootFolderTitle: rootFolderTitle,
                  contents: processPageContent(path, contents),
                  sidebarContents: getSidebarContent(contents),
                  breadcrumbs: breadcrumbs,
                  featuredImageSrc: featuredImageSrc,
                  menus: req.kuntaApi.data.menus,
                  activeIds: activeIds,
                  children: mapOpenChildren(children, activeIds, openTreeNodes),
                  openTreeNodes: openTreeNodes,
                  bannerSrc: bannerSrc
                });
              });

            }, function(contentErr) {
              console.error(contentErr);
              res.status(500).send(contentErr);
            });

        }, function(err) {
          console.error(err);
          res.status(500).send(err);
        });
    });

    app.get(util.format('%s/:slug', NEWS_FOLDER), function(req, res) {
      var slug = req.params.slug;

      if (!slug) {
        res.status(404).send('Not found');
        return;
      }

      new ModulesClass(config)
        .news.latest(0, 10)
        .news.findBySlug(slug)
        .callback(function(data) {
          var newsArticle = data[1];
          var siblings = data[0];
          if (!newsArticle) {
            res.status(404).send("Not Found");
            return;
          }
          // TODO: Banner should come from API
          var bannerSrc = '/gfx/layout/mikkeli-page-banner-default.jpg';

           res.render('pages/news-article.pug', {
            id: newsArticle.id,
            slug: newsArticle.slug,
            title: newsArticle.title,
            contents: processPageContent('/', newsArticle.contents),
            sidebarContents: getSidebarContent(newsArticle.contents),
            imageSrc: newsArticle.imageSrc,
            menus: req.kuntaApi.data.menus,
            bannerSrc: bannerSrc,
            siblings: siblings,
            breadcrumbs : [{path: util.format('%s/%s', NEWS_FOLDER, newsArticle.slug), title: newsArticle.title }]
          });

        }, function(err) {
          console.error(err);
          res.status(500).send(err);
        });
    });

    app.get(util.format('%s/:slug', ANNOUNCEMENTS_FOLDER), function(req, res) {
      var slug = req.params.slug;

      if (!slug) {
        res.status(404).send('Not found');
        return;
      }

        new ModulesClass(config)
        .announcements.list(ANNOUNCEMENT_COUNT_PAGE, 'PUBLICATION_DATE', 'DESCENDING')
        .announcements.findBySlug(slug)
        .callback(function(data) {
          var announcement = data[1];
          var siblings = data[0];
          if (!announcement) {
            res.status(404).send("Not Found");
            return;
          }
          // TODO: Banner should come from API
          var bannerSrc = '/gfx/layout/mikkeli-page-banner-default.jpg';

           res.render('pages/announcement.pug', {
            id: announcement.id,
            slug: announcement.slug,
            title: announcement.title,
            contents: processPageContent('/', announcement.contents),
            sidebarContents: getSidebarContent(announcement.contents),
            menus: req.kuntaApi.data.menus,
            bannerSrc: bannerSrc,
            siblings: siblings,
            breadcrumbs : [{path: util.format('%s/%s', ANNOUNCEMENTS_FOLDER, announcement.slug), title: announcement.title }]
          });

        }, function(err) {
          console.error(err);
          res.status(500).send(err);
        });
    });

  };

}).call(this);<commit_msg>Fixed file downloading from autocomplete search<commit_after>/*jshint esversion: 6 */
(function() {
  'use strict';

  const util = require('util');
  const moment = require('moment');
  const _ = require('lodash');
  const cheerio = require('cheerio');

  const EVENT_COUNT = 9;
  const JOB_COUNT = 5;
  const ANNOUNCEMENT_COUNT = 5;
  const ANNOUNCEMENT_COUNT_PAGE = 10;
  const SOCIAL_MEDIA_POSTS = 4 * 3;
  const FILES_FOLDER = '/tiedostot';
  const CONTENT_FOLDER = '/sisalto';
  const NEWS_FOLDER = '/uutiset';
  const ANNOUNCEMENTS_FOLDER = '/kuulutukset';

  function resolveLinkType(link) {
    if (!link || link.startsWith('#')) {
      return 'NONE';
    }

    if (link.startsWith('/')) {
      return 'PATH';
    } else if (link.match(/[a-zA-Z]*:\/\/.*/)) {
      return 'ABSOLUTE';
    }

    return 'RELATIVE';
  }

  function processLink(currentPage, text) {
    if (!text) {
      return null;
    }

    var link = text.trim();
    if (!link) {
      return null;
    }

    switch (resolveLinkType(link)) {
      case 'PATH':
        return util.format('%s%s', CONTENT_FOLDER, link);
      case 'RELATIVE':
        return util.format('%s/%s', currentPage.split('/').splice(-1), link);
      default:
    }

    return link;
  }

  function processPageContent(currentPage, content) {
    if (!content) {
      return '';
    }

    const $ = cheerio.load(content);

    $('a[href]').each(function(index, link) {
      var href = $(link).attr('href');
      $(link).attr('href', processLink(currentPage, href));
    });

    $('aside').remove();

    return $.html();
  }

  function getSidebarContent(content) {
    if (!content) {
      return '';
    }

    const $ = cheerio.load(content);
    return $('aside').html();
  }

  module.exports = function(app, config, ModulesClass) {

    function loadChildPages(pages, preferLanguages, callback) {
      var module = new ModulesClass(config);

      pages.forEach((page) => {
        if (!page.meta || !page.meta.hideMenuChildren) {
          module.pages.listMetaByParentId(page.id, preferLanguages);
        }
      });

      module.callback(function (data) {
        var index = 0;
        pages.forEach((page) => {
          if (!page.meta || !page.meta.hideMenuChildren) {
            pages[index].hasChildren = data[index] && data[index].length > 0;
            index++;
          }
        });

        callback(pages);
      });
    }

    app.use(function(req, res, next) {
      var modules = new ModulesClass(config);

      modules.menus.list()
        .callback(function(data) {
          var menus = data[0];

          _.keys(menus).forEach(menuKey => {
            var menu = menus[menuKey];

            menu.items = menu.items.map(item => {
              if (item.url) {
                item.url = processLink(null, item.url);
              }

              return item;
            });
          });

          req.kuntaApi = {
            data: {
              menus: menus
            }
          };

          next();
        }, function(err) {
       	  console.error(err);
          res.status(500).send(err);
        });
    });

    app.get('/', function(req, res) {
      new ModulesClass(config)
        .events.latest(EVENT_COUNT)
        .news.latest(0, 9)
        .banners.list()
        .tiles.list()
        .socialMedia.latest(SOCIAL_MEDIA_POSTS)
        .jobs.list(JOB_COUNT, 'PUBLICATION_END', 'ASCENDING')
        .announcements.list(ANNOUNCEMENT_COUNT, 'PUBLICATION_DATE', 'DESCENDING')
        .callback(function(data) {
          var events = _.clone(data[0] || []).map(event => {
            return Object.assign(event, {
              "shortDate": moment(event.start).format("D/M")
            });
          });

          var news = _.clone(data[1]).map(newsArticle => {
            return Object.assign(newsArticle, {
              "shortDate": moment(newsArticle.published).format("D.M.YYYY")
            });
          });

          var banners = _.clone(data[2] || []).map(banner => {
            return Object.assign(banner, {
              imageSrc: banner.imageSrc ? banner.imageSrc : '/gfx/layout/mikkeli-banner-default.jpg'
            });
          });

          var tiles = _.clone(data[3] || []).map(tile => {
            return Object.assign(tile, {
              imageSrc: tile.imageSrc ? tile.imageSrc : '/gfx/layout/mikkeli-tile-default.jpg'
            });
          });

          var socialMediaItems = _.clone(data[4] || []).map(socialMediaItem => {
            return Object.assign(socialMediaItem, {
              "shortDate": moment(socialMediaItem.created).format("D.M.YYYY hh:mm")
            });
          });

          var jobs = _.clone(data[5] || []);
          var announcements = _.clone(data[6] || []).map(announcement => {
            return Object.assign(announcement, {
              "shortDate": moment(announcement.published).format("D.M.YYYY")
            });
          });

          res.render('pages/index.pug', {
            events: events,
            banners: banners,
            tiles: tiles,
            socialMediaItems: socialMediaItems,
            jobs: jobs,
            announcements: announcements,
            news: {
              top: news.splice(0, 1)[0],
              thumbs: news.splice(0, 4),
              texts: news
            },
            menus: req.kuntaApi.data.menus
          });

        }, function(err) {
          console.error(err);
          res.status(500).send(err);
        });
    });

    app.get('/redirect/:type/:id', function (req, res) {
      var type = req.params.type;
      var id = req.params.id;

      switch (type) {
        case 'page':
          new ModulesClass(config)
            .pages.resolvePath(id)
            .callback((data) => {
              if (data) {
                res.redirect(util.format("%s/%s", CONTENT_FOLDER, data));
              } else {
                res.redirect('/');
              }
            });
        break;
        case 'file':
          res.redirect(util.format("%s/%s", FILES_FOLDER, id));
        break;
        default:
          res.status(400).send('Invalid type');
        break;
      }
    });

    app.get(util.format('%s/:id', FILES_FOLDER), function(req, res) {
      var id = req.params.id;
      if (!id) {
        res.status(404).send('Not found');
        return;
      }

      new ModulesClass(config)
        .files.findById(id)
        .files.streamData(id)
        .callback((result) => {
          var file = result[0];
          var stream = result[1];

          if (file && stream) {
            res
              .set('Content-Length', file.size)
              .set('Content-Type', file.contentType)
              .set("content-disposition", util.format("attachment; filename=%s", file.slug))
            stream.pipe(res);
          } else {
            res.status(500).send("Tiedoston lataus epäonnistui");
          }
        });
    });

    app.get('/ajax/pagenav', function (req, res) {
      var pageId = req.query.pageId;
      var preferLanguages = req.headers['accept-language'];

      new ModulesClass(config)
        .pages.listMetaByParentId(pageId, preferLanguages)
        .callback(function(data) {
          loadChildPages(data[0], preferLanguages, (children) => {
            res.render('ajax/pagenav.pug', {
              childPages: children,
              activeIds: []
            });
          });
        });
    });

    app.get('/ajax/search', function (req, res) {
      var search = req.query.search;
      var preferLanguages = req.headers['accept-language'];

      new ModulesClass(config)
        .pages.search(search, preferLanguages)
        .files.search(search, preferLanguages)
        .callback(function(data) {
          var pages = data[0];
          var files = data[1];

          res.render('ajax/search.pug', {
            pages: pages,
            files: files
          });
        });
    });

    function mapOpenChildren(children, activeIds, openTreeNodes) {
      if (openTreeNodes.length > 0) {
        for (var i = 0; i < children.length; i++) {
          if (activeIds.indexOf(children[i].id) != -1) {
            children[i].children = openTreeNodes.shift();
            mapOpenChildren(children[i].children, activeIds, openTreeNodes);
            break;
          }
        }
      }

      return children;
    }

    app.get(util.format('%s*', CONTENT_FOLDER), function(req, res) {
      var path = req.path.substring(9);
      var rootPath = path.split('/')[0];
      var preferLanguages = req.headers['accept-language'];

      new ModulesClass(config)
        .pages.findByPath(path, preferLanguages)
        .pages.findByPath(rootPath, preferLanguages)
        .callback(function(data) {
          var page = data[0];
          var rootPage = data[1];
          if (!page || !rootPage) {
            res.status(404).send("Not Found");
            return;
          }

          new ModulesClass(config)
            .pages.getContent(page.id, preferLanguages)
            .pages.resolveBreadcrumbs(CONTENT_FOLDER, page, preferLanguages)
            .pages.listMetaByParentId(rootPage.id, preferLanguages)
            .pages.readMenuTree(rootPage.id, page.parentId, preferLanguages)
            .callback(function(pageData) {
              var contents = pageData[0];
              var breadcrumbs = pageData[1];
              var rootFolderTitle = rootPage.title;
              var featuredImageSrc = page.featuredImageSrc ? page.featuredImageSrc : '/gfx/layout/mikkeli-page-image-default.jpg';
              // TODO: Banner should come from API
              var bannerSrc = '/gfx/layout/mikkeli-page-banner-default.jpg';
              var openTreeNodes = pageData[3];
              var activeIds = _.map(breadcrumbs, (breadcrumb) => {
                return breadcrumb.id;
              });

              loadChildPages(pageData[2], preferLanguages, (children) => {
                res.render('pages/contents.pug', {
                  id: page.id,
                  slug: page.slug,
                  rootPath: util.format("%s/%s", CONTENT_FOLDER, rootPath),
                  title: page.title,
                  rootFolderTitle: rootFolderTitle,
                  contents: processPageContent(path, contents),
                  sidebarContents: getSidebarContent(contents),
                  breadcrumbs: breadcrumbs,
                  featuredImageSrc: featuredImageSrc,
                  menus: req.kuntaApi.data.menus,
                  activeIds: activeIds,
                  children: mapOpenChildren(children, activeIds, openTreeNodes),
                  openTreeNodes: openTreeNodes,
                  bannerSrc: bannerSrc
                });
              });

            }, function(contentErr) {
              console.error(contentErr);
              res.status(500).send(contentErr);
            });

        }, function(err) {
          console.error(err);
          res.status(500).send(err);
        });
    });

    app.get(util.format('%s/:slug', NEWS_FOLDER), function(req, res) {
      var slug = req.params.slug;

      if (!slug) {
        res.status(404).send('Not found');
        return;
      }

      new ModulesClass(config)
        .news.latest(0, 10)
        .news.findBySlug(slug)
        .callback(function(data) {
          var newsArticle = data[1];
          var siblings = data[0];
          if (!newsArticle) {
            res.status(404).send("Not Found");
            return;
          }
          // TODO: Banner should come from API
          var bannerSrc = '/gfx/layout/mikkeli-page-banner-default.jpg';

           res.render('pages/news-article.pug', {
            id: newsArticle.id,
            slug: newsArticle.slug,
            title: newsArticle.title,
            contents: processPageContent('/', newsArticle.contents),
            sidebarContents: getSidebarContent(newsArticle.contents),
            imageSrc: newsArticle.imageSrc,
            menus: req.kuntaApi.data.menus,
            bannerSrc: bannerSrc,
            siblings: siblings,
            breadcrumbs : [{path: util.format('%s/%s', NEWS_FOLDER, newsArticle.slug), title: newsArticle.title }]
          });

        }, function(err) {
          console.error(err);
          res.status(500).send(err);
        });
    });

    app.get(util.format('%s/:slug', ANNOUNCEMENTS_FOLDER), function(req, res) {
      var slug = req.params.slug;

      if (!slug) {
        res.status(404).send('Not found');
        return;
      }

        new ModulesClass(config)
        .announcements.list(ANNOUNCEMENT_COUNT_PAGE, 'PUBLICATION_DATE', 'DESCENDING')
        .announcements.findBySlug(slug)
        .callback(function(data) {
          var announcement = data[1];
          var siblings = data[0];
          if (!announcement) {
            res.status(404).send("Not Found");
            return;
          }
          // TODO: Banner should come from API
          var bannerSrc = '/gfx/layout/mikkeli-page-banner-default.jpg';

           res.render('pages/announcement.pug', {
            id: announcement.id,
            slug: announcement.slug,
            title: announcement.title,
            contents: processPageContent('/', announcement.contents),
            sidebarContents: getSidebarContent(announcement.contents),
            menus: req.kuntaApi.data.menus,
            bannerSrc: bannerSrc,
            siblings: siblings,
            breadcrumbs : [{path: util.format('%s/%s', ANNOUNCEMENTS_FOLDER, announcement.slug), title: announcement.title }]
          });

        }, function(err) {
          console.error(err);
          res.status(500).send(err);
        });
    });

  };

}).call(this);<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');

/* GET home page. */
router.get('/home', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

var j = $.noConflict();

j(document).ready(function() {
  j(document).on('click', '#btnSearch', search);
});

function search(){

  //url = 'http://www.imdb.com/title/tt1229340/';

  var searchValue = j('#inputSearch').val();
  url = 'http://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=' + searchValue;

  request(url, function(error, response, html){
		if(!error){
			var $ = cheerio.load(html);
      console.log(html);

			var title, release, rating;
			var json = { title : "", release : "", rating : ""};

			$('.header').filter(function(){
		        var data = $(this);
		        title = data.children().first().text();
		        release = data.children().last().children().text();

		        json.title = title;
		        json.release = release;
	        })

	        $('.star-box-giga-star').filter(function(){
	        	var data = $(this);
	        	rating = data.text();

	        	json.rating = rating;
	        })
		}

		fs.writeFile('output.json', JSON.stringify(json, null, 4), function(err){
        	console.log('File successfully written! - Check your project directory for the output.json file');
        })

      res.send(JSON.stringify(json));
      })

}

module.exports = router;
<commit_msg>Update index.js<commit_after>var express = require('express');
var router = express.Router();
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');

/* GET home page. */
router.get('/home', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

var j = jQuery.noConflict();

j(document).ready(function() {
  j(document).on('click', '#btnSearch', search);
});

function search(){

  //url = 'http://www.imdb.com/title/tt1229340/';

  var searchValue = j('#inputSearch').val();
  url = 'http://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=' + searchValue;

  request(url, function(error, response, html){
		if(!error){
			var $ = cheerio.load(html);
      console.log(html);

			var title, release, rating;
			var json = { title : "", release : "", rating : ""};

			$('.header').filter(function(){
		        var data = $(this);
		        title = data.children().first().text();
		        release = data.children().last().children().text();

		        json.title = title;
		        json.release = release;
	        })

	        $('.star-box-giga-star').filter(function(){
	        	var data = $(this);
	        	rating = data.text();

	        	json.rating = rating;
	        })
		}

		fs.writeFile('output.json', JSON.stringify(json, null, 4), function(err){
        	console.log('File successfully written! - Check your project directory for the output.json file');
        })

      res.send(JSON.stringify(json));
      })

}

module.exports = router;
<|endoftext|>


<commit_before>const express = require('express');
const router = express.Router();
const Twit = require('twit');
const config = require('./config.js')
const { Twitter } = require('../database/database.js')

router.get('/', function(req, res, next) {
  Twitter.getAllTweets().then((results) => {
    res.render('index', {results})
  })
})

console.log('this bot is running...');

let T = new Twit(config);

let techCrunchSearch = {
  q: "#Technology OR #Tech OR #STEM",
  count: 15,
  result_type: 'popular OR recent'
}

retweetLatest = () => {
  T.get('search/tweets', techCrunchSearch, (error, data) => {
    if(!error) {
      let retweetId = data.statuses[0].id_str
      T.post('statuses/retweet/' + retweetId, {}, (error, response) => {
        if(response) {
          console.log('success, twitbot is working');
          Twitter.addTweets(response.text)
        }
        if(error) {
          console.log('there was an error with Twitter: ' + error);
        }
      })
    } else {
        console.log('there was an error with your hashtag search: ' + error);
    }
  })
}

router.get('/tweets/:id', function(req, res) {
  T.post('statuses/update', {status: req.query.status}, (error, response) => {
    if(response) {
      console.log('success, it worked!');
      Twitter.addTweets(response.text)
    } else {
      console.log('errorrrrrrr.... ', + error);
    }
  })
})

// router.get('/mySecretRoutelol', (req, res) => {
//   T.get('search/tweets', { q:'testingtwitbot', count:10 } , function (error, data) {
//     let arrayOfTweets = []
//       if(data) {
//         let tweets = data.statuses;
//         for(let i = 0; i < tweets.length; i++) {
//           arrayOfTweets.push(tweets[i].text)
//         }
//         Twitter.addTweets(arrayOfTweets)
//         .then( results => {
//           res.send( results )
//         })
//       } else {
//         console.log('there was an error: ' + error);
//       }
//   });
// })

retweetLatest();

setInterval(retweetLatest, 1000*60*30)

module.exports = router;
<commit_msg>clean up code: get rid of comments, console.logs, etc.<commit_after>const express = require('express');
const router = express.Router();
const Twit = require('twit');
const config = require('./config.js')
const { Twitter } = require('../database/database.js')

router.get('/', function(req, res, next) {
  Twitter.getAllTweets().then((results) => {
    res.render('index', {results})
  })
})

console.log('this bot is running...');

let T = new Twit(config);

let techCrunchSearch = {
  q: "#Technology OR #Tech OR #STEM",
  count: 15,
  result_type: 'popular OR recent'
}

retweetLatest = () => {
  T.get('search/tweets', techCrunchSearch, (error, data) => {
    if(!error) {
      let retweetId = data.statuses[0].id_str
      T.post('statuses/retweet/' + retweetId, {}, (error, response) => {
        if(response) {
          console.log('success, twitbot is working');
          Twitter.addTweets(response.text)
        }
        if(error) {
          console.log('there was an error with Twitter: ' + error);
        }
      })
    } else {
        console.log('there was an error with your hashtag search: ' + error);
    }
  })
}

router.get('/tweets/:id', function(req, res) {
  T.post('statuses/update', {status: req.query.status}, (error, response) => {
    if(response) {
      console.log('success, it worked!');
      Twitter.addTweets(response.text)
    } else {
      console.log('errorrrrrrr.... ', + error);
    }
  })
})

retweetLatest();

setInterval(retweetLatest, 1000*60*30)

module.exports = router;
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var request = require('request');
var _ = require('lodash');

router.get('/', function(req, res) {
   var url = "https://seeclickfix.com/api/v2/issues?place_url=hampton&state=VA&per_page=10&page=1";
   request(url, function(err, response, body) {
   	if(err){
   		console.error(err);
   	}
   	 var list = JSON.parse(body).issues;
  	 var metadata = JSON.parse(body).metadata;
   	 var per_page = metadata.pagination.per_page;
   	 var city = 'hampton';
   	 var pages = list.length;
  	 var lat = _.pluck(list,'lat');
   	 var lng = _.pluck(list, 'lng');
     var start = 0;
   	 var summary = _.pluck(list, 'summary');
     var address = _.pluck(list, 'address');
   	res.render('index', { title: 'Hampton', list: list,
      lat:lat, lng:lng,
      summary:summary, per_page:pages,
      start:start,pages:pages, city:city,
      address:address});
    });
});

router.get('/:city', function(req, res) {
  var city = req.params.city;

  res.redirect('/' + city + '/1');
 // var city = req.params.city;
 // var url = "https://seeclickfix.com/api/v2/issues?place_url="+ city +"&state=VA&per_page=20&page=1";
 // request(url, function(err, response, body) {
 //  if(err){
 //    console.error(err);
 //  }
 //  var list = JSON.parse(body).issues;
 //  var metadata = JSON.parse(body).metadata;
 //  var per_page = metadata.pagination.per_page;
 //  var lat = _.pluck(list,'lat');
 //  var lng = _.pluck(list, 'lng');
 //  var summary = _.pluck(list, 'summary');

 //  if (city == 'newport-news') {
 //    city = "newport news";
 //  } else if (city == 'virginia-beach') {
 //    city = "virginia beach";
 //  }
 //  else {
 //  city = city.split('-');
 //  city = city[0];
 //  }
 //  res.render('index', { title: city, list: list, lat:lat, lng:lng, summary:summary, per_page:per_page });
 //  });
});

router.get('/:city/:id',function(req,res) {
	var city = req.params.city;
  var id = req.params.id;
  var url = "https://seeclickfix.com/api/v2/issues?place_url="+ city +"&state=VA&per_page=20&page=" + id;

   request(url, function(err, response, body) {
    if(err) {
      console.error(err);
    }
    var list = JSON.parse(body).issues;
    var metadata = JSON.parse(body).metadata;
    var per_page = metadata.pagination.per_page;
    var pages = metadata.pagination.pages;
    var lat = _.pluck(list,'lat');
    var lng = _.pluck(list, 'lng');
    var summary = _.pluck(list, 'summary');
    var address = _.pluck(list, 'address');
    var start = 0;
    var next_page = 2;
    console.log('This is how many pages ', pages);
    if (id <= pages) {
      start = per_page * (id-1);

    }
    if(id < pages) {
      next_page = (Number(id)+1);
    }

    if (city == 'newport-news') {
      title = "newport news";
    } else if (city == 'virginia-beach') {
      title = "virginia beach";
    } else if(city == 'hampton') {
      title = 'hampton';
    } else {
    title = city;
    }
    res.render('index', { title: title, list: list, lat:lat, lng:lng, summary:summary, per_page:per_page, pages:pages,
    start:start, city:city, next_page:next_page, address: address });
    });
});

router.post('/',function(req,res){
  //req.body.city = city name from drop down
  var city = req.body.city;
  var url = "https://seeclickfix.com/api/v2/issues?place_url=" + city + "&state=VA"; //insert city in this link
  request(url, function(err, response, body) {
    if(err){
      console.error(err);
    }
    var list = JSON.parse(body).issues;
    var lat = _.pluck(list,'lat');
    var lng = _.pluck(list, 'lng');
    var summary = _.pluck(list, 'summary');
    res.render('index', { title: city, list:list, lat:lat, lng:lng, summary:summary });
  });

});

module.exports = router;
<commit_msg>Deleted commented code<commit_after>var express = require('express');
var router = express.Router();
var request = require('request');
var _ = require('lodash');

router.get('/', function(req, res) {
   var url = "https://seeclickfix.com/api/v2/issues?place_url=hampton&state=VA&per_page=10&page=1";
   request(url, function(err, response, body) {
   	if(err){
   		console.error(err);
   	}
   	 var list = JSON.parse(body).issues;
  	 var metadata = JSON.parse(body).metadata;
   	 var per_page = metadata.pagination.per_page;
   	 var city = 'hampton';
   	 var pages = list.length;
  	 var lat = _.pluck(list,'lat');
   	 var lng = _.pluck(list, 'lng');
     var start = 0;
   	 var summary = _.pluck(list, 'summary');
     var address = _.pluck(list, 'address');
   	res.render('index', { title: 'Hampton', list: list,
      lat:lat, lng:lng,
      summary:summary, per_page:pages,
      start:start,pages:pages, city:city,
      address:address});
    });
});

router.get('/:city', function(req, res) {
  var city = req.params.city;

  res.redirect('/' + city + '/1');

});

router.get('/:city/:id',function(req,res) {
	var city = req.params.city;
  var id = req.params.id;
  var url = "https://seeclickfix.com/api/v2/issues?place_url="+ city +"&state=VA&per_page=20&page=" + id;

   request(url, function(err, response, body) {
    if(err) {
      console.error(err);
    }
    var list = JSON.parse(body).issues;
    var metadata = JSON.parse(body).metadata;
    var per_page = metadata.pagination.per_page;
    var pages = metadata.pagination.pages;
    var lat = _.pluck(list,'lat');
    var lng = _.pluck(list, 'lng');
    var summary = _.pluck(list, 'summary');
    var address = _.pluck(list, 'address');
    var start = 0;
    var next_page = 2;
    console.log('This is how many pages ', pages);
    if (id <= pages) {
      start = per_page * (id-1);

    }
    if(id < pages) {
      next_page = (Number(id)+1);
    }

    if (city == 'newport-news') {
      title = "newport news";
    } else if (city == 'virginia-beach') {
      title = "virginia beach";
    } else if(city == 'hampton') {
      title = 'hampton';
    } else {
    title = city;
    }
    res.render('index', { title: title, list: list, lat:lat, lng:lng, summary:summary, per_page:per_page, pages:pages,
    start:start, city:city, next_page:next_page, address: address });
    });
});

router.post('/',function(req,res){
  //req.body.city = city name from drop down
  var city = req.body.city;
  var url = "https://seeclickfix.com/api/v2/issues?place_url=" + city + "&state=VA"; //insert city in this link
  request(url, function(err, response, body) {
    if(err){
      console.error(err);
    }
    var list = JSON.parse(body).issues;
    var lat = _.pluck(list,'lat');
    var lng = _.pluck(list, 'lng');
    var summary = _.pluck(list, 'summary');
    res.render('index', { title: city, list:list, lat:lat, lng:lng, summary:summary });
  });

});

module.exports = router;
<|endoftext|>


<commit_before>// load Geolocation library
var geo = require("geo");

// load sharing library
var sharing = require("sharing");

// load push notifications library
var push = require('pushNotifications');

var args = arguments[0] || {};

OS_IOS && $.cameraButton.addEventListener("click", function(_event) {
  $.cameraButtonClicked(_event);
});

$.feedTable.addEventListener("click", processTableClicks);

/* for the view toggle */
$.filter.addEventListener( OS_IOS ? 'click' : 'change', filterTabbedBarClicked);

/* map clicked */
$.mapview.addEventListener('click', mapAnnotationClicked);

// handlers

function processTableClicks(_event) {
  if (_event.source.id === "commentButton") {
    handleCommentButtonClicked(_event);
  } else if (_event.source.id === "locationButton") {
    handleLocationButtonClicked(_event);
  } else if (_event.source.id === "shareButton") {
    handleShareButtonClicked(_event);
  }
}

/**
 *
 */
function filterTabbedBarClicked(_event) {
  var itemSelected = OS_IOS ? _event.index : _event.rowIndex;
  switch (itemSelected) {
    case 0 :
      // List View Display
      $.mapview.visible = false;
      $.feedTable.visible = true;
      break;
    case 1 :
      // Map View Display
      $.feedTable.visible = false;
      $.mapview.visible = true;
      showLocalImages();
      break;
  }
}

function handleShareButtonClicked(_event) {
  var collection, model;

  if (!_event.row) {
    model = _event.data;
  } else {
    collection = Alloy.Collections.instance("Photo");
    model = collection.get(_event.row.row_id);
  }

  // commonjs library for sharing
  sharing.sharingOptions({
    model : model
  });
}

function handleLocationButtonClicked(_event) {

  var collection = Alloy.Collections.instance("Photo");
  var model = collection.get(_event.row.row_id);
  debugger;

  var customFields = model.get("custom_fields");

  if (customFields && customFields.coordinates) {
    var mapController = Alloy.createController("mapView", {
      photo : model,
      parentController : $
    });

    // open the view
    Alloy.Globals.openCurrentTabWindow(mapController.getView());
  } else {
    alert("No Location was Saved with Photo");
  }
}

/**
 *
 */
function handleCommentButtonClicked(_event) {
  var collection, model = null;

  // handle call from mapDetail or feedRow
  if (!_event.row) {
    model = _event.data;
  } else {
    collection = Alloy.Collections.instance("Photo");
    model = collection.get(_event.row.row_id);
  }

  var controller = Alloy.createController("comment", {
    photo : model,
    parentController : $
  });

  // initialize the data in the view, load content
  controller.initialize();

  // open the view
  Alloy.Globals.openCurrentTabWindow(controller.getView());

}

/**
 *
 */
$.cameraButtonClicked = function(_event) {
  //alert("user clicked camera button");
  var photoSource;

  Ti.API.debug('Ti.Media.isCameraSupported ' + Ti.Media.isCameraSupported);

  if (!Ti.Media.isCameraSupported) {
    photoSource = 'openPhotoGallery';
  } else {
    photoSource = 'showCamera';
  }

  Titanium.Media[photoSource]({
    success : function(event) {

      Alloy.Globals.PW.showIndicator("Saving Image", false);
      var ImageFactory = require('ti.imagefactory');

      if (OS_ANDROID || event.media.width > 700) {
        var w, h;
        w = event.media.width * .50;
        h = event.media.height * .50;
        $.resizedPhoto = ImageFactory.imageAsResized(event.media, {
          width : w,
          height : h
        });
      } else {
        // we do not need to compress here
        $.resizedPhoto = event.media;
      }

      processImage($.resizedPhoto, function(_photoResp) {

        Alloy.Globals.PW.hideIndicator();

        if (_photoResp.success) {

          // create the row
          var row = Alloy.createController("feedRow", _photoResp.model);

          // add the controller view, which is a row to the table
          if ($.feedTable.getData().length === 0) {
            $.feedTable.setData([]);
            $.feedTable.appendRow(row.getView(), true);
          } else {
            $.feedTable.insertRowBefore(0, row.getView(), true);
          }

          //now add to the backbone collection
          var collection = Alloy.Collections.instance("Photo");
          collection.add(_photoResp.model, {
            at : 0,
            silent : true
          });

          // notify followers
          notifyFollowers(_photoResp.model, "New Photo Added");

        } else {
          alert("Error saving photo " + processResponse.message);
        }

      });
    },
    cancel : function() {
      // called when user cancels taking a picture
    },
    error : function(error) {
      // display alert on error
      if (error.code == Titanium.Media.NO_CAMERA) {
        alert('Please run this test on device');
      } else {
        alert('Unexpected error: ' + error.code);
      }
    },
    saveToPhotoGallery : false,
    allowEditing : true,
    // only allow for photos, no video
    mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO]
  });

};

/**
 *
 * @param {Object} _mediaObject object from the camera
 * @param {Function} _callback where to call when the function is completed
 */
function processImage(_mediaObject, _callback) {

  geo.getCurrentLocation(function(_coords) {
    var parameters = {
      "photo" : _mediaObject,
      "title" : "Sample Photo " + new Date(),
      "photo_sizes[preview]" : "200x200#",
      "photo_sizes[iphone]" : "320x320#",
      // We need this since we are showing the image immediately
      "photo_sync_sizes[]" : "preview"
    };

    // if we got a location, then set it
    if (_coords) {
      parameters.custom_fields = {
        coordinates : [_coords.coords.longitude, _coords.coords.latitude],
        location_string : _coords.title
      };
    }

    var photo = Alloy.createModel('Photo', parameters);

    photo.save({}, {
      success : function(_model, _response) {
        Ti.API.debug('success: ' + _model.toJSON());
        _callback({
          model : _model,
          message : null,
          success : true
        });
      },
      error : function(e) {
        Ti.API.error('error: ' + e.message);
        _callback({
          model : parameters,
          message : e.message,
          success : false
        });
      }
    });
  });
}

/**
 *
 */
function loadPhotos() {
  var rows = [];

  // creates or gets the global instance of photo collection
  var photos = Alloy.Collections.photo || Alloy.Collections.instance("Photo");

  // be sure we ignore profile photos;
  var where = {
    title : {
      "$exists" : true
    }
  };

  photos.fetch({
    data : {
      order : '-created_at',
      where : where
    },
    success : function(model, response) {
      photos.each(function(photo) {
        var photoRow = Alloy.createController("feedRow", photo);
        rows.push(photoRow.getView());
      });
      $.feedTable.data = rows;
    },
    error : function(error) {
      alert('Error loading Feed ' + error.message);
      Ti.API.error(JSON.stringify(error));
    }
  });
}

/**
 * only show images that are local and are from friends of the
 * current user
 */
function showLocalImages() {
  // create new photo collection
  $.locationCollection = Alloy.createCollection('photo');

  // find all photos within 5 miles of current location
  geo.getCurrentLocation(function(_coords) {
    var user = Alloy.Globals.currentUser;

    $.locationCollection.findPhotosNearMe(user, _coords, 5, {
      success : function(_collection, _response) {
        Ti.API.debug('findPhotosNearMe ' + JSON.stringify(_collection));

        // add the annotations/map pins to map
        if (_collection.models.length) {
          addPhotosToMap(_collection);
        } else {
          alert("No Local Images Found");
          filterTabbedBarClicked({
            index : 0,
            rowIndex : 0,
          });

          if (OS_ANDROID) {
            $.filter.setSelectedRow(0, 0, false);
          } else {
            $.filter.setIndex(0);
          }
        }
      },
      error : function(error) {
        alert('Error loading Feed ' + e.message);
        Ti.API.error(JSON.stringify(error));
      }
    });
  });
}

/**
 *
 * @param {Object} _collection
 */
function addPhotosToMap(_collection) {
  var annotationArray = [];
  var lastLat;

  // remove all annotations from map
  $.mapview.removeAllAnnotations();

  var annotationRightButton = function() {
    var button = Ti.UI.createButton({
      title : "X",
    });
    return button;
  };

  for (var i in _collection.models) {
    var mapData = _collection.models[i].toJSON();
    var coords = mapData.custom_fields.coordinates;
    var annotation = Alloy.Globals.Map.createAnnotation({
      latitude : Number(coords[0][1]),
      longitude : Number(coords[0][0]),
      subtitle : mapData.custom_fields.location_string,
      title : mapData.title,
      //animate : true,
      data : _collection.models[i].clone()
    });

    if (OS_IOS) {
      annotation.setPincolor(Alloy.Globals.Map.ANNOTATION_RED);
      annotation.setRightButton(Titanium.UI.iPhone.SystemButton.DISCLOSURE);
    } else {
      annotation.setRightView(annotationRightButton);
    }
    annotationArray.push(annotation);

  }

  // calculate the map region based on the annotations
  var region = geo.calculateMapRegion(annotationArray);
  $.mapview.setRegion(region);

  // add the annotations to the map
  $.mapview.setAnnotations(annotationArray);
}

function mapAnnotationClicked(_event) {
  // get event properties
  var annotation = _event.annotation;
  //get the Myid from annotation
  var clickSource = _event.clicksource;

  var showDetails = false;

  if (OS_IOS) {
    showDetails = (clickSource === 'rightButton');
  } else {
    showDetails = (clickSource === 'subtitle' || clickSource === 'title');
  }

  if (showDetails) {

    // load the mapDetail controller
    var mapDetailCtrl = Alloy.createController('mapDetail', {
      photo : annotation.data,
      parentController : $,
      clickHandler : processTableClicks
    });

    // open the view
    Alloy.Globals.openCurrentTabWindow(mapDetailCtrl.getView());

  } else {
    Ti.API.info('clickSource ' + clickSource);
  }
};

function notifyFollowers(_model, _message) {

  var currentUser = Alloy.Globals.currentUser;

  currentUser.getFollowers(function(_resp) {
    if (_resp.success) {
      $.followersList = _.pluck(_resp.collection.models, "id");

      if ($.followersList.length) {

        // send a push notification to all friends
        var msg = _message + " " + currentUser.get("email");

        // make the api call using the library
        push.sendPush({
          payload : {
            custom : {
              photo_id : _model.get("id"),
            },
            sound : "default",
            alert : msg
          },
          to_ids : $.followersList.join(),
        }, function(_repsonsePush) {
          if (_repsonsePush.success) {
            alert("Notified friends of new photo");
          } else {
            alert("Error notifying friends of new photo");
          }
        });
      }
    } else {
      alert("Error updating friends and followers");
    }
  });

}

//
//
//
$.initialize = function() {
  loadPhotos();
};
<commit_msg>https://trello.com/c/hXKMkLfg/11-crash-on-open-map error handler for findPhotosNearMe isn't always run, but crashes when it is triggered.  fixes typo from "e" to "error"<commit_after>// load Geolocation library
var geo = require("geo");

// load sharing library
var sharing = require("sharing");

// load push notifications library
var push = require('pushNotifications');

var args = arguments[0] || {};

OS_IOS && $.cameraButton.addEventListener("click", function(_event) {
  $.cameraButtonClicked(_event);
});

$.feedTable.addEventListener("click", processTableClicks);

/* for the view toggle */
$.filter.addEventListener( OS_IOS ? 'click' : 'change', filterTabbedBarClicked);

/* map clicked */
$.mapview.addEventListener('click', mapAnnotationClicked);

// handlers

function processTableClicks(_event) {
  if (_event.source.id === "commentButton") {
    handleCommentButtonClicked(_event);
  } else if (_event.source.id === "locationButton") {
    handleLocationButtonClicked(_event);
  } else if (_event.source.id === "shareButton") {
    handleShareButtonClicked(_event);
  }
}

/**
 *
 */
function filterTabbedBarClicked(_event) {
  var itemSelected = OS_IOS ? _event.index : _event.rowIndex;
  switch (itemSelected) {
    case 0 :
      // List View Display
      $.mapview.visible = false;
      $.feedTable.visible = true;
      break;
    case 1 :
      // Map View Display
      $.feedTable.visible = false;
      $.mapview.visible = true;
      showLocalImages();
      break;
  }
}

function handleShareButtonClicked(_event) {
  var collection, model;

  if (!_event.row) {
    model = _event.data;
  } else {
    collection = Alloy.Collections.instance("Photo");
    model = collection.get(_event.row.row_id);
  }

  // commonjs library for sharing
  sharing.sharingOptions({
    model : model
  });
}

function handleLocationButtonClicked(_event) {

  var collection = Alloy.Collections.instance("Photo");
  var model = collection.get(_event.row.row_id);
  debugger;

  var customFields = model.get("custom_fields");

  if (customFields && customFields.coordinates) {
    var mapController = Alloy.createController("mapView", {
      photo : model,
      parentController : $
    });

    // open the view
    Alloy.Globals.openCurrentTabWindow(mapController.getView());
  } else {
    alert("No Location was Saved with Photo");
  }
}

/**
 *
 */
function handleCommentButtonClicked(_event) {
  var collection, model = null;

  // handle call from mapDetail or feedRow
  if (!_event.row) {
    model = _event.data;
  } else {
    collection = Alloy.Collections.instance("Photo");
    model = collection.get(_event.row.row_id);
  }

  var controller = Alloy.createController("comment", {
    photo : model,
    parentController : $
  });

  // initialize the data in the view, load content
  controller.initialize();

  // open the view
  Alloy.Globals.openCurrentTabWindow(controller.getView());

}

/**
 *
 */
$.cameraButtonClicked = function(_event) {
  //alert("user clicked camera button");
  var photoSource;

  Ti.API.debug('Ti.Media.isCameraSupported ' + Ti.Media.isCameraSupported);

  if (!Ti.Media.isCameraSupported) {
    photoSource = 'openPhotoGallery';
  } else {
    photoSource = 'showCamera';
  }

  Titanium.Media[photoSource]({
    success : function(event) {

      Alloy.Globals.PW.showIndicator("Saving Image", false);
      var ImageFactory = require('ti.imagefactory');

      if (OS_ANDROID || event.media.width > 700) {
        var w, h;
        w = event.media.width * .50;
        h = event.media.height * .50;
        $.resizedPhoto = ImageFactory.imageAsResized(event.media, {
          width : w,
          height : h
        });
      } else {
        // we do not need to compress here
        $.resizedPhoto = event.media;
      }

      processImage($.resizedPhoto, function(_photoResp) {

        Alloy.Globals.PW.hideIndicator();

        if (_photoResp.success) {

          // create the row
          var row = Alloy.createController("feedRow", _photoResp.model);

          // add the controller view, which is a row to the table
          if ($.feedTable.getData().length === 0) {
            $.feedTable.setData([]);
            $.feedTable.appendRow(row.getView(), true);
          } else {
            $.feedTable.insertRowBefore(0, row.getView(), true);
          }

          //now add to the backbone collection
          var collection = Alloy.Collections.instance("Photo");
          collection.add(_photoResp.model, {
            at : 0,
            silent : true
          });

          // notify followers
          notifyFollowers(_photoResp.model, "New Photo Added");

        } else {
          alert("Error saving photo " + processResponse.message);
        }

      });
    },
    cancel : function() {
      // called when user cancels taking a picture
    },
    error : function(error) {
      // display alert on error
      if (error.code == Titanium.Media.NO_CAMERA) {
        alert('Please run this test on device');
      } else {
        alert('Unexpected error: ' + error.code);
      }
    },
    saveToPhotoGallery : false,
    allowEditing : true,
    // only allow for photos, no video
    mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO]
  });

};

/**
 *
 * @param {Object} _mediaObject object from the camera
 * @param {Function} _callback where to call when the function is completed
 */
function processImage(_mediaObject, _callback) {

  geo.getCurrentLocation(function(_coords) {
    var parameters = {
      "photo" : _mediaObject,
      "title" : "Sample Photo " + new Date(),
      "photo_sizes[preview]" : "200x200#",
      "photo_sizes[iphone]" : "320x320#",
      // We need this since we are showing the image immediately
      "photo_sync_sizes[]" : "preview"
    };

    // if we got a location, then set it
    if (_coords) {
      parameters.custom_fields = {
        coordinates : [_coords.coords.longitude, _coords.coords.latitude],
        location_string : _coords.title
      };
    }

    var photo = Alloy.createModel('Photo', parameters);

    photo.save({}, {
      success : function(_model, _response) {
        Ti.API.debug('success: ' + _model.toJSON());
        _callback({
          model : _model,
          message : null,
          success : true
        });
      },
      error : function(e) {
        Ti.API.error('error: ' + e.message);
        _callback({
          model : parameters,
          message : e.message,
          success : false
        });
      }
    });
  });
}

/**
 *
 */
function loadPhotos() {
  var rows = [];

  // creates or gets the global instance of photo collection
  var photos = Alloy.Collections.photo || Alloy.Collections.instance("Photo");

  // be sure we ignore profile photos;
  var where = {
    title : {
      "$exists" : true
    }
  };

  photos.fetch({
    data : {
      order : '-created_at',
      where : where
    },
    success : function(model, response) {
      photos.each(function(photo) {
        var photoRow = Alloy.createController("feedRow", photo);
        rows.push(photoRow.getView());
      });
      $.feedTable.data = rows;
    },
    error : function(error) {
      alert('Error loading Feed ' + error.message);
      Ti.API.error(JSON.stringify(error));
    }
  });
}

/**
 * only show images that are local and are from friends of the
 * current user
 */
function showLocalImages() {
  // create new photo collection
  $.locationCollection = Alloy.createCollection('photo');

  // find all photos within 5 miles of current location
  geo.getCurrentLocation(function(_coords) {
    var user = Alloy.Globals.currentUser;

    $.locationCollection.findPhotosNearMe(user, _coords, 5, {
      success : function(_collection, _response) {
        Ti.API.debug('findPhotosNearMe ' + JSON.stringify(_collection));

        // add the annotations/map pins to map
        if (_collection.models.length) {
          addPhotosToMap(_collection);
        } else {
          alert("No Local Images Found");
          filterTabbedBarClicked({
            index : 0,
            rowIndex : 0,
          });

          if (OS_ANDROID) {
            $.filter.setSelectedRow(0, 0, false);
          } else {
            $.filter.setIndex(0);
          }
        }
      },
      error : function(error) {
        alert('Error loading Feed ' + error.message);
        Ti.API.error(JSON.stringify(error));
      }
    });
  });
}

/**
 *
 * @param {Object} _collection
 */
function addPhotosToMap(_collection) {
  var annotationArray = [];
  var lastLat;

  // remove all annotations from map
  $.mapview.removeAllAnnotations();

  var annotationRightButton = function() {
    var button = Ti.UI.createButton({
      title : "X",
    });
    return button;
  };

  for (var i in _collection.models) {
    var mapData = _collection.models[i].toJSON();
    var coords = mapData.custom_fields.coordinates;
    var annotation = Alloy.Globals.Map.createAnnotation({
      latitude : Number(coords[0][1]),
      longitude : Number(coords[0][0]),
      subtitle : mapData.custom_fields.location_string,
      title : mapData.title,
      //animate : true,
      data : _collection.models[i].clone()
    });

    if (OS_IOS) {
      annotation.setPincolor(Alloy.Globals.Map.ANNOTATION_RED);
      annotation.setRightButton(Titanium.UI.iPhone.SystemButton.DISCLOSURE);
    } else {
      annotation.setRightView(annotationRightButton);
    }
    annotationArray.push(annotation);

  }

  // calculate the map region based on the annotations
  var region = geo.calculateMapRegion(annotationArray);
  $.mapview.setRegion(region);

  // add the annotations to the map
  $.mapview.setAnnotations(annotationArray);
}

function mapAnnotationClicked(_event) {
  // get event properties
  var annotation = _event.annotation;
  //get the Myid from annotation
  var clickSource = _event.clicksource;

  var showDetails = false;

  if (OS_IOS) {
    showDetails = (clickSource === 'rightButton');
  } else {
    showDetails = (clickSource === 'subtitle' || clickSource === 'title');
  }

  if (showDetails) {

    // load the mapDetail controller
    var mapDetailCtrl = Alloy.createController('mapDetail', {
      photo : annotation.data,
      parentController : $,
      clickHandler : processTableClicks
    });

    // open the view
    Alloy.Globals.openCurrentTabWindow(mapDetailCtrl.getView());

  } else {
    Ti.API.info('clickSource ' + clickSource);
  }
};

function notifyFollowers(_model, _message) {

  var currentUser = Alloy.Globals.currentUser;

  currentUser.getFollowers(function(_resp) {
    if (_resp.success) {
      $.followersList = _.pluck(_resp.collection.models, "id");

      if ($.followersList.length) {

        // send a push notification to all friends
        var msg = _message + " " + currentUser.get("email");

        // make the api call using the library
        push.sendPush({
          payload : {
            custom : {
              photo_id : _model.get("id"),
            },
            sound : "default",
            alert : msg
          },
          to_ids : $.followersList.join(),
        }, function(_repsonsePush) {
          if (_repsonsePush.success) {
            alert("Notified friends of new photo");
          } else {
            alert("Error notifying friends of new photo");
          }
        });
      }
    } else {
      alert("Error updating friends and followers");
    }
  });

}

//
//
//
$.initialize = function() {
  loadPhotos();
};
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016-present, Alejandro Mantilla <@AlejoJamC>.
 * All rights reserved.
 *
 * This source code is licensed under the MIT license found in the LICENSE
 * file in the root directory of this source tree or translated in the assets folder.
 */

var express     = require('express');
var indexRouter = express.Router();
var logger      = require('../config/logger').logger;
var oracledb    = require('oracledb');

/* GET Login page. */
indexRouter.get('/', function (req, res) {
    res.render('auth/index', {
        title   : 'Analytics Website | Login',
        level   : '',
        layout  : 'auth'
    });
});

module.exports = indexRouter;<commit_msg>get login page route<commit_after>/**
 * Copyright (c) 2016-present, Alejandro Mantilla <@AlejoJamC>.
 * All rights reserved.
 *
 * This source code is licensed under the MIT license found in the LICENSE
 * file in the root directory of this source tree or translated in the assets folder.
 */

var express     = require('express');
var indexRouter = express.Router();
var logger      = require('../config/logger').logger;
var oracledb    = require('oracledb');

/* GET Index page. */
indexRouter.get('/', function (req, res) {
    res.redirect('/login');
});
    res.render('auth/index', {
        title   : 'Analytics Website | Login',
        level   : '',
        layout  : 'auth'
    });
});

module.exports = indexRouter;<|endoftext|>


<commit_before>var args = arguments[0] || {};
var animation = require('alloy/animation');

var Entity = require('entity');

var player = args;

var enemies = [];
var turn = 0;

var currentEnemyIndex = -1,
	numHearts = 0,
	numSkulls = 0;

loadEnemies();

function loadEnemies() {
	var url = "https://quasar-9.herokuapp.com/api/v1/job_postings?auth_token=1pSst1P7LAQBzNGc2bgW&site_of_origin=EG&q=java&employer_id=1526";
	var client = Ti.Network.createHTTPClient({
    	 // function called when the response data is available
	     onload : function(e) {
    	     var json = JSON.parse(this.responseText);
    	     enemies = [];
    	     for (var i = 0; i < json.job_postings.length; i++) {
    	     	var enemy = new Entity.Enemy(json.job_postings[i]);
    	     	enemies.push(enemy);
    	     }

    	     Reset();
	     },
    	 // function called when an error occurs, including a timeout
	     onerror : function(e) {
    	     Ti.API.debug(e.error);
        	 alert('error');
	     },
    	 timeout : 5000  // in milliseconds
	 });
 	 // Prepare the connection.
 	 client.open("GET", url);
	 // Send the request.
	 client.send();
}

function resetButtons () {
	$.btnAttack.touchEnabled = false;
	$.btnAttack.backgroundColor = "#999";
	$.btnPickSkill.title = "Pick a Skill";
}

function onAttackClick(e){
	animation.shake($.jobCard);
	var result = player.useSkill($.btnPickSkill.title, enemies[currentEnemyIndex]);

	if(result > 0)
	{
		SkillSuccessful();
	}
	//Unsuccessful attack
	else
	{
		SkillUnsuccessful();
	}
	resetButtons();
	++turn;
}

function SkillSuccessful(){
	numHearts++;
	$.hearts.children[turn].image = '/images/heart.png';
	if(numHearts >= 3)
	{
		EnemyDefeated();
		Reset();
	}
}

function EnemyDefeated(){
	//Launch URL for player to apply to the position.
}

function SkillUnsuccessful(){
	numSkulls++;
	$.hearts.children[turn].image = '/images/skull.png';
	if(numSkulls >= 3)
	{
		EnemyVictory();
		Reset();
	}
}

function EnemyVictory(){
	//Do stuff if player is defeated.
	//Show URL for player to view job description?
}

function Reset()
{
	currentEnemyIndex++;
	numSkulls = 0;
	numHearts = 0;

	var data = [];
	//Iterate player skills and create table rows
	_.each(player.skills, function(skill){
		var row = Ti.UI.createTableViewRow({
			title: skill
		});
		data.push(row);
	});
	//Update table
	$.skillList.data = data;
	$.jobTitle.text = enemies[currentEnemyIndex].name;
	$.employerTitle.text = enemies[currentEnemyIndex].employer;
	$.jobLocation.text = enemies[currentEnemyIndex].city + ", " + enemies[currentIndex].state;
}

$.btnPickSkill.addEventListener('click', function(e){
	$.skillList.animate({
		top: 20,
		duration: 300
	});
});
$.skillList.addEventListener('click', function(e){
	$.skillList.animate({
		top: "70%",
		duration: 300
	});
	$.btnPickSkill.title = e.row.title;
	$.btnAttack.touchEnabled = true;
	$.btnAttack.backgroundColor = 'red';
	$.skillList.remove(e.row);
});
$.btnAttack.addEventListener('click', onAttackClick);
<commit_msg>fix spelling mistake<commit_after>var args = arguments[0] || {};
var animation = require('alloy/animation');

var Entity = require('entity');

var player = args;

var enemies = [];
var turn = 0;

var currentEnemyIndex = -1,
	numHearts = 0,
	numSkulls = 0;

loadEnemies();

function loadEnemies() {
	var url = "https://quasar-9.herokuapp.com/api/v1/job_postings?auth_token=1pSst1P7LAQBzNGc2bgW&site_of_origin=EG&q=java&employer_id=1526";
	var client = Ti.Network.createHTTPClient({
    	 // function called when the response data is available
	     onload : function(e) {
    	     var json = JSON.parse(this.responseText);
    	     enemies = [];
    	     for (var i = 0; i < json.job_postings.length; i++) {
    	     	var enemy = new Entity.Enemy(json.job_postings[i]);
    	     	enemies.push(enemy);
    	     }

    	     Reset();
	     },
    	 // function called when an error occurs, including a timeout
	     onerror : function(e) {
    	     Ti.API.debug(e.error);
        	 alert('error');
	     },
    	 timeout : 5000  // in milliseconds
	 });
 	 // Prepare the connection.
 	 client.open("GET", url);
	 // Send the request.
	 client.send();
}

function resetButtons () {
	$.btnAttack.touchEnabled = false;
	$.btnAttack.backgroundColor = "#999";
	$.btnPickSkill.title = "Pick a Skill";
}

function onAttackClick(e){
	animation.shake($.jobCard);
	var result = player.useSkill($.btnPickSkill.title, enemies[currentEnemyIndex]);

	if(result > 0)
	{
		SkillSuccessful();
	}
	//Unsuccessful attack
	else
	{
		SkillUnsuccessful();
	}
	resetButtons();
	++turn;
}

function SkillSuccessful(){
	numHearts++;
	$.hearts.children[turn].image = '/images/heart.png';
	if(numHearts >= 3)
	{
		EnemyDefeated();
		Reset();
	}
}

function EnemyDefeated(){
	//Launch URL for player to apply to the position.
}

function SkillUnsuccessful(){
	numSkulls++;
	$.hearts.children[turn].image = '/images/skull.png';
	if(numSkulls >= 3)
	{
		EnemyVictory();
		Reset();
	}
}

function EnemyVictory(){
	//Do stuff if player is defeated.
	//Show URL for player to view job description?
}

function Reset()
{
	currentEnemyIndex++;
	numSkulls = 0;
	numHearts = 0;

	var data = [];
	//Iterate player skills and create table rows
	_.each(player.skills, function(skill){
		var row = Ti.UI.createTableViewRow({
			title: skill
		});
		data.push(row);
	});
	//Update table
	$.skillList.data = data;
	$.jobTitle.text = enemies[currentEnemyIndex].name;
	$.employerTitle.text = enemies[currentEnemyIndex].employer;
	$.jobLocation.text = enemies[currentEnemyIndex].city + ", " + enemies[currentEnemyIndex].state;
}

$.btnPickSkill.addEventListener('click', function(e){
	$.skillList.animate({
		top: 20,
		duration: 300
	});
});
$.skillList.addEventListener('click', function(e){
	$.skillList.animate({
		top: "70%",
		duration: 300
	});
	$.btnPickSkill.title = e.row.title;
	$.btnAttack.touchEnabled = true;
	$.btnAttack.backgroundColor = 'red';
	$.skillList.remove(e.row);
});
$.btnAttack.addEventListener('click', onAttackClick);
<|endoftext|>