<commit_before>"use strict";

var utils = require("./utils");
var cheerio = require("cheerio");
var log = require("npmlog");

var defaultLogRecordSize = 100;
log.maxRecordSize = defaultLogRecordSize;

function setOptions(globalOptions, options) {
  Object.keys(options).map(function(key) {
    switch (key) {
      case 'logLevel':
        log.level = options.logLevel;
        globalOptions.logLevel = options.logLevel;
        break;
      case 'logRecordSize':
        log.maxRecordSize = options.logRecordSize;
        globalOptions.logRecordSize = options.logRecordSize;
        break;
      case 'selfListen':
        globalOptions.selfListen = options.selfListen;
        break;
      case 'listenEvents':
        globalOptions.listenEvents = options.listenEvents;
        break;
      case 'pageID':
        globalOptions.pageID = options.pageID.toString();
        break;
      case 'updatePresence':
        globalOptions.updatePresence = options.updatePresence;
        break;
      case 'forceLogin':
        globalOptions.forceLogin = options.forceLogin;
        break;
      default:
        log.warn("setOptions", "Unrecognized option given to setOptions: " + key);
        break;
    }
  });
}

function buildAPI(globalOptions, html, jar) {
  var maybeCookie = jar.getCookies("https://www.facebook.com").filter(function(val) {
    return val.cookieString().split("=")[0] === "c_user";
  });

  if(maybeCookie.length === 0) {
    throw {error: "Error retrieving userID. This can be caused by a lot of things, including getting blocked by Facebook for logging in from an unknown location. Try logging in with a browser to verify."};
  }

  var userID = maybeCookie[0].cookieString().split("=")[1].toString();
  log.info("login", "Logged in");

  var clientID = (Math.random() * 2147483648 | 0).toString(16);

  // All data available to api functions
  var ctx = {
    userID: userID,
    jar: jar,
    clientID: clientID,
    globalOptions: globalOptions,
    loggedIn: true,
    access_token: 'NONE',
    clientMutationId: 0
  };

  var api = {
    setOptions: setOptions.bind(null, globalOptions),
    getAppState: function getAppState() {
      return utils.getAppState(jar);
    },
  };

  var apiFuncNames = [
    'addUserToGroup',
    'changeArchivedStatus',
    'changeBlockedStatus',
    'changeGroupImage',
    'changeThreadColor',
    'changeThreadEmoji',
    'changeNickname',
    'createPoll',
    'deleteMessage',
    'deleteThread',
    'forwardAttachment',
    'getCurrentUserID',
    'getEmojiUrl',
    'getFriendsList',
    'getThreadHistory',
    'getThreadInfo',
    'getThreadList',
    'getThreadPictures',
    'getUserID',
    'getUserInfo',
    'threadColors',
    'handleMessageRequest',
    'listen',
    'logout',
    'markAsRead',
    'muteThread',
    'removeUserFromGroup',
    'resolvePhotoUrl',
    'searchForThread',
    'sendMessage',
    'sendTypingIndicator',
    'setMessageReaction',
    'setTitle',

    // Beta features
    'getThreadHistoryGraphQL',
    'getThreadInfoGraphQL',
  ];

  var defaultFuncs = utils.makeDefaults(html, userID, ctx);

  // Load all api functions in a loop
  apiFuncNames.map(function(v) {
    api[v] = require('./src/' + v)(defaultFuncs, api, ctx);
  });

  return [ctx, defaultFuncs, api];
}

function makeLogin(jar, email, password, loginOptions, callback) {
  return function(res) {
    var html = res.body;
    var $ = cheerio.load(html);
    var arr = [];

    // This will be empty, but just to be sure we leave it
    $("#login_form input").map(function(i, v){
      arr.push({val: $(v).val(), name: $(v).attr("name")});
    });

    arr = arr.filter(function(v) {
      return v.val && v.val.length;
    });

    var form = utils.arrToForm(arr);
    form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
    form.lgndim = new Buffer("{\"w\":1440,\"h\":900,\"aw\":1440,\"ah\":834,\"c\":24}").toString('base64');
    form.email = email;
    form.pass = password;
    form.default_persistent = '0';
    form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
    form.locale = 'en_US';
    form.timezone = '240';
    form.lgnjs = ~~(Date.now() / 1000);

    // Getting cookies from the HTML page... (kill me now plz)
    // we used to get a bunch of cookies in the headers of the response of the
    // request, but FB changed and they now send those cookies inside the JS.
    // They run the JS which then injects the cookies in the page.
    // The "solution" is to parse through the html and find those cookies
    // which happen to be conveniently indicated with a _js_ in front of their
    // variable name.
    //
    // ---------- Very Hacky Part Starts -----------------
    var willBeCookies = html.split("\"_js_");
    willBeCookies.slice(1).map(function(val) {
      var cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
      jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
    });
    // ---------- Very Hacky Part Ends -----------------

    log.info("login", "Logging in...");
    return utils
      .post("https://www.facebook.com/login.php?login_attempt=1&lwv=110", jar, form)
      .then(utils.saveCookies(jar))
      .then(function(res) {
        var headers = res.headers;
        if (!headers.location) {
          throw {error: "Wrong username/password."};
        }

        // This means the account has login approvals turned on.
        if (headers.location.indexOf('https://www.facebook.com/checkpoint/') > -1) {
          var nextURL = 'https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php';

          return utils
            .get(headers.location, jar)
            .then(utils.saveCookies(jar))
            .then(function(res) {
              var html = res.body;
              // Make the form in advance which will contain the fb_dtsg and nh
              var $ = cheerio.load(html);
              var arr = [];
              $("form input").map(function(i, v){
                arr.push({val: $(v).val(), name: $(v).attr("name")});
              });

              arr = arr.filter(function(v) {
                return v.val && v.val.length;
              });

              var form = utils.arrToForm(arr);
              if (html.indexOf("Enter Security Code to Continue") > -1 ||
                  html.indexOf("Enter Your Login Code") > -1) {
                throw {
                  error: 'login-approval',
                  continue: function(code) {
                    form.approvals_code = code;
                    form['submit[Continue]'] = 'Continue';
                    return utils
                      .post(nextURL, jar, form)
                      .then(utils.saveCookies(jar))
                      .then(function() {
                        // Use the same form (safe I hope)
                        form.name_action_selected = 'save_device';

                        return utils
                          .post(nextURL, jar, form)
                          .then(utils.saveCookies(jar));
                      })
                      .then(function(res) {
                        var headers = res.headers;
                        if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
                          throw {error: "Something went wrong with login approvals."};
                        }

                        var appState = utils.getAppState(jar);

                        // Simply call loginHelper because all it needs is the jar
                        // and will then complete the login process
                        return loginHelper(appState, email, password, loginOptions, callback);
                      })
                      .catch(function(err) {
                        callback(err);
                      });
                  }
                };
              } else {
                if (!loginOptions.forceLogin) {
                  throw {error: "Couldn't login. Facebook might have blocked this account. Please login with a browser or enable the option 'forceLogin' and try again."};
                }
                if (html.indexOf("Suspicious Login Attempt") > -1) {
                  form['submit[This was me]'] = "This was me";
                } else {
                  form['submit[This Is Okay]'] = "This Is Okay";
                }

                return utils
                  .post(nextURL, jar, form)
                  .then(utils.saveCookies(jar))
                  .then(function() {
                    // Use the same form (safe I hope)
                    form.name_action_selected = 'save_device';

                    return utils
                      .post(nextURL, jar, form)
                      .then(utils.saveCookies(jar));
                  })
                  .then(function(res) {
                    var headers = res.headers;

                    if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
                      throw {error: "Something went wrong with review recent login."};
                    }

                    var appState = utils.getAppState(jar);

                    // Simply call loginHelper because all it needs is the jar
                    // and will then complete the login process
                    return loginHelper(appState, email, password, loginOptions, callback);
                  })
                  .catch(function(e) {
                    callback(e);
                  });
              }
            });
        }

        return utils
          .get('https://www.facebook.com/', jar)
          .then(utils.saveCookies(jar));
      });
  };
}

// Helps the login
function loginHelper(appState, email, password, globalOptions, callback) {
  var mainPromise = null;
  var jar = utils.getJar();

  // If we're given an appState we loop through it and save each cookie
  // back into the jar.
  if(appState) {
    appState.map(function(c) {
      var str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
      jar.setCookie(str, "http://" + c.domain);
    });

    // Load the main page.
    mainPromise = utils
      .get('https://www.facebook.com/', jar)
      .then(utils.saveCookies(jar));
  } else {
    // Open the main page, then we login with the given credentials and finally
    // load the main page again (it'll give us some IDs that we need)
    mainPromise = utils
      .get("https://www.facebook.com/", null)
      .then(utils.saveCookies(jar))
      .then(makeLogin(jar, email, password, globalOptions, callback))
      .then(function() {
        return utils
          .get('https://www.facebook.com/', jar)
          .then(utils.saveCookies(jar));
      });
  }

  var ctx = null;
  var defaultFuncs = null;
  var api = null;

  mainPromise = mainPromise
    .then(function(res) {
      var html = res.body;
      var stuff = buildAPI(globalOptions, html, jar);
      ctx = stuff[0];
      defaultFuncs = stuff[1];
      api = stuff[2];
      return res;
    })
    .then(function() {
      var form = {
        reason: 6
      };
      log.info("login", 'Request to reconnect');
      return defaultFuncs
        .get("https://www.facebook.com/ajax/presence/reconnect.php", ctx.jar, form)
        .then(utils.saveCookies(ctx.jar));
    })
    .then(function(res) {
      log.info("login", 'Request to pull 1');
      var form = {
        channel : 'p_' + ctx.userID,
        seq : 0,
        partition : -2,
        clientid : ctx.clientID,
        viewer_uid : ctx.userID,
        uid : ctx.userID,
        state : 'active',
        idle : 0,
        cap : 8,
        msgs_recv: 0
      };
      var presence = utils.generatePresence(ctx.userID);
      ctx.jar.setCookie("presence=" + presence + "; path=/; domain=.facebook.com; secure", "https://www.facebook.com");
      ctx.jar.setCookie("presence=" + presence + "; path=/; domain=.messenger.com; secure", "https://www.messenger.com");
      ctx.jar.setCookie("locale=en_US; path=/; domain=.facebook.com; secure", "https://www.facebook.com");
      ctx.jar.setCookie("locale=en_US; path=/; domain=.messenger.com; secure", "https://www.messenger.com");
      ctx.jar.setCookie("a11y=" + utils.generateAccessiblityCookie() + "; path=/; domain=.facebook.com; secure", "https://www.facebook.com");

      return utils
        .get("https://0-edge-chat.facebook.com/pull", ctx.jar, form)
        .then(utils.saveCookies(ctx.jar))
        .then(function(res) {
          var ret = null;
          try {
            ret = JSON.parse(utils.makeParsable(res.body));
          } catch(e) {
            throw {error: "Error inside first pull request. Received HTML instead of JSON. Logging in inside a browser might help fix this."};
          }

          return ret;
        });
    })
    .then(function(resData) {
      if (resData.t !== 'lb') throw {error: "Bad response from pull 1"};

      var form = {
        channel : 'p_' + ctx.userID,
        seq : 0,
        partition : -2,
        clientid : ctx.clientID,
        viewer_uid : ctx.userID,
        uid : ctx.userID,
        state : 'active',
        idle : 0,
        cap : 8,
        msgs_recv:0,
        sticky_token: resData.lb_info.sticky,
        sticky_pool: resData.lb_info.pool,
      };

      log.info("login", "Request to pull 2");
      return utils
        .get("https://0-edge-chat.facebook.com/pull", ctx.jar, form)
        .then(utils.saveCookies(ctx.jar));
    })
    .then(function() {
      var form = {
        'client' : 'mercury',
        'folders[0]': 'inbox',
        'last_action_timestamp' : '0'
      };
      log.info("login", "Request to thread_sync");

      return defaultFuncs
        .post("https://www.facebook.com/ajax/mercury/thread_sync.php", ctx.jar, form)
        .then(utils.saveCookies(ctx.jar));
    });

  // given a pageID we log in as a page
  if (globalOptions.pageID) {
    mainPromise = mainPromise
      .then(function() {
        return utils
          .get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar);
      })
      .then(function(resData) {
        var url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
        url = url.substring(0, url.length - 1);

        return utils
          .get('https://www.facebook.com' + url, ctx.jar);
      });
  }

  // At the end we call the callback or catch an exception
  mainPromise
    .then(function() {
      log.info("login", 'Done logging in.');
      return callback(null, api);
    })
    .catch(function(e) {
      log.error("login", e.error || e);
      callback(e);
    });
}

