<commit_before>(function() {
    var loadFont = {LOAD_FONT};
    var color = {COLOR};

    //var remote = 'http://applauding.herokuapp.com';
    var remote = 'http://localhost:3000';
    var local = location.host + location.pathname;

    var main_css = "<link rel='stylesheet' type='text/css' href='" + remote + "/embed.min.css?color=" + color + "'>";
    var cleanslate_css = "<link rel='stylesheet' type='text/css' href='" + remote + "/cleanslate.css'>";
    var font_css = "<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>"

    var css_stack = cleanslate_css + main_css;
    if(loadFont) { css_stack += font_css; }
    document.querySelector('head').innerHTML += css_stack;

    function createCORSRequest(method, url) {
      var xhr = new XMLHttpRequest();
      if ("withCredentials" in xhr) {

        // Check if the XMLHttpRequest object has a "withCredentials" property.
        // "withCredentials" only exists on XMLHTTPRequest2 objects.
        xhr.open(method, url, true);

      } else if (typeof XDomainRequest != "undefined") {

        // Otherwise, check if XDomainRequest.
        // XDomainRequest only exists in IE, and is IE's way of making CORS requests.
        xhr = new XDomainRequest();
        xhr.open(method, url);

      } else {

        // Otherwise, CORS is not supported by the browser.
        xhr = null;

      }
      return xhr;
    }

    function error() {
        throw new Error('Error with Applause request.');
    }

    function fuzzify(num) {
        if(num >= 1000) {
            return (Math.round(num / 100) / 10) + "k";
        } else {
            return num;
        }
    }

    document.addEventListener('DOMContentLoaded', function() {
        var applause = document.querySelector('#applause');

        applause.className += "cleanslate";
        applause.innerHTML = "
0Applaud
";

        applause.addEventListener('click', function() {
            sendRequest('update');
        }, false);

        sendRequest('get');
    });

    function updateCount(num) {
        var count = fuzzify(num);
        document.querySelector('#applause span.applause-count').innerHTML = count;
    }

    function sendRequest(type) {
        var xhr = createCORSRequest('GET', remote + '/' + type + '?url=' + encodeURIComponent(local) );
        if (!xhr) {
          throw new Error('Applause won\'t work because CORS is not supported.');
          document.querySelector('#applause span').style.display = 'none';
        }

        if(type === 'get') {
            xhr.onload = function() {
                var json = JSON.parse(xhr.responseText);
                updateCount(json.votes);
                if(json.voted) {
                    document.querySelector('#applause').className += ' applause-voted';
                    document.querySelector('#applause .applause-action').innerHTML = 'Applauded';
                }
                document.querySelector('#applause').style.display = 'table';
            };
        } else {
            xhr.onload = function() {
                var json = JSON.parse(xhr.responseText);
                updateCount(json.votes);
                var applauseAction = document.querySelector('#applause .applause-action');
                if((" " + applause.className + " ").indexOf( " applause-voted " ) <= -1) {
                    applause.className += ' applause-voted';
                    applauseAction.innerHTML = 'Applauded';
                } else {
                    applause.className = (" " + applause.className + " ").replace(/(?:^|\s)applause-voted(?!\S)/, '' );
                    applauseAction.innerHTML = 'Applaud';
                }
              };
        }

        xhr.onerror = error;

        xhr.send();
    }
})();
<commit_msg>Set remote back to production version<commit_after>(function() {
    var loadFont = {LOAD_FONT};
    var color = {COLOR};

    var remote = 'http://applauding.herokuapp.com';
    //var remote = 'http://localhost:3000';
    var local = location.host + location.pathname;

    var main_css = "<link rel='stylesheet' type='text/css' href='" + remote + "/embed.min.css?color=" + color + "'>";
    var cleanslate_css = "<link rel='stylesheet' type='text/css' href='" + remote + "/cleanslate.css'>";
    var font_css = "<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>"

    var css_stack = cleanslate_css + main_css;
    if(loadFont) { css_stack += font_css; }
    document.querySelector('head').innerHTML += css_stack;

    function createCORSRequest(method, url) {
      var xhr = new XMLHttpRequest();
      if ("withCredentials" in xhr) {

        // Check if the XMLHttpRequest object has a "withCredentials" property.
        // "withCredentials" only exists on XMLHTTPRequest2 objects.
        xhr.open(method, url, true);

      } else if (typeof XDomainRequest != "undefined") {

        // Otherwise, check if XDomainRequest.
        // XDomainRequest only exists in IE, and is IE's way of making CORS requests.
        xhr = new XDomainRequest();
        xhr.open(method, url);

      } else {

        // Otherwise, CORS is not supported by the browser.
        xhr = null;

      }
      return xhr;
    }

    function error() {
        throw new Error('Error with Applause request.');
    }

    function fuzzify(num) {
        if(num >= 1000) {
            return (Math.round(num / 100) / 10) + "k";
        } else {
            return num;
        }
    }

    document.addEventListener('DOMContentLoaded', function() {
        var applause = document.querySelector('#applause');

        applause.className += "cleanslate";
        applause.innerHTML = "
0Applaud
";

        applause.addEventListener('click', function() {
            sendRequest('update');
        }, false);

        sendRequest('get');
    });

    function updateCount(num) {
        var count = fuzzify(num);
        document.querySelector('#applause span.applause-count').innerHTML = count;
    }

    function sendRequest(type) {
        var xhr = createCORSRequest('GET', remote + '/' + type + '?url=' + encodeURIComponent(local) );
        if (!xhr) {
          throw new Error('Applause won\'t work because CORS is not supported.');
          document.querySelector('#applause span').style.display = 'none';
        }

        if(type === 'get') {
            xhr.onload = function() {
                var json = JSON.parse(xhr.responseText);
                updateCount(json.votes);
                if(json.voted) {
                    document.querySelector('#applause').className += ' applause-voted';
                    document.querySelector('#applause .applause-action').innerHTML = 'Applauded';
                }
                document.querySelector('#applause').style.display = 'table';
            };
        } else {
            xhr.onload = function() {
                var json = JSON.parse(xhr.responseText);
                updateCount(json.votes);
                var applauseAction = document.querySelector('#applause .applause-action');
                if((" " + applause.className + " ").indexOf( " applause-voted " ) <= -1) {
                    applause.className += ' applause-voted';
                    applauseAction.innerHTML = 'Applauded';
                } else {
                    applause.className = (" " + applause.className + " ").replace(/(?:^|\s)applause-voted(?!\S)/, '' );
                    applauseAction.innerHTML = 'Applaud';
                }
              };
        }

        xhr.onerror = error;

        xhr.send();
    }
})();
<|endoftext|>


<commit_before>Vimeo = function(arrayOfVideoIds, callback) {
  var getAndAddMetaData, id, runCallbackIfDone, self, _i, _len;
  self = this;
  check(arrayOfVideoIds, Match.Where(function(arr) {
    var item, _i, _len, _results;
    check(arr, Array);
    _results = [];
    for (_i = 0, _len = arr.length; _i < _len; _i++) {
      item = arr[_i];
      _results.push(check(item, String));
    }
    return _results;
  }));
  this._dep = new Deps.Dependency();
  this._len = arrayOfVideoIds.length;
  this._done = 0;
  this.videos = [];
  this.getVideos = function() {
    self._dep.depend();
    return self.videos;
  };
  runCallbackIfDone = function() {
    if (self._done === self._len) {
      if (callback != null) {
        callback();
      }
      return self._dep.changed();
    }
  };
  getAndAddMetaData = function(id,idx) {
    return HTTP.get("http://vimeo.com/api/v2/video/" + id + ".json", function(err, res) {
      if ((err != null) && ((typeof console !== "undefined" && console !== null ? console.error : void 0) != null)) {
        return console.error(err);
      } else {
        self.videos.splice(idx,0,{
          preview: res.data[0].thumbnail_large,
          src: "//player.vimeo.com/video/" + id,
          summary: res.data[0].description,
          title: res.data[0].title
        });
        self._done++;
        return runCallbackIfDone();
      }
    });
  };
  for (_i = 0, _len = arrayOfVideoIds.length; _i < _len; _i++) {
    id = arrayOfVideoIds[_i];
    getAndAddMetaData(id,_i);
  }
  return void 0;
};
<commit_msg>make get request protocol agnostic.<commit_after>Vimeo = function(arrayOfVideoIds, callback) {
  var getAndAddMetaData, id, runCallbackIfDone, self, _i, _len;
  self = this;
  check(arrayOfVideoIds, Match.Where(function(arr) {
    var item, _i, _len, _results;
    check(arr, Array);
    _results = [];
    for (_i = 0, _len = arr.length; _i < _len; _i++) {
      item = arr[_i];
      _results.push(check(item, String));
    }
    return _results;
  }));
  this._dep = new Deps.Dependency();
  this._len = arrayOfVideoIds.length;
  this._done = 0;
  this.videos = [];
  this.getVideos = function() {
    self._dep.depend();
    return self.videos;
  };
  runCallbackIfDone = function() {
    if (self._done === self._len) {
      if (callback != null) {
        callback();
      }
      return self._dep.changed();
    }
  };
  getAndAddMetaData = function(id,idx) {
    return HTTP.get("//vimeo.com/api/v2/video/" + id + ".json", function(err, res) {
      if ((err != null) && ((typeof console !== "undefined" && console !== null ? console.error : void 0) != null)) {
        return console.error(err);
      } else {
        self.videos.splice(idx,0,{
          preview: res.data[0].thumbnail_large,
          src: "//player.vimeo.com/video/" + id,
          summary: res.data[0].description,
          title: res.data[0].title
        });
        self._done++;
        return runCallbackIfDone();
      }
    });
  };
  for (_i = 0, _len = arrayOfVideoIds.length; _i < _len; _i++) {
    id = arrayOfVideoIds[_i];
    getAndAddMetaData(id,_i);
  }
  return void 0;
};
<|endoftext|>


<commit_before>require('dotenv').load();
var crypto = require('crypto');
var base64url = require('base64-url');
var Promise = require('bluebird');
var bcrypt = Promise.promisifyAll(require('bcryptjs'));
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
Promise.promisifyAll(Object.getPrototypeOf(s3));
var mandrill = require('mandrill-api/mandrill');
var mandrill_client = new mandrill.Mandrill(process.env.MANDRILL_API_KEY);

function getObj(bucket, key) {
  console.log("Going to get " + key + " from " + bucket);
  return s3.getObjectAsync({Bucket: bucket, Key: key}).then(function(data) {
    var s = new Buffer(data.Body).toString();
    return JSON.parse(s);
  });
}

function putJSON(bucket, key, obj) {
  console.log("Going to put " + key + " into " + bucket);
  return s3.putObjectAsync({Bucket: bucket, Key: key, Body: JSON.stringify(obj), ContentType: 'application/json'});
}

