<commit_before>Events = new Mongo.Collection("events");

function Event(name, location, line, votes, createdAt, lastConfirmedAt) {
	this.name = name;
	this.location = location;
  this.line = line;
	this.votes = votes;
  this.createdAt = createdAt;
	this.lastConfirmedAt = lastConfirmedAt;
}

Event.prototype = {
  save: function() {
		var docId = Events.findOne({
			name: this.name,
			location: this.location,
			expired: false
		});

		if (docId) { // Upvote
			if (Session.get(docId._id) == null) { // Can upvote
				// Avoid future upvotes
				Session.setPersistent(docId._id, "upvoted");
				return Events.update(docId._id, {$inc: {votes: 1}});
			}
		} else { // Create
			newEvent =  Events.insert({
	      name: this.name,
	      location: this.location,
        line: this.line,
	      votes: this.votes,
	      createdAt: this.createdAt,
				lastConfirmedAt: this.lastConfirmedAt,
				expired: false
	    });
			// Avoid user to upvote her own alert
			Session.setPersistent(newEvent, "created")
			return newEvent;
		}
  }
};

if (Meteor.isClient) {

  var stations = [
    {name: "Alewife"},
    {name: "Davis"},
    {name: "Porter Square"},
    {name: "Harvard Square"},
    {name: "Central Square"},
    {name: "Kendall"},
    {name: "Charles/MGH"},
    {name: "Park Street"},
    {name: "Downtown Crossing"},
    {name: "South Station"},
    {name: "Broadway"},
    {name: "Andrew"},
    {name: "JFK/UMass"},
    {name: "North Quincy"},
    {name: "Wollaston"},
    {name: "Quincy Center"},
    {name: "Quincy Adams"},
    {name: "Braintree"},
    {name: "Savin Hill"},
    {name: "Fields Corner"},
    {name: "Shawmut"},
    {name: "Ashmont"},
  ];

  var eventTypes = [
    {name: "Delayed train"},
    {name: "Train too crowded to board"},
    {name: "Overcrowded platform"},
    {name: "Overcrowded train"},
    {name: "Train stopped between stations"},
    {name: "Disabled train"},
    {name: "Medical emergency"},
    {name: "Normal conditions"}
  ]

  var stationsWithBetween = function () {
    var result = []
    for(var i = 0; i < stations.length; i++) {
      result.push(stations[i]);
      if(i != stations.length - 1) {
        var between = {
          name: stations[i].name + " ~ " + stations[i+1].name
        };
        result.push(between);
      }
    }
    return result;
  }

  // Get a list of all the events
  Template.body.helpers({
    stations: function() {
      if(Session.get("lineBeingViewed") == "red-line-southbound") {
        return stations;
      }
      else {
        return stations.reverse();
      }
    }
  });

  Template.station.helpers({
    events: function () {
      return Events.find({
        location: this.name,
        line: Session.get("lineBeingViewed"),
        expired: false
      });
    }
  });

  Template.createEvent.helpers({
    stations: stations,
    stationsWithBetween: stationsWithBetween,
    eventTypes: eventTypes
  })

  Template.createEvent.events({
    'click .submit': function() {
      var nameInput = $("#nameInput");
      var name = nameInput.val();

      var locationInput = $("#locationInput");
      var location = locationInput.val();

      var votes = 0;
      var line = Session.get("lineBeingViewed");

      newEvent = new Event(
				name,
        location,
        line,
        votes,
        new Date(),
        new Date()
			).save();
      console.log(Events.find({}).fetch());
    }
  });

  Template.event.events({
    // Upvote the current event
    "click .upvote": function () {
			if (!Session.get(this._id)) {
	      Events.update(this._id, {$inc: {votes: 1}});
				Events.update(this._id, {$set: {lastConfirmedAt: new Date()}});
				Session.setPersistent(this._id, "upvoted")
			} else { console.log("Cannot upvote again!") }
    }
  });

	Template.event.helpers({
		canUpvote: function() {
  		return Session.get(this._id) == null
		},
    positive: function(eventName) {
      return (eventName == "Normal conditions");
    }
	});

  Template.introModal.events({
    // Select a line to view
    "click .line-selector": function (e) {
      var selectedLine = $(e.target).attr("data-line");
      Session.set("lineBeingViewed", selectedLine);
      $("#intro-screen").hide();
      $("body, html").removeClass("noscroll");
    }
  });

  $(document).ready(function(){
    // Enable modal triggering with + button
    $('.modal-trigger').leanModal();

    // prevent scrolling while intro screen is shown
    $("body, html").addClass("noscroll");
  });
}

if (Meteor.isServer) {
	Meteor.startup(function () {
	});

	SyncedCron.add({
		name: 'Expire old events',
		schedule: function(parser) {
			// parser is a later.parse object
			return parser.text('every 1 minute');
		},
		job: function() {
			// Expire events older than 30 minutes
			Events.update(
				{lastConfirmedAt: {$lt: new Date(new Date()-30*60000)}},
				{$set: {expired: true}},
				{multi: true}
			);
		}
	});

	SyncedCron.start();
}
<commit_msg>Fixed dedup of events, now filtering by line<commit_after>Events = new Mongo.Collection("events");

function Event(name, location, line, votes, createdAt, lastConfirmedAt) {
	this.name = name;
	this.location = location;
  this.line = line;
	this.votes = votes;
  this.createdAt = createdAt;
	this.lastConfirmedAt = lastConfirmedAt;
}

Event.prototype = {
  save: function() {
		var docId = Events.findOne({
			name: this.name,
			location: this.location,
			line: this.line,
			expired: false
		});

		if (docId) { // Upvote
			if (Session.get(docId._id) == null) { // Can upvote
				// Avoid future upvotes
				Session.setPersistent(docId._id, "upvoted");
				return Events.update(docId._id, {$inc: {votes: 1}});
			}
		} else { // Create
			newEvent =  Events.insert({
	      name: this.name,
	      location: this.location,
        line: this.line,
	      votes: this.votes,
	      createdAt: this.createdAt,
				lastConfirmedAt: this.lastConfirmedAt,
				expired: false
	    });
			// Avoid user to upvote her own alert
			Session.setPersistent(newEvent, "created")
			return newEvent;
		}
  }
};

if (Meteor.isClient) {

  var stations = [
    {name: "Alewife"},
    {name: "Davis"},
    {name: "Porter Square"},
    {name: "Harvard Square"},
    {name: "Central Square"},
    {name: "Kendall"},
    {name: "Charles/MGH"},
    {name: "Park Street"},
    {name: "Downtown Crossing"},
    {name: "South Station"},
    {name: "Broadway"},
    {name: "Andrew"},
    {name: "JFK/UMass"},
    {name: "North Quincy"},
    {name: "Wollaston"},
    {name: "Quincy Center"},
    {name: "Quincy Adams"},
    {name: "Braintree"},
    {name: "Savin Hill"},
    {name: "Fields Corner"},
    {name: "Shawmut"},
    {name: "Ashmont"},
  ];

  var eventTypes = [
    {name: "Delayed train"},
    {name: "Train too crowded to board"},
    {name: "Overcrowded platform"},
    {name: "Overcrowded train"},
    {name: "Train stopped between stations"},
    {name: "Disabled train"},
    {name: "Medical emergency"},
    {name: "Normal conditions"}
  ]

  var stationsWithBetween = function () {
    var result = []
    for(var i = 0; i < stations.length; i++) {
      result.push(stations[i]);
      if(i != stations.length - 1) {
        var between = {
          name: stations[i].name + " ~ " + stations[i+1].name
        };
        result.push(between);
      }
    }
    return result;
  }

  // Get a list of all the events
  Template.body.helpers({
    stations: function() {
      if(Session.get("lineBeingViewed") == "red-line-southbound") {
        return stations;
      }
      else {
        return stations.reverse();
      }
    }
  });

  Template.station.helpers({
    events: function () {
      return Events.find({
        location: this.name,
        line: Session.get("lineBeingViewed"),
        expired: false
      });
    }
  });

  Template.createEvent.helpers({
    stations: stations,
    stationsWithBetween: stationsWithBetween,
    eventTypes: eventTypes
  })

  Template.createEvent.events({
    'click .submit': function() {
      var nameInput = $("#nameInput");
      var name = nameInput.val();

      var locationInput = $("#locationInput");
      var location = locationInput.val();

      var votes = 0;
      var line = Session.get("lineBeingViewed");

      newEvent = new Event(
				name,
        location,
        line,
        votes,
        new Date(),
        new Date()
			).save();
      console.log(Events.find({}).fetch());
    }
  });

  Template.event.events({
    // Upvote the current event
    "click .upvote": function () {
			if (!Session.get(this._id)) {
	      Events.update(this._id, {$inc: {votes: 1}});
				Events.update(this._id, {$set: {lastConfirmedAt: new Date()}});
				Session.setPersistent(this._id, "upvoted")
			} else { console.log("Cannot upvote again!") }
    }
  });

	Template.event.helpers({
		canUpvote: function() {
  		return Session.get(this._id) == null
		},
    positive: function(eventName) {
      return (eventName == "Normal conditions");
    }
	});

  Template.introModal.events({
    // Select a line to view
    "click .line-selector": function (e) {
      var selectedLine = $(e.target).attr("data-line");
      Session.set("lineBeingViewed", selectedLine);
      $("#intro-screen").hide();
      $("body, html").removeClass("noscroll");
    }
  });

  $(document).ready(function(){
    // Enable modal triggering with + button
    $('.modal-trigger').leanModal();

    // prevent scrolling while intro screen is shown
    $("body, html").addClass("noscroll");
  });
}