function login(loginData, options, callback) {
  if(utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
    callback = options;
    options = {};
  }

  var globalOptions = {
    selfListen: false,
    listenEvents: false,
    updatePresence: false,
    forceLogin: false,
    logRecordSize: defaultLogRecordSize
  };

  setOptions(globalOptions, options);

  loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback);
}

module.exports = login;
<commit_msg>Login approvals fix (#548)<commit_after>"use strict";

var utils = require("./utils");
var cheerio = require("cheerio");
var log = require("npmlog");

var defaultLogRecordSize = 100;
log.maxRecordSize = defaultLogRecordSize;

function setOptions(globalOptions, options) {
  Object.keys(options).map(function(key) {
    switch (key) {
      case 'logLevel':
        log.level = options.logLevel;
        globalOptions.logLevel = options.logLevel;
        break;
      case 'logRecordSize':
        log.maxRecordSize = options.logRecordSize;
        globalOptions.logRecordSize = options.logRecordSize;
        break;
      case 'selfListen':
        globalOptions.selfListen = options.selfListen;
        break;
      case 'listenEvents':
        globalOptions.listenEvents = options.listenEvents;
        break;
      case 'pageID':
        globalOptions.pageID = options.pageID.toString();
        break;
      case 'updatePresence':
        globalOptions.updatePresence = options.updatePresence;
        break;
      case 'forceLogin':
        globalOptions.forceLogin = options.forceLogin;
        break;
      default:
        log.warn("setOptions", "Unrecognized option given to setOptions: " + key);
        break;
    }
  });
}

function buildAPI(globalOptions, html, jar) {
  var maybeCookie = jar.getCookies("https://www.facebook.com").filter(function(val) {
    return val.cookieString().split("=")[0] === "c_user";
  });

  if(maybeCookie.length === 0) {
    throw {error: "Error retrieving userID. This can be caused by a lot of things, including getting blocked by Facebook for logging in from an unknown location. Try logging in with a browser to verify."};
  }

  var userID = maybeCookie[0].cookieString().split("=")[1].toString();
  log.info("login", "Logged in");

  var clientID = (Math.random() * 2147483648 | 0).toString(16);

  // All data available to api functions
  var ctx = {
    userID: userID,
    jar: jar,
    clientID: clientID,
    globalOptions: globalOptions,
    loggedIn: true,
    access_token: 'NONE',
    clientMutationId: 0
  };

  var api = {
    setOptions: setOptions.bind(null, globalOptions),
    getAppState: function getAppState() {
      return utils.getAppState(jar);
    },
  };

  var apiFuncNames = [
    'addUserToGroup',
    'changeArchivedStatus',
    'changeBlockedStatus',
    'changeGroupImage',
    'changeThreadColor',
    'changeThreadEmoji',
    'changeNickname',
    'createPoll',
    'deleteMessage',
    'deleteThread',
    'forwardAttachment',
    'getCurrentUserID',
    'getEmojiUrl',
    'getFriendsList',
    'getThreadHistory',
    'getThreadInfo',
    'getThreadList',
    'getThreadPictures',
    'getUserID',
    'getUserInfo',
    'threadColors',
    'handleMessageRequest',
    'listen',
    'logout',
    'markAsRead',
    'muteThread',
    'removeUserFromGroup',
    'resolvePhotoUrl',
    'searchForThread',
    'sendMessage',
    'sendTypingIndicator',
    'setMessageReaction',
    'setTitle',

    // Beta features
    'getThreadHistoryGraphQL',
    'getThreadInfoGraphQL',
  ];

  var defaultFuncs = utils.makeDefaults(html, userID, ctx);

  // Load all api functions in a loop
  apiFuncNames.map(function(v) {
    api[v] = require('./src/' + v)(defaultFuncs, api, ctx);
  });

  return [ctx, defaultFuncs, api];
}

function makeLogin(jar, email, password, loginOptions, callback) {
  return function(res) {
    var html = res.body;
    var $ = cheerio.load(html);
    var arr = [];

    // This will be empty, but just to be sure we leave it
    $("#login_form input").map(function(i, v){
      arr.push({val: $(v).val(), name: $(v).attr("name")});
    });

    arr = arr.filter(function(v) {
      return v.val && v.val.length;
    });

    var form = utils.arrToForm(arr);
    form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
    form.lgndim = new Buffer("{\"w\":1440,\"h\":900,\"aw\":1440,\"ah\":834,\"c\":24}").toString('base64');
    form.email = email;
    form.pass = password;
    form.default_persistent = '0';
    form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
    form.locale = 'en_US';
    form.timezone = '240';
    form.lgnjs = ~~(Date.now() / 1000);

    // Getting cookies from the HTML page... (kill me now plz)
    // we used to get a bunch of cookies in the headers of the response of the
    // request, but FB changed and they now send those cookies inside the JS.
    // They run the JS which then injects the cookies in the page.
    // The "solution" is to parse through the html and find those cookies
    // which happen to be conveniently indicated with a _js_ in front of their
    // variable name.
    //
    // ---------- Very Hacky Part Starts -----------------
    var willBeCookies = html.split("\"_js_");
    willBeCookies.slice(1).map(function(val) {
      var cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
      jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
    });
    // ---------- Very Hacky Part Ends -----------------

    log.info("login", "Logging in...");
    return utils
      .post("https://www.facebook.com/login.php?login_attempt=1&lwv=110", jar, form)
      .then(utils.saveCookies(jar))
      .then(function(res) {
        var headers = res.headers;
        if (!headers.location) {
          throw {error: "Wrong username/password."};
        }

        // This means the account has login approvals turned on.
        if (headers.location.indexOf('https://www.facebook.com/checkpoint/') > -1) {
          log.info("login", "You have login approvals turned on.");
          var nextURL = 'https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php';

          return utils
            .get(headers.location, jar)
            .then(utils.saveCookies(jar))
            .then(function(res) {
              var html = res.body;
              // Make the form in advance which will contain the fb_dtsg and nh
              var $ = cheerio.load(html);
              var arr = [];
              $("form input").map(function(i, v){
                arr.push({val: $(v).val(), name: $(v).attr("name")});
              });

              arr = arr.filter(function(v) {
                return v.val && v.val.length;
              });

              var form = utils.arrToForm(arr);
              if (html.indexOf("checkpoint/?next") > -1) {
                throw {
                  error: 'login-approval',
                  continue: function(code) {
                    form.approvals_code = code;
                    form['submit[Continue]'] = 'Continue';
                    return utils
                      .post(nextURL, jar, form)
                      .then(utils.saveCookies(jar))
                      .then(function() {
                        // Use the same form (safe I hope)
                        form.name_action_selected = 'save_device';

                        return utils
                          .post(nextURL, jar, form)
                          .then(utils.saveCookies(jar));
                      })
                      .then(function(res) {
                        var headers = res.headers;
                        if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
                          throw {error: "Something went wrong with login approvals."};
                        }

                        var appState = utils.getAppState(jar);

                        // Simply call loginHelper because all it needs is the jar
                        // and will then complete the login process
                        return loginHelper(appState, email, password, loginOptions, callback);
                      })
                      .catch(function(err) {
                        callback(err);
                      });
                  }
                };
              } else {
                if (!loginOptions.forceLogin) {
                  throw {error: "Couldn't login. Facebook might have blocked this account. Please login with a browser or enable the option 'forceLogin' and try again."};
                }
                if (html.indexOf("Suspicious Login Attempt") > -1) {
                  form['submit[This was me]'] = "This was me";
                } else {
                  form['submit[This Is Okay]'] = "This Is Okay";
                }

                return utils
                  .post(nextURL, jar, form)
                  .then(utils.saveCookies(jar))
                  .then(function() {
                    // Use the same form (safe I hope)
                    form.name_action_selected = 'save_device';

                    return utils
                      .post(nextURL, jar, form)
                      .then(utils.saveCookies(jar));
                  })
                  .then(function(res) {
                    var headers = res.headers;

                    if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
                      throw {error: "Something went wrong with review recent login."};
                    }

                    var appState = utils.getAppState(jar);

                    // Simply call loginHelper because all it needs is the jar
                    // and will then complete the login process
                    return loginHelper(appState, email, password, loginOptions, callback);
                  })
                  .catch(function(e) {
                    callback(e);
                  });
              }
            });
        }

        return utils
          .get('https://www.facebook.com/', jar)
          .then(utils.saveCookies(jar));
      });
  };
}