function randomString() {
  return base64url.escape(crypto.randomBytes(48).toString('base64'));
}

function checkEmail(username, email) {
  console.log("Going to check email for " + username);
  var bucket = 'constellational-meta';
  return new Promise(function(resolve, reject) {
    return getObj(bucket, username).then(function(obj) {
      return bcrypt.compareAsync(email, obj.emailHash);
    }).then(function(res) {
      if (!res) reject('Signin failed');
      else resolve(obj);
    });
  });
}

function sendEmail(username, email) {
/*
  var message = {
    "html": "
Example HTML content
",
    "text": "Example text content",
    "subject": "example subject",
    "from_email": "message.from_email@example.com",
    "from_name": "Example Name",
    "to": [{
            "email": "recipient.email@example.com",
            "name": "Recipient Name",
            "type": "to"
        }],
    "headers": {
        "Reply-To": "message.reply@example.com"
    },
    "important": false,
    "track_opens": null,
    "track_clicks": null,
    "auto_text": null,
    "auto_html": null,
    "inline_css": null,
    "url_strip_qs": null,
    "preserve_recipients": null,
    "view_content_link": null,
    "bcc_address": "message.bcc_address@example.com",
    "tracking_domain": null,
    "signing_domain": null,
    "return_path_domain": null,
    "merge": true,
    "merge_language": "mailchimp",
    "global_merge_vars": [{
            "name": "merge1",
            "content": "merge1 content"
        }],
    "merge_vars": [{
            "rcpt": "recipient.email@example.com",
            "vars": [{
                    "name": "merge2",
                    "content": "merge2 content"
                }]
        }],
    "tags": [
        "password-resets"
    ],
    "subaccount": "customer-123",
    "google_analytics_domains": [
        "example.com"
    ],
    "google_analytics_campaign": "message.from_email@example.com",
    "metadata": {
        "website": "www.example.com"
    },
    "recipient_metadata": [{
            "rcpt": "recipient.email@example.com",
            "values": {
                "user_id": 123456
            }
        }],
    "attachments": [{
            "type": "text/plain",
            "name": "myfile.txt",
            "content": "ZXhhbXBsZSBmaWxl"
        }],
    "images": [{
            "type": "image/png",
            "name": "IMAGECID",
            "content": "ZXhhbXBsZSBmaWxl"
        }]
};
var async = false;
var ip_pool = "Main Pool";
var send_at = "example send_at";
mandrill_client.messages.send({"message": message, "async": async, "ip_pool": ip_pool, "send_at": send_at}, function(result) {
    console.log(result);
}, function(e) {
    // Mandrill returns the error as an object with name and message keys
    console.log('A mandrill error occurred: ' + e.name + ' - ' + e.message);
    // A mandrill error occurred: Unknown_Subaccount - No subaccount exists with the id 'customer-123'
});
*/
}

function signin(username, email) {
  console.log("Going to sign " + username + " in");
  var user;
  var bucket = 'constellational-meta';
  var token = {
    id: randomString(),
    secret: randomString()
  };
  return checkEmail(username, email).then(function(details) {
    user = details;
    console.log("Going to bcrypt temporary token");
    return bcrypt.hashAsync(token.secret, 10);
  }).then(function(hash) {
    if (!user.tempTokens) user.tempTokens = [];
    user.tempTokens.push({id: id, hash: hash, timestamp: Date.now()});
    console.log("Going to store bcrypted hash of temporary token");
    return putJSON(bucket, username, user);
  }).then(function() {
    console.log("Going to send email");
    return {username: username, token: token};
  });
}

exports.handler = function(event, context) {
  console.log("Started");
  console.log(event);
  signup(event.username).then(context.succeed).catch(context.fail);
};
<commit_msg>user temp tokens is an object (key is temp token id)<commit_after>require('dotenv').load();
var crypto = require('crypto');
var base64url = require('base64-url');
var Promise = require('bluebird');
var bcrypt = Promise.promisifyAll(require('bcryptjs'));
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
Promise.promisifyAll(Object.getPrototypeOf(s3));
var mandrill = require('mandrill-api/mandrill');
var mandrill_client = new mandrill.Mandrill(process.env.MANDRILL_API_KEY);

function getObj(bucket, key) {
  console.log("Going to get " + key + " from " + bucket);
  return s3.getObjectAsync({Bucket: bucket, Key: key}).then(function(data) {
    var s = new Buffer(data.Body).toString();
    return JSON.parse(s);
  });
}

function putJSON(bucket, key, obj) {
  console.log("Going to put " + key + " into " + bucket);
  return s3.putObjectAsync({Bucket: bucket, Key: key, Body: JSON.stringify(obj), ContentType: 'application/json'});
}

function randomString() {
  return base64url.escape(crypto.randomBytes(48).toString('base64'));
}

function checkEmail(username, email) {
  console.log("Going to check email for " + username);
  var bucket = 'constellational-meta';
  return new Promise(function(resolve, reject) {
    return getObj(bucket, username).then(function(obj) {
      return bcrypt.compareAsync(email, obj.emailHash);
    }).then(function(res) {
      if (!res) reject('Signin failed');
      else resolve(obj);
    });
  });
}

function sendEmail(username, email) {
/*
  var message = {
    "html": "
Example HTML content
",
    "text": "Example text content",
    "subject": "example subject",
    "from_email": "message.from_email@example.com",
    "from_name": "Example Name",
    "to": [{
            "email": "recipient.email@example.com",
            "name": "Recipient Name",
            "type": "to"
        }],
    "headers": {
        "Reply-To": "message.reply@example.com"
    },
    "important": false,
    "track_opens": null,
    "track_clicks": null,
    "auto_text": null,
    "auto_html": null,
    "inline_css": null,
    "url_strip_qs": null,
    "preserve_recipients": null,
    "view_content_link": null,
    "bcc_address": "message.bcc_address@example.com",
    "tracking_domain": null,
    "signing_domain": null,
    "return_path_domain": null,
    "merge": true,
    "merge_language": "mailchimp",
    "global_merge_vars": [{
            "name": "merge1",
            "content": "merge1 content"
        }],
    "merge_vars": [{
            "rcpt": "recipient.email@example.com",
            "vars": [{
                    "name": "merge2",
                    "content": "merge2 content"
                }]
        }],
    "tags": [
        "password-resets"
    ],
    "subaccount": "customer-123",
    "google_analytics_domains": [
        "example.com"
    ],
    "google_analytics_campaign": "message.from_email@example.com",
    "metadata": {
        "website": "www.example.com"
    },
    "recipient_metadata": [{
            "rcpt": "recipient.email@example.com",
            "values": {
                "user_id": 123456
            }
        }],
    "attachments": [{
            "type": "text/plain",
            "name": "myfile.txt",
            "content": "ZXhhbXBsZSBmaWxl"
        }],
    "images": [{
            "type": "image/png",
            "name": "IMAGECID",
            "content": "ZXhhbXBsZSBmaWxl"
        }]
};
var async = false;
var ip_pool = "Main Pool";
var send_at = "example send_at";
mandrill_client.messages.send({"message": message, "async": async, "ip_pool": ip_pool, "send_at": send_at}, function(result) {
    console.log(result);
}, function(e) {
    // Mandrill returns the error as an object with name and message keys
    console.log('A mandrill error occurred: ' + e.name + ' - ' + e.message);
    // A mandrill error occurred: Unknown_Subaccount - No subaccount exists with the id 'customer-123'
});
*/
}

function signin(username, email) {
  console.log("Going to sign " + username + " in");
  var user;
  var bucket = 'constellational-meta';
  var token = {
    id: randomString(),
    secret: randomString()
  };
  return checkEmail(username, email).then(function(details) {
    user = details;
    console.log("Going to bcrypt temporary token");
    return bcrypt.hashAsync(token.secret, 10);
  }).then(function(hash) {
    if (!user.tempTokens) user.tempTokens = {};
    user.tempTokens[id] = {hash: hash, created: Date.now()});
    console.log("Going to store bcrypted hash of temporary token");
    return putJSON(bucket, username, user);
  }).then(function() {
    console.log("Going to send email");
    return {username: username, token: token};
  });
}

exports.handler = function(event, context) {
  console.log("Started");
  console.log(event);
  signup(event.username).then(context.succeed).catch(context.fail);
};
<|endoftext|>