if (Meteor.isServer) {
	Meteor.startup(function () {
	});

	SyncedCron.add({
		name: 'Expire old events',
		schedule: function(parser) {
			// parser is a later.parse object
			return parser.text('every 1 minute');
		},
		job: function() {
			// Expire events older than 30 minutes
			Events.update(
				{lastConfirmedAt: {$lt: new Date(new Date()-30*60000)}},
				{$set: {expired: true}},
				{multi: true}
			);
		}
	});

	SyncedCron.start();
}
<|endoftext|>


<commit_before>/*
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

var iteratorCode = 0; // UID For Repeat Loops
/*
Block Spefifications:
Key to properties:
  title - Display name for block use these modifiers to add input:
    %s - string
    %e - entity - variable
    %n - number - float
  type - Tells DropBlox how to color blocks (see style.css)
  code - function that takes one array argument and returns a string contaning the JavaScript run for that block
*/
var blockSpecs = [
  {
    title: "Alert %s",
    type: "action",
    code: function(args) { return "alert(" + args[0] + ");"; }
  },
  {
    title: "Show copy box %s",
    type: "action",
    code: function(args) { return "prompt(\"Copy this text:\"," + args[0] + ");"; }
  },
  {
    title: "Define variable %e",
    type: "variable",
    code: function(args) { return "var " + args[0] + ";"; }
  },
  {
    title: "Set %e to %s",
    type: "variable",
    code: function(args) { return args[0] + "=" + args[1] + ";"; }
  },
  {
    title: "Repeat %n Times",
    type: "control",
    code: function(args) {
      i++;
      return "for(var i" + iteratorCode + "=0;i" + iteratorCode + "<" + args[0] + ";i" + iteratorCode + "++){";
    }
  },
  {
    title: "End",
    type: "control",
    code: function(args) { return "}"; }
  }
]
/*
  This function parses through the blocks and returns the entire JS needed to run the current project.
*/
function getJS() {
  var blocks = document.getElementById("script").children; // Get all of the "block" elements
  var code = ""; // A buffer to store the JS code
  for (var i = 0; i < blocks.length; i++) { // Loop through the "block" elements
    var block = blocks[i];
    blockSpec = blockSpecs[block.getAttribute("data-block-id")]; // Get the blockSpec for the current block
    var blockSpecTitle = blockSpec.title;
    var isField = false;
    var buffer = "";
    var parts = []; // Place to hold all of the block parts
    for (var c = 0; c < blockSpecTitle.length; c++) {
      var char = blockSpecTitle.charAt(c);
      if (isField) { // Check the field type
        if (char === "s") {
          parts.push({
            type: "string"
          })
        }else if (char === "e") {
          parts.push({
            type: "entity"
          })
        }else if (char === "n") {
          parts.push({
            type: "number"
          })
        }
        isField = false;
      }else{
        if (char === "%") { // We got ourselves a field let's handle it
          parts.push({
            type: "title",
            value: buffer
          })
          buffer = ""
          isField = true;
        }else{ // Add to the buffer
          buffer += char;
        }
      }
    }
    parts.push({ // Add the final title (probably could get rid of this)
      type: "title",
      value: buffer
    })
    var args = []; // Place to hold user provided arguments
    for (var b = 0; b < parts.length; b++) {
      var part = parts[b];
      if (part.type === "string") {
        args.push("\"" + block.children[b].value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\[\[(.*)\]\]/, function(m, v) {
          // This function is cool, it allows you to embed variables in string inputs :)
          return "\"+ent_" + v.replace(/[^a-zA-Z_$\-]/g, "___Unknown___") + "+\"";
        }) + "\"")
      }else if (part.type === "entity") {
        args.push("ent_" + block.children[b].value.replace(/[^a-zA-Z_$\-]/g, "___Unknown___")) // Entity inputs with added saftey feature
      }else if (part.type === "number") {
        args.push(parseFloat(block.children[b].value))
      }
    }
    code += blockSpec.code(args);
  }
  return code;
}
for (var i = 0; i < blockSpecs.length; i++) { // Loop through blockSpecs and add blocks to library
  var blockSpecTitle = blockSpecs[i].title;
  var isField = false;
  var buffer = "";
  var parts = [];
  for (var c = 0; c < blockSpecTitle.length; c++) {
    var char = blockSpecTitle.charAt(c);
    if (isField) { // Check the field type
      if (char === "s") {
        parts.push({
          type: "string"
        })
      }else if (char === "e") {
        parts.push({
          type: "entity"
        })
      }else if (char === "n") {
        parts.push({
          type: "number"
        })
      }
      isField = false;
    }else{
      if (char === "%") { // We got ourselves a field let's handle it
        parts.push({
          type: "title",
          value: buffer
        })
        buffer = ""
        isField = true;
      }else{ // Add to the buffer
        buffer += char;
      }
    }
  }
  parts.push({ // Add the final title
    type: "title",
    value: buffer
  })
  var blockDiv = document.createElement("div"); // Create <div> representing block
  blockDiv.setAttribute("data-block-id", i); // Set block-id (this is important when parsing)
  blockDiv.className = "block " + blockSpecs[i].type; // Set class
  for (var p = 0; p < parts.length; p++) { // Add ALL the fields (insert "ALL THE" meme here)
    var part = parts[p];
    if (part.type === "title") {
      var title = document.createElement("span");
      title.textContent = part.value
      blockDiv.appendChild(title)
    }else if (part.type === "string") {
      var input = document.createElement("input");
      input.className = "string";
      blockDiv.appendChild(input);
    }else if (part.type === "entity") {
      var input = document.createElement("input");
      input.className = "entity";
      blockDiv.appendChild(input);
    }else if (part.type === "number") {
      var input = document.createElement("input");
      input.className = "number";
      blockDiv.appendChild(input);
    }
  }
  document.getElementById("library").appendChild(blockDiv); // Append finished block to the library
}
document.getElementById("run").addEventListener("click", function(){
  // Run user's code
  var code = getJS();
  try {
    // DropBlox isn't perfect, the user's code could error so let's handle that
    eval(code);
  } catch (err) {
    alert(err.message);
  }
});
document.getElementById("getJS").addEventListener("click", function(){
  // Give the user their unreadable code. :P
  prompt("The JavaScript for this project is:", getJS());
});
document.getElementById("about").addEventListener("click", function(){
  // Take the user to this repo
  location.assign("https://github.com/Iwotastic/DropBlox")
});
var dragger = dragula({ // Initialize Dragula (bevacqua/dragula)
  containers: [document.getElementById("library"), document.getElementById("script")],
  copy: function (el, source) {
    return source === document.getElementById("library")
  },
  accepts: function (el, target) {
    return target !== document.getElementById("library")
  },
  removeOnSpill: true
});
<commit_msg>IF Blox!<commit_after>/*
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

var iteratorCode = 0; // UID For Repeat Loops
/*
Block Spefifications:
Key to properties:
  title - Display name for block use these modifiers to add input:
    %s - string
    %e - entity - variable
    %n - number - float
  type - Tells DropBlox how to color blocks (see style.css)
  code - function that takes one array argument and returns a string contaning the JavaScript run for that block
*/
var blockSpecs = [
  {
    title: "Alert %s",
    type: "action",
    code: function(args) { return "alert(" + args[0] + ");"; }
  },
  {
    title: "Show Copy Box %s",
    type: "action",
    code: function(args) { return "prompt(\"Copy this text:\"," + args[0] + ");"; }
  },
  {
    title: "Define Variable %e",
    type: "variable",
    code: function(args) { return "var " + args[0] + ";"; }
  },
  {
    title: "Set %e To %s",
    type: "variable",
    code: function(args) { return args[0] + "=" + args[1] + ";"; }
  },
  {
    title: "Repeat %n Times",
    type: "control",
    code: function(args) {
      i++;
      return "for(var i" + iteratorCode + "=0;i" + iteratorCode + "<" + args[0] + ";i" + iteratorCode + "++){";
    }
  },
  {
    title: "If %s Equals %s Then",
    type: "control",
    code: function(args) {
      i++;
      return "if(" + args[0] + " == " + args[1] + "){";
    }
  },
  {
    title: "End",
    type: "control",
    code: function(args) { return "}"; }
  }
]
/*
  This function parses through the blocks and returns the entire JS needed to run the current project.
*/
function getJS() {
  var blocks = document.getElementById("script").children; // Get all of the "block" elements
  var code = ""; // A buffer to store the JS code
  for (var i = 0; i < blocks.length; i++) { // Loop through the "block" elements
    var block = blocks[i];
    blockSpec = blockSpecs[block.getAttribute("data-block-id")]; // Get the blockSpec for the current block
    var blockSpecTitle = blockSpec.title;
    var isField = false;
    var buffer = "";
    var parts = []; // Place to hold all of the block parts
    for (var c = 0; c < blockSpecTitle.length; c++) {
      var char = blockSpecTitle.charAt(c);
      if (isField) { // Check the field type
        if (char === "s") {
          parts.push({
            type: "string"
          })
        }else if (char === "e") {
          parts.push({
            type: "entity"
          })
        }else if (char === "n") {
          parts.push({
            type: "number"
          })
        }
        isField = false;
      }else{
        if (char === "%") { // We got ourselves a field let's handle it
          parts.push({
            type: "title",
            value: buffer
          })
          buffer = ""
          isField = true;
        }else{ // Add to the buffer
          buffer += char;
        }
      }
    }
    parts.push({ // Add the final title (probably could get rid of this)
      type: "title",
      value: buffer
    })
    var args = []; // Place to hold user provided arguments
    for (var b = 0; b < parts.length; b++) {
      var part = parts[b];
      if (part.type === "string") {
        args.push("\"" + block.children[b].value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\[\[(.*)\]\]/, function(m, v) {
          // This function is cool, it allows you to embed variables in string inputs :)
          return "\"+ent_" + v.replace(/[^a-zA-Z_$\-]/g, "___Unknown___") + "+\"";
        }) + "\"")
      }else if (part.type === "entity") {
        args.push("ent_" + block.children[b].value.replace(/[^a-zA-Z_$\-]/g, "___Unknown___")) // Entity inputs with added saftey feature
      }else if (part.type === "number") {
        args.push(parseFloat(block.children[b].value))
      }
    }
    code += blockSpec.code(args);
  }
  return code;
}
for (var i = 0; i < blockSpecs.length; i++) { // Loop through blockSpecs and add blocks to library
  var blockSpecTitle = blockSpecs[i].title;
  var isField = false;
  var buffer = "";
  var parts = [];
  for (var c = 0; c < blockSpecTitle.length; c++) {
    var char = blockSpecTitle.charAt(c);
    if (isField) { // Check the field type
      if (char === "s") {
        parts.push({
          type: "string"
        })
      }else if (char === "e") {
        parts.push({
          type: "entity"
        })
      }else if (char === "n") {
        parts.push({
          type: "number"
        })
      }
      isField = false;
    }else{
      if (char === "%") { // We got ourselves a field let's handle it
        parts.push({
          type: "title",
          value: buffer
        })
        buffer = ""
        isField = true;
      }else{ // Add to the buffer
        buffer += char;
      }
    }
  }
  parts.push({ // Add the final title
    type: "title",
    value: buffer
  })
  var blockDiv = document.createElement("div"); // Create <div> representing block
  blockDiv.setAttribute("data-block-id", i); // Set block-id (this is important when parsing)
  blockDiv.className = "block " + blockSpecs[i].type; // Set class
  for (var p = 0; p < parts.length; p++) { // Add ALL the fields (insert "ALL THE" meme here)
    var part = parts[p];
    if (part.type === "title") {
      var title = document.createElement("span");
      title.textContent = part.value
      blockDiv.appendChild(title)
    }else if (part.type === "string") {
      var input = document.createElement("input");
      input.className = "string";
      blockDiv.appendChild(input);
    }else if (part.type === "entity") {
      var input = document.createElement("input");
      input.className = "entity";
      blockDiv.appendChild(input);
    }else if (part.type === "number") {
      var input = document.createElement("input");
      input.className = "number";
      blockDiv.appendChild(input);
    }
  }
  document.getElementById("library").appendChild(blockDiv); // Append finished block to the library
}
document.getElementById("run").addEventListener("click", function(){
  // Run user's code
  var code = getJS();
  try {
    // DropBlox isn't perfect, the user's code could error so let's handle that
    eval(code);
  } catch (err) {
    alert(err.message);
  }
});
document.getElementById("getJS").addEventListener("click", function(){
  // Give the user their unreadable code. :P
  prompt("The JavaScript for this project is:", getJS());
});
document.getElementById("about").addEventListener("click", function(){
  // Take the user to this repo
  location.assign("https://github.com/Iwotastic/DropBlox")
});
var dragger = dragula({ // Initialize Dragula (bevacqua/dragula)
  containers: [document.getElementById("library"), document.getElementById("script")],
  copy: function (el, source) {
    return source === document.getElementById("library")
  },
  accepts: function (el, target) {
    return target !== document.getElementById("library")
  },
  removeOnSpill: true
});
<|endoftext|>