// Helps the login
function loginHelper(appState, email, password, globalOptions, callback) {
  var mainPromise = null;
  var jar = utils.getJar();

  // If we're given an appState we loop through it and save each cookie
  // back into the jar.
  if(appState) {
    appState.map(function(c) {
      var str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
      jar.setCookie(str, "http://" + c.domain);
    });

    // Load the main page.
    mainPromise = utils
      .get('https://www.facebook.com/', jar)
      .then(utils.saveCookies(jar));
  } else {
    // Open the main page, then we login with the given credentials and finally
    // load the main page again (it'll give us some IDs that we need)
    mainPromise = utils
      .get("https://www.facebook.com/", null)
      .then(utils.saveCookies(jar))
      .then(makeLogin(jar, email, password, globalOptions, callback))
      .then(function() {
        return utils
          .get('https://www.facebook.com/', jar)
          .then(utils.saveCookies(jar));
      });
  }

  var ctx = null;
  var defaultFuncs = null;
  var api = null;

  mainPromise = mainPromise
    .then(function(res) {
      var html = res.body;
      var stuff = buildAPI(globalOptions, html, jar);
      ctx = stuff[0];
      defaultFuncs = stuff[1];
      api = stuff[2];
      return res;
    })
    .then(function() {
      var form = {
        reason: 6
      };
      log.info("login", 'Request to reconnect');
      return defaultFuncs
        .get("https://www.facebook.com/ajax/presence/reconnect.php", ctx.jar, form)
        .then(utils.saveCookies(ctx.jar));
    })
    .then(function(res) {
      log.info("login", 'Request to pull 1');
      var form = {
        channel : 'p_' + ctx.userID,
        seq : 0,
        partition : -2,
        clientid : ctx.clientID,
        viewer_uid : ctx.userID,
        uid : ctx.userID,
        state : 'active',
        idle : 0,
        cap : 8,
        msgs_recv: 0
      };
      var presence = utils.generatePresence(ctx.userID);
      ctx.jar.setCookie("presence=" + presence + "; path=/; domain=.facebook.com; secure", "https://www.facebook.com");
      ctx.jar.setCookie("presence=" + presence + "; path=/; domain=.messenger.com; secure", "https://www.messenger.com");
      ctx.jar.setCookie("locale=en_US; path=/; domain=.facebook.com; secure", "https://www.facebook.com");
      ctx.jar.setCookie("locale=en_US; path=/; domain=.messenger.com; secure", "https://www.messenger.com");
      ctx.jar.setCookie("a11y=" + utils.generateAccessiblityCookie() + "; path=/; domain=.facebook.com; secure", "https://www.facebook.com");

      return utils
        .get("https://0-edge-chat.facebook.com/pull", ctx.jar, form)
        .then(utils.saveCookies(ctx.jar))
        .then(function(res) {
          var ret = null;
          try {
            ret = JSON.parse(utils.makeParsable(res.body));
          } catch(e) {
            throw {error: "Error inside first pull request. Received HTML instead of JSON. Logging in inside a browser might help fix this."};
          }

          return ret;
        });
    })
    .then(function(resData) {
      if (resData.t !== 'lb') throw {error: "Bad response from pull 1"};

      var form = {
        channel : 'p_' + ctx.userID,
        seq : 0,
        partition : -2,
        clientid : ctx.clientID,
        viewer_uid : ctx.userID,
        uid : ctx.userID,
        state : 'active',
        idle : 0,
        cap : 8,
        msgs_recv:0,
        sticky_token: resData.lb_info.sticky,
        sticky_pool: resData.lb_info.pool,
      };

      log.info("login", "Request to pull 2");
      return utils
        .get("https://0-edge-chat.facebook.com/pull", ctx.jar, form)
        .then(utils.saveCookies(ctx.jar));
    })
    .then(function() {
      var form = {
        'client' : 'mercury',
        'folders[0]': 'inbox',
        'last_action_timestamp' : '0'
      };
      log.info("login", "Request to thread_sync");

      return defaultFuncs
        .post("https://www.facebook.com/ajax/mercury/thread_sync.php", ctx.jar, form)
        .then(utils.saveCookies(ctx.jar));
    });

  // given a pageID we log in as a page
  if (globalOptions.pageID) {
    mainPromise = mainPromise
      .then(function() {
        return utils
          .get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar);
      })
      .then(function(resData) {
        var url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
        url = url.substring(0, url.length - 1);

        return utils
          .get('https://www.facebook.com' + url, ctx.jar);
      });
  }

  // At the end we call the callback or catch an exception
  mainPromise
    .then(function() {
      log.info("login", 'Done logging in.');
      return callback(null, api);
    })
    .catch(function(e) {
      log.error("login", e.error || e);
      callback(e);
    });
}

function login(loginData, options, callback) {
  if(utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
    callback = options;
    options = {};
  }

  var globalOptions = {
    selfListen: false,
    listenEvents: false,
    updatePresence: false,
    forceLogin: false,
    logRecordSize: defaultLogRecordSize
  };

  setOptions(globalOptions, options);

  loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback);
}

module.exports = login;
<|endoftext|>


<commit_before>var async = require('async');
var fs = require('fs');
var exec = require('child_process').exec;