<commit_before>(function() {
let randint = m => Math.floor(Math.random() * m);
let pad = ((s, l) => new Array(l + 1 - s.length).join("0") + s);

function CheckoutSE() {
	let isValidRegNo = no => no.split("").filter(c => c !== "-").map(c => c - "0").map((c, i) => ((i + 1) % 2 + 1) * c).map(s => (s % 10) + Math.floor(s / 10)).reduce((a, b) => a + b) % 10 === 0;
	let reg;
	do {
		reg = pad(randint(1000000).toString(), 6) + "-" + pad(randint(1000).toString(), 4);
	} while (!isValidRegNo(reg));
	document.getElementById("Customer_OrgNo").value = reg;
	let mail = document.getElementById("CompanyContactEmail").innerText;
	document.getElementById("Customer_Name").value = mail.split("@")[0];
	document.getElementById("Customer_InvoicingAddress1").value = "A";
	document.getElementById("Customer_InvoicingPostalCode").value = "22222";
	document.getElementById("Customer_InvoicingCity").value = "Lund";
	document.getElementById("Customer_PhoneNumber").value = "070-5572927";
	document.getElementById("AcceptTermsOfService").checked = true;
}

function CheckoutNO() {
	let ctrl = [3, 2, 7, 6, 5, 4, 3, 2, 1];
	let isValidRegNo = no => no.split("").filter(c => c !== "-").map(c => c - "0").map((c, i) => ctrl[i] * c).reduce((a, b) => a + b) % 11 === 0;
	let reg;
	do {
		reg = pad(randint(1000000000).toString(), 9);
	} while (!isValidRegNo(reg));
	document.getElementById("Customer_OrgNo").value = reg;
	let mail = document.getElementById("CompanyContactEmail").innerText;
	document.getElementById("Customer_Name").value = mail.split("@")[0];
	document.getElementById("Customer_InvoicingAddress1").value = "A";
	document.getElementById("Customer_InvoicingPostalCode").value = "1234";
	document.getElementById("Customer_InvoicingCity").value = "Norge";
	document.getElementById("Customer_PhoneNumber").value = "12345678";
	document.getElementById("AcceptTermsOfService").checked = true;
}

function NewVONCustomer() {
	var customerNumber = document.getElementById("maincontentholder_CustomerNoTextBox").value;
	if(!customerNumber.match("\d+")) {
	  document.getElementById("maincontentholder_CustomerNoTextBox").value = customerNumber = randint(100000000);
	}
	document.getElementById("maincontentholder_CustomerNameTextBox").value = "s" + customerNumber;
	document.getElementById("maincontentholder_NewOrgNoTextBox").value = "555555-5555";
	document.getElementById("maincontentholder_NewInvoiceAddress1TextBox").value = "A";
	document.getElementById("maincontentholder_NewInvoicePostalCodeTextBox").value = "22222";
	document.getElementById("maincontentholder_NewInvoiceCityTextBox").value = "Lund";
	document.getElementById("maincontentholder_EmailTextBox").value = "s" + customerNumber + "@vline.spcs.se";
	document.getElementById("maincontentholder_FirstNameTextBox").value = "Sam";
	document.getElementById("maincontentholder_LastNameTextBox").value = customerNumber;
}

if(window.location.href.match(/\/sv\-SE\/checkout\/buy\b/)) {
  CheckoutSE();
} else if(window.location.href.match(/\/nb\-NO\/checkout\/buy\b/)) {
  CheckoutNO();
} else if(window.location.href.match(/\/administration\/Internal\/AddNewCustomer\.aspx\b/)) {
  NewVONCustomer();
}

})();
<commit_msg>Fix regex syntax<commit_after>(function() {
let randint = m => Math.floor(Math.random() * m);
let pad = ((s, l) => new Array(l + 1 - s.length).join("0") + s);

function CheckoutSE() {
	let isValidRegNo = no => no.split("").filter(c => c !== "-").map(c => c - "0").map((c, i) => ((i + 1) % 2 + 1) * c).map(s => (s % 10) + Math.floor(s / 10)).reduce((a, b) => a + b) % 10 === 0;
	let reg;
	do {
		reg = pad(randint(1000000).toString(), 6) + "-" + pad(randint(1000).toString(), 4);
	} while (!isValidRegNo(reg));
	document.getElementById("Customer_OrgNo").value = reg;
	let mail = document.getElementById("CompanyContactEmail").innerText;
	document.getElementById("Customer_Name").value = mail.split("@")[0];
	document.getElementById("Customer_InvoicingAddress1").value = "A";
	document.getElementById("Customer_InvoicingPostalCode").value = "22222";
	document.getElementById("Customer_InvoicingCity").value = "Lund";
	document.getElementById("Customer_PhoneNumber").value = "070-5572927";
	document.getElementById("AcceptTermsOfService").checked = true;
}

function CheckoutNO() {
	let ctrl = [3, 2, 7, 6, 5, 4, 3, 2, 1];
	let isValidRegNo = no => no.split("").filter(c => c !== "-").map(c => c - "0").map((c, i) => ctrl[i] * c).reduce((a, b) => a + b) % 11 === 0;
	let reg;
	do {
		reg = pad(randint(1000000000).toString(), 9);
	} while (!isValidRegNo(reg));
	document.getElementById("Customer_OrgNo").value = reg;
	let mail = document.getElementById("CompanyContactEmail").innerText;
	document.getElementById("Customer_Name").value = mail.split("@")[0];
	document.getElementById("Customer_InvoicingAddress1").value = "A";
	document.getElementById("Customer_InvoicingPostalCode").value = "1234";
	document.getElementById("Customer_InvoicingCity").value = "Norge";
	document.getElementById("Customer_PhoneNumber").value = "12345678";
	document.getElementById("AcceptTermsOfService").checked = true;
}

function NewVONCustomer() {
	var customerNumber = document.getElementById("maincontentholder_CustomerNoTextBox").value;
	if(!customerNumber.match(/\d+/)) {
	  document.getElementById("maincontentholder_CustomerNoTextBox").value = customerNumber = randint(100000000);
	}
	document.getElementById("maincontentholder_CustomerNameTextBox").value = "s" + customerNumber;
	document.getElementById("maincontentholder_NewOrgNoTextBox").value = "555555-5555";
	document.getElementById("maincontentholder_NewInvoiceAddress1TextBox").value = "A";
	document.getElementById("maincontentholder_NewInvoicePostalCodeTextBox").value = "22222";
	document.getElementById("maincontentholder_NewInvoiceCityTextBox").value = "Lund";
	document.getElementById("maincontentholder_EmailTextBox").value = "s" + customerNumber + "@vline.spcs.se";
	document.getElementById("maincontentholder_FirstNameTextBox").value = "Sam";
	document.getElementById("maincontentholder_LastNameTextBox").value = customerNumber;
}

if(window.location.href.match(/\/sv\-SE\/checkout\/buy\b/)) {
  CheckoutSE();
} else if(window.location.href.match(/\/nb\-NO\/checkout\/buy\b/)) {
  CheckoutNO();
} else if(window.location.href.match(/\/administration\/Internal\/AddNewCustomer\.aspx\b/)) {
  NewVONCustomer();
}

})();
<|endoftext|>


<commit_before>/*
Name:       nsapi.js - Unofficial NodeJS module for Nederlandse Spoorwegen API
Author:     Franklin van de Meent
Source:     https://github.com/fvdm/nodejs-ns-api
Feedback:   https://github.com/fvdm/nodejs-ns-api/issues
API Docs:   https://apiportal.ns.nl
License:    Unlicense (Public Domain, see LICENSE file)
*/

const { doRequest } = require ('httpreq');

module.exports = class NSAPI {

  /**
   * Configuration
   *
   * @param   {string}  key             Primary API key
   * @param   {number}  [timeout=5000]  Request timeout in ms
   */

  constructor ({

    key,
    timeout = 8000,

  }) {

    this._config = {
      key,
      timeout,
    };

  }

  /**
   * HTTP request
   *
   * @param   {object}  options  httpreq.doRequest options
   * @return  {Promise<object>}
   */

  _httpRequest (options) {
    return new Promise ((resolve, reject) => {
      doRequest (options, (err, res) => {
        if (err) {
          reject (err);
          return;
        }

        resolve (res);
      });
    });
  }

  /**
   * Talk to the API
   *
   * @param   {string}  path          Method path
   * @param   {object}  [parameters]  Request details
   *
   * @return  {Promise<object>}
   */

  async _request ({ path, parameters }) {
    const options = {
      method: 'GET',
      url: `https://gateway.apiportal.ns.nl${path}`,
      parameters,
      timeout: this._config.timeout,
      headers: {
        'Accept': 'application/json',
        'Ocp-Apim-Subscription-Key': this._config.key,
      },
    };

    const res = await this._httpRequest (options);
    const data = JSON.parse (res.body);
    let error;

    // Normal API error
    if (data.code && data.message) {
      error = new Error (data.message);
      error.code = data.code;
      error.errors = data.errors;
      throw error;
    }

    // API field error - hard to replicate
    /* istanbul ignore next */
    if (data.fieldErrors && data.fieldErrors.length) {
      error = new Error ('API field error');
      error.errors = data.fieldErrors;
      throw error;
    }

    // API error without message - hard to replate
    /* istanbul ignore next */
    if (data.errors && data.errors[0]) {
      error = new Error ('API error');
      error.errors = data.errors;
      throw error;
    }

    // API server error
    if (res.statusCode >= 300) {
      error = new Error ('API error');
      error.statusCode = res.statusCode;
      throw error;
    }

    // ok
    return data;
  }

  // ! REISINFORMATIE

  /**
   * Get a list of all stations
   *
   * @return  {Promise<array>}
   */

  async getAllStations () {
    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/stations',
    });

    return data.payload;
  }

  /**
   * Get arrivals for a station
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getArrivals (parameters) {
    if (parameters.dateTime && !(parameters.dateTime instanceof Date)) {
      parameters.dateTime = new Date (parameters.dateTime).toString();
    }

    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/arrivals',
      parameters,
    });

    return data.payload.arrivals;
  }

  /**
   * Get calamities
   *
   * @param   {object}          [parameters]  Request parameters
   * @return  {Promise<array>}
   */

  async getCalamities (parameters = {}) {
    const data = await this._request ({
      path: '/reisinformatie-api/api/v1/calamities',
      parameters,
    });

    return data.meldingen;
  }

  /**
   * Get a list of departure times
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getDepartures (parameters) {
    if (parameters.dateTime && !(parameters.dateTime instanceof Date)) {
      parameters.dateTime = new Date (parameters.dateTime).toISOString();
    }

    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/departures',
      parameters,
    });

    return data.payload.departures;
  }

  /**
   * Get details about one disruption
   *
   * @param   {object}           parameters     Request parameters
   * @param   {string}           parameters.id  Disruption ID
   *
   * @return  {Promise<object>}
   */

  async getDisruption (parameters) {
    const id = parameters.id;

    delete parameters.id;

    const data = await this._request ({
      path: `/reisinformatie-api/api/v2/disruptions/${id}`,
      parameters,
    });

    return data.payload;
  }

  /**
   * Get a list of disruptions
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getDisruptions (parameters = {}) {
    parameters.actual = parameters.actual === true ? 'true' : 'false';

    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/disruptions',
      parameters,
    });

    return data.payload;
  }

  /**
   * Get a list of disruptions for a specific station
   *
   * @param   {object}           parameters       Request parameters
   * @param   {object}           parameters.code  UICCode or station code
   *
   * @return  {Promise<object>}
   */

  async getStationDisruption (parameters) {
    const code = parameters.code;

    delete parameters.code;

    const data = await this._request ({
      path: `/reisinformatie-api/api/v2/disruptions/station/${code}`,
      parameters,
    });

    return data.payload;
  }

  /**
   * Reconstruct a trip if possible using the given reconCtx
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getTrip (parameters = {}) {

    /*
    if (parameters.date && !(parameters.date instanceof Date)) {
      parameters.date = new Date (parameters.date).toISOString();
    }
    */

    const data = await this._request ({
      path: '/reisinformatie-api/api/v3/trips/trip',
      parameters,
    });

    return data;
  }

  /**
   * Searches for a travel advice with the specified options between the
   * possible backends (HARP, 9292 or PAS/AVG)
   *
   * For door-to-door trips you need a special API key
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getTrips (parameters) {
    if (parameters.dateTime && !(parameters.dateTime instanceof Date)) {
      parameters.dateTime = new Date (parameters.dateTime).toISOString();
    }

    const data = await this._request ({
      path: '/reisinformatie-api/api/v3/trips',
      parameters,
    });

    return data.trips;
  }

  /**
   * Get pricing for travel between two stations
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getPrice (parameters) {
    // YYYY-MM-DD
    if (parameters.date && !(parameters.date instanceof Date)) {
      parameters.date = new Date (parameters.date).toISOString().split ('T')[0];
    }

    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/price',
      parameters,
    });

    return data.payload;
  }

  /**
   * Get information about a specific journey
   *
   * @param   {object}          Parameters  Request parameters
   * @return  {Promise<object>
   */

  async getJourney (parameters) {
    if (parameters.dateTime && !(parameters.date instanceof Date)) {
      parameters.dateTime = new Date (parameters.dateTime).toISOString();
    }

    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/journey',
      parameters,
    });

    return data.payload;
  }

  // ! PLACES

  /**
   * Get list of places
   *
   * @param   {object}  parameters  Request parameters
   * @return  {Promise<array>}
   */

  async placesList (parameters) {
    const data = await this._request ({
      path: '/places-api/v2/places',
      parameters,
    });

    return data.payload;
  }

  /**
   * Get list of OV Fiets locations
   *
   * @param   {object}  parameters  Request parameters
   * @return  {Promise<array>}
   */

  async placesOvfiets (parameters) {
    const data = await this._request ({
      path: '/places-api/v2/ovfiets',
      parameters,
    });

    return data.payload;
  }

  /**
   * Get place
   *
   * @param   {string}  type    Place type, ie. stationV2
   * @param   {string}  id      Place ID, ie. AMF
   * @param   {string}  [lang]  Response language
   *
   * @return  {Promise<object>}
   */

  async placesGet ({
    type,
    id,
    lang = '',
  }) {
    const data = await this._request ({
      path: `/places-api/v2/places/${type}/${id}`,
      parameters: {
        lang,
      },
    });

    return data.payload;
  }

};
<commit_msg>Style: Fix comment typo<commit_after>/*
Name:       nsapi.js - Unofficial NodeJS module for Nederlandse Spoorwegen API
Author:     Franklin van de Meent
Source:     https://github.com/fvdm/nodejs-ns-api
Feedback:   https://github.com/fvdm/nodejs-ns-api/issues
API Docs:   https://apiportal.ns.nl
License:    Unlicense (Public Domain, see LICENSE file)
*/