<commit_before>import * as Reflux from 'reflux'
import * as _ from 'lodash'
import mapActions from '../actions/mapActions'
import userStore from './userStore'
import {PlayableMap, LocalMap} from '../models/map'

import * as classicMap from '../data/maps/classic.json'
import * as northfieldMap from '../data/maps/northfield.json'

let mapStore = Reflux.createStore({
	listenables: mapActions,

	init() {
		this.maps = [];

		this.localMaps = [
			new LocalMap(classicMap),
			new LocalMap(northfieldMap),
		];

		this.listenTo(userStore, this._updateDataFromParse, this._updateDataFromParse);
	},

	_updateDataFromParse() {
		let allMaps = new Parse.Query(PlayableMap)
		allMaps.find()
			.then(results => {
				this.maps = _.uniq(this.localMaps.concat(results), (map) => map.id)
				console.log('maps', this.maps)
				this.trigger(this.maps)
			})
	},

	getInitialState() {
		return this.maps;
	},

	updateMapList() {
		console.log('updateMapList')
		this._updateDataFromParse()
	},

	createMap(options) {
		let map = new PlayableMap()
		map.set('name', options.name || 'Untitled Map')
		map.set('players', options.players || 2)
		map.set('width', options.width || 'auto')
		map.set('height', options.height || 'auto')
		map.set('countries', options.countries || [])
		map.set('spaces', options.spaces || [])

		map.save()
			.then(this._updateDataFromParse)
	},

	updateMap(options) {
		let map = _.find(this.maps, {id: options.mapId})
		console.log(map, options.mapId)

		map.set('name', options.name || map.get('name'))
		map.set('players', options.players || map.get('players'))
		map.set('width', options.width || map.get('width'))
		map.set('height', options.height || map.get('height'))
		map.set('countries', options.countries || map.get('countries'))
		map.set('spaces', options.spaces || map.get('spaces'))
		console.log(options, map)

		map.save()
			.then(this._updateDataFromParse)
	},

	destroyMap(mapId) {
		let mapToDestroy = _.find(this.maps, {id: mapId})
		mapToDestroy.destroy()
			.then(this._updateDataFromParse)
	},
})

export default mapStore
<commit_msg>Look inside of parsemaps for the map<commit_after>import * as Reflux from 'reflux'
import * as _ from 'lodash'
import mapActions from '../actions/mapActions'
import userStore from './userStore'
import {PlayableMap, LocalMap} from '../models/map'

import * as classicMap from '../data/maps/classic.json'
import * as northfieldMap from '../data/maps/northfield.json'

let mapStore = Reflux.createStore({
	listenables: mapActions,

	init() {
		this.maps = [];

		this.parseMaps = [];
		this.localMaps = [
			new LocalMap(classicMap),
			new LocalMap(northfieldMap),
		];

		this.listenTo(userStore, this._updateDataFromParse, this._updateDataFromParse);
	},

	_updateDataFromParse() {
		let allMaps = new Parse.Query(PlayableMap)
		allMaps.find()
			.then(results => {
				this.parseMaps = results;
				this.maps = _.uniq(this.localMaps.concat(results), (map) => map.id)
				console.log('maps', this.maps)
				this.trigger(this.maps)
			})
	},

	getInitialState() {
		return this.maps;
	},

	updateMapList() {
		console.log('updateMapList')
		this._updateDataFromParse()
	},

	createMap(options) {
		let map = new PlayableMap()
		map.set('name', options.name || 'Untitled Map')
		map.set('players', options.players || 2)
		map.set('width', options.width || 'auto')
		map.set('height', options.height || 'auto')
		map.set('countries', options.countries || [])
		map.set('spaces', options.spaces || [])

		map.save()
			.then(this._updateDataFromParse)
	},

	updateMap(options) {
		let map = _.find(this.parseMaps, {id: options.mapId})
		console.log(map, options.mapId)

		map.set('name', options.name || map.get('name'))
		map.set('players', options.players || map.get('players'))
		map.set('width', options.width || map.get('width'))
		map.set('height', options.height || map.get('height'))
		map.set('countries', options.countries || map.get('countries'))
		map.set('spaces', options.spaces || map.get('spaces'))
		console.log(options, map)

		map.save()
			.then(this._updateDataFromParse)
	},

	destroyMap(mapId) {
		let mapToDestroy = _.find(this.maps, {id: mapId})
		mapToDestroy.destroy()
			.then(this._updateDataFromParse)
	},
})

export default mapStore
<|endoftext|>


<commit_before>module.exports = {
  "Details tag" : function (browser) {
    browser
      .deleteCookies()
      .url(browser.launch_url + '/checker')
      .assert.containsText('h123', 'Your problem', 'page has correct title')
      .assert.elementPresent('details', 'details tag exists')
      .assert.hidden('details > div', 'details content not visible')
      .execute(function () {
        $("details:first").find('summary').click().trigger('click');
      })
      .assert.visible('details > *', 'details content is visible')
      .end();
  }
};
<commit_msg>Removed test test failure.<commit_after>module.exports = {
  "Details tag" : function (browser) {
    browser
      .deleteCookies()
      .url(browser.launch_url + '/checker')
      .assert.containsText('h1', 'Your problem', 'page has correct title')
      .assert.elementPresent('details', 'details tag exists')
      .assert.hidden('details > div', 'details content not visible')
      .execute(function () {
        $("details:first").find('summary').click().trigger('click');
      })
      .assert.visible('details > *', 'details content is visible')
      .end();
  }
};
<|endoftext|>


<commit_before>import React from 'react';

const Fork = (props) => {
  return (
    <div className="btn-fork">
    </div>
  );
};
export default Fork;
<commit_msg>Make Fork its own component<commit_after>import React from 'react';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import actions from '../actions/index.js';
import { forkRecipe } from '../utils/utils';

const Fork = (props) => {
  let forkComponent;
  if (props.userID) {
    forkComponent = (<button className="btn-fork" onClick={ props.onForkClick.bind(null, props.recipeID, props.userID) }>
      Fork
    </button>);
  } else {
    forkComponent = (<button className="btn-fork" disabled>Fork</button>);
  }
  return forkComponent;
};

const mapStateToProps = (state) => {
  return {};
};