module.exports = function (session){
    return function (track, path, callback){

        console.log('Downloading: ' + track.title + ' by ' + track.artist.name);

        var player = session.getPlayer();

        var regex = /[\:\^\`\'\"\*\\\]\[\{\}\/\s\(\)]/g;

        if(!(fs.existsSync(path + '/' + track.artist.name.replace(regex, '_') + '/' + track.album.name.replace(regex, '_')))){

            if(!(fs.existsSync(path + '/' + track.artist.name.replace(regex, '_')))){
                fs.mkdirSync(path + '/' + track.artist.name.replace(regex, '_'))
            }

            fs.mkdirSync(path + '/' + track.artist.name.replace(regex, '_') + '/' + track.album.name.replace(regex, '_'))

        }

        var destiny = path + '/' + track.artist.name.replace(regex, '_') + '/' + track.album.name.replace(regex, '_') + '/' + track.name.replace(regex, '_');

        if(fs.existsSync(destiny + '.mp3')){
            console.log('Already downloaded');
            return callback(null);
        }

        var ws = fs.createWriteStream(destiny + '.raw');

        player.load(track);
        player.play();

        player.pipe(ws);
        player.once('track-end', function() {
            player.stop();
            ws.end();

            async.waterfall([

                function (callback){
                    console.log('Converting raw file to wav');
                    exec('sox ' + [
                        '-r', 44100,
                        '-b', 16,
                        '-L',
                        '-c', 2,
                        '-e', 'signed-integer',
                        '-t', 'raw',
                        destiny + '.raw',
                        destiny + '.wav'].join(' '), function (err){callback(err)});
                }, function (callback){
                    console.log('Converting wav file to mp3 at 320kbps');
                    exec('lame ' + [
                        '--preset', 'insane',
                        '-b', 320,
                        '-h',
                        destiny + '.wav',
                        destiny + '.mp3'].join(' '), function (err){callback(err)});
                }, function (callback){
                    track.album.coverImage(function (err, buffer){
                        if(err){
                            return callback(null, false)
                        }
                        fs.writeFile(destiny + '.png', buffer, function (err){
                            callback(null, true);
                        });
                    });
                }, function (cover, callback){

                    console.log('Adding id3 tags');

                    var coverCmd = ['--add-image', destiny + '.png:FRONT_COVER'];

                    var args = [
                        '-t', '"'+track.title+'"',
                        '-a', '"'+track.artist.name+'"',
                        '-A', '"'+track.album.name+'"',
                        '-Y', '"'+track.album.year+'"',
                        '-Q',
                        destiny +'.mp3'
                    ]

                    if (cover){
                        args = coverCmd.concat(args); // Adds the command to add a ilustration to the file
                    }

                    var cmd = 'eyeD3 ' + args.join(' ');

                    exec(cmd, function (err){callback(err)});

                }, function (callback){
                    var shit = [destiny + '.raw', destiny + '.wav', destiny + '.png'];
                    async.map(shit, fs.unlink, callback)
                }

            ], function (err){
                console.log('Done');
                ws.end()
                delete player, ws
                callback(err);
            });

        });

        player.on('error', function (err){
            ws.end();
            callback(err);
        });
    }
}<commit_msg>Moar fixes<commit_after>var async = require('async');
var fs = require('fs');
var exec = require('child_process').exec;

module.exports = function (session){
    return function (track, path, callback){

        console.log('Downloading: ' + track.title + ' by ' + track.artist.name);

        var player = session.getPlayer();

        var regex = /[\:\^\`\'\"\*\\\]\[\{\}\/\s\(\)]/g;

        if(!(fs.existsSync(path + '/' + track.artist.name.replace(regex, '_') + '/' + track.album.name.replace(regex, '_')))){

            if(!(fs.existsSync(path + '/' + track.artist.name.replace(regex, '_')))){
                fs.mkdirSync(path + '/' + track.artist.name.replace(regex, '_'))
            }

            fs.mkdirSync(path + '/' + track.artist.name.replace(regex, '_') + '/' + track.album.name.replace(regex, '_'))

        }

        var destiny = path + '/' + track.artist.name.replace(regex, '_') + '/' + track.album.name.replace(regex, '_') + '/' + track.name.replace(regex, '_');

        if(fs.existsSync(destiny + '.mp3')){
            console.log('Already downloaded');
            return callback(null);
        }

        var ws = fs.createWriteStream(destiny + '.raw');

        player.load(track);
        player.play();

        player.pipe(ws);
        player.once('track-end', function() {
            player.stop();
            ws.end();

            async.waterfall([

                function (callback){
                    console.log('Converting raw file to wav');
                    exec('sox ' + [
                        '-r', 44100,
                        '-b', 16,
                        '-L',
                        '-c', 2,
                        '-e', 'signed-integer',
                        '-t', 'raw',
                        destiny + '.raw',
                        destiny + '.wav'].join(' '), function (err){callback(err)});
                }, function (callback){
                    console.log('Converting wav file to mp3 at 320kbps');
                    exec('lame ' + [
                        '--preset', 'insane',
                        '-b', 320,
                        '-h',
                        destiny + '.wav',
                        destiny + '.mp3'].join(' '), function (err){callback(err)});
                }, function (callback){
                    track.album.coverImage(function (err, buffer){
                        if(err){
                            return callback(null, false)
                        }
                        fs.writeFile(destiny + '.png', buffer, function (err){
                            callback(null, true);
                        });
                    });
                }, function (cover, callback){

                    console.log('Adding id3 tags');

                    var coverCmd = ['--add-image', destiny + '.png:FRONT_COVER'];

                    var args = [
                        '-t', '"'+track.title+'"',
                        '-a', '"'+track.artist.name+'"',
                        '-A', '"'+track.album.name+'"',
                        '-Y', '"'+track.album.year+'"',
                        '-Q',
                        destiny +'.mp3'
                    ]

                    if (cover){
                        args = coverCmd.concat(args); // Adds the command to add a ilustration to the file
                    }

                    var cmd = 'eyeD3 ' + args.join(' ');

                    exec(cmd, function (err){callback(err, cover)});

                }, function (cover, callback){
                    var shit = [destiny + '.raw', destiny + '.wav'];
                    if(cover){ shit.push(destiny + '.png') }
                    async.map(shit, fs.unlink, callback)
                }

            ], function (err){
                console.log('Done');
                ws.end()
                delete player, ws
                callback(err);
            });

        });

        player.on('error', function (err){
            ws.end();
            callback(err);
        });
    }
}<|endoftext|>


<commit_before>'use strict'

const convert = require('jscss/lib/convert')
const pretty = require('jscss/lib/compile').pretty
const compact = require('jscss/lib/compile').compact

exports.name = 'jscss'
exports.inputFormats = ['jscss', 'css', 'js']
exports.outputFormat = 'css'

exports.render = function (str, opts) {
  return jscss(str, opts)
}

// Just workaround, PRs sent
function jscss(jscss, opts) {
  opts = typeof opts === 'object' ? opts : {}
  const converted = convert(jscss)

  if (opts.pretty || opts.prettify) {
    return pretty(converted)
  }

  if (opts.intermediate) {
    return converted
  }

  return compact(converted)
}
<commit_msg>Update eslint<commit_after>'use strict'

const convert = require('jscss/lib/convert')
const {pretty, compact} = require('jscss/lib/compile')

exports.name = 'jscss'
exports.inputFormats = ['jscss', 'css', 'js']
exports.outputFormat = 'css'

exports.render = function (str, opts) {
  return jscss(str, opts)
}

// Just workaround, PRs sent
function jscss(jscss, opts) {
  opts = typeof opts === 'object' ? opts : {}
  const converted = convert(jscss)

  if (opts.pretty || opts.prettify) {
    return pretty(converted)
  }

  if (opts.intermediate) {
    return converted
  }

  return compact(converted)
}
<|endoftext|>


<commit_before>/**
 * Created by karl on 24/08/14.
 */

module.exports = function(sailsConfig) {
    return sailsConfig.configurator('session', {
        modules: {
            'connect-mongo': {
                uninstall: true
            }
        },
        configs: {
            development: {
                adapter: 'mongo',
                host: 'localhost',
                port: 27017,
                collection: 'sessions'
            }
        }
    });
};
<commit_msg>changed configurator into plugin<commit_after>/**
 * Created by karl on 24/08/14.
 */

module.exports = function(sailsConfig) {
    return sailsConfig.plugin('session', {
        modules: {
            'connect-mongo': {
                uninstall: true
            }
        },
        configs: {
            development: {
                adapter: 'mongo',
                host: 'localhost',
                port: 27017,
                collection: 'sessions'
            }
        }
    });
};
<|endoftext|>


<commit_before>angular.module("app", ['ui.bootstrap'])

.controller('appController', function($scope, $http, $document){
  $scope.state = "Start"
  $scope.payload = {
    category: "",
    timestamp: "",
    state: ""
  }

  $scope.changeState = function(){
    $scope.state === "Start" ? $scope.state = "Stop" : $scope.state = "Start"
  }

  $scope.sendData = function($event, $document){
    var target = document.getElementById('category').innerHTML
    $scope.payload.category = target;
    $scope.payload.timestamp = Date.now();
    $scope.payload.state = $scope.state
    $http.post('/api/toggleActivity', JSON.stringify($scope.payload))
  }

  $scope.recieveData = function(){

  }
})
<commit_msg>testing the new git workflow<commit_after>angular.module("app", ['ui.bootstrap'])

.controller('appController', function($scope, $http, $document){
  $scope.state = "Start"
  $scope.payload = {
    category: "",
    timestamp: "",
    state: ""

  }

  $scope.changeState = function(){
    $scope.state === "Start" ? $scope.state = "Stop" : $scope.state = "Start"
  }

  $scope.sendData = function($event, $document){
    var target = document.getElementById('category').innerHTML
    $scope.payload.category = target;
    $scope.payload.timestamp = Date.now();
    $scope.payload.state = $scope.state
    $http.post('/api/toggleActivity', JSON.stringify($scope.payload))
  }

  $scope.recieveData = function(){

  }
})
<|endoftext|>


<commit_before>window.App = Ember.Application.create({
  LOG_TRANSITIONS: true
});

App.JsonTransform = DS.Transform.extend({
  serialize: function (data) {
    return JSON.stringify(data);
  },
  deserialize: function (data) {
    return data;
  }
});

App.Set = DS.Model.extend({
  name: DS.attr('string'),
  takenAt: DS.attr('date'),
  photos: DS.hasMany('photo')
});

App.Photo = DS.Model.extend({
  path: DS.attr('string'),
  size: DS.attr('number'),
  width: DS.attr('number'),
  height: DS.attr('number'),
  takenAt: DS.attr('date'),
  exif: DS.attr('json'),
  bigThumbUrl: DS.attr('string'),
  smallThumbUrl: DS.attr('string'),
  set: DS.belongsTo('set')
});

App.Router.map(function () {
  this.resource('sets', { path: '/' }, function () {
    this.resource('set', { path: '/set/:set_id' }, function () {
      this.resource('photo', { path: '/photo/:photo_id' });
    });
  });
});

App.SetsRoute = Ember.Route.extend({
  model: function () {
    return this.store.find('set');
  }
});

App.SetRoute = Ember.Route.extend({
  model: function (params) {
    return this.store.find('set', params.set_id);
  }
});

App.PhotoRoute = Ember.Route.extend({
  model: function (params) {
    return this.store.find('photo', params.photo_id);
  }
});

App.SetController = Ember.ObjectController.extend({
  photosCount: function () {
    return this.get('model.photos.length');
  }.property('model.photos.length'),
  photosCountTitle: function () {
    var n = this.get('photosCount');
    return (n === 1) ? '1 photo' : n + ' photos';
  }.property('photosCount'),
  thumbUrl: function () {
    return this.get('model.photos.firstObject.smallThumbUrl');
  }.property('model.photos.firstObject.smallThumbUrl')
});

App.PhotoController = Ember.ObjectController.extend({
  aspectRatio: function () {
    var width = this.get('model.width');
    var height = this.get('model.height');
    var gcd = (function gcd(a, b) {
      return b ? gcd(b, a % b) : Math.abs(a);
    })(width, height);
    return (width / gcd) + ':' + (height / gcd);
  }.property('model.width, model.height'),
  fileName: function () {
    return this.get('model.path').split('/').reverse()[0];
  }.property('model.path'),
  formattedSize: function () {
    return (Math.round((this.get('model.size') / 1048576) * 100) / 100) + ' MB';
  }.property('model.size'),
  formattedTakenAt: function () {
    return moment(this.get('model.taken_at')).format(
      'ddd, D MMM YYYY HH:mm:ss z');
  }.property('model.taken_at')
});

// http://mavilein.github.io/javascript/2013/08/01/Ember-JS-After-Render-Event/
Ember.View.reopen({
  didInsertElement: function () {
    this._super();
    Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
  },
  afterRenderEvent: function () {}
});

App.ThumbsView = Ember.View.extend({
  scrollToActive: function (container) {
    var $container = Ember.$(container);
    var $target = $container.find('.active');

    if ($target.length) {
      if ($target.prev().length) {
        $target = $target.prev();
      }

      $container.scrollTop(
        $target.offset().top - $container.offset().top + $container.scrollTop()
      );
    }
  }
});

App.SetView = App.ThumbsView.extend({
  afterRenderEvent: function () {
    this.scrollToActive('#sets');
  }
});

App.PhotoView = App.ThumbsView.extend({
  afterRenderEvent: function () {
    this.scrollToActive('#photos');
  }
});

Ember.Handlebars.helper('truncate', function (text, length) {
  if (text.length < length) {
    return text;
  }

  return text.slice(0, length).replace(/\s+$/, '') + '...';
});
<commit_msg>Fix auto-scroll to active set and photo thumbs<commit_after>window.App = Ember.Application.create({
  LOG_TRANSITIONS: true
});

App.JsonTransform = DS.Transform.extend({
  serialize: function (data) {
    return JSON.stringify(data);
  },
  deserialize: function (data) {
    return data;
  }
});

App.Set = DS.Model.extend({
  name: DS.attr('string'),
  takenAt: DS.attr('date'),
  photos: DS.hasMany('photo')
});

App.Photo = DS.Model.extend({
  path: DS.attr('string'),
  size: DS.attr('number'),
  width: DS.attr('number'),
  height: DS.attr('number'),
  takenAt: DS.attr('date'),
  exif: DS.attr('json'),
  bigThumbUrl: DS.attr('string'),
  smallThumbUrl: DS.attr('string'),
  set: DS.belongsTo('set')
});

App.Router.map(function () {
  this.resource('sets', { path: '/' }, function () {
    this.resource('set', { path: '/set/:set_id' }, function () {
      this.resource('photo', { path: '/photo/:photo_id' });
    });
  });
});

App.SetsRoute = Ember.Route.extend({
  model: function () {
    return this.store.find('set');
  }
});

App.SetRoute = Ember.Route.extend({
  model: function (params) {
    return this.store.find('set', params.set_id);
  }
});

App.PhotoRoute = Ember.Route.extend({
  model: function (params) {
    return this.store.find('photo', params.photo_id);
  }
});

App.SetController = Ember.ObjectController.extend({
  photosCount: function () {
    return this.get('model.photos.length');
  }.property('model.photos.length'),
  photosCountTitle: function () {
    var n = this.get('photosCount');
    return (n === 1) ? '1 photo' : n + ' photos';
  }.property('photosCount'),
  thumbUrl: function () {
    return this.get('model.photos.firstObject.smallThumbUrl');
  }.property('model.photos.firstObject.smallThumbUrl')
});

App.PhotoController = Ember.ObjectController.extend({
  aspectRatio: function () {
    var width = this.get('model.width');
    var height = this.get('model.height');
    var gcd = (function gcd(a, b) {
      return b ? gcd(b, a % b) : Math.abs(a);
    })(width, height);
    return (width / gcd) + ':' + (height / gcd);
  }.property('model.width, model.height'),
  fileName: function () {
    return this.get('model.path').split('/').reverse()[0];
  }.property('model.path'),
  formattedSize: function () {
    return (Math.round((this.get('model.size') / 1048576) * 100) / 100) + ' MB';
  }.property('model.size'),
  formattedTakenAt: function () {
    return moment(this.get('model.taken_at')).format(
      'ddd, D MMM YYYY HH:mm:ss z');
  }.property('model.taken_at')
});

// http://mavilein.github.io/javascript/2013/08/01/Ember-JS-After-Render-Event/
Ember.View.reopen({
  didInsertElement: function () {
    this._super();
    Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
  },
  afterRenderEvent: function () {}
});

App.ThumbsView = Ember.View.extend({
  scrollToActive: function (container) {
    var $container = Ember.$(container);
    var $target = $container.find('.active').parent();

    if ($target.length) {
      var $targetPrev = $target.prevAll('li:first');

      if ($targetPrev.length) {
        $target = $targetPrev;
      }

      $container.scrollTop(
        $target.offset().top - $container.offset().top + $container.scrollTop()
      );
    }
  }
});

App.SetView = App.ThumbsView.extend({
  afterRenderEvent: function () {
    this.scrollToActive('#sets');
  }
});

App.PhotoView = App.ThumbsView.extend({
  afterRenderEvent: function () {
    this.scrollToActive('#photos');
  }
});

Ember.Handlebars.helper('truncate', function (text, length) {
  if (text.length < length) {
    return text;
  }

  return text.slice(0, length).replace(/\s+$/, '') + '...';
});
<|endoftext|>


<commit_before>'use strict';
var through2 = require('through2'),
    inquirer = require('inquirer'),
    gutil = require('gulp-util'),
    diff = require('diff'),
    fs = require('fs'),
    path = require('path'),
    pkg = require('./package');

module.exports = function conflict (dest, opt) {
  if (!dest) {
    error('Missing destination dir parameter!');
  }

  opt = opt || {};

  var all = false;

  return through2.obj(function (file, enc, cb) {
    var newPath = path.resolve(opt.cwd || process.cwd(), dest, file.relative);
    fs.stat(newPath, function (err, stat) {
      if (!all && stat && !stat.isDirectory()) {
        fs.readFile(newPath, 'utf8', function (err, contents) {
          if (err) {
            error('Reading old file for comparison failed with: ' + err.message);
          }
          if (contents === String(file.contents)) {
            log('Skipping ' + file.relative + ' (identical)');
            return cb();
          }
          var askCb = function askCb (action) {
            switch (action) {
              case 'all':
                all = true;
                /* falls through */
              case 'replace':
                log('Keeping ' + file.relative);
                this.push(file);
                break;
              case 'skip':
                log('Skipping ' + file.relative);
                break;
              case 'end':
                log(gutil.colors.red('Aborting...'));
                process.exit(0);
                break;
              case 'diff':
                log('Showing diff for ' + file.relative);
                diffFiles(file, newPath);
                ask(file, askCb.bind(this));
                return;
            }
            cb();
          };
          ask(file, askCb.bind(this));
        }.bind(this));
      } else {
        log('Keeping ' + file.relative);
        this.push(file);
        cb();
      }
    }.bind(this));
  });
};

function ask (file, cb) {
  inquirer.prompt([{
    type: 'expand',
    name: 'replace',
    message: 'Replace ' + file.relative + '?',
    choices: [{
      key: 'y',
      name: 'replace',
      value: 'replace'
    }, {
      key: 'n',
      name: 'do not replace',
      value: 'skip'
    }, {
      key: 'a',
      name: 'replace this and all others',
      value: 'all'
    }, {
      key: 'x',
      name: 'abort',
      value: 'end'
    }, {
      key: 'd',
      name: 'show the differences between the old and the new',
      value: 'diff'
    }]
  }],
  function (answers) {
    cb(answers.replace);
  });
}

function diffFiles (newFile, oldFilePath) {
  if (newFile.isStream()) {
    error('Diff does not support file streams');
  }
  try {
    var content = fs.readFileSync(oldFilePath, 'utf8');
    var differences = diff.diffLines(content, String(newFile.contents));
    log('File differences: ' + gutil.colors.bgGreen('added') + ' ' + gutil.colors.bgRed('removed') + '\n\n' + differences.map(formatPart).join(''));
  } catch (err) {
    error('Reading old file for diff failed with: ' + err.message);
  }
}

function formatPart (part, i) {
  var indent = new Array(8).join(' ');
  return (!i ? indent : '') + part.value.split('\n').map(function (line) {
    return gutil.colors[colorFromPart(part)](line);
  }).join('\n' + indent);
}

function colorFromPart (part) {
  if (part.added) {
    return 'bgGreen';
  } else if (part.removed) {
    return 'bgRed';
  }
  return 'grey';
}

function log () {
  var logger = gutil.log.bind(gutil, '[' + gutil.colors.cyan('conflict') + ']');
  logger.apply(logger, arguments);
}

function error (message) {
  throw new gutil.PluginError(pkg.name, message);
}

<commit_msg>Add skipAll option<commit_after>'use strict';
var through2 = require('through2'),
    inquirer = require('inquirer'),
    gutil = require('gulp-util'),
    diff = require('diff'),
    fs = require('fs'),
    path = require('path'),
    pkg = require('./package');

module.exports = function conflict (dest, opt) {
  if (!dest) {
    error('Missing destination dir parameter!');
  }

  opt = opt || {};

  var all = opt.skipAll || false;

  return through2.obj(function (file, enc, cb) {
    var newPath = path.resolve(opt.cwd || process.cwd(), dest, file.relative);
    fs.stat(newPath, function (err, stat) {
      if (!all && stat && !stat.isDirectory()) {
        fs.readFile(newPath, 'utf8', function (err, contents) {
          if (err) {
            error('Reading old file for comparison failed with: ' + err.message);
          }
          if (contents === String(file.contents)) {
            log('Skipping ' + file.relative + ' (identical)');
            return cb();
          }
          var askCb = function askCb (action) {
            switch (action) {
              case 'all':
                all = true;
                /* falls through */
              case 'replace':
                log('Keeping ' + file.relative);
                this.push(file);
                break;
              case 'skip':
                log('Skipping ' + file.relative);
                break;
              case 'end':
                log(gutil.colors.red('Aborting...'));
                process.exit(0);
                break;
              case 'diff':
                log('Showing diff for ' + file.relative);
                diffFiles(file, newPath);
                ask(file, askCb.bind(this));
                return;
            }
            cb();
          };
          ask(file, askCb.bind(this));
        }.bind(this));
      } else {
        log('Keeping ' + file.relative);
        this.push(file);
        cb();
      }
    }.bind(this));
  });
};

function ask (file, cb) {
  inquirer.prompt([{
    type: 'expand',
    name: 'replace',
    message: 'Replace ' + file.relative + '?',
    choices: [{
      key: 'y',
      name: 'replace',
      value: 'replace'
    }, {
      key: 'n',
      name: 'do not replace',
      value: 'skip'
    }, {
      key: 'a',
      name: 'replace this and all others',
      value: 'all'
    }, {
      key: 'x',
      name: 'abort',
      value: 'end'
    }, {
      key: 'd',
      name: 'show the differences between the old and the new',
      value: 'diff'
    }]
  }],
  function (answers) {
    cb(answers.replace);
  });
}

function diffFiles (newFile, oldFilePath) {
  if (newFile.isStream()) {
    error('Diff does not support file streams');
  }
  try {
    var content = fs.readFileSync(oldFilePath, 'utf8');
    var differences = diff.diffLines(content, String(newFile.contents));
    log('File differences: ' + gutil.colors.bgGreen('added') + ' ' + gutil.colors.bgRed('removed') + '\n\n' + differences.map(formatPart).join(''));
  } catch (err) {
    error('Reading old file for diff failed with: ' + err.message);
  }
}

function formatPart (part, i) {
  var indent = new Array(8).join(' ');
  return (!i ? indent : '') + part.value.split('\n').map(function (line) {
    return gutil.colors[colorFromPart(part)](line);
  }).join('\n' + indent);
}

function colorFromPart (part) {
  if (part.added) {
    return 'bgGreen';
  } else if (part.removed) {
    return 'bgRed';
  }
  return 'grey';
}

function log () {
  var logger = gutil.log.bind(gutil, '[' + gutil.colors.cyan('conflict') + ']');
  logger.apply(logger, arguments);
}

function error (message) {
  throw new gutil.PluginError(pkg.name, message);
}

<|endoftext|>


<commit_before>/**
 * The MIT License
 *
 * Copyright (c) 2014 Martin Micunda
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

/**
 * Module dependencies.
 */
var extend         = require('util')._extend,
    nodemailer     = require('nodemailer'),
    emailTemplates = require('email-templates');

/**
 * A node module for sending e-mails.
 *
 * @module mm-node-mailer
 * @example
 *  ```js
 *      var mailer = new mmMailer({
 *          config: {
 *              service: 'Gmail',
 *              auth: {
 *                  user: 'test@gmail.com',
 *                  pass: 'password'
 *              }
 *          },
 *          mail: {
 *              from: 'test@gmail.com',
 *              subject: 'Hello',
 *              text: 'Hello world!',
 *              html: '<b>Hello world!</b>'
 *          }
 *      });
 *      var mailOptions = {
 *          to: 'your.email@address.com',
 *      }
 *      mailer.send(mailOptions, function (err, respond) {
 *          if (err) return console.error(err);
 *          console.log('An e-mail has been sent successfully. Server responded with "' + respond + '"');
 *      });
 *  ```
 */
module.exports = Mailer;

/**
 * Define default mailer options.
 *
 * @type {Object} defaultOptions - the default mailer options
 * @type {Object} defaultOptions.config - the nodemailer configuration. See {@link https://github.com/andris9/nodemailer-smtp-transport `nodemailer-smtp-transport`} for full description of config fields.
 * @type {Object} defaultOptions.mail - the to, from, cc, etc, fields for all emails. See {@link https://github.com/andris9/Nodemailer#e-mail-message-fields `e-mail-message-fields`} for full description of email fields.
 * @type {string} defaultOptions.mail.templateName - (optional) the template folder name that is store in templates directory
 * @type {Object} defaultOptions.mail.templateContent - (optional) the template JSON content
 * @type {string} defaultOptions.templatesDir - (optional) the templates directory path
 * @type {Object} defaultOptions.templateEngineOptions - (optional) the template engine options e.g. helpers, partials etc. See {@link https://github.com/niftylettuce/node-email-templates#templating-language-options-eg-ejs-custom-tags `node-email-templates`} for options.
 * @private
 */
var defaultOptions = {
    config: {},
    mail: {
        templateName: '',
        templateContent: {}
    },
    templatesDir: '',
    templateEngineOptions: {}
};

/**
 * A `Mailer` constructor.
 *
 * @class Mailer
 * @constructor
 *
 * @param {Object} options - custom mailer configuration options
 */
function Mailer(options) {
    if (!(this instanceof Mailer)) {return new Mailer(options);}
    // extend default options
    this.options = extend(defaultOptions, options);
    // create transporter that is able to send mail
    this.transporter = nodemailer.createTransport(options.config);
}

/**
 * Sends an email using the preselected transport object.
 *
 * @method send
 * @param {Object}   mailOptions - the email data options, see {@link https://github.com/andris9/Nodemailer#e-mail-message-fields `e-mail-message-fields`} for full description of email fields.
 * @param {Function} cb          - the callback function
 *
 * @returns {Function} the callback function
 */
Mailer.prototype.send = function(mailOptions, cb) {
    var self = this;

    // extend the default mail options with options passed by user
    self.options.mail = extend(self.options.mail, mailOptions);

    if(!self.options.mail.from) {
        return cb(new Error('Sender email address required'));
    }
    if(!self.options.mail.to) {
        return cb(new Error('Receiver email address required'));
    }

    if(self.options.templatesDir && self.options.mail.templateName) {
        emailTemplates(self.options.templatesDir, self.options.templateEngineOptions, function (err, template) {
            if (err) {return cb(err);}

            template(self.options.mail.templateName, self.options.mail.templateContent, function (err, html, text) {
                if (err) {return cb(err);}

                self.options.mail.html = html;
                self.options.mail.text = text;

                // if we are testing don't send out an email instead return success, info response, html and txt strings for inspection
                if (process.env.NODE_ENV === 'test') {
                    return cb(null, '250 2.0.0 OK 1407018531 gc8sm23308604wic.3 - gsmtp', html, text);
                }

                self.transporter.sendMail(self.options.mail, function (err, info) {
                    if (err) {return cb(err);}

                    return cb(null, info.response, html, text);
                });
            });
        });
    } else {
        // if we are testing don't send out an email instead return success and info response for inspection
        if (process.env.NODE_ENV === 'test') {
            return cb(null, '250 2.0.0 OK 1407018531 gc8sm23308604wic.3 - gsmtp');
        }
        self.transporter.sendMail(self.options.mail, function (err, info) {
            if (err) {return cb(err);}

            return cb(null, info.response);
        });
    }
};

/**
 * Shut down the connection pool so no more messages are send (use if you don't
 * want to use transport object anymore).
 *
 * @method close
 */
Mailer.prototype.close = function() {
    this.transporter.close();
};

/**
 * Retrieves the Mailer configuration options.
 *
 * @method getOptions
 * @returns {Object} the mailer configuration options
 */
Mailer.prototype.getOptions = function() {
    return this.options;
};<commit_msg>chore(comments): add more comments<commit_after>/**
 * The MIT License
 *
 * Copyright (c) 2014 Martin Micunda
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

/**
 * Module dependencies.
 */
var extend         = require('util')._extend,
    nodemailer     = require('nodemailer'),
    emailTemplates = require('email-templates');

/**
 * A node module for sending e-mails.
 *
 * @module mm-node-mailer
 * @example
 *  ```js
 *      var mailer = new mmMailer({
 *          config: {
 *              service: 'Gmail',
 *              auth: {
 *                  user: 'test@gmail.com',
 *                  pass: 'password'
 *              }
 *          },
 *          mail: {
 *              from: 'test@gmail.com',
 *              subject: 'Hello',
 *              text: 'Hello world!',
 *              html: '<b>Hello world!</b>'
 *          }
 *      });
 *      var mailOptions = {
 *          to: 'your.email@address.com',
 *      }
 *      mailer.send(mailOptions, function (err, respond) {
 *          if (err) return console.error(err);
 *          console.log('An e-mail has been sent successfully. Server responded with "' + respond + '"');
 *      });
 *  ```
 */
module.exports = Mailer;

/**
 * Define default mailer options.
 *
 * @type {Object} defaultOptions - the default mailer options
 * @type {Object} defaultOptions.config - the nodemailer configuration. See {@link https://github.com/andris9/nodemailer-smtp-transport `nodemailer-smtp-transport`} for full description of config fields.
 * @type {Object} defaultOptions.mail - the to, from, cc, etc, fields for all emails. See {@link https://github.com/andris9/Nodemailer#e-mail-message-fields `e-mail-message-fields`} for full description of email fields.
 * @type {string} defaultOptions.mail.templateName - (optional) the template folder name that is store in templates directory
 * @type {Object} defaultOptions.mail.templateContent - (optional) the template JSON content
 * @type {string} defaultOptions.templatesDir - (optional) the templates directory path
 * @type {Object} defaultOptions.templateEngineOptions - (optional) the template engine options e.g. helpers, partials etc. See {@link https://github.com/niftylettuce/node-email-templates#templating-language-options-eg-ejs-custom-tags `node-email-templates`} for options.
 * @private
 */
var defaultOptions = {
    config: {},
    mail: {
        templateName: '',
        templateContent: {}
    },
    templatesDir: '',
    templateEngineOptions: {}
};

/**
 * A `Mailer` constructor.
 *
 * @class Mailer
 * @constructor
 *
 * @param {Object} options - custom mailer configuration options
 */
function Mailer(options) {
    if (!(this instanceof Mailer)) {return new Mailer(options);}
    // extend default options
    this.options = extend(defaultOptions, options);
    // create transporter that is able to send mail
    this.transporter = nodemailer.createTransport(options.config);
}

/**
 * Sends an email using the preselected transport object.
 *
 * @method send
 * @param {Object}   mailOptions - the email data options, see {@link https://github.com/andris9/Nodemailer#e-mail-message-fields `e-mail-message-fields`} for full description of email fields.
 * @param {Function} cb          - the callback function
 *
 * @returns {Function} the callback function
 */
Mailer.prototype.send = function(mailOptions, cb) {
    var self = this;

    // extend the default mail options with options passed by user
    self.options.mail = extend(self.options.mail, mailOptions);

    if(!self.options.mail.from) {
        return cb(new Error('Sender email address required'));
    }
    if(!self.options.mail.to) {
        return cb(new Error('Receiver email address required'));
    }

    // check if it should send text or template e-mail
    if(self.options.templatesDir && self.options.mail.templateName) {
        emailTemplates(self.options.templatesDir, self.options.templateEngineOptions, function (err, template) {
            if (err) {return cb(err);}

            template(self.options.mail.templateName, self.options.mail.templateContent, function (err, html, text) {
                if (err) {return cb(err);}

                self.options.mail.html = html;
                self.options.mail.text = text;

                // if we are testing don't send out an email instead return success, info response, html and txt strings for inspection
                if (process.env.NODE_ENV === 'test') {
                    return cb(null, '250 2.0.0 OK 1407018531 gc8sm23308604wic.3 - gsmtp', html, text);
                }

                self.transporter.sendMail(self.options.mail, function (err, info) {
                    if (err) {return cb(err);}

                    return cb(null, info.response, html, text);
                });
            });
        });
    } else {
        // if we are testing don't send out an email instead return success and info response for inspection
        if (process.env.NODE_ENV === 'test') {
            return cb(null, '250 2.0.0 OK 1407018531 gc8sm23308604wic.3 - gsmtp');
        }
        self.transporter.sendMail(self.options.mail, function (err, info) {
            if (err) {return cb(err);}

            return cb(null, info.response);
        });
    }
};

/**
 * Shut down the connection pool so no more messages are send (use if you don't
 * want to use transport object anymore).
 *
 * @method close
 */
Mailer.prototype.close = function() {
    this.transporter.close();
};

/**
 * Retrieves the Mailer configuration options.
 *
 * @method getOptions
 * @returns {Object} the mailer configuration options
 */
Mailer.prototype.getOptions = function() {
    return this.options;
};<|endoftext|>


<commit_before>const urlLib = require('url');

const request = (url, options = {}) => new Promise((resolve, reject) => {
	const urlParts = urlLib.parse(url);
	const lib = urlParts.protocol === 'http:' ? require('http') : require('https');

	lib.get({
		host: urlParts.host,
		path: urlParts.path,
		headers: Object.assign({}, options.headers)
	}, resp => {
		if(resp.statusCode >= 300 && resp.statusCode < 400 && resp.headers.location){
			request(urlLib.resolve(url, resp.headers.location), options).then(resolve).catch(reject);
			resp.destroy();
		}else if(resp.statusCode === 200){
			if(options.stream){
				resolve(resp);
			}else{
				let body = '';
				resp.on('data', chunk => {
					body += chunk;
				});
				resp.on('end', () => {
					resolve(body);
				});
				resp.on('error', err => {
					reject(err);
				});
			}
		}else{
			reject(resp);
		}
	});
});

module.exports = request;<commit_msg>Add POST<commit_after>const urlLib = require('url');
const querystring = require('querystring');

const request = (url, {method = 'GET', body, post, headers = {}, redirects = 5, stream = false} = {}) => new Promise((resolve, reject) => {
	if(redirects-- < 0){
		reject(new Error('Too much redirect!'));
	}
	const {host, path, protocol} = urlLib.parse(url);
	const lib = protocol === 'http:' ? require('http') : require('https');

	if(post){
		method = 'POST';
		body = post;
	}
	if(typeof body === 'object' && body !== null){
		body = JSON.stringify(body);
		if(!headers['Content-Type']){
			headers['Content-Type'] = 'application/json';
		}
	}
	if(body && !headers['Content-Length']){
		headers['Content-Length'] = Buffer.byteLength(body);
	}
	console.log(method, body, headers);

	const req = lib.request({ host, path, headers, method }, resp => {
		if(resp.statusCode >= 300 && resp.statusCode < 400 && resp.headers.location){
			request(urlLib.resolve(url, resp.headers.location), {method, body, headers, redirects: redirects - 1, stream}).then(resolve).catch(reject);
			resp.destroy();
		}else if(resp.statusCode === 200){
			if(stream){
				resolve(resp);
			}else{
				let body = '';
				resp.on('data', chunk => {
					body += chunk;
				});
				resp.on('end', () => {
					resolve(body);
				});
				resp.on('error', err => {
					reject(err);
				});
			}
		}else{
			reject(resp);
		}
	});

	if(body){
		req.write(body);
	}
	req.end();
});

module.exports = request;<|endoftext|>


<commit_before>/* global window */
import 'can-define-stream';
import canStream from 'can-stream';
import DefineMap from 'can-define/map/';
import route from 'can-route';
//import 'can-route-pushstate';
import Session from 'bitcentive/models/session';
// import 'bitcentive/models/fixtures/';

// viewmodel debugging
import viewModel from 'can-view-model';
window.viewModel = viewModel;

const AppViewModel = DefineMap.extend({

  /**
   * By default, viewModel attributes will not be serialized into the URL as
   * route attributes.
   */
  '*': {
    serialize: false
  },

  /**
   * Uses whatever session data is available from Feathers JWT token, if
   * available. Because the token data is limited, a request is sent
   * to obtain the full session data.
   */
  session: {
    value () {
      var self = this;
      Session.get().catch(err => console.log(err));
      Session.on('created', (event, session) => {
        self.session = session;
        // redirect to the dashboard if on the auth page
        if (self.page === 'auth') {
          window.history.replaceState(self.title, null, route.url({page: 'dashboard'}));
        }
      });
      Session.on('destroyed', (event, session) => {
        self.session = undefined;
      });
    },
    // stream(setStream){
      // var self = this;
      // console.log('streaming');
      // return canStream.toStream(Session, 'created').onValue(event => {
      //   let session = event.args[0];
      //   console.log(session);
      //   setTimeout(() => {
      //     self.session = session;
      //   }, 1);
      // });
    // }
  },

  /**
   * The `page` attribute determines which page-component is displayed.
   */
  page: {
    serialize: true,
    get(page, setPage){
      return this.routePage(page);
    }
  },

  pageId: {
    type: "string"
  },

  /**
   * The auth page uses the subpage attribute to switch between the 'login'
   * view and the 'signup' view. We have to set serialize to true to allow the
   * auth routes to work.
   */
  subpage: {
    serialize: true
  },

  /**
   * The `title` attribute is used in index.stache as the HTML title.
   */
  title: {
    value: 'Bitcentive'
  },

  /**
   * `routePage` controls the pages that the current user can view.
   * If a non-authenticated user tries to access a private page, they will be
   * shown the login page. Also handles 404s.
   */
  routePage: function(page){
    let pageConfig = {
      home: 'public',
      auth: 'public',
      login: 'public',
      signup: 'public',
      dashboard: 'private',
      contributors: 'private'
    };

    if (page === 'logout') {
      page = 'home';
      this.session && this.session.destroy()
        .then(() => {
          if (!window.doneSsr) {
            window.location.href = '/';
          }
        });
    }

    if (this.session) {
      // Perform some custom logic for logged-in users.

    } else {
      // Logic for non-authenticated users.
      if (pageConfig[page] !== 'public') {
        page = 'login';
      }
    }

    // 404 if the page isn't in the config.
    if(!pageConfig[page]){
      page = 'four-oh-four';
    }
    return page;
  }
});

route('login', {page: 'auth', subpage: 'login'});
route('signup', {page: 'auth', subpage: 'signup'});
route('auth/success', {page: 'auth', subpage: 'success'});
route('auth/failure', {page: 'auth', subpage: 'failure'});
route('{page}', {page: 'home'});

export default AppViewModel;
<commit_msg>Remove can-route-pushstate related code.<commit_after>/* global window */
import 'can-define-stream';
import canStream from 'can-stream';
import DefineMap from 'can-define/map/';
import route from 'can-route';
//import 'can-route-pushstate';
import Session from 'bitcentive/models/session';
// import 'bitcentive/models/fixtures/';

// viewmodel debugging
import viewModel from 'can-view-model';
window.viewModel = viewModel;

const AppViewModel = DefineMap.extend({

  /**
   * By default, viewModel attributes will not be serialized into the URL as
   * route attributes.
   */
  '*': {
    serialize: false
  },

  /**
   * Uses whatever session data is available from Feathers JWT token, if
   * available. Because the token data is limited, a request is sent
   * to obtain the full session data.
   */
  session: {
    value () {
      var self = this;
      Session.get().catch(err => console.log(err));
      Session.on('created', (event, session) => {
        self.session = session;
        self.page = 'dashboard';
      });
      Session.on('destroyed', (event, session) => {
        self.session = undefined;
      });
    },
    // stream(setStream){
      // var self = this;
      // console.log('streaming');
      // return canStream.toStream(Session, 'created').onValue(event => {
      //   let session = event.args[0];
      //   console.log(session);
      //   setTimeout(() => {
      //     self.session = session;
      //   }, 1);
      // });
    // }
  },

  /**
   * The `page` attribute determines which page-component is displayed.
   */
  page: {
    serialize: true,
    get(page, setPage){
      return this.routePage(page);
    }
  },

  pageId: {
    type: "string"
  },

  /**
   * The auth page uses the subpage attribute to switch between the 'login'
   * view and the 'signup' view. We have to set serialize to true to allow the
   * auth routes to work.
   */
  subpage: {
    serialize: true
  },

  /**
   * The `title` attribute is used in index.stache as the HTML title.
   */
  title: {
    value: 'Bitcentive'
  },

  /**
   * `routePage` controls the pages that the current user can view.
   * If a non-authenticated user tries to access a private page, they will be
   * shown the login page. Also handles 404s.
   */
  routePage: function(page){
    let pageConfig = {
      home: 'public',
      auth: 'public',
      login: 'public',
      signup: 'public',
      dashboard: 'private',
      contributors: 'private'
    };

    if (page === 'logout') {
      page = 'home';
      this.session && this.session.destroy()
        .then(() => {
          if (!window.doneSsr) {
            window.location.href = '/';
          }
        });
    }

    if (this.session) {
      // Perform some custom logic for logged-in users.

    } else {
      // Logic for non-authenticated users.
      if (pageConfig[page] !== 'public') {
        page = 'login';
      }
    }

    // 404 if the page isn't in the config.
    if(!pageConfig[page]){
      page = 'four-oh-four';
    }
    return page;
  }
});

route('login', {page: 'auth', subpage: 'login'});
route('signup', {page: 'auth', subpage: 'signup'});
route('auth/success', {page: 'auth', subpage: 'success'});
route('auth/failure', {page: 'auth', subpage: 'failure'});
route('{page}', {page: 'home'});

export default AppViewModel;
<|endoftext|>


<commit_before>var u = require('underscore')
var _ = Object.create(u, {})

function strwrap (c) {
  return function (str) { return (str ? c + str + c : undefined ) }
}
function sstrwrap (l, r) {
  return function (str) { return (str ? l + str + r : undefined) }
}

_.extend(_, {
  $ : _.compose,

  // boolean: do our best to figure out if something is a true object
  isObject: function (value) {
    return (String(value) === '[object Object]' && !_.isString(value))
  },

  // boolean: true if null|undefined, false otherwise
  isMissing : function (value){ return (undefined === value || null === value) },

  // takes a field, returns a function that takes an object and returns the
  // value of the field or undefined if either object or field is missing
  getv: function (f) { return function (o) { return o ? o[f] : undefined } },

  // perform a root canal on an object. depends on getv
  extract: function (o, path) {
    var iterator = function (m, p) { return _.getv(p)(m) }
    return _.reduce(path, iterator, o);
  },

  // takes an object, return a function that takes an objec and
  // returns the value of the field.
  getter: function (o) { return function (f) { return o[f] } },

  // takes a function, returns a function that processes arguments in reverse
  frev: function (fn) { return function () {
    return fn.apply(fn, _.tail(arguments, 0).reverse());
  th
  }},

  // takes a function with signature (a, b), returns a new function
  // with the signature (b, a)
  swap: function (fn) { return function (a, b) { return fn(b, a) } },

  // takes a function that returns true given a certain value,
  // returns a function that returns false given that same value
  not: function (fn) { return function () { return !fn.apply(fn, arguments) } },

  // takes a number `i`, returns a function that gets a[i]
  nth: function (i) { return function (a) { return a[i] } },

  // takes an object, returns [ [ field, value ], ...]
  ozip: function (o) { return _.map(o, _.swap(Array)); },

  // iterator: takes [ field, val ], adds field : value to memo
  assoc: function (h, a) { h[a[0]] = a[1]; return h; },

  // inverse of ozip: takes [ [ field, value ], ...], returns { field: value, ... }
  zippo: function (a) { return _.reduce(a, _.assoc, {}) },

  // takes field arr, value arr, returns { field: value, ... }
  zippo2: function (a1, a2) { return _.zippo(_.zip(a1, a2)) },

  // push only defined elements to the array
  push: function (a) {
    var elements = _.reject(_.rest(arguments), _.isMissing)
    return a.push.apply(a, elements)
  },

  // return a new function with args partially applied
  partial: function (fun, args) {
    for (var i=0; args[i]; i++)
      fun = _.bind(fun, null, args[i]);
    return fun;
  },

  // this takes advantage of ES5 bind's awesome ability to do partial application
  curry: function curry (fn, obj) {
    // create a local copy of the function. don't apply anything yet
    // optionally bind an object to the `this` of the function.
    var newFunction = _.bind(fn, (obj || null))

    // curried functions always take one argument
    return function () {
      // create another copy of the function with the arguments applied
      var me = _.partial(newFunction, arguments);

      // take advantage of the fact that bind changes the method signature:
      // if we have no arguments left, run the method
      if (!me.length) return me();

      // otherwise, curry again and return that.
      return curry(me);
    }
  },

  // takes { key: [ Function ] }, { key: value }, returns { key: Function(value) }
  callWith: function (fns, vals) {
    var caller = function (fn, key) { return [key, fn(vals[key])]; }
    return _.zippo(_.map(fns, caller));
  },
  strwrap: strwrap,
  sstrwrap: sstrwrap,
  paren: sstrwrap('(', ')'),
  quote: strwrap('"'),
  squote: strwrap("'"),
  backtick: strwrap("`"),
  chomp: function (str, search) {
    // naive, will break if search is not regex escaped
    search = search ? new RegExp(search+'$') : /\s*$/;
    return str.replace(search, '');
  },
  upcase: function (str) { return str.toUpperCase() },
  downcase: function (str) { return str.toLowerCase() },
  strjoin: function (arr) {
    if (arguments.length > 1) arr = _.tail(arguments, 0);
    arr = _.reject(_.flatten(arr), _.isMissing);
    return arr.join(' ');
  },
  placeholders: function (arr) { return _.map(arr, function(){ return '?' }) }
});

module.exports = _<commit_msg>Blurgh, remove stupid thing.<commit_after>var u = require('underscore')
var _ = Object.create(u, {})

function strwrap (c) {
  return function (str) { return (str ? c + str + c : undefined ) }
}
function sstrwrap (l, r) {
  return function (str) { return (str ? l + str + r : undefined) }
}

_.extend(_, {
  $ : _.compose,

  // boolean: do our best to figure out if something is a true object
  isObject: function (value) {
    return (String(value) === '[object Object]' && !_.isString(value))
  },

  // boolean: true if null|undefined, false otherwise
  isMissing : function (value){ return (undefined === value || null === value) },

  // takes a field, returns a function that takes an object and returns the
  // value of the field or undefined if either object or field is missing
  getv: function (f) { return function (o) { return o ? o[f] : undefined } },

  // perform a root canal on an object. depends on getv
  extract: function (o, path) {
    var iterator = function (m, p) { return _.getv(p)(m) }
    return _.reduce(path, iterator, o);
  },

  // takes an object, return a function that takes an objec and
  // returns the value of the field.
  getter: function (o) { return function (f) { return o[f] } },

  // takes a function, returns a function that processes arguments in reverse
  frev: function (fn) { return function () {
    return fn.apply(fn, _.tail(arguments, 0).reverse());
  }},

  // takes a function with signature (a, b), returns a new function
  // with the signature (b, a)
  swap: function (fn) { return function (a, b) { return fn(b, a) } },

  // takes a function that returns true given a certain value,
  // returns a function that returns false given that same value
  not: function (fn) { return function () { return !fn.apply(fn, arguments) } },

  // takes a number `i`, returns a function that gets a[i]
  nth: function (i) { return function (a) { return a[i] } },

  // takes an object, returns [ [ field, value ], ...]
  ozip: function (o) { return _.map(o, _.swap(Array)); },

  // iterator: takes [ field, val ], adds field : value to memo
  assoc: function (h, a) { h[a[0]] = a[1]; return h; },

  // inverse of ozip: takes [ [ field, value ], ...], returns { field: value, ... }
  zippo: function (a) { return _.reduce(a, _.assoc, {}) },

  // takes field arr, value arr, returns { field: value, ... }
  zippo2: function (a1, a2) { return _.zippo(_.zip(a1, a2)) },

  // push only defined elements to the array
  push: function (a) {
    var elements = _.reject(_.rest(arguments), _.isMissing)
    return a.push.apply(a, elements)
  },

  // return a new function with args partially applied
  partial: function (fun, args) {
    for (var i=0; args[i]; i++)
      fun = _.bind(fun, null, args[i]);
    return fun;
  },

  // this takes advantage of ES5 bind's awesome ability to do partial application
  curry: function curry (fn, obj) {
    // create a local copy of the function. don't apply anything yet
    // optionally bind an object to the `this` of the function.
    var newFunction = _.bind(fn, (obj || null))

    // curried functions always take one argument
    return function () {
      // create another copy of the function with the arguments applied
      var me = _.partial(newFunction, arguments);

      // take advantage of the fact that bind changes the method signature:
      // if we have no arguments left, run the method
      if (!me.length) return me();

      // otherwise, curry again and return that.
      return curry(me);
    }
  },

  // takes { key: [ Function ] }, { key: value }, returns { key: Function(value) }
  callWith: function (fns, vals) {
    var caller = function (fn, key) { return [key, fn(vals[key])]; }
    return _.zippo(_.map(fns, caller));
  },
  strwrap: strwrap,
  sstrwrap: sstrwrap,
  paren: sstrwrap('(', ')'),
  quote: strwrap('"'),
  squote: strwrap("'"),
  backtick: strwrap("`"),
  chomp: function (str, search) {
    // naive, will break if search is not regex escaped
    search = search ? new RegExp(search+'$') : /\s*$/;
    return str.replace(search, '');
  },
  upcase: function (str) { return str.toUpperCase() },
  downcase: function (str) { return str.toLowerCase() },
  strjoin: function (arr) {
    if (arguments.length > 1) arr = _.tail(arguments, 0);
    arr = _.reject(_.flatten(arr), _.isMissing);
    return arr.join(' ');
  },
  placeholders: function (arr) { return _.map(arr, function(){ return '?' }) }
});

module.exports = _<|endoftext|>


<commit_before>function something()
{
    var x = window.localStorage.getItem('aaa');//x=hh['aaa']
    x = x * 1 + 1;

    window.localStorage.setItem('aaa', x); //hh['aaa']=x

    alert(x);
}

function add_to_cart(id)
{
    var key = 'product_' + id;

    var x = window.localStorage.getItem(key);
    x = x * 1 + 1;

    window.localStorage.setItem(key, x);
}

function cart_get_number_of_items()
{
    var cnt = 0;

    for(var i = 0; i < window.localStorage.length; i++)
    {
        var key = window.localStorage.key(i); //получаем ключ
        var value = window.localStorage.getItem(key); //получаем значение

        if(key.indexOf('product_') == 0)
        {
            cnt = cnt + value * 1;
        }
    }
    return cnt;
}<commit_msg>update cart_get_number_of_items<commit_after>function something()
{
    var x = window.localStorage.getItem('aaa');//x=hh['aaa']
    x = x * 1 + 1;

    window.localStorage.setItem('aaa', x); //hh['aaa']=x

    alert(x);
}

function add_to_cart(id)
{
    var key = 'product_' + id;

    var x = window.localStorage.getItem(key);
    x = x * 1 + 1;

    window.localStorage.setItem(key, x);

    //вывод кол-во товара в корзине
    alert('Items in your cart: ' + cart_get_number_of_items());
}

function cart_get_number_of_items()
{
    var cnt = 0;

    for(var i = 0; i < window.localStorage.length; i++)
    {
        var key = window.localStorage.key(i); //получаем ключ
        var value = window.localStorage.getItem(key); //получаем значение

        if(key.indexOf('product_') == 0)
        {
            cnt = cnt + value * 1;
        }
    }
    return cnt;
}<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-concurrency',
  included: function(app) {
    this._super.included(app);
  }
};
<commit_msg>Remove unused `included` hook.<commit_after>/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-concurrency'
};
<|endoftext|>