const { doRequest } = require ('httpreq');

module.exports = class NSAPI {

  /**
   * Configuration
   *
   * @param   {string}  key             Primary API key
   * @param   {number}  [timeout=5000]  Request timeout in ms
   */

  constructor ({

    key,
    timeout = 8000,

  }) {

    this._config = {
      key,
      timeout,
    };

  }

  /**
   * HTTP request
   *
   * @param   {object}  options  httpreq.doRequest options
   * @return  {Promise<object>}
   */

  _httpRequest (options) {
    return new Promise ((resolve, reject) => {
      doRequest (options, (err, res) => {
        if (err) {
          reject (err);
          return;
        }

        resolve (res);
      });
    });
  }

  /**
   * Talk to the API
   *
   * @param   {string}  path          Method path
   * @param   {object}  [parameters]  Request details
   *
   * @return  {Promise<object>}
   */

  async _request ({ path, parameters }) {
    const options = {
      method: 'GET',
      url: `https://gateway.apiportal.ns.nl${path}`,
      parameters,
      timeout: this._config.timeout,
      headers: {
        'Accept': 'application/json',
        'Ocp-Apim-Subscription-Key': this._config.key,
      },
    };

    const res = await this._httpRequest (options);
    const data = JSON.parse (res.body);
    let error;

    // Normal API error
    if (data.code && data.message) {
      error = new Error (data.message);
      error.code = data.code;
      error.errors = data.errors;
      throw error;
    }

    // API field error - hard to replicate
    /* istanbul ignore next */
    if (data.fieldErrors && data.fieldErrors.length) {
      error = new Error ('API field error');
      error.errors = data.fieldErrors;
      throw error;
    }

    // API error without message - hard to replicate
    /* istanbul ignore next */
    if (data.errors && data.errors[0]) {
      error = new Error ('API error');
      error.errors = data.errors;
      throw error;
    }

    // API server error
    if (res.statusCode >= 300) {
      error = new Error ('API error');
      error.statusCode = res.statusCode;
      throw error;
    }

    // ok
    return data;
  }

  // ! REISINFORMATIE

  /**
   * Get a list of all stations
   *
   * @return  {Promise<array>}
   */

  async getAllStations () {
    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/stations',
    });

    return data.payload;
  }

  /**
   * Get arrivals for a station
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getArrivals (parameters) {
    if (parameters.dateTime && !(parameters.dateTime instanceof Date)) {
      parameters.dateTime = new Date (parameters.dateTime).toString();
    }

    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/arrivals',
      parameters,
    });

    return data.payload.arrivals;
  }

  /**
   * Get calamities
   *
   * @param   {object}          [parameters]  Request parameters
   * @return  {Promise<array>}
   */

  async getCalamities (parameters = {}) {
    const data = await this._request ({
      path: '/reisinformatie-api/api/v1/calamities',
      parameters,
    });

    return data.meldingen;
  }

  /**
   * Get a list of departure times
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getDepartures (parameters) {
    if (parameters.dateTime && !(parameters.dateTime instanceof Date)) {
      parameters.dateTime = new Date (parameters.dateTime).toISOString();
    }

    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/departures',
      parameters,
    });

    return data.payload.departures;
  }

  /**
   * Get details about one disruption
   *
   * @param   {object}           parameters     Request parameters
   * @param   {string}           parameters.id  Disruption ID
   *
   * @return  {Promise<object>}
   */

  async getDisruption (parameters) {
    const id = parameters.id;

    delete parameters.id;

    const data = await this._request ({
      path: `/reisinformatie-api/api/v2/disruptions/${id}`,
      parameters,
    });

    return data.payload;
  }

  /**
   * Get a list of disruptions
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getDisruptions (parameters = {}) {
    parameters.actual = parameters.actual === true ? 'true' : 'false';

    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/disruptions',
      parameters,
    });

    return data.payload;
  }

  /**
   * Get a list of disruptions for a specific station
   *
   * @param   {object}           parameters       Request parameters
   * @param   {object}           parameters.code  UICCode or station code
   *
   * @return  {Promise<object>}
   */

  async getStationDisruption (parameters) {
    const code = parameters.code;

    delete parameters.code;

    const data = await this._request ({
      path: `/reisinformatie-api/api/v2/disruptions/station/${code}`,
      parameters,
    });

    return data.payload;
  }

  /**
   * Reconstruct a trip if possible using the given reconCtx
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getTrip (parameters = {}) {

    /*
    if (parameters.date && !(parameters.date instanceof Date)) {
      parameters.date = new Date (parameters.date).toISOString();
    }
    */

    const data = await this._request ({
      path: '/reisinformatie-api/api/v3/trips/trip',
      parameters,
    });

    return data;
  }

  /**
   * Searches for a travel advice with the specified options between the
   * possible backends (HARP, 9292 or PAS/AVG)
   *
   * For door-to-door trips you need a special API key
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getTrips (parameters) {
    if (parameters.dateTime && !(parameters.dateTime instanceof Date)) {
      parameters.dateTime = new Date (parameters.dateTime).toISOString();
    }

    const data = await this._request ({
      path: '/reisinformatie-api/api/v3/trips',
      parameters,
    });

    return data.trips;
  }

  /**
   * Get pricing for travel between two stations
   *
   * @param   {object}          parameters  Request parameters
   * @return  {Promise<array>}
   */

  async getPrice (parameters) {
    // YYYY-MM-DD
    if (parameters.date && !(parameters.date instanceof Date)) {
      parameters.date = new Date (parameters.date).toISOString().split ('T')[0];
    }

    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/price',
      parameters,
    });

    return data.payload;
  }

  /**
   * Get information about a specific journey
   *
   * @param   {object}          Parameters  Request parameters
   * @return  {Promise<object>
   */

  async getJourney (parameters) {
    if (parameters.dateTime && !(parameters.date instanceof Date)) {
      parameters.dateTime = new Date (parameters.dateTime).toISOString();
    }

    const data = await this._request ({
      path: '/reisinformatie-api/api/v2/journey',
      parameters,
    });

    return data.payload;
  }

  // ! PLACES

  /**
   * Get list of places
   *
   * @param   {object}  parameters  Request parameters
   * @return  {Promise<array>}
   */

  async placesList (parameters) {
    const data = await this._request ({
      path: '/places-api/v2/places',
      parameters,
    });

    return data.payload;
  }

  /**
   * Get list of OV Fiets locations
   *
   * @param   {object}  parameters  Request parameters
   * @return  {Promise<array>}
   */

  async placesOvfiets (parameters) {
    const data = await this._request ({
      path: '/places-api/v2/ovfiets',
      parameters,
    });

    return data.payload;
  }

  /**
   * Get place
   *
   * @param   {string}  type    Place type, ie. stationV2
   * @param   {string}  id      Place ID, ie. AMF
   * @param   {string}  [lang]  Response language
   *
   * @return  {Promise<object>}
   */

  async placesGet ({
    type,
    id,
    lang = '',
  }) {
    const data = await this._request ({
      path: `/places-api/v2/places/${type}/${id}`,
      parameters: {
        lang,
      },
    });

    return data.payload;
  }

};
<|endoftext|>


<commit_before>var ASTRAL = {}

// sets up the Astral flash streaming module and instructs it to upload to and
function previewStream(streamSlug) {
    $.ajax({
        url: "http://localhost:8000/settings",
        success: function(data) {
            ASTRAL.astral_streaming_module.setupAndStream(
                ASTRAL.userRole,
                streamSlug,
                "",
                "rtmp://localhost:" + data.rtmp_port + "/"
                    + data.rtmp_resource,
                "");
        },
        dataType: 'jsonp'
    });
}

function changeStreamStatus(streamSlug, streamingStatus) {
    $.ajax({
        url: "http://localhost:8000/stream/" + streamSlug + "?streaming="
                + streamingStatus,
        dataType: 'jsonp'
    });
}

function stopStream() {
    ASTRAL.astral_streaming_module.stopStreaming();
    $.ajax({
        url: "http://localhost:8000/settings",
        success: function(data) {
            ASTRAL.astral_streaming_module.setupAndStream(ASTRAL.userRole,
                streamSlug,
                "rtmp://localhost:" + data.rtmp_port + "/"
                    + data.rtmp_resource);
        },
        dataType: 'jsonp'
    });

    $.ajax({
        type: "DELETE",
        url: "http://localhost:8000/stream/" + streamSlug,
        dataType: 'jsonp'
    });
}

// sets up the Astral flash streaming module and instructs it to connect to a
// specific port on localhost, an HTTP tunnel to a remote RTMP server
function startConsuming(streamSlug) {
    $.ajax({
        type: "POST",
        url: "http://localhost:8000/stream/" + streamSlug + "/tickets",
        success: function(data) {
            $.ajax({
                url: "http://localhost:8000/settings",
                success: function(data) {
                    ASTRAL.astral_streaming_module.setupAndStream(
                        ASTRAL.userRole,
                        streamSlug,
                        "",
                        "",
                        "rtmp://localhost:" + data.rtmp_tunnel_port + "/"
                            + data.rtmp_resource);
                },
                dataType: 'jsonp'
            });
        }
    });
}