const mapDispatchToProps = (dispatch) => {
  return {
    onForkClick: (recipeID, userID) => {
      forkRecipe(recipeID, userID, (newRecipe) => {
        dispatch(actions.forkRecipe(newRecipe));
        dispatch(push(`/recipe/${newRecipe.id}`));
      });
    },
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Fork);
<|endoftext|>


<commit_before>import * as React from 'react'
import * as M from '@material-ui/core'

import Bar from 'website/components/Bar'
import ChevronLink from 'website/components/ChevronLink'
import Overlay1Full from 'website/components/Backgrounds/Overlay1Full'
import Overlay2 from 'website/components/Backgrounds/Overlay2'
import Screenshots from 'website/components/Screenshots'

const useStyles = M.makeStyles((t) => ({
  root: {
    paddingTop: t.spacing(9),
    position: 'relative',
  },
  container: {
    display: 'grid',
    paddingBottom: t.spacing(5),
    position: 'relative',
    [t.breakpoints.up('md')]: {
      gridColumnGap: t.spacing(10),
      gridTemplateColumns: '1fr 1fr',
      gridTemplateAreas: '"text carousel"',
    },
    [t.breakpoints.up('lg')]: {
      gridTemplateColumns: '1fr 640px',
    },
    [t.breakpoints.down('sm')]: {
      gridRowGap: t.spacing(8),
      gridTemplateRows: 'auto auto',
      gridTemplateAreas: `
        "text"
        "carousel"
      `,
    },
  },
  text: {
    gridArea: 'text',
  },
  textInner: {
    [t.breakpoints.up('md')]: {
      maxWidth: 400,
    },
  },
  carousel: {
    gridArea: 'carousel',
    [t.breakpoints.up('md')]: {
      paddingTop: t.spacing(6),
    },
  },
}))

export default function Showcase() {
  const classes = useStyles()
  return (

      <Overlay2 />
      <Overlay1Full top={-80} />
      <M.Container maxWidth="lg" className={classes.container}>

            <Bar color="primary" />
            <M.Box mt={5}>
              <M.Typography variant="h1" color="textPrimary">
                Experiment faster with versioned data sets
              </M.Typography>
            </M.Box>
            <M.Box mt={4}>
              <M.Typography variant="body1" color="textSecondary">
                Quilt gives you a Python API, web catalog, and backend stack to manage
                data sets in S3.
              </M.Typography>
            </M.Box>
            <M.Box mt={2}>
              <M.Typography variant="body1" color="textSecondary">
                Share, understand, discover, and model data at scale.
              </M.Typography>
            </M.Box>
            <M.Box mt={5}>
              <M.Button
                variant="contained"
                color="primary"
                href="https://www.meetingbird.com/m/S19vxyVOH"
              >
                Book demo
              </M.Button>
              <M.Box display="inline-block" ml={2} />
              <M.Button
                variant="contained"
                color="secondary"
                href="https://open.quiltdata.com"
              >
                Explore open data
              </M.Button>
            </M.Box>
            <M.Box mt={5}>
              <ChevronLink href="#pricing">Try now</ChevronLink>
            </M.Box>
            <M.Box mt={1}>
              <ChevronLink href="#get-notified">Stay informed about Quilt</ChevronLink>
            </M.Box>

        <Screenshots className={classes.carousel} />
      </M.Container>

  )
}
<commit_msg>revise landing messaging (#1455)<commit_after>import * as React from 'react'
import * as M from '@material-ui/core'

import Bar from 'website/components/Bar'
import ChevronLink from 'website/components/ChevronLink'
import Overlay1Full from 'website/components/Backgrounds/Overlay1Full'
import Overlay2 from 'website/components/Backgrounds/Overlay2'
import Screenshots from 'website/components/Screenshots'

const useStyles = M.makeStyles((t) => ({
  root: {
    paddingTop: t.spacing(9),
    position: 'relative',
  },
  container: {
    display: 'grid',
    paddingBottom: t.spacing(5),
    position: 'relative',
    [t.breakpoints.up('md')]: {
      gridColumnGap: t.spacing(10),
      gridTemplateColumns: '1fr 1fr',
      gridTemplateAreas: '"text carousel"',
    },
    [t.breakpoints.up('lg')]: {
      gridTemplateColumns: '1fr 640px',
    },
    [t.breakpoints.down('sm')]: {
      gridRowGap: t.spacing(8),
      gridTemplateRows: 'auto auto',
      gridTemplateAreas: `
        "text"
        "carousel"
      `,
    },
  },
  text: {
    gridArea: 'text',
  },
  textInner: {
    [t.breakpoints.up('md')]: {
      maxWidth: 400,
    },
  },
  carousel: {
    gridArea: 'carousel',
    [t.breakpoints.up('md')]: {
      paddingTop: t.spacing(6),
    },
  },
}))

export default function Showcase() {
  const classes = useStyles()
  return (

      <Overlay2 />
      <Overlay1Full top={-80} />
      <M.Container maxWidth="lg" className={classes.container}>

            <Bar color="primary" />
            <M.Box mt={5}>
              <M.Typography variant="h1" color="textPrimary">
                Experiment faster by managing data like code
              </M.Typography>
            </M.Box>
            <M.Box mt={4}>
              <M.Typography variant="body1" color="textSecondary">
                Most teams are already on top of their code and containers, but their data
                lags behind.
              </M.Typography>
            </M.Box>
            <M.Box mt={4}>
              <M.Typography variant="body1" color="textSecondary">
                Quilt transforms data into versioned, reusable datasets so that teams in
                machine learning and computational biology can iterate faster, reduce
                errors, and deploy smarter models.
              </M.Typography>
            </M.Box>
            <M.Box mt={4}>
              <M.Typography variant="body1" color="textSecondary">
                Quilt consists of a Python API, web catalog, and backend stack to manage
                data sets in S3.
              </M.Typography>
            </M.Box>
            <M.Box mt={5}>
              <M.Button
                variant="contained"
                color="primary"
                href="https://www.meetingbird.com/m/S19vxyVOH"
              >
                Book demo
              </M.Button>
              <M.Box display="inline-block" ml={2} />
              <M.Button
                variant="contained"
                color="secondary"
                href="https://open.quiltdata.com"
              >
                Explore data with Quilt
              </M.Button>
            </M.Box>
            <M.Box mt={5}>
              <ChevronLink href="https://docs.quiltdata.com/installation">
                Create your first dataset in Python
              </ChevronLink>
            </M.Box>
            <M.Box mt={1}>
              <ChevronLink href="#pricing">Install the Quilt portal for AWS</ChevronLink>
            </M.Box>
            <M.Box mt={1}>
              <ChevronLink href="#get-notified">Stay informed about Quilt</ChevronLink>
            </M.Box>

        <Screenshots className={classes.carousel} />
      </M.Container>

  )
}
<|endoftext|>


<commit_before>// @flow
import type {CurrentGameActions} from './actions/current-game'
import type {EntryActions} from './actions/ui/entry'
import type {GameState} from './reducer/current-game'
import type {EntryState} from './reducer/ui/entry'
import type {SettingsState} from './reducer/ui/settings'

export type PlayerMap<T> = {[playerID: string]: T}

export type T = (translate: string, opt: ?any) => string

export type DropdownSource<T> = {
  value: T,
  label: string,
  disabled?: boolean
}

export type RootState = {
  currentGame: GameState,
  ui: {
    entry: EntryState,
    settings: SettingsState
  }
}

export type Actions =
  | CurrentGameActions
  | EntryActions

export type Dispatch = (action: Actions) => void
<commit_msg>Fix incorrect dispatch type<commit_after>// @flow
import type {CurrentGameActions} from './actions/current-game'
import type {EntryActions} from './actions/ui/entry'
import type {GameState} from './reducer/current-game'
import type {EntryState} from './reducer/ui/entry'
import type {SettingsState} from './reducer/ui/settings'

export type PlayerMap<T> = {[playerID: string]: T}

export type T = (translate: string, opt: ?any) => string

export type DropdownSource<T> = {
  value: T,
  label: string,
  disabled?: boolean
}

export type RootState = {
  currentGame: GameState,
  ui: {
    entry: EntryState,
    settings: SettingsState
  }
}

export type Actions =
  | CurrentGameActions
  | EntryActions
  | SettingsActions

export type Dispatch = (action: Actions) => void
<|endoftext|>


<commit_before><commit_msg>fixed legend color<commit_after><|endoftext|>


<commit_before>const Plugin = require('../Plugin')

module.exports = class AwsS3 extends Plugin {
  constructor (core, opts) {
    super(core, opts)
    this.type = 'uploader'
    this.id = 'AwsS3'
    this.title = 'AWS S3'

    const defaultOptions = {
    }

    this.opts = Object.assign({}, defaultOptions, opts)

    this.prepareUpload = this.prepareUpload.bind(this)
  }

  getFile (id) {
    return this.core.getState().files[id]
  }

  getCredentials (fileID) {
    const file = this.getFile(fileID)

    const filename = encodeURIComponent(file.name)
    const type = encodeURIComponent(`${file.type.general}/${file.type.specific}`)
    return fetch(`${this.opts.host}/s3/credentials?filename=${filename}&type=${type}`, {
      method: 'get',
      headers: { accept: 'application/json' }
    }).then((response) => response.json())
  }

  prepareUpload (fileIDs) {
    return Promise.all(
      fileIDs.map((id) => this.getCredentials(id))
    ).then((credentials) => {
      const updatedFiles = {}
      fileIDs.forEach((id, index) => {
        const file = this.getFile(id)
        const { endpoint, params } = credentials[index]
        const updatedFile = Object.assign({}, file, {
          meta: Object.assign({}, file.meta, params),
          multipart: {
            endpoint,
            fieldName: 'file'
          }
        })

        updatedFiles[id] = updatedFile
      })

      this.core.setState({
        files: Object.assign({}, this.core.getState().files, updatedFiles)
      })
    })
  }

  install () {
    this.core.addPreProcessor(this.prepareUpload)
  }

  uninstall () {
    this.core.removePreProcessor(this.prepareUpload)
  }
}
<commit_msg>s3: Configure Multipart plugin correctly :tada:<commit_after>const Plugin = require('../Plugin')

module.exports = class AwsS3 extends Plugin {
  constructor (core, opts) {
    super(core, opts)
    this.type = 'uploader'
    this.id = 'AwsS3'
    this.title = 'AWS S3'

    const defaultOptions = {
    }

    this.opts = Object.assign({}, defaultOptions, opts)

    this.prepareUpload = this.prepareUpload.bind(this)
  }

  getFile (id) {
    return this.core.getState().files[id]
  }

  getCredentials (fileID) {
    const file = this.getFile(fileID)

    const filename = encodeURIComponent(file.name)
    const type = encodeURIComponent(`${file.type.general}/${file.type.specific}`)
    return fetch(`${this.opts.host}/s3/credentials?filename=${filename}&type=${type}`, {
      method: 'get',
      headers: { accept: 'application/json' }
    }).then((response) => response.json())
  }

  prepareUpload (fileIDs) {
    return Promise.all(
      fileIDs.map((id) => this.getCredentials(id))
    ).then((credentials) => {
      const updatedFiles = {}
      fileIDs.forEach((id, index) => {
        const file = this.getFile(id)
        const { endpoint, params } = credentials[index]
        const updatedFile = Object.assign({}, file, {
          // TODO maybe move this into a parameter in the `multipart` object.
          // `meta` may contain other important data, but S3 will reject the request
          // if it contains any parameters it does not know.
          // Perhaps a `fieldsOverride` option in the Multipart plugin, idk.
          meta: params,
          multipart: {
            endpoint,
            fieldName: 'file',
            getUploadUrl (xhr) {
              const locationEl = xhr.responseXML.querySelector('Location')
              return locationEl.textContent
            }
          }
        })

        updatedFiles[id] = updatedFile
      })

      this.core.setState({
        files: Object.assign({}, this.core.getState().files, updatedFiles)
      })
    })
  }

  install () {
    this.core.addPreProcessor(this.prepareUpload)
  }

  uninstall () {
    this.core.removePreProcessor(this.prepareUpload)
  }
}
<|endoftext|>


<commit_before>/* Cached Variables *******************************************************************************/
var context = sessionStorage.getItem('context');
var rowThumbnails = document.querySelector('.row-thumbnails');

/* Initialization *********************************************************************************/
rowThumbnails.addEventListener("click", moeRedirect, false);

function moeRedirect(event) {

  var target = event.target;

  var notImage = target.className !== 'thumbnail-image';
  if(notImage) return;

  var pageId = target.getAttribute('data-page-id');

  window.location.href = context + '/page/' + pageId;

}

var thumbnails = window.document.querySelectorAll('.thumbnail');
var tallestThumbnailSize = 0;

thumbnails.forEach(function(value, key, listObj, argument) {
	var offsetHeight = listObj[key].offsetHeight;
	if(offsetHeight > tallestThumbnailSize) tallestThumbnailSize = offsetHeight;
});

thumbnails.forEach(function(value, key, listObj, argument) {
	listObj[key].setAttribute('style','min-height:' + tallestThumbnailSize + 'px');
});

//After thumbnail processing, remove the page-loading blocker
document.querySelector('body').classList.remove('content-loading');

<commit_msg>Change nodelist.foreach to a normal for loop<commit_after>/* Cached Variables *******************************************************************************/
var context = sessionStorage.getItem('context');
var rowThumbnails = document.querySelector('.row-thumbnails');

/* Initialization *********************************************************************************/
rowThumbnails.addEventListener("click", moeRedirect, false);

function moeRedirect(event) {

  var target = event.target;

  var notImage = target.className !== 'thumbnail-image';
  if(notImage) return;

  var pageId = target.getAttribute('data-page-id');

  window.location.href = context + '/page/' + pageId;

}

var thumbnails = window.document.querySelectorAll('.thumbnail');
var tallestThumbnailSize = 0;

for (var i = 0; i < thumbnails.length; i++) {
  var offsetHeight = thumbnails[i].offsetHeight;
  if(offsetHeight > tallestThumbnailSize) tallestThumbnailSize = offsetHeight;
};

for (var i = 0; i < thumbnails.length; i++) {
  thumbnails[i].setAttribute('style','min-height:' + tallestThumbnailSize + 'px');
};

//After thumbnail processing, remove the page-loading blocker
document.querySelector('body').classList.remove('content-loading');<|endoftext|>


<commit_before>/* This module provides an interface into whatever mechanism we might
 * want to use to cache and retrieve bundles.
 */

//var request = require('superagent');
var _ = require('lodash');
var path = require('path');
var fs = require('fs');

// To keep things simple (albeit inefficient), we will store locally cached bundles
// in a JSON file. TODO make this more efficient
var cacheFile = path.join('cache', 'bundles.json');

/* Cache objects provide a uniform interface to access and store data from and to
 * any of the kinds of media we may want to use to cache bundles.
 * A Cache object's read method accepts:
 *   1. A description of the source to read from (typically a URL)
 *   2. A callback for handling the read data
 * The write method accepts:
 *   1. A description of the data to write
 *   2. A callback for handling the result of writing data
 * In both cases, callbacks should be passed
 *   1. An error object/description if one occurred
 *   2. Any result data
 * Note that the `from` and `data` arguments to `read` and `write` respectively
 * can be any kind of value- a string, object, etc. and it is up to the
 * implementations of the reader and writer supplied to the Cache object
 * to determine how to interpret them and provide data to the callbacks.
 */
var Cache = function () {
  this.initialize.apply(this, arguments);
};

_.extend(Cache.prototype, {
  initialize: function (reader, writer) {
    this.read = function (from, callback) {
      reader(from, callback);
    };

    this.write = function (data, callback) {
      writer(data, callback);
    };
  }
});

/* Each retriever and storer function provide closures over any configuration
 * data they may need to retain. This allows us to simply export from this
 * module configuration functions that close over whatever configuration data
 * may be required.
 */

function localRetriever() {
  return function (url, callback) {
    console.log('Reading bundle for URL ' + url);
    fs.readFile(cacheFile, function (err, content) {
      if (err) {
        console.log('Failed to read cache file.');
        callback(err, null);
      } else {
        console.log('Successfully read cache file.');
        var bundle = JSON.parse(content)[url];
        if (typeof bundle === 'undefined' || !bundle) {
          // We don't need the ID for anything in the local case, so default to 0.
          callback(null, {bundleFound: false, bundleID: 0});
        } else {
          callback(null, {bundleFound: true, bundle: bundle});
        }
      }
    });
  };
}

function localStorer() {
  return function (data, callback) {
    console.log('Writing bundle for ' + data.url);
    fs.readFile(cacheFile, function (err, content) {
      if (err) {
        console.log('Failed to read cache file.');
        callback(err);
      } else {
        console.log('Read cache file.');
        var cacheData = JSON.parse(content);
        cacheData[data.url] = data.bundle;
        fs.writeFile(cacheFile, JSON.stringify(cacheData), function (err, data) {
          if (err) {
            console.log('Failed to write new cache data.');
            callback(err);
          } else {
            console.log('Successfuly wrote new cache data.');
            callback(null);
          }
        });
      }
    });
  };
}

function httpRetriever(addr) {
  return function (url, callback) {
    console.log('Requesting URL ' + url + ' from freenet at ' + addr);
    callback(null, 'Woah');
  };
}

function httpStorer(addr) {
  return function (data, callback) {
    console.log('Writing to freenet at ' + addr);
    console.log(data);
    callback(null, 'Dude');
  };
}

module.exports = {
  local: function () {
    // Initialize the cache file.
    try {
      var fd = fs.openSync(cacheFile, 'wx');
      fs.writeSync(fd, new Buffer('{}'), 0, 2, 0);
      console.log('Created new cache file.');
    } catch (err) {}
    return new Cache(localRetriever(), localStorer());
  },

  http: function (addr) {
    return new Cache(httpRetriever(addr), httpStorer(addr));
  }
  // etc.
};
<commit_msg>Wrote cache interface functions for interacting with the cache server and transport server<commit_after>/* This module provides an interface into whatever mechanism we might
 * want to use to cache and retrieve bundles.
 */

var request = require('superagent');
var _ = require('lodash');
var path = require('path');
var fs = require('fs');
var urllib = require('url');

// To keep things simple (albeit inefficient), we will store locally cached bundles
// in a JSON file. TODO make this more efficient
var cacheFile = path.join('cache', 'bundles.json');

/* Cache objects provide a uniform interface to access and store data from and to
 * any of the kinds of media we may want to use to cache bundles.
 * A Cache object's read method accepts:
 *   1. A description of the source to read from (typically a URL)
 *   2. A callback for handling the read data
 * The write method accepts:
 *   1. A description of the data to write
 *   2. A callback for handling the result of writing data
 * In both cases, callbacks should be passed
 *   1. An error object/description if one occurred
 *   2. Any result data
 * Note that the `from` and `data` arguments to `read` and `write` respectively
 * can be any kind of value- a string, object, etc. and it is up to the
 * implementations of the reader and writer supplied to the Cache object
 * to determine how to interpret them and provide data to the callbacks.
 */
var Cache = function () {
  this.initialize.apply(this, arguments);
};

_.extend(Cache.prototype, {
  initialize: function (reader, writer) {
    this.read = function (from, callback) {
      reader(from, callback);
    };

    this.write = function (data, callback) {
      writer(data, callback);
    };
  }
});

/* Each retriever and storer function provide closures over any configuration
 * data they may need to retain. This allows us to simply export from this
 * module configuration functions that close over whatever configuration data
 * may be required.
 */

function localRetriever() {
  return function (url, callback) {
    fs.readFile(cacheFile, function (err, content) {
      if (err) {
        callback(err, null);
      } else {
        var bundle = JSON.parse(content)[url];
        if (typeof bundle === 'undefined' || !bundle) {
          // We don't need the ID for anything in the local case, so default to 0.
          callback(null, {bundleFound: false, bundleID: 0});
        } else {
          callback(null, {bundleFound: true, bundle: bundle});
        }
      }
    });
  };
}

function localStorer() {
  return function (data, callback) {
    fs.readFile(cacheFile, function (err, content) {
      if (err) {
        callback(err);
      } else {
        var cacheData = JSON.parse(content);
        cacheData[data.url] = data.bundle;
        fs.writeFile(cacheFile, JSON.stringify(cacheData), function (err, data) {
          if (err) {
            callback(err);
          } else {
            callback(null);
          }
        });
      }
    });
  };
}

function httpRetriever(cacheAddr) {
  return function (url, callback) {
    var requrl = urllib.resolve(cacheAddr, '/?url=' + url);
    request.get(requrl).end(function (err, response) {
      if (err) {
        callback(err, {bundleFound: false});
      } else {
        callback(null, JSON.parse(response.text));
      }
    });
  };
}

function httpStorer(bundlerAddr) {
  return function (url, callback) {
    var requrl = urllib.resolve(bundlerAddr, '/?url=' + url);
    request.get(requrl).end(function (err, response) {
      if (err) {
        callback(err, null);
      } else {
        var json = JSON.parse(response.text);
        if (!json.hasOwnProperty('processID')) {
          callback(new Error('Transport response contains no processID.'), null);
        } else {
          var pid = json['processID'];
          callback(null, pid);
        }
      }
    });
  };
}

module.exports = {
  local: function () {
    // Initialize the cache file.
    try {
      var fd = fs.openSync(cacheFile, 'wx');
      fs.writeSync(fd, new Buffer('{}'), 0, 2, 0);
    } catch (err) {}
    return new Cache(localRetriever(), localStorer());
  },

  http: function (cacheAddr, bundlerAddr) {
    return new Cache(httpRetriever(cacheAddr), httpStorer(bundlerAddr));
  }
  // etc.
};
<|endoftext|>


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

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

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

/**
  The top line of this file will allow this script to be run as
  a UNIX shell script, as well as being a valid Node.js program.
 */

if (typeof WScript != 'undefined') {
  var shell = WScript.CreateObject("WScript.Shell");
  try {
    // Don't worry about passing along arguments here. It's stricly a double-click convenience.
    var ret = shell.Run('cmd /c node "' + WScript.ScriptFullName + '" --pause_on_exit', 1, true);
  } catch (e) {
    shell.Popup('NodeJS is not installed. Please install it from http://nodejs.org');
    ret = 1;
  }
  WScript.Quit(ret);
}

process.on('uncaughtException', function(e) {
  fatal('Uncaught exception: ' + e);
});

var childProcess = require('child_process');
var fs = require('fs');
var path = require('path');

var commandLineFlags = {};
var commandLineArgs = process.argv.slice(2).filter(function(arg) {
  if (arg.slice(0, 2) == '--') {
    commandLineFlags[arg.slice(2)] = true;
  }
  return arg.slice(0, 2) != '--';
});

var origDir = process.cwd();
var isWindows = process.platform.slice(0, 3) == 'win';
var eventQueue = [];
var scriptDir = path.dirname(process.argv[1]);
var scriptName = path.basename(process.argv[1]);
var hasAndroidSdk = false;
var hasXcode = false;

function exit(code) {
  if (eventQueue) {
    eventQueue.length = 0;
  }
  if (commandLineFlags['pause_on_exit']) {
    waitForKey(function() {
      process.exit(code);
    });
  } else {
    process.exit(code);
  }
}

function fatal(msg) {
  console.error(msg);
  exit(1);
}

function exec(cmd, onSuccess, opt_onError, opt_silent) {
  var onError = opt_onError || function(e) {
    fatal('command failed: ' + cmd + '\n' + e);
  };
  if (!opt_silent) {
    console.log('Running: ' + cmd);
  }
  childProcess.exec(cmd, function(error, stdout, stderr) {
    if (error) {
      onError(error);
    } else {
      onSuccess(stdout.trim());
    }
  });
}

function sudo(cmd, onSuccess, opt_onError, silent) {
  if (!isWindows) {
    cmd = 'sudo ' + cmd;
  }
  exec(cmd, onSuccess, opt_onError, silent);
}

function cordovaCmd(args) {
  return '"' + process.argv[0] + '" "' + path.join(scriptDir, 'cordova-cli', 'bin', 'cordova') + '" ' + args.join(' ');
}

function chdir(d) {
  d = path.resolve(scriptDir, d);
  if (process.cwd() != d) {
    console.log('Changing directory to: ' + d);
    process.chdir(d);
  }
}

function copyFile(src, dst, callback) {
  var rd = fs.createReadStream(src);
  var wr = fs.createWriteStream(dst);
  wr.on('error', function(err) {
    fatal('Copy file error: ' + err);
  });
  wr.on('close', callback);
  rd.pipe(wr);
}

function recursiveDelete(dirPath) {
  if (fs.existsSync(dirPath)) {
    console.log('Deleting: ' + dirPath);
    helper(dirPath);
  }
  function helper(dirPath) {
    try {
       var files = fs.readdirSync(dirPath);
    } catch(e) {
      return;
    }
    for (var i = 0; i < files.length; i++) {
      var filePath = path.join(dirPath, files[i]);
      fs.chmodSync(filePath, '777');
      if (fs.statSync(filePath).isFile()) {
        fs.unlinkSync(filePath);
      } else {
        helper(filePath);
      }
    }
    fs.rmdirSync(dirPath);
  }
}

function waitForKey(callback) {
  console.log('press a key');
  function cont(key) {
    if (key == '\u0003') {
      process.exit(2);
    }
    process.stdin.removeListener('data', cont);
    process.stdin.pause();
    callback();
  }
  process.stdin.resume();
  process.stdin.setRawMode(true);
  process.stdin.on('data', cont);
}

function pump() {
  if (eventQueue.length) {
    eventQueue.shift()(pump);
  }
}

////////////////////////// INIT LOGIC //////////////////////////
function initRepoMain() {
  function checkGit(callback) {
    var errMsg = 'git is not installed (or not available on your PATH). Please install it from http://git-scm.com';
    exec('git --version', callback, function() {
      if (isWindows) {
        // See if it's at the default install path.
        process.env['PATH'] += ';' + path.join(process.env['ProgramFiles'], 'Git', 'bin');
        exec('git --version', callback, function() {
          fatal(errMsg);
        }, true);
      } else {
        fatal(errMsg);
      }
    }, true);
  }

  function computeGitVersion(callback) {
    exec('git describe --tags --long', function(stdout) {
      var version = stdout.replace(/^2.5.0-.*?-/, 'dev-');
      callback(version);
    }, null, true);
  }

  function checkOutSelf(callback) {
    console.log('## Checking Out mobile-chrome-apps');
    // If the repo doesn't exist where the script is, then use the CWD as the checkout location.
    var requiresClone = true;
    // First - try the directory of the script.
    if (scriptDir.slice(0, 2) != '\\\\') {
      process.chdir(scriptDir);
      requiresClone = !fs.existsSync('.git');
    }
    // Next - try the CWD.
    if (requiresClone) {
      scriptDir = origDir;
      process.chdir(scriptDir);
      requiresClone = !fs.existsSync('.git');
    }
    // Next - see if it exists within the CWD.
    if (requiresClone) {
      if (fs.existsSync(path.join(origDir, 'mobile-chrome-apps'))) {
        scriptDir = path.join(origDir, 'mobile-chrome-apps');
        process.chdir(scriptDir);
        requiresClone = !fs.existsSync('.git');
      }
    }
    if (requiresClone) {
      scriptDir = origDir;
      chdir(origDir);
      recursiveDelete('mobile-chrome-apps');
      exec('git clone "https://github.com/MobileChromeApps/mobile-chrome-apps.git"', function() {
        scriptDir = path.join(origDir, 'mobile-chrome-apps');
        chdir(scriptDir);
        console.log('Successfully cloned mobile-chrome-apps repo. Delegating to checked-out version of ' + scriptName);
        // TODO: We should quote the args.
        exec('"' + process.argv[0] + '" ' + scriptName + ' ' + process.argv.slice(2).join(' '), function() {
          exit(0);
        });
      });
    } else {
      callback();
    }
  }

  function checkOutSubModules(callback) {
    console.log('## Checking Out SubModules');
    chdir(scriptDir);
    exec('git pull --rebase', function() {
      exec('git submodule init', function() {
        exec('git submodule update', function() {
          chdir(path.join(scriptDir, 'cordova-cli'));
          exec('git submodule init', function() {
            exec('git submodule update', callback);
          });
        });
      });
    });
  }

  function buildCordovaJs(callback) {
    console.log('## Building cordova-js');
    chdir(path.join(scriptDir, 'cordova-js'));
    var needsBuildJs = true;
    computeGitVersion(function(version) {
      if (fs.existsSync('pkg/cordova.ios.js')) {
        needsBuildJs = (fs.readFileSync('pkg/cordova.ios.js').toString().indexOf(version) == -1);
      }
      if (needsBuildJs) {
        console.log('CordovaJS needs to be built.');
        var packager = require('./cordova-js/build/packager');
        packager.generate('ios', version);
        packager.generate('android', version);
      } else {
        console.log('CordovaJS is up-to-date.');
      }
      callback();
    });
  }

  function initCli(callback) {
    console.log('## Setting up cordova-cli');
    // TODO: Figure out when this should be re-run (e.g. upon update).
    if (fs.existsSync('cordova-cli/node_modules')) {
      //console.log('cordova-cli already has its dependencies installed.');
      callback();
    } else {
      chdir(path.join(scriptDir, 'cordova-cli'));
      exec('npm install', callback);
    }
  }

  eventQueue.push(checkGit);
  eventQueue.push(checkOutSelf);
  eventQueue.push(checkOutSubModules);
  eventQueue.push(buildCordovaJs);
  eventQueue.push(initCli);
}

function createAppMain(appName) {
  if (!/\w+\.\w+\.\w+/.exec(appName)) {
    fatal('App Name must follow the pattern: com.company.id');
  }
  function createApp(callback) {
    console.log('## Creating Your Application');
    chdir(origDir);
    var name = /\w+\.(\w+)$/.exec(appName)[1];

    // TODO: add android.
    var cmds = [];
    if (hasXcode) {
      cmds.push(['platform', 'add', 'ios']);
    }
    if (hasAndroidSdk) {
      cmds.push(['platform', 'add', 'android']);
    }
    ['bootstrap', 'common', 'file-chooser', 'fileSystem', 'i18n', 'identity', 'socket', 'storage'].forEach(function(pluginName) {
      cmds.push(['plugin', 'add', path.join(scriptDir, 'chrome-cordova', 'plugins', pluginName)]);
    });

    function runCmd() {
      var curCmd = cmds.shift();
      if (curCmd) {
        console.log(curCmd.join(' '));
        exec(cordovaCmd(curCmd), runCmd, undefined, true);
      } else {
        // Create a script that runs update.js.
        if (isWindows) {
          fs.writeFileSync('mca_update.bat', '"' + process.argv[0] + '" "' + path.join(scriptDir, scriptName) + '" --update_app');
        } else {
          fs.writeFileSync('mca_update.sh', '#!/bin/sh\ncd "`dirname "$0"`"\n"' + process.argv[0] + '" "' + path.join(scriptDir, scriptName) + '" --update_app');
          fs.chmodSync('mca_update.sh', '777');
        }
        callback();
      }
    }

    var curCmd = ['create', name, appName, name];
    console.log(curCmd.join(' '));
    exec(cordovaCmd(curCmd), function() {
      chdir(path.join(origDir, name));
      runCmd();
    }, undefined, true);
  }

  eventQueue.push(createApp);
}

function updateMain() {
  var hasAndroid = fs.existsSync(path.join('platforms', 'android'));
  var hasIos = fs.existsSync(path.join('platforms', 'ios'));

  if (!fs.existsSync('platforms')) {
    fatal('No platforms directory found. Please run script from the root of your project.');
  }

  function runPrepare(callback) {
    console.log('## Preparing your project')
    exec(cordovaCmd(['prepare']), callback, undefined, true);
  }

  function createAddJsStep(platform) {
    return function(callback) {
      console.log('## Updating cordova.js for ' + platform);
      copyFile(path.join(scriptDir, 'cordova-js', 'pkg', 'cordova.' + platform + '.js'), path.join('platforms', platform, 'www', 'cordova.js'), callback);
    };
  }

  function createAddAccessTagStep(platform) {
    return function(callback) {
      console.log('## Setting <access> tag for ' + platform);
      var appName = path.basename(origDir);
      var configFilePath = platform == 'android' ?
          path.join('platforms', 'android', 'res', 'xml', 'config.xml') :
          path.join('platforms', 'ios', appName, 'config.xml');
      if (!fs.existsSync(configFilePath)) {
        fatal('Expected file to exist: ' + configFilePath);
      }
      var contents = fs.readFileSync(configFilePath);
      //contents = contents.replace();
  //\ \ \ \ <access origin="chrome-extension://*" />
      fs.writeFileSync(configFilePath, contents);
      callback();
    };
  };

  eventQueue.push(runPrepare);
  if (hasAndroid) {
    eventQueue.push(createAddJsStep('android'));
    eventQueue.push(createAddAccessTagStep('android'));
  }
  if (hasIos) {
    eventQueue.push(createAddJsStep('ios'));
    eventQueue.push(createAddAccessTagStep('ios'));
  }
}

function toolsCheckMain() {
  function checkAndroid(callback) {
    exec('android list targets', function() {
      hasAndroidSdk = true;
      console.log('Android SDK is installed.');
      callback();
      }, function() {
        console.log('Android SDK is not installed.');
        callback();
      }, true);
  }
  function checkXcode(callback) {
    if (process.platform == 'darwin') {
      exec('which xcodebuild', function() {
        hasXcode = true;
        console.log('Xcode is installed.');
        callback();
      }, function() {
        console.log('Xcode is not installed.');
        callback();
      }, true);
    } else {
      callback();
    }
  }
  function checkAtLeastOneTool(callback) {
    if (!hasAndroidSdk && !hasIos) {
      if (process.platform == 'darwin') {
        fatal('Neither android nor xcodebuild were found on your PATH. Please install at least one of them.');
      } else {
        fatal('Android SDK was not found on your PATH. Please ensure that the android tool is available.');
      }
    }
    callback();
  }
  eventQueue.push(checkAndroid);
  eventQueue.push(checkXcode);
  eventQueue.push(checkAtLeastOneTool);
}
function main() {
  toolsCheckMain();
  if (commandLineFlags['update_app']) {
    updateMain();
  } else {
    initRepoMain();
    var appName = commandLineArgs[0];
    if (appName) {
      createAppMain(appName);
    }
  }
  pump();
}
main();
<commit_msg>console.log checking for tools<commit_after>//usr/bin/env node $0 $*; exit $?
/**
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

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

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

/**
  The top line of this file will allow this script to be run as
  a UNIX shell script, as well as being a valid Node.js program.
 */

if (typeof WScript != 'undefined') {
  var shell = WScript.CreateObject("WScript.Shell");
  try {
    // Don't worry about passing along arguments here. It's stricly a double-click convenience.
    var ret = shell.Run('cmd /c node "' + WScript.ScriptFullName + '" --pause_on_exit', 1, true);
  } catch (e) {
    shell.Popup('NodeJS is not installed. Please install it from http://nodejs.org');
    ret = 1;
  }
  WScript.Quit(ret);
}

process.on('uncaughtException', function(e) {
  fatal('Uncaught exception: ' + e);
});

var childProcess = require('child_process');
var fs = require('fs');
var path = require('path');

var commandLineFlags = {};
var commandLineArgs = process.argv.slice(2).filter(function(arg) {
  if (arg.slice(0, 2) == '--') {
    commandLineFlags[arg.slice(2)] = true;
  }
  return arg.slice(0, 2) != '--';
});

var origDir = process.cwd();
var isWindows = process.platform.slice(0, 3) == 'win';
var eventQueue = [];
var scriptDir = path.dirname(process.argv[1]);
var scriptName = path.basename(process.argv[1]);
var hasAndroidSdk = false;
var hasXcode = false;

function exit(code) {
  if (eventQueue) {
    eventQueue.length = 0;
  }
  if (commandLineFlags['pause_on_exit']) {
    waitForKey(function() {
      process.exit(code);
    });
  } else {
    process.exit(code);
  }
}

function fatal(msg) {
  console.error(msg);
  exit(1);
}

function exec(cmd, onSuccess, opt_onError, opt_silent) {
  var onError = opt_onError || function(e) {
    fatal('command failed: ' + cmd + '\n' + e);
  };
  if (!opt_silent) {
    console.log('Running: ' + cmd);
  }
  childProcess.exec(cmd, function(error, stdout, stderr) {
    if (error) {
      onError(error);
    } else {
      onSuccess(stdout.trim());
    }
  });
}

function sudo(cmd, onSuccess, opt_onError, silent) {
  if (!isWindows) {
    cmd = 'sudo ' + cmd;
  }
  exec(cmd, onSuccess, opt_onError, silent);
}

function cordovaCmd(args) {
  return '"' + process.argv[0] + '" "' + path.join(scriptDir, 'cordova-cli', 'bin', 'cordova') + '" ' + args.join(' ');
}

function chdir(d) {
  d = path.resolve(scriptDir, d);
  if (process.cwd() != d) {
    console.log('Changing directory to: ' + d);
    process.chdir(d);
  }
}

function copyFile(src, dst, callback) {
  var rd = fs.createReadStream(src);
  var wr = fs.createWriteStream(dst);
  wr.on('error', function(err) {
    fatal('Copy file error: ' + err);
  });
  wr.on('close', callback);
  rd.pipe(wr);
}

function recursiveDelete(dirPath) {
  if (fs.existsSync(dirPath)) {
    console.log('Deleting: ' + dirPath);
    helper(dirPath);
  }
  function helper(dirPath) {
    try {
       var files = fs.readdirSync(dirPath);
    } catch(e) {
      return;
    }
    for (var i = 0; i < files.length; i++) {
      var filePath = path.join(dirPath, files[i]);
      fs.chmodSync(filePath, '777');
      if (fs.statSync(filePath).isFile()) {
        fs.unlinkSync(filePath);
      } else {
        helper(filePath);
      }
    }
    fs.rmdirSync(dirPath);
  }
}

function waitForKey(callback) {
  console.log('press a key');
  function cont(key) {
    if (key == '\u0003') {
      process.exit(2);
    }
    process.stdin.removeListener('data', cont);
    process.stdin.pause();
    callback();
  }
  process.stdin.resume();
  process.stdin.setRawMode(true);
  process.stdin.on('data', cont);
}

function pump() {
  if (eventQueue.length) {
    eventQueue.shift()(pump);
  }
}

////////////////////////// INIT LOGIC //////////////////////////
function initRepoMain() {
  function checkGit(callback) {
    var errMsg = 'git is not installed (or not available on your PATH). Please install it from http://git-scm.com';
    exec('git --version', callback, function() {
      if (isWindows) {
        // See if it's at the default install path.
        process.env['PATH'] += ';' + path.join(process.env['ProgramFiles'], 'Git', 'bin');
        exec('git --version', callback, function() {
          fatal(errMsg);
        }, true);
      } else {
        fatal(errMsg);
      }
    }, true);
  }

  function computeGitVersion(callback) {
    exec('git describe --tags --long', function(stdout) {
      var version = stdout.replace(/^2.5.0-.*?-/, 'dev-');
      callback(version);
    }, null, true);
  }

  function checkOutSelf(callback) {
    console.log('## Checking Out mobile-chrome-apps');
    // If the repo doesn't exist where the script is, then use the CWD as the checkout location.
    var requiresClone = true;
    // First - try the directory of the script.
    if (scriptDir.slice(0, 2) != '\\\\') {
      process.chdir(scriptDir);
      requiresClone = !fs.existsSync('.git');
    }
    // Next - try the CWD.
    if (requiresClone) {
      scriptDir = origDir;
      process.chdir(scriptDir);
      requiresClone = !fs.existsSync('.git');
    }
    // Next - see if it exists within the CWD.
    if (requiresClone) {
      if (fs.existsSync(path.join(origDir, 'mobile-chrome-apps'))) {
        scriptDir = path.join(origDir, 'mobile-chrome-apps');
        process.chdir(scriptDir);
        requiresClone = !fs.existsSync('.git');
      }
    }
    if (requiresClone) {
      scriptDir = origDir;
      chdir(origDir);
      recursiveDelete('mobile-chrome-apps');
      exec('git clone "https://github.com/MobileChromeApps/mobile-chrome-apps.git"', function() {
        scriptDir = path.join(origDir, 'mobile-chrome-apps');
        chdir(scriptDir);
        console.log('Successfully cloned mobile-chrome-apps repo. Delegating to checked-out version of ' + scriptName);
        // TODO: We should quote the args.
        exec('"' + process.argv[0] + '" ' + scriptName + ' ' + process.argv.slice(2).join(' '), function() {
          exit(0);
        });
      });
    } else {
      callback();
    }
  }

  function checkOutSubModules(callback) {
    console.log('## Checking Out SubModules');
    chdir(scriptDir);
    exec('git pull --rebase', function() {
      exec('git submodule init', function() {
        exec('git submodule update', function() {
          chdir(path.join(scriptDir, 'cordova-cli'));
          exec('git submodule init', function() {
            exec('git submodule update', callback);
          });
        });
      });
    });
  }

  function buildCordovaJs(callback) {
    console.log('## Building cordova-js');
    chdir(path.join(scriptDir, 'cordova-js'));
    var needsBuildJs = true;
    computeGitVersion(function(version) {
      if (fs.existsSync('pkg/cordova.ios.js')) {
        needsBuildJs = (fs.readFileSync('pkg/cordova.ios.js').toString().indexOf(version) == -1);
      }
      if (needsBuildJs) {
        console.log('CordovaJS needs to be built.');
        var packager = require('./cordova-js/build/packager');
        packager.generate('ios', version);
        packager.generate('android', version);
      } else {
        console.log('CordovaJS is up-to-date.');
      }
      callback();
    });
  }

  function initCli(callback) {
    console.log('## Setting up cordova-cli');
    // TODO: Figure out when this should be re-run (e.g. upon update).
    if (fs.existsSync('cordova-cli/node_modules')) {
      //console.log('cordova-cli already has its dependencies installed.');
      callback();
    } else {
      chdir(path.join(scriptDir, 'cordova-cli'));
      exec('npm install', callback);
    }
  }

  eventQueue.push(checkGit);
  eventQueue.push(checkOutSelf);
  eventQueue.push(checkOutSubModules);
  eventQueue.push(buildCordovaJs);
  eventQueue.push(initCli);
}

function createAppMain(appName) {
  if (!/\w+\.\w+\.\w+/.exec(appName)) {
    fatal('App Name must follow the pattern: com.company.id');
  }
  function createApp(callback) {
    console.log('## Creating Your Application');
    chdir(origDir);
    var name = /\w+\.(\w+)$/.exec(appName)[1];

    // TODO: add android.
    var cmds = [];
    if (hasXcode) {
      cmds.push(['platform', 'add', 'ios']);
    }
    if (hasAndroidSdk) {
      cmds.push(['platform', 'add', 'android']);
    }
    ['bootstrap', 'common', 'file-chooser', 'fileSystem', 'i18n', 'identity', 'socket', 'storage'].forEach(function(pluginName) {
      cmds.push(['plugin', 'add', path.join(scriptDir, 'chrome-cordova', 'plugins', pluginName)]);
    });

    function runCmd() {
      var curCmd = cmds.shift();
      if (curCmd) {
        console.log(curCmd.join(' '));
        exec(cordovaCmd(curCmd), runCmd, undefined, true);
      } else {
        // Create a script that runs update.js.
        if (isWindows) {
          fs.writeFileSync('mca_update.bat', '"' + process.argv[0] + '" "' + path.join(scriptDir, scriptName) + '" --update_app');
        } else {
          fs.writeFileSync('mca_update.sh', '#!/bin/sh\ncd "`dirname "$0"`"\n"' + process.argv[0] + '" "' + path.join(scriptDir, scriptName) + '" --update_app');
          fs.chmodSync('mca_update.sh', '777');
        }
        callback();
      }
    }

    var curCmd = ['create', name, appName, name];
    console.log(curCmd.join(' '));
    exec(cordovaCmd(curCmd), function() {
      chdir(path.join(origDir, name));
      runCmd();
    }, undefined, true);
  }

  eventQueue.push(createApp);
}

function updateMain() {
  var hasAndroid = fs.existsSync(path.join('platforms', 'android'));
  var hasIos = fs.existsSync(path.join('platforms', 'ios'));

  if (!fs.existsSync('platforms')) {
    fatal('No platforms directory found. Please run script from the root of your project.');
  }

  function runPrepare(callback) {
    console.log('## Preparing your project')
    exec(cordovaCmd(['prepare']), callback, undefined, true);
  }

  function createAddJsStep(platform) {
    return function(callback) {
      console.log('## Updating cordova.js for ' + platform);
      copyFile(path.join(scriptDir, 'cordova-js', 'pkg', 'cordova.' + platform + '.js'), path.join('platforms', platform, 'www', 'cordova.js'), callback);
    };
  }

  function createAddAccessTagStep(platform) {
    return function(callback) {
      console.log('## Setting <access> tag for ' + platform);
      var appName = path.basename(origDir);
      var configFilePath = platform == 'android' ?
          path.join('platforms', 'android', 'res', 'xml', 'config.xml') :
          path.join('platforms', 'ios', appName, 'config.xml');
      if (!fs.existsSync(configFilePath)) {
        fatal('Expected file to exist: ' + configFilePath);
      }
      var contents = fs.readFileSync(configFilePath);
      //contents = contents.replace();
  //\ \ \ \ <access origin="chrome-extension://*" />
      fs.writeFileSync(configFilePath, contents);
      callback();
    };
  };

  eventQueue.push(runPrepare);
  if (hasAndroid) {
    eventQueue.push(createAddJsStep('android'));
    eventQueue.push(createAddAccessTagStep('android'));
  }
  if (hasIos) {
    eventQueue.push(createAddJsStep('ios'));
    eventQueue.push(createAddAccessTagStep('ios'));
  }
}

function toolsCheckMain() {
  console.log('## Checking that tools are installed');
  function checkAndroid(callback) {
    exec('android list targets', function() {
      hasAndroidSdk = true;
      console.log('Android SDK is installed.');
      callback();
      }, function() {
        console.log('Android SDK is not installed.');
        callback();
      }, true);
  }
  function checkXcode(callback) {
    if (process.platform == 'darwin') {
      exec('which xcodebuild', function() {
        hasXcode = true;
        console.log('Xcode is installed.');
        callback();
      }, function() {
        console.log('Xcode is not installed.');
        callback();
      }, true);
    } else {
      callback();
    }
  }
  function checkAtLeastOneTool(callback) {
    if (!hasAndroidSdk && !hasIos) {
      if (process.platform == 'darwin') {
        fatal('Neither android nor xcodebuild were found on your PATH. Please install at least one of them.');
      } else {
        fatal('Android SDK was not found on your PATH. Please ensure that the android tool is available.');
      }
    }
    callback();
  }
  eventQueue.push(checkAndroid);
  eventQueue.push(checkXcode);
  eventQueue.push(checkAtLeastOneTool);
}
function main() {
  toolsCheckMain();
  if (commandLineFlags['update_app']) {
    updateMain();
  } else {
    initRepoMain();
    var appName = commandLineArgs[0];
    if (appName) {
      createAppMain(appName);
    }
  }
  pump();
}
main();
<|endoftext|>