<commit_before>function something()
{
  var x = window.localStorage.getItem('bbb');
  x = x * 1 + 1;
  window.localStorage.setItem('bbb', x);

  alert(x);
}

function add_to_cart(id)
{
  var key = 'product_' + id;
  var x = window.localStorage.getItem(key);
  x = x * 1 + 1;
  window.localStorage.setItem(key, x);

  update_orders_input();
  update_orders_button();
}

function update_orders_input()
{
  var orders = cart_get_orders();
  $('#orders_input').val(orders);
}

function update_orders_button()
{
  var text = 'Cart ('+ list_all_Items() +')';
  $('#orders_button').val(text);
}

function list_all_Items()
{
  total = 0;
  $.each(localStorage, function(key, value){
    total += value * 1;
  });
  return total;
}

function cart_get_orders()
{
  var orders = '';
  for(var i = 0; i < window.localStorage.length; i++)
  {
    var key = window.localStorage.key(i); // get key
    var value = window.localStorage.getItem(key); // get value by key from hash
    if(key.indexOf('product_') == 0)
    {
      orders = orders + key + '=' + value + ',';
    }
  }
  return orders;
}

function cancel_order()
{
  alert('aaa');
  return false;
}
<commit_msg>Clear local Storage on cancel<commit_after>function something()
{
  var x = window.localStorage.getItem('bbb');
  x = x * 1 + 1;
  window.localStorage.setItem('bbb', x);

  alert(x);
}