function stopConsuming(streamSlug) {
    $.ajax({
        type: "DELETE",
        url: "http://localhost:8000/stream/" + streamSlug + "/ticket",
        dataType: 'jsonp'
    });
}

// used by flash to display error messages
function displayFromFlash(msg) {
    $("div#streaming_flash_error").text(msg);
}

$(document).ready(function() {
    WebFont.load({
        custom: {
            families: ['star-lit-night'],
            urls: ['/css/font.css']
        }
    });

    ASTRAL.astral_streaming_module = document.getElementById("astral");
    // Either publisher or consumer
    ASTRAL.userRole = $("#publish_start").length != 0 ?
            "publisher" : "consumer";
    if (ASTRAL.astral_streaming_module) {
        // get the stream's unique identifier on the network
        var streamSlug = $("div#slug").text();
        if(streamSlug && ASTRAL.userRole === "publisher") {
            previewStream(streamSlug);
            $("#streaming_notice").text("This is a preview - the video " +
                "will not be streaming until you being publishing.");
        }

        $("#consume_start").removeClass("hidden");
        $("#publish_start").removeClass("hidden");
        $("#publish_stop").removeClass("hidden");

        $("#publish_start").click(function(e) {
            $("#publish_pause").removeClass("hidden");
            $("#publish_start").addClass("hidden");
            $("#streaming_notice").text("Video is streaming to the network.");

            changeStreamStatus(streamSlug, true);
            return false;
        });

        $("#publish_pause").click(function(e) {
            $("#publish_start").removeClass("hidden");
            $("#publish_pause").addClass("hidden");
            $("#streaming_notice").text("Streaming is now paused.");
            changeStreamStatus(streamSlug, false);
            return false;
        });

        $("#publish_stop").click(function(e) {
            $("#consume_start").removeClass("hidden");
            $("#publish_stop").addClass("hidden");
            $("#publish_pause").addClass("hidden");
            $("#publish_start").addClass("hidden");
            $("#streaming_notice").text(
                    "Stopped publishing. Please reload page.");
            stopStream();
            return false;
        });

        $("#consume_stop").click(function(e) {
            $("#consume_start").removeClass("hidden");
            $("#consume_stop").addClass("hidden");
            $("#streaming_notice").text("Stopped streaming.");
            stopConsuming(streamSlug);
            return false;
        });

        $("#consume_start").click(function(e) {
            $("#streaming_notice").text("Streaming from network.");
            $("#consume_start").addClass("hidden");
            $("#consume_stop").removeClass("hidden");
            startConsuming(streamSlug);
            return false;
        });
    }
});
<commit_msg>Remove incorrect ajax call - shutting down, not starting up.<commit_after>var ASTRAL = {}

// sets up the Astral flash streaming module and instructs it to upload to and
function previewStream(streamSlug) {
    $.ajax({
        url: "http://localhost:8000/settings",
        success: function(data) {
            ASTRAL.astral_streaming_module.setupAndStream(
                ASTRAL.userRole,
                streamSlug,
                "",
                "rtmp://localhost:" + data.rtmp_port + "/"
                    + data.rtmp_resource,
                "");
        },
        dataType: 'jsonp'
    });
}

function changeStreamStatus(streamSlug, streamingStatus) {
    $.ajax({
        url: "http://localhost:8000/stream/" + streamSlug + "?streaming="
                + streamingStatus,
        dataType: 'jsonp'
    });
}

function stopStream() {
    ASTRAL.astral_streaming_module.stopStreaming();
    $.ajax({
        type: "DELETE",
        url: "http://localhost:8000/stream/" + streamSlug,
        dataType: 'jsonp'
    });
}

// sets up the Astral flash streaming module and instructs it to connect to a
// specific port on localhost, an HTTP tunnel to a remote RTMP server
function startConsuming(streamSlug) {
    $.ajax({
        type: "POST",
        url: "http://localhost:8000/stream/" + streamSlug + "/tickets",
        success: function(data) {
            $.ajax({
                url: "http://localhost:8000/settings",
                success: function(data) {
                    ASTRAL.astral_streaming_module.setupAndStream(
                        ASTRAL.userRole,
                        streamSlug,
                        "",
                        "",
                        "rtmp://localhost:" + data.rtmp_tunnel_port + "/"
                            + data.rtmp_resource);
                },
                dataType: 'jsonp'
            });
        }
    });
}

function stopConsuming(streamSlug) {
    $.ajax({
        type: "DELETE",
        url: "http://localhost:8000/stream/" + streamSlug + "/ticket",
        dataType: 'jsonp'
    });
}

// used by flash to display error messages
function displayFromFlash(msg) {
    $("div#streaming_flash_error").text(msg);
}

$(document).ready(function() {
    WebFont.load({
        custom: {
            families: ['star-lit-night'],
            urls: ['/css/font.css']
        }
    });

    ASTRAL.astral_streaming_module = document.getElementById("astral");
    // Either publisher or consumer
    ASTRAL.userRole = $("#publish_start").length != 0 ?
            "publisher" : "consumer";
    if (ASTRAL.astral_streaming_module) {
        // get the stream's unique identifier on the network
        var streamSlug = $("div#slug").text();
        if(streamSlug && ASTRAL.userRole === "publisher") {
            previewStream(streamSlug);
            $("#streaming_notice").text("This is a preview - the video " +
                "will not be streaming until you being publishing.");
        }

        $("#consume_start").removeClass("hidden");
        $("#publish_start").removeClass("hidden");
        $("#publish_stop").removeClass("hidden");

        $("#publish_start").click(function(e) {
            $("#publish_pause").removeClass("hidden");
            $("#publish_start").addClass("hidden");
            $("#streaming_notice").text("Video is streaming to the network.");

            changeStreamStatus(streamSlug, true);
            return false;
        });

        $("#publish_pause").click(function(e) {
            $("#publish_start").removeClass("hidden");
            $("#publish_pause").addClass("hidden");
            $("#streaming_notice").text("Streaming is now paused.");
            changeStreamStatus(streamSlug, false);
            return false;
        });

        $("#publish_stop").click(function(e) {
            $("#consume_start").removeClass("hidden");
            $("#publish_stop").addClass("hidden");
            $("#publish_pause").addClass("hidden");
            $("#publish_start").addClass("hidden");
            $("#streaming_notice").text(
                    "Stopped publishing. Please reload page.");
            stopStream();
            return false;
        });

        $("#consume_stop").click(function(e) {
            $("#consume_start").removeClass("hidden");
            $("#consume_stop").addClass("hidden");
            $("#streaming_notice").text("Stopped streaming.");
            stopConsuming(streamSlug);
            return false;
        });

        $("#consume_start").click(function(e) {
            $("#streaming_notice").text("Streaming from network.");
            $("#consume_start").addClass("hidden");
            $("#consume_stop").removeClass("hidden");
            startConsuming(streamSlug);
            return false;
        });
    }
});
<|endoftext|>


<commit_before>window.jsel = JSONSelect;