function add_to_cart(id)
{
  var key = 'product_' + id;
  var x = window.localStorage.getItem(key);
  x = x * 1 + 1;
  window.localStorage.setItem(key, x);

  update_orders_input();
  update_orders_button();
}

function update_orders_input()
{
  var orders = cart_get_orders();
  $('#orders_input').val(orders);
}

function update_orders_button()
{
  var text = 'Cart ('+ list_all_Items() +')';
  $('#orders_button').val(text);
}

function list_all_Items()
{
  total = 0;
  $.each(localStorage, function(key, value){
    total += value * 1;
  });
  return total;
}

function cart_get_orders()
{
  var orders = '';
  for(var i = 0; i < window.localStorage.length; i++)
  {
    var key = window.localStorage.key(i); // get key
    var value = window.localStorage.getItem(key); // get value by key from hash
    if(key.indexOf('product_') == 0)
    {
      orders = orders + key + '=' + value + ',';
    }
  }
  return orders;
}

function cancel_order()
{
  window.localStorage.clear();
  update_orders_input();
  update_orders_button();
  return false;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 peeracle contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

'use strict';

/**
 * Peeracle
 * @namespace Peeracle
 */

// @exclude
var Peeracle = require('./src/Peeracle');

Peeracle.BinaryStream = require('./src/BinaryStream');

Peeracle.Crypto = require('./src/Crypto');
Peeracle.Crypto.Crc32 = require('./src/Crypto.Crc32');

Peeracle.DataSource = require('./src/DataSource');
Peeracle.DataSource.File = require('./src/DataSource.File');
Peeracle.DataSource.Http = require('./src/DataSource.Http');

Peeracle.Listenable = require('./src/Listenable');

Peeracle.Media = require('./src/Media');
Peeracle.Media.WebM = require('./src/Media.WebM');
Peeracle.Media.MP4 = require('./src/Media.MP4');

Peeracle.Metadata = require('./src/Metadata');
Peeracle.MetadataSerializer = require('./src/MetadataSerializer');
Peeracle.MetadataUnserializer = require('./src/MetadataUnserializer');

Peeracle.Storage = require('./src/Storage');
Peeracle.Storage.NodeFile = require('./src/Storage.NodeFile');
Peeracle.Storage.Memory = require('./src/Storage.Memory');

Peeracle.Tracker = require('./src/Tracker');

Peeracle.Utils = require('./src/Utils');

module.exports = Peeracle;

return;
// @endexclude

window['Peeracle'] = Peeracle;

var RTCPeerConnection = window.mozRTCPeerConnection ||
  window.webkitRTCPeerConnection ||
  window.RTCPeerConnection;

var RTCSessionDescription = window.mozRTCSessionDescription ||
  window.webkitRTCSessionDescription ||
  window.RTCSessionDescription;

var RTCIceCandidate = window.mozRTCIceCandidate ||
  window.webkitRTCIceCandidate ||
  window.RTCIceCandidate;

function bindMedia(media) {
  if (media.dataset && media.dataset.hasOwnProperty('peeracleIgnore')) {
    return;
  }

  media.pause();
  media.src = '';
}

function bindMedias() {
  var medias = document.querySelectorAll('audio, video');
  var i;
  var l = medias.length;

  for (i = 0; i < l; ++i) {
    var media = medias[i];
    if (media instanceof HTMLVideoElement) {
      bindMedia(media);
    }
  }
}

bindMedias();
<commit_msg>Index: Remove the browser code<commit_after>/*
 * Copyright (c) 2015 peeracle contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

'use strict';

/**
 * Peeracle
 * @namespace Peeracle
 */

// @exclude
var Peeracle = require('./src/Peeracle');

Peeracle.BinaryStream = require('./src/BinaryStream');

Peeracle.Crypto = require('./src/Crypto');
Peeracle.Crypto.Crc32 = require('./src/Crypto.Crc32');

Peeracle.DataSource = require('./src/DataSource');
Peeracle.DataSource.File = require('./src/DataSource.File');
Peeracle.DataSource.Http = require('./src/DataSource.Http');

Peeracle.Listenable = require('./src/Listenable');

Peeracle.Media = require('./src/Media');
Peeracle.Media.WebM = require('./src/Media.WebM');
Peeracle.Media.MP4 = require('./src/Media.MP4');

Peeracle.Metadata = require('./src/Metadata');
Peeracle.MetadataSerializer = require('./src/MetadataSerializer');
Peeracle.MetadataUnserializer = require('./src/MetadataUnserializer');

Peeracle.Storage = require('./src/Storage');
Peeracle.Storage.NodeFile = require('./src/Storage.NodeFile');
Peeracle.Storage.Memory = require('./src/Storage.Memory');

Peeracle.Tracker = require('./src/Tracker');

Peeracle.Utils = require('./src/Utils');

module.exports = Peeracle;
<|endoftext|>


<commit_before>var peer = require('./src/peer')
var Blockchain = require('./src/blockchain')

Blockchain.init('./db/headers').then(function (topHeight) {
  // dns.resolve('mainnet')
  console.log('Bitcoin p2p network started. The local node has %d block(s).', topHeight)
  peer.buildPool('mainnet')(['104.237.2.189'])
})
<commit_msg>start from dns resolving<commit_after>var dns = require('./src/dns')
var peer = require('./src/peer')
var Blockchain = require('./src/blockchain')

Blockchain.init('./db/headers').then(function (topHeight) {
  console.log('Bitcoin p2p network started. The local node has %d block(s).', topHeight)
  dns.resolve('mainnet')
  // peer.buildPool('mainnet')(['104.237.2.189', '13.73.0.61']) // node for test
})
<|endoftext|>