$(document).ready(function() {
    var theDoc = JSON.parse($("pre.doc").text());

    function highlightMatches(ar) {
        // first calculate match offsets
        var wrk = [];
        var html = $.trim(JSON.stringify(theDoc, undefined, 4));
        var ss = "";
        var es = "";
        for (var i = 0; i < ar.length; i++) {
            var found = $.trim(JSON.stringify(ar[i], undefined, 4));
            // turn the string into a regex to handle indentation
            found = found.replace(/[-[\]{}()*+?.,\\^$|#]/g, "\\$&").replace(/\s+/gm, "\\s*");
            var re = new RegExp(found, "m");
            var m = re.exec(html);
            if (!m) {
                console.log("ERROR, can't match: " + found);
                continue;
            }
            wrk.push({ off: m.index, typ: "s" });
            wrk.push({ off: m[0].length+m.index, typ: "e" });
        }
        // sort by offset
        wrk = wrk.sort(function(a,b) { return a.off - b.off; });

        // now start injecting spans into the text
        var cur = 0;
        var cons = 0;
        for (var i = 0; i < wrk.length; i++) {
            var diff = wrk[i].off - cons;
            cons = wrk[i].off;
            var tag = (wrk[i].typ == 's' ? ss : es);
            cur += diff;
            html = html.substr(0, cur) + tag + html.substr(cur);
            cur += tag.length;
        }
        return html;
    }

    // when a selector is chosen, update the text box
    $(".selectors .selector").click(function() {
        $(".current input").val($(this).text()).keyup();
    });

    var lastSel;
    $(".current input").keyup(function () {
        try {
            var sel = $(".current input").val()
            if (lastSel === $.trim(sel)) return;
            lastSel = $.trim(sel);
            var ar = jsel.match(sel, theDoc);
            $(".current .results").text(ar.length + " match" + (ar.length == 1 ? "" : "es"))
                .removeClass("error");
            $("pre.doc").html(highlightMatches(ar));
            $("pre.doc .selected").hide().fadeIn(700);
        } catch(e) {
            $(".current .results").text(e.toString()).addClass("error");
            $("pre.doc").text($.trim(JSON.stringify(theDoc, undefined, 4)));
        }
        $(".selectors .selector").removeClass("inuse");
        $(".selectors div.selector").each(function() {
            if ($(this).text() === sel) $(this).addClass("inuse");
        });
    });
});
<commit_msg>remove debug output<commit_after>window.jsel = JSONSelect;

$(document).ready(function() {
    var theDoc = JSON.parse($("pre.doc").text());

    function highlightMatches(ar) {
        // first calculate match offsets
        var wrk = [];
        var html = $.trim(JSON.stringify(theDoc, undefined, 4));
        var ss = "";
        var es = "";
        for (var i = 0; i < ar.length; i++) {
            var found = $.trim(JSON.stringify(ar[i], undefined, 4));
            // turn the string into a regex to handle indentation
            found = found.replace(/[-[\]{}()*+?.,\\^$|#]/g, "\\$&").replace(/\s+/gm, "\\s*");
            var re = new RegExp(found, "m");
            var m = re.exec(html);
            if (!m) continue;
            wrk.push({ off: m.index, typ: "s" });
            wrk.push({ off: m[0].length+m.index, typ: "e" });
        }
        // sort by offset
        wrk = wrk.sort(function(a,b) { return a.off - b.off; });

        // now start injecting spans into the text
        var cur = 0;
        var cons = 0;
        for (var i = 0; i < wrk.length; i++) {
            var diff = wrk[i].off - cons;
            cons = wrk[i].off;
            var tag = (wrk[i].typ == 's' ? ss : es);
            cur += diff;
            html = html.substr(0, cur) + tag + html.substr(cur);
            cur += tag.length;
        }
        return html;
    }

    // when a selector is chosen, update the text box
    $(".selectors .selector").click(function() {
        $(".current input").val($(this).text()).keyup();
    });

    var lastSel;
    $(".current input").keyup(function () {
        try {
            var sel = $(".current input").val()
            if (lastSel === $.trim(sel)) return;
            lastSel = $.trim(sel);
            var ar = jsel.match(sel, theDoc);
            $(".current .results").text(ar.length + " match" + (ar.length == 1 ? "" : "es"))
                .removeClass("error");
            $("pre.doc").html(highlightMatches(ar));
            $("pre.doc .selected").hide().fadeIn(700);
        } catch(e) {
            $(".current .results").text(e.toString()).addClass("error");
            $("pre.doc").text($.trim(JSON.stringify(theDoc, undefined, 4)));
        }
        $(".selectors .selector").removeClass("inuse");
        $(".selectors div.selector").each(function() {
            if ($(this).text() === sel) $(this).addClass("inuse");
        });
    });
});
<|endoftext|>


<commit_before>var child_process = require('child_process'); // http://nodejs.org/api/child_process.html
var path = require('path'); // File path processing. http://nodejs.org/api/path.html
var _ = require('lodash'); // Utilities. http://underscorejs.org/
var Backbone = require('backbone'); // Data model utilities. http://backbonejs.org/
var moment = require('moment'); // Date processing. http://momentjs.com/
var request = require('request'); // Simpler HTTP. https://github.com/mikeal/request
var progress = require('request-progress'); // Progress events on downloads. https://github.com/IndigoUnited/node-request-progress
var XRegExp = require('xregexp').XRegExp; // Fancy regular expressions. http://xregexp.com/
var fs = require('node-fs'); // Recursive directory creation. https://github.com/bpedro/node-fs
var ncp = require('ncp').ncp; // Recursive directory copy. https://npmjs.org/package/ncp
var winston = require('winston'); // Logging. https://github.com/flatiron/winston
var BaseModel = require('./baseModel.js').BaseModel;

// Update content for the application, as well as the application itself.
exports.ContentUpdater = BaseModel.extend({

    defaults: {
        // When the content was last updated.
        downloaded: null,
        updated: null,

        // The remote URL to the root XML.
        remote: null,

        // The final local path for content.
        local: 'content/',

        // The temp path for content.
        temp: null,

        // The path for content backups.
        backup: null,

        // A collection of file objects that are being processed.
        files: null,

        // After a download is initiated, indicates whether anything new was discovered.
        needsUpdate: false,

        // Indicates whether an update is currently in progress.
        isUpdating: false,

        // Indicates whether there is a backup of content to roll back to.
        canRollBack: false
    },

    // A callback to call when updating is complete.
    _callback: null,

    initialize: function() {
        BaseModel.prototype.initialize.apply(this);

        // Normalize slashes at the end of paths.
        this.set('local', path.join(this.get('local'), '/'));

        // Even if there's only one remote configured, make it an object so it's standard.
        if (!_.isObject(this.get('remote'))) {
            this.set('remote', {
                remote: this.get('remote')
            });
        }

        // Set up the temp and backup paths.
        var temp = {};
        var backup = {};
        var defaultSource = savedState.contentSource;
        for (var source in this.get('remote')) {
            if (!defaultSource) {
                defaultSource = source;
            }

            temp[source] = path.join(path.dirname(this.get('local')), path.basename(this.get('local')) + '.' + source + '.temp', '/');
            backup[source] = path.join(path.dirname(this.get('local')), path.basename(this.get('local')) + '.' + source + '.backup', '/');
        }

        this.set('temp', temp);
        this.set('backup', backup);

        // Save the initial default source.
        if (!savedState.contentSource) {
            global.saveState('contentSource', defaultSource);
            global.saveState('lastContentSource', defaultSource);
        }

        fs.exists(this.get('backup')[defaultSource], _.bind(function(exists) {
            this.set('canRollBack', exists);
        }, this));
    },

    // Download new content to the temp folder.
    download: function(source, callback) {
        var remote = this.get('remote');

        remote = remote[source];
        this._callback = callback;

        if (!remote) {
            this._callback();
            return;
        }

        this.set('needsUpdate', false);
        this.set('isUpdating', true);

        this._doDownload(source);
    },

    _doDownload: function(source) {
        this._initDirectories(source, _.bind(function() {
            var remote = this.get('remote')[source];
            if (remote.indexOf('http') === 0) {
                // We're going to pull down an XML file from the web and parse it for other files.
                request(remote, _.bind(function(error, response, body) {
                    this._processContentRoot(source, error, response, body);
                }, this));
            } else {
                // We're going to just robocopy from another folder instead.
                this._robocopy(remote, path.resolve(this.get('temp')[source]), null, _.bind(function(code) {
                    this.set('needsUpdate', code > 0 && code <= 8);
                    this._callback(code > 8 ? code : 0);
                    if (code > 8) {
                        // Something bad happened.
                        logger.error('Robocopy failed with code ' + code);
                    }
                }, this));
            }
        }, this));
    },

    // Set up the temp and output directories.
    _initDirectories: function(source, callback) {
        // Make the temp directory.
        fs.mkdir(this.get('temp')[source], 0777, true, _.bind(function(error) {
            this._handleError('Error creating temp directory.', error);

            fs.exists(this.get('local'), _.bind(function(exists) {
                if (exists) {
                    callback();
                    return;
                }

                // Make the ouput directory.
                fs.mkdir(this.get('local'), 0777, true, _.bind(function(error) {
                    this._handleError('Error creating ouput directory.', error);
                    callback();
                }, this));
            }, this));
        }, this));
    },

    // Process the XML file to extract files to load.
    _processContentRoot: function(source, error, response, body) {
        if (response.statusCode != 200) {
            this._handleError('Error loading root XML -- bad password?');
            return;
        }

        this._handleError('Error loading root XML.', error);

        // Write the root XML file.
        fs.writeFile(this.get('temp')[source] + 'content.xml', body, _.bind(function(error) {
            this._handleError('Error writing root XML.', error);
            this.set('files', new exports.ContentFiles());

            // Collect any URLs in root file.
            var pattern = new XRegExp(/>(http.*?)</gi);
            var matches = [];
            var match;

            while (true) {
                match = pattern.exec(body);
                if (!match) {
                    break;
                }
                matches.push(match);
            }

            // Figure out what each URL begins with -- this is removed to create the relative path.
            var prefix = '';

            function iterator(element, index, list) {
                return element[1].indexOf(prefix) === 0;
            }

            while (true) {
                prefix += matches[0][1][prefix.length];
                if (!_.every(matches, iterator)) {
                    prefix = prefix.substr(0, prefix.length - 1);
                    break;
                }
            }

            // Build file objects.
            _.each(matches, function(element, index, list) {
                var url = element[1];
                var relativePath = url.substr(prefix.length);
                var file = new exports.ContentFile({
                    url: url,
                    filePath: this.get('local') + relativePath,
                    tempPath: this.get('temp')[source] + relativePath
                });

                file.on('loaded', this._onFileLoaded, this);
                this.get('files').add(file);
            }, this);

            _.each(this.get('files').models, _.bind(this._processFile, this));
        }, this));
    },

    // Determine if the file needs to be loaded, or if it's already up to date.
    _processFile: function(contentFile) {
        fs.exists(contentFile.get('tempPath'), _.bind(function(exists) {
            if (!exists) {
                // The file doesn't exist locally, so download it.
                this._downloadFile(contentFile);
                return;
            }

            // The file does exist locally, check if the remote one is newer.
            fs.stat(contentFile.get('tempPath'), _.bind(function(error, stats) {
                var localFileModified = moment(stats.mtime);
                request({
                    url: contentFile.get('url'),
                    method: 'HEAD'
                }, _.bind(function(error, response, body) {
                    var remoteFileModified = moment(response.headers['last-modified']);
                    if (remoteFileModified.isAfter(localFileModified)) {
                        // The remote file is newer, go get it.
                        this._downloadFile(contentFile);
                        return;
                    }

                    // The local file is newer, flag it as loaded.
                    contentFile.set('progress', 1);
                }, this));
            }, this));
        }, this));
    },

    // Load the file into memory and create its temp output directory.
    _downloadFile: function(contentFile) {
        logger.info('Downloading ' + contentFile.get('url'));

        // Request the file from the network.
        progress(request({
            url: contentFile.get('url'),
            encoding: null // Required for binary files.
        }, _.bind(function(error, response, body) {
            if (!error && response.statusCode != 200) {
                error = response.statusCode;
            }

            this.set('needsUpdate', !error);
            this._handleError('Error loading ' + contentFile.get('url'), error);

            // Create the file's output directory if needed.
            var dir = path.dirname(contentFile.get('tempPath'));
            fs.exists(dir, _.bind(function(exists) {
                if (!exists) {
                    fs.mkdir(dir, 0777, true, _.bind(function(error) {
                        this._handleError('Error creating temp directory for file.', error);
                        this._writeFile(contentFile, body);
                    }, this));
                } else {
                    this._writeFile(contentFile, body);
                }
            }, this));

        }, this))).on('progress', function(state) {

            // Set progress properties on the file.
            contentFile.set('receivedBytes', state.received);
            contentFile.set('totalBytes', state.total);
            contentFile.set('progress', state.percent / 100);
        });
    },

    // When the file is done loading, write it to disk.
    _writeFile: function(contentFile, body) {
        fs.writeFile(contentFile.get('tempPath'), body, null, _.bind(function(error) {
            this._handleError('Error writing file.', error);
            contentFile.set('progress', 1);
        }, this));
    },

    // Called when the progress of a file is set to 1.
    _onFileLoaded: function(contentFile) {
        contentFile.off('loaded', this._onFileLoaded, this);

        // Determine if all files are loaded.
        var filesToGo = _.filter(this.get('files').models, function(file) {
            return file.get('progress') < 1;
        }).length;
        var style = contentFile.get('totalBytes') ? 'loaded' : 'cached';
        logger.info(contentFile.get('url') + ' ' + style + ', ' + filesToGo + ' to go');

        if (!filesToGo) {
            this.set('isUpdating', false);
            this.set('downloaded', moment());
            this._callback();
        }
    },

    // Copy files to their final destination when all files are loaded.
    deploy: function(force, callback) {
        var source = savedState.contentSource;
        var lastSource = savedState.lastContentSource;
        this.set('isUpdating', true);
        this._callback = callback;
        if (!force && !this.get('needsUpdate')) {
            this._completed();
            return;
        }

        deployFromTemp = _.bind(function() {
            logger.info('Deploying from ' + this.get('temp')[source] + ' to ' + this.get('local'));
            ncp(this.get('temp')[source], this.get('local'), _.bind(function(error) {
                this._handleError('Error copying from temp folder.', error);
                this._completed();
            }, this));
        }, this);

        backupThenDeploy = _.bind(function() {
            logger.info('Backing up from ' + this.get('local') + ' to ' + this.get('backup')[lastSource]);
            ncp(this.get('local'), this.get('backup')[source], _.bind(function(error) {
                this._handleError('Error copying to backup folder.', error);
                if (error) {
                    this._completed();
                    return;
                }

                deployFromTemp();
            }, this));
        }, this);

        if (force) {
            deployFromTemp();
        } else {
            backupThenDeploy();
        }
    },

    // Notify on completion.
    _completed: function() {
        this.set('updated', moment());
        this.set('isUpdating', false);
        this.saveState('lastContentSource', savedState.contentSource);
        this.trigger('complete');
        if (this._callback) {
            this._callback();
        }
    },

    // Generic error handling function.
    _handleError: function(message, error) {
        if (!error) {
            return;
        }

        logger.error(message, error);
        if (this._callback) {
            this._callback(error);
        }
    },

    // Robocopy files instead of downloading them.
    _robocopy: function(sourceDir, targetDir, file, callback) {
        // http://technet.microsoft.com/en-us/library/cc733145.aspx
        var args = [
            sourceDir,
            targetDir,
            file,
            '/e', // Copies subdirectories. Note that this option includes empty directories.
            '/v', // Produces verbose output, and shows all skipped files.
            '/np', // Specifies that the progress of the copying operation (the number of files or directories copied so far) will not be displayed.
            '/njs', // Specifies that there is no job summary.
            '/njh', // Specifies that there is no job header.
            '/bytes', // Prints sizes, as bytes.
            '/fft', // Assumes FAT file times (two-second precision).
            '/ndl' // Specifies that directory names are not to be logged.
        ];

        if (!file) {
            // We're copying full directories, remove the file argument.
            args.splice(2, 1);
        } else {
            // We're copying one file, remove the copy-subdirectories argument.
            args.splice(3, 1);
        }

        var copy = child_process.spawn('robocopy', args);
        logger.info('robocopy: robocopy ' + args.join(' '));

        copy.stdout.on('data', _.bind(function(data) {
            var lines = data.toString().split('\r\n');
            _.each(lines, function(line) {
                line = line.trim();
                if (line) {
                    logger.info('robocopy: ' + line);
                }
            });
        }, this));

        copy.stderr.on('data', _.bind(function(data) {
            logger.error('robocopy: ' + data.toString());
        }, this));

        copy.on('close', _.bind(function(code) {
            // The return codes are weird. http://support.microsoft.com/kb/954404
            this.set('downloaded', moment());
            if (callback) {
                callback(code);
            }
        }, this));
    },

    // Roll back content -- copy it from the backup folder to the temp folder, and then to live.
    rollBack: function(callback) {
        var source = savedState.contentSource;
        if (!this.get('canRollBack')) {
            callback(false);
        }

        this.set('isUpdating', true);
        logger.info('Rolling back, copying from ' + this.get('backup')[source] + ' to ' + this.get('temp')[source]);

        ncp(this.get('backup')[source], this.get('temp')[source], _.bind(function(error) {
            this._handleError('Error copying to temp folder.', error);

            logger.info('Rolling back, copying from ' + this.get('temp')[source] + ' to ' + this.get('local'));
            ncp(this.get('temp')[source], this.get('local'), _.bind(function(error) {
                this._handleError('Error copying to deploy folder.', error);
                this.set('isUpdating', false);
                callback(!error);
            }, this));
        }, this));
    }
});

exports.ContentFile = Backbone.Model.extend({
    defaults: {
        url: null,
        filePath: null,
        tempPath: null,
        progress: 0,
        receivedBytes: 0,
        totalBytes: 0
    },

    initialize: function() {
        this.on('change:progress', function(model, value, options) {
            if (value >= 1) {
                this.trigger('loaded', this);
            }
        }, this);
    }
});

exports.ContentFiles = Backbone.Collection.extend({
    model: exports.ContentFile
});<commit_msg>more for #7266<commit_after>var child_process = require('child_process'); // http://nodejs.org/api/child_process.html
var path = require('path'); // File path processing. http://nodejs.org/api/path.html
var _ = require('lodash'); // Utilities. http://underscorejs.org/
var Backbone = require('backbone'); // Data model utilities. http://backbonejs.org/
var moment = require('moment'); // Date processing. http://momentjs.com/
var request = require('request'); // Simpler HTTP. https://github.com/mikeal/request
var progress = require('request-progress'); // Progress events on downloads. https://github.com/IndigoUnited/node-request-progress
var XRegExp = require('xregexp').XRegExp; // Fancy regular expressions. http://xregexp.com/
var fs = require('node-fs'); // Recursive directory creation. https://github.com/bpedro/node-fs
var ncp = require('ncp').ncp; // Recursive directory copy. https://npmjs.org/package/ncp
var winston = require('winston'); // Logging. https://github.com/flatiron/winston
var BaseModel = require('./baseModel.js').BaseModel;

// Update content for the application, as well as the application itself.
exports.ContentUpdater = BaseModel.extend({

    defaults: {
        // When the content was last updated.
        downloaded: null,
        updated: null,

        // The remote URL to the root XML.
        remote: null,

        // The final local path for content.
        local: 'content/',

        // The temp path for content.
        temp: null,

        // The path for content backups.
        backup: null,

        // A collection of file objects that are being processed.
        files: null,

        // After a download is initiated, indicates whether anything new was discovered.
        needsUpdate: false,

        // Indicates whether an update is currently in progress.
        isUpdating: false,

        // Indicates whether there is a backup of content to roll back to.
        canRollBack: false
    },

    // A callback to call when updating is complete.
    _callback: null,

    initialize: function() {
        BaseModel.prototype.initialize.apply(this);

        // Normalize slashes at the end of paths.
        this.set('local', path.join(this.get('local'), '/'));

        // Even if there's only one remote configured, make it an object so it's standard.
        if (!_.isObject(this.get('remote'))) {
            this.set('remote', {
                remote: this.get('remote')
            });
        }

        // Set up the temp and backup paths.
        var temp = {};
        var backup = {};
        var defaultSource = savedState.contentSource;
        for (var source in this.get('remote')) {
            if (!defaultSource) {
                defaultSource = source;
            }

            temp[source] = path.join(path.dirname(this.get('local')), path.basename(this.get('local')) + '.' + source + '.temp', '/');
            backup[source] = path.join(path.dirname(this.get('local')), path.basename(this.get('local')) + '.' + source + '.backup', '/');
        }

        this.set('temp', temp);
        this.set('backup', backup);

        // Save the initial default source.
        if (!savedState.contentSource) {
            global.saveState('contentSource', defaultSource);
            global.saveState('lastContentSource', defaultSource);
        }

        fs.exists(this.get('backup')[defaultSource], _.bind(function(exists) {
            this.set('canRollBack', exists);
        }, this));
    },

    // Download new content to the temp folder.
    download: function(source, callback) {
        var remote = this.get('remote');

        remote = remote[source];
        this._callback = callback;

        if (!remote) {
            this._callback();
            return;
        }

        this.set('needsUpdate', false);
        this.set('isUpdating', true);

        this._doDownload(source);
    },

    _doDownload: function(source) {
        this._initDirectories(source, _.bind(function() {
            var remote = this.get('remote')[source];
            if (remote.indexOf('http') === 0) {
                // We're going to pull down an XML file from the web and parse it for other files.
                request(remote, _.bind(function(error, response, body) {
                    this._processContentRoot(source, error, response, body);
                }, this));
            } else {
                // We're going to just robocopy from another folder instead.
                this._robocopy(remote, path.resolve(this.get('temp')[source]), null, _.bind(function(code) {
                    this.set('needsUpdate', code > 0 && code <= 8);
                    this._callback(code > 8 ? code : 0);
                    if (code > 8) {
                        // Something bad happened.
                        logger.error('Robocopy failed with code ' + code);
                    }
                }, this));
            }
        }, this));
    },

    // Set up the temp and output directories.
    _initDirectories: function(source, callback) {
        // Make the temp directory.
        fs.mkdir(this.get('temp')[source], 0777, true, _.bind(function(error) {
            this._handleError('Error creating temp directory.', error);

            fs.exists(this.get('local'), _.bind(function(exists) {
                if (exists) {
                    callback();
                    return;
                }

                // Make the ouput directory.
                fs.mkdir(this.get('local'), 0777, true, _.bind(function(error) {
                    this._handleError('Error creating ouput directory.', error);
                    callback();
                }, this));
            }, this));
        }, this));
    },

    // Process the XML file to extract files to load.
    _processContentRoot: function(source, error, response, body) {
        if (response.statusCode != 200) {
            this._handleError('Error loading root XML -- bad password?');
            return;
        }

        this._handleError('Error loading root XML.', error);

        // Write the root XML file.
        fs.writeFile(this.get('temp')[source] + 'content.xml', body, _.bind(function(error) {
            this._handleError('Error writing root XML.', error);
            this.set('files', new exports.ContentFiles());

            // Collect any URLs in root file.
            var pattern = new XRegExp(/>(http.*?)</gi);
            var matches = [];
            var match;

            while (true) {
                match = pattern.exec(body);
                if (!match) {
                    break;
                }
                matches.push(match);
            }

            // Figure out what each URL begins with -- this is removed to create the relative path.
            var prefix = '';

            function iterator(element, index, list) {
                return element[1].indexOf(prefix) === 0;
            }

            while (true) {
                prefix += matches[0][1][prefix.length];
                if (!_.every(matches, iterator)) {
                    prefix = prefix.substr(0, prefix.length - 1);
                    break;
                }
            }

            // Build file objects.
            _.each(matches, function(element, index, list) {
                var url = element[1];
                var relativePath = url.substr(prefix.length);
                var file = new exports.ContentFile({
                    url: url,
                    filePath: this.get('local') + relativePath,
                    tempPath: this.get('temp')[source] + relativePath
                });

                file.on('loaded', this._onFileLoaded, this);
                this.get('files').add(file);
            }, this);

            _.each(this.get('files').models, _.bind(this._processFile, this));
        }, this));
    },

    // Determine if the file needs to be loaded, or if it's already up to date.
    _processFile: function(contentFile) {
        fs.exists(contentFile.get('tempPath'), _.bind(function(exists) {
            if (!exists) {
                // The file doesn't exist locally, so download it.
                this._downloadFile(contentFile);
                return;
            }

            // The file does exist locally, check if the remote one is newer.
            fs.stat(contentFile.get('tempPath'), _.bind(function(error, stats) {
                var localFileModified = moment(stats.mtime);
                request({
                    url: contentFile.get('url'),
                    method: 'HEAD'
                }, _.bind(function(error, response, body) {
                    var remoteFileModified = moment(response.headers['last-modified']);
                    if (remoteFileModified.isAfter(localFileModified)) {
                        // The remote file is newer, go get it.
                        this._downloadFile(contentFile);
                        return;
                    }

                    // The local file is newer, flag it as loaded.
                    contentFile.set('progress', 1);
                }, this));
            }, this));
        }, this));
    },

    // Load the file into memory and create its temp output directory.
    _downloadFile: function(contentFile) {
        logger.info('Downloading ' + contentFile.get('url'));

        // Request the file from the network.
        progress(request({
            url: contentFile.get('url'),
            encoding: null // Required for binary files.
        }, _.bind(function(error, response, body) {
            if (!error && response.statusCode != 200) {
                error = response.statusCode;
            }

            this.set('needsUpdate', !error);
            this._handleError('Error loading ' + contentFile.get('url'), error);

            // Create the file's output directory if needed.
            var dir = path.dirname(contentFile.get('tempPath'));
            fs.exists(dir, _.bind(function(exists) {
                if (!exists) {
                    fs.mkdir(dir, 0777, true, _.bind(function(error) {
                        this._handleError('Error creating temp directory for file.', error);
                        this._writeFile(contentFile, body);
                    }, this));
                } else {
                    this._writeFile(contentFile, body);
                }
            }, this));

        }, this))).on('progress', function(state) {

            // Set progress properties on the file.
            contentFile.set('receivedBytes', state.received);
            contentFile.set('totalBytes', state.total);
            contentFile.set('progress', state.percent / 100);
        });
    },

    // When the file is done loading, write it to disk.
    _writeFile: function(contentFile, body) {
        fs.writeFile(contentFile.get('tempPath'), body, null, _.bind(function(error) {
            this._handleError('Error writing file.', error);
            contentFile.set('progress', 1);
        }, this));
    },

    // Called when the progress of a file is set to 1.
    _onFileLoaded: function(contentFile) {
        contentFile.off('loaded', this._onFileLoaded, this);

        // Determine if all files are loaded.
        var filesToGo = _.filter(this.get('files').models, function(file) {
            return file.get('progress') < 1;
        }).length;
        var style = contentFile.get('totalBytes') ? 'loaded' : 'cached';
        logger.info(contentFile.get('url') + ' ' + style + ', ' + filesToGo + ' to go');

        if (!filesToGo) {
            this.set('isUpdating', false);
            this.set('downloaded', moment());
            this._callback();
        }
    },

    // Copy files to their final destination when all files are loaded.
    deploy: function(force, callback) {
        var source = savedState.contentSource;
        var lastSource = savedState.lastContentSource;
        this.set('isUpdating', true);
        this._callback = callback;
        if (!force && !this.get('needsUpdate')) {
            this._completed();
            return;
        }

        deployFromTemp = _.bind(function() {
            logger.info('Deploying from ' + this.get('temp')[source] + ' to ' + this.get('local'));
            ncp(this.get('temp')[source], this.get('local'), _.bind(function(error) {
                this._handleError('Error copying from temp folder.', error);
                this._completed();
            }, this));
        }, this);

        backupThenDeploy = _.bind(function() {
            logger.info('Backing up from ' + this.get('local') + ' to ' + this.get('backup')[lastSource]);
            ncp(this.get('local'), this.get('backup')[source], _.bind(function(error) {
                this._handleError('Error copying to backup folder.', error);
                if (error) {
                    this._completed();
                    return;
                }

                deployFromTemp();
            }, this));
        }, this);

        if (force) {
            deployFromTemp();
        } else {
            backupThenDeploy();
        }
    },

    // Notify on completion.
    _completed: function() {
        this.set('updated', moment());
        this.set('isUpdating', false);
        saveState('lastContentSource', savedState.contentSource);
        this.trigger('complete');
        if (this._callback) {
            this._callback();
        }
    },

    // Generic error handling function.
    _handleError: function(message, error) {
        if (!error) {
            return;
        }

        logger.error(message, error);
        if (this._callback) {
            this._callback(error);
        }
    },

    // Robocopy files instead of downloading them.
    _robocopy: function(sourceDir, targetDir, file, callback) {
        // http://technet.microsoft.com/en-us/library/cc733145.aspx
        var args = [
            sourceDir,
            targetDir,
            file,
            '/e', // Copies subdirectories. Note that this option includes empty directories.
            '/v', // Produces verbose output, and shows all skipped files.
            '/np', // Specifies that the progress of the copying operation (the number of files or directories copied so far) will not be displayed.
            '/njs', // Specifies that there is no job summary.
            '/njh', // Specifies that there is no job header.
            '/bytes', // Prints sizes, as bytes.
            '/fft', // Assumes FAT file times (two-second precision).
            '/ndl' // Specifies that directory names are not to be logged.
        ];

        if (!file) {
            // We're copying full directories, remove the file argument.
            args.splice(2, 1);
        } else {
            // We're copying one file, remove the copy-subdirectories argument.
            args.splice(3, 1);
        }

        var copy = child_process.spawn('robocopy', args);
        logger.info('robocopy: robocopy ' + args.join(' '));

        copy.stdout.on('data', _.bind(function(data) {
            var lines = data.toString().split('\r\n');
            _.each(lines, function(line) {
                line = line.trim();
                if (line) {
                    logger.info('robocopy: ' + line);
                }
            });
        }, this));

        copy.stderr.on('data', _.bind(function(data) {
            logger.error('robocopy: ' + data.toString());
        }, this));

        copy.on('close', _.bind(function(code) {
            // The return codes are weird. http://support.microsoft.com/kb/954404
            this.set('downloaded', moment());
            if (callback) {
                callback(code);
            }
        }, this));
    },

    // Roll back content -- copy it from the backup folder to the temp folder, and then to live.
    rollBack: function(callback) {
        var source = savedState.contentSource;
        if (!this.get('canRollBack')) {
            callback(false);
        }

        this.set('isUpdating', true);
        logger.info('Rolling back, copying from ' + this.get('backup')[source] + ' to ' + this.get('temp')[source]);

        ncp(this.get('backup')[source], this.get('temp')[source], _.bind(function(error) {
            this._handleError('Error copying to temp folder.', error);

            logger.info('Rolling back, copying from ' + this.get('temp')[source] + ' to ' + this.get('local'));
            ncp(this.get('temp')[source], this.get('local'), _.bind(function(error) {
                this._handleError('Error copying to deploy folder.', error);
                this.set('isUpdating', false);
                callback(!error);
            }, this));
        }, this));
    }
});

exports.ContentFile = Backbone.Model.extend({
    defaults: {
        url: null,
        filePath: null,
        tempPath: null,
        progress: 0,
        receivedBytes: 0,
        totalBytes: 0
    },

    initialize: function() {
        this.on('change:progress', function(model, value, options) {
            if (value >= 1) {
                this.trigger('loaded', this);
            }
        }, this);
    }
});

exports.ContentFiles = Backbone.Collection.extend({
    model: exports.ContentFile
});<|endoftext|>


<commit_before>'use strict';

define([
    'jquery',
    'jquery-ui',
    'util/Templater'
], function($, jui, Templater) {
    class ConfigPage {
        constructor() {
            this.$el = $('.config-page');

            this.templates = {
                common: Templater.compile('#common-props-template'),
                layer: Templater.compile('#layer-template')
            };

            this.targets = {
                common: this.$el.find('#common-props'),
                layers: this.$el.find('#layers-container')
            };

            var $layers = this.$el.find('#layers-container');
            $layers.sortable();

            $layers.on('.remove click', (e) => {
                $(e.target).closest('.layer').remove();
            });

            this.$el.find('.add').click((e) => {
                var defaultLayer = {
                    name: 'Layer',
                    type: 'input',
                    w: 5,
                    h: 5,
                    d: 3
                };
                this.addLayer(defaultLayer);
            });

            this.$el.find('.save').click((e) => {
                var config = this.serialize();
                console.log(config);

                // TODO: send to server
                alert('Not implemented');
            });
        }

        render(config) {
            var commonHtml = this.templates.common({
                c: config.common
            });
            this.targets.common.html(commonHtml);

            this.targets.layers.empty();
            for (let layer of config.layers) {
                this.addLayer(layer);
            }
        }

        serialize() {
            var config = {
                common: {},
                layers: []
            };

            this.targets.common.find('.value').each((i, el) => {
                var $el = $(el);
                var key = $el.data('key');
                config.common[key] = $el.val();
            });

            this.targets.layers.find('.layer').each((i, layer) => {
                var $layer = $(layer);

                var data = {};
                $layer.find('.value').each((j, el) => {
                    var $el = $(el);
                    var key = $el.data('key');
                    data[key] = $el.val();
                });
                config.layers.push(data);
            });

            return config;
        }

        addLayer(data) {
            var layerHtml = this.templates.layer({
                l: data
            });

            var $layerHtml = $(layerHtml);
            $layerHtml.appendTo(this.targets.layers);
        }
    }

    return ConfigPage;
});<commit_msg>Remove layer bug fixed<commit_after>'use strict';

define([
    'jquery',
    'jquery-ui',
    'util/Templater'
], function($, jui, Templater) {
    class ConfigPage {
        constructor() {
            this.$el = $('.config-page');

            this.templates = {
                common: Templater.compile('#common-props-template'),
                layer: Templater.compile('#layer-template')
            };

            this.targets = {
                common: this.$el.find('#common-props'),
                layers: this.$el.find('#layers-container')
            };

            var $layers = this.$el.find('#layers-container');
            $layers.sortable();

            $layers.on('click', '.remove', (e) => {
                $(e.target).closest('.layer').remove();
            });

            this.$el.find('.add').click((e) => {
                var defaultLayer = {
                    name: 'Layer',
                    type: 'input',
                    w: 5,
                    h: 5,
                    d: 3
                };
                this.addLayer(defaultLayer);
            });

            this.$el.find('.save').click((e) => {
                var config = this.serialize();
                console.log(config);

                // TODO: send to server
                alert('Not implemented');
            });
        }

        render(config) {
            var commonHtml = this.templates.common({
                c: config.common
            });
            this.targets.common.html(commonHtml);

            this.targets.layers.empty();
            for (let layer of config.layers) {
                this.addLayer(layer);
            }
        }

        serialize() {
            var config = {
                common: {},
                layers: []
            };

            this.targets.common.find('.value').each((i, el) => {
                var $el = $(el);
                var key = $el.data('key');
                config.common[key] = $el.val();
            });

            this.targets.layers.find('.layer').each((i, layer) => {
                var $layer = $(layer);

                var data = {};
                $layer.find('.value').each((j, el) => {
                    var $el = $(el);
                    var key = $el.data('key');
                    data[key] = $el.val();
                });
                config.layers.push(data);
            });

            return config;
        }

        addLayer(data) {
            var layerHtml = this.templates.layer({
                l: data
            });

            var $layerHtml = $(layerHtml);
            $layerHtml.appendTo(this.targets.layers);
        }
    }

    return ConfigPage;
});<|endoftext|>