<commit_before>#!/usr/bin/env node
"use strict";

//    EXTERNAL DEPENDENCIES
const fs                = require("fs"),
      iq                = require("inquirer"),
      octonode          = require("octonode"),
      gitLabel          = require("git-label");
//    UTILS ARE STANDALONE METHODS WITH NO DEPENDENCIES
const banner            = require("./utils/banners"),
      configGitLabel    = require("./utils/configGitLabel"),
      replaceAll        = require("./utils/replaceAll");
//    PROMPTS ARE THE PROMPTS ARRAYS FOR VARIOUS QUESTIONS
const prompts           = {
        addCustom:        require("./prompts/addCustom"),
        mainMenu:         require("./prompts/mainMenu")
      };
//    MODULES ARE UTILS WITH DEPENDENCIES
const readRepo          = require("./modules/readRepo"),
      setToken          = require("./modules/setToken"),
      fetchToken        = require("./modules/fetchToken"),
      isGitRepo         = require("./modules/isGitRepo"),
      readGitConfig     = require("./modules/readGitConfig");

//    A simple prompt util, returns a promise with the prompt answers
const prompt = (prompts) => {
        return new Promise((res, rej)=>{
          iq.prompt(prompts, (answers) => {
            if ( !answers ) rej(answers);
            res(answers);
          });
        });
      };

//    A simple util that promisifies our GitHub API call
///   NOT IN USE
const requestLabels = ( token, repo ) => {
        return new Promise((res, rej)=>{
          octonode.client(token).get('/repos/'+repo+'/labels', (e, status, body) => {
            if (e) rej(e);
            res(body);
          });
        });
      };

//  Recursivly asks if you want to add another new label, then calls a callback when youre all done
const doCustomLabelPrompts = ( newLabels, done ) => {
        iq.prompt( prompts.addCustom, ( answers ) => {
          newLabels.push({ name: answers.labelName, color: answers.labelColor });
          if ( answers.addAnother ){
            doCustomLabelPrompts( newLabels, done );
          }else{
            done( newLabels );
          }
        });
      };

//    TODO: this function is ripe for some refactoring
const doRemovePrompts = ( token, repo ) => {
        octonode.client(token).get('/repos/'+repo+'/labels', (e, status, body) => {
          iq.prompt([{
            name:     "removals",
            type:     "checkbox",
            message:  "Which labels would you like to remove?",
            choices:  body.map((label) => label.name),
            filter:   (removals) => {
              return body.filter((label) => {
                return removals.indexOf(label.name) > -1 ? { name: label.name, color: label.color } : false;
              });
            }
          }], (answers) => {
            //  early return if no labels
            //  TODO: this could be a check in the above prompt
            if ( answers.removals.length === 0 ) {
              console.log("No labels chosen to remove.");
              return ;
            };

            //  Tell the user what they're about to lose
            console.log("About to delete the following labels:")
            answers.removals.map((label)=>{
              return " - "+label.name;
            }).forEach((prettyLabel)=>{
              console.log(prettyLabel);
            });
            //  Ya sure ya wanna do this bud?
            iq.prompt([{
              name:     "youSure",
              type:     "confirm",
              message:  "Are you sure you want to delete these labels?",
              default:  true
            }], (confirmRemove) => {
              if ( confirmRemove.youSure ) {
                gitLabel.remove( configGitLabel(repo, token), answers.removals )
                .then(console.log)
                .catch(console.warn);
              } else {
                process.exit(1)
              }
            })

          });
        });
      };

//    TODO: could be refactored to return the git.add as a promise..?
const handleAddPrompts = (repo, token, newLabels) => {
        gitLabel.add( configGitLabel(repo, token), newLabels )
          .then(console.log)
          .catch(console.warn);
      };

const handleMainPrompts = (repo, ans) => {
        if ( ans.main.toLowerCase() === "reset token" ){
          banner.resetToken();
          //  process will end after new token is set
          return setToken((token) => {
            banner.welcome();
            iq.prompt( prompts.mainMenu, handleMainPrompts.bind(null, repo));
          });
        }
        //  if it's not to reset the token then we
        fetchToken()
          .then((token)=>{
            if ( ans.main.toLowerCase() === "add custom labels" ){
              banner.addCustom();
              return doCustomLabelPrompts( [], handleAddPrompts.bind(null, repo, token));
            }
            if ( ans.main.toLowerCase() === "add labels from package" ){
              banner.addFromPackage();
              let packagePath;
              iq.prompt([{
                name: "path",
                type: "input",
                message: "What is the path & name of the package you want to use? (eg: `packages/my-label-pkg.json`)",
                validate: (path) => {
                  try {
                    if (path.indexOf(".json") < 0) throw "Not a JSON file";
                    packagePath = path.indexOf("/") === 0 ? path.replace("/","") : path;
                    //  TODO: make that fn loop over an array of replaces, or make it REMOVEALL and ditch that 3rd param
                    packagePath = replaceAll( replaceAll( replaceAll(packagePath, '`', ""), '"', "" ), "'", "" )
                    if ( fs.statSync( process.cwd()+"/"+packagePath ) ){
                      return true;
                    }
                  } catch (e){
                    return e;
                  }
                }
              }], (ans) => {
                gitLabel.find( replaceAll( replaceAll( replaceAll(ans.path, '`', ""), '"', "" ), "'", "" ) )
                  .then((newLabels)=>{
                    return gitLabel.add( configGitLabel(repo, token), newLabels )
                  })
                  .then(console.log)
                  .catch(console.warn);
              });
            }
            if ( ans.main.toLowerCase() === "remove labels" ){
              banner.removeLabels();
              doRemovePrompts(token, repo);
            }
          })
          .catch((msg)=>{
            console.log(msg);
            setToken((token) => {
              banner.welcome();
              iq.prompt( prompts.mainMenu, handleMainPrompts.bind(null, repo));
            });
          });
      };

//    Kicks things off and arrows program to
const gitLabelmaker = () => {

  Promise.all([ isGitRepo(), readGitConfig(), fetchToken() ])
  .then(( values )=>{
    let repo = readRepo(values[1]);
    let token = values[2];
    banner.welcome();
    iq.prompt( prompts.mainMenu, handleMainPrompts.bind(null, repo));
  })
  .catch((e)=>{
    console.warn(e.err);
    if (e.id === "TOKEN") {
      setToken(gitLabelmaker);
    } else {
      process.exit(1);
    }
  });

};

gitLabelmaker();
<commit_msg>Some refactoring<commit_after>#!/usr/bin/env node
"use strict";

//    EXTERNAL DEPENDENCIES
const fs                = require("fs"),
      iq                = require("inquirer"),
      octonode          = require("octonode"),
      gitLabel          = require("git-label");
//    UTILS ARE STANDALONE METHODS WITH NO DEPENDENCIES
const banner            = require("./utils/banners"),
      configGitLabel    = require("./utils/configGitLabel"),
      removeAll         = require("./utils/removeAll");
//    PROMPTS ARE THE PROMPTS ARRAYS FOR VARIOUS QUESTIONS
const prompts           = {
        addCustom:        require("./prompts/addCustom"),
        deleteConfirm:    require("./prompts/deleteConfirm"),
        mainMenu:         require("./prompts/mainMenu")
      };
//    MODULES ARE UTILS WITH DEPENDENCIES
const readRepo          = require("./modules/readRepo"),
      setToken          = require("./modules/setToken"),
      fetchToken        = require("./modules/fetchToken"),
      isGitRepo         = require("./modules/isGitRepo"),
      readGitConfig     = require("./modules/readGitConfig");

/////reset the token fn
const resetToken = () => {
  banner.resetToken();
  return setToken(gitLabelmaker);
};
/////add custom labels fn
const addCustom = (repo, token) => {
  banner.addCustom();
  return doCustomLabelPrompts( [], handleAddPrompts.bind(null, repo, token));
};
/////add labels from package
const addFromPackage = (repo, token, path) => {
  gitLabel.find( removeAll( path, [ "`", '"', "'" ] ) )
    .then((newLabels)=>{
      return gitLabel.add( configGitLabel(repo, token), newLabels )
    })
    .then(console.log)
    .catch(console.warn);
};
/////

//  Recursivly asks if you want to add another new label, then calls a callback when youre all done
const doCustomLabelPrompts = ( newLabels, done ) => {
        iq.prompt( prompts.addCustom, ( answers ) => {
          newLabels.push({ name: answers.labelName, color: answers.labelColor });
          if ( answers.addAnother ){
            doCustomLabelPrompts( newLabels, done );
          }else{
            done( newLabels );
          }
        });
      };

//    TODO: this function is ripe for some refactoring
const doRemovePrompts = ( token, repo ) => {
        octonode.client(token).get('/repos/'+repo+'/labels', (e, status, body) => {
          iq.prompt([{
            name:     "removals",
            type:     "checkbox",
            message:  "Which labels would you like to remove?",
            choices:  body.map((label) => label.name),
            validate: (removals) => {
                return removals.length === 0 ? "Please select at least one label to remove." : true;
            },
            filter:   (removals) => {
              return body.filter((label) => {
                return removals.indexOf(label.name) > -1 ? { name: label.name, color: label.color } : false;
              });
            }
          }], (answers) => {
            //  Tell the user what they're about to lose
            console.log("About to delete the following labels:")
            answers.removals.map((label)=>{
              return " - "+label.name;
            }).forEach((prettyLabel)=>{
              console.log(prettyLabel);
            });
            //  Ya sure ya wanna do this bud?
            iq.prompt([prompts.deleteConfirm], (confirmRemove) => {
              if ( confirmRemove.youSure ) {
                gitLabel.remove( configGitLabel(repo, token), answers.removals )
                .then(console.log)
                .catch(console.warn);
              } else {
                process.exit(1);
              }
            })

          });
        });
      };

//    TODO: could be refactored to return the git.add as a promise..?
const handleAddPrompts = (repo, token, newLabels) => {
        gitLabel.add( configGitLabel(repo, token), newLabels )
          .then(console.log)
          .catch(console.warn);
      };

//    TODO: refactor into some kind of switch statement?
const handleMainPrompts = (repo, token, ans) => {
        if ( ans.main.toLowerCase() === "reset token" ){
          resetToken();
        }
        if ( ans.main.toLowerCase() === "add custom labels" ){
          addCustom(repo, token);
        }
        if ( ans.main.toLowerCase() === "add labels from package" ){
          banner.addFromPackage();
          let packagePath;
          iq.prompt([{
            name: "path",
            type: "input",
            message: "What is the path & name of the package you want to use? (eg: `packages/my-label-pkg.json`)",
            validate: (path) => {
              try {
                if (path.indexOf(".json") < 0) throw "Not a JSON file";
                packagePath = path.indexOf("/") === 0 ? path.replace("/","") : path;
                packagePath = removeAll( packagePath, [ "`", '"', "'" ] );
                if ( fs.statSync( process.cwd()+"/"+packagePath ) ){
                  return true;
                }
              } catch (e){
                return e;
              }
            }
          }], (ans) => {
            addFromPackage( repo, token, ans.path );
          });
        }
        if ( ans.main.toLowerCase() === "remove labels" ){
          banner.removeLabels();
          return doRemovePrompts(token, repo);
        }
      };

//    Kicks things off and arrows program to
const gitLabelmaker = () => {

  Promise.all([ isGitRepo(), readGitConfig(), fetchToken() ])
  .then(( values )=>{
    let repo = readRepo(values[1]);
    let token = values[2];
    banner.welcome();
    iq.prompt( prompts.mainMenu, handleMainPrompts.bind(null, repo, token));
  })
  .catch((e)=>{
    console.warn(e.err);
    if (e.id === "TOKEN") {
      setToken(gitLabelmaker);
    } else {
      process.exit(1);
    }
  });

};

gitLabelmaker();

////////////////////
//  CODE GRAVEYARD
/////////////////////
//    A simple prompt util, returns a promise with the prompt answers
///   NOT IN USE
const prompt = (prompts) => {
        return new Promise((res, rej)=>{
          iq.prompt(prompts, (answers) => {
            if ( !answers ) rej(answers);
            res(answers);
          });
        });
      };

//    A simple util that promisifies our GitHub API call
///   NOT IN USE
const requestLabels = ( token, repo ) => {
        return new Promise((res, rej)=>{
          octonode.client(token).get('/repos/'+repo+'/labels', (e, status, body) => {
            if (e) rej(e);
            res(body);
          });
        });
      };
<|endoftext|>


<commit_before>const fastify = require('fastify')()
const path = require('path')
const shortid = require('shortid')
const { URL } = require('url')

const baseUrl = process.env.WINNIPEG_BASE_URL || 'http://localhost:3000'
const storage = require('./storage/map')()

fastify.register(require('fastify-static'), {
  root: path.join(__dirname, 'public'),
  prefix: '/public/'
})

fastify.route({
  method: 'GET',
  url: '/',
  handler: function (request, reply) {
    reply.sendFile('html.html')
  }
})

fastify.route({
  method: 'GET',
  url: '/:short',
  schema: {
    params: {
      short: { type: 'string' }
    }
  },
  handler: async function (request, reply) {
    try {
      const url = await storage.get(request.params.short)

      if (url) {
        reply.code(302)
        reply.header('Location', url.href)

        return ''
      } else {
        reply.code(404)

        return new Error('Not Found')
      }
    } catch (err) {
      reply.code(400)

      return err
    }
  }
})

fastify.route({
  method: 'GET',
  url: '/css.css',
  handler: function (request, reply) {
    reply.sendFile('css.css')
  }
})

fastify.route({
  method: 'GET',
  url: '/js.js',
  handler: function (request, reply) {
    reply.sendFile('js.js')
  }
})

fastify.route({
  method: 'POST',
  url: '/',
  schema: {
    body: {
      url: { type: 'string' }
    },
    response: {
      200: {
        type: 'object',
        properties: {
          short: { type: 'string' }
        }
      }
    }
  },
  handler: async function (request, reply) {
    try {
      const url = new URL(request.body.url)
      const shortUrl = shortid.generate()

      await storage.set(shortUrl, url)

      return {
        short: `${baseUrl}/${shortUrl}`
      }
    } catch (err) {
      reply.code(400)

      return err
    }
  }
})

fastify.listen(3000, function (err) {
  if (err) throw err
  console.log(`server listening on ${fastify.server.address().port}`)
})
<commit_msg>store url string<commit_after>const fastify = require('fastify')()
const path = require('path')
const shortid = require('shortid')
const { URL } = require('url')

const baseUrl = process.env.WINNIPEG_BASE_URL || 'http://localhost:3000'
const storage = require('./storage/map')()

fastify.register(require('fastify-static'), {
  root: path.join(__dirname, 'public'),
  prefix: '/public/'
})

fastify.route({
  method: 'GET',
  url: '/',
  handler: function (request, reply) {
    reply.sendFile('html.html')
  }
})

fastify.route({
  method: 'GET',
  url: '/:short',
  schema: {
    params: {
      short: { type: 'string' }
    }
  },
  handler: async function (request, reply) {
    try {
      const url = await storage.get(request.params.short)

      if (url) {
        reply.code(302)
        reply.header('Location', url)

        return ''
      } else {
        reply.code(404)

        return new Error('Not Found')
      }
    } catch (err) {
      reply.code(400)

      return err
    }
  }
})

fastify.route({
  method: 'GET',
  url: '/css.css',
  handler: function (request, reply) {
    reply.sendFile('css.css')
  }
})

fastify.route({
  method: 'GET',
  url: '/js.js',
  handler: function (request, reply) {
    reply.sendFile('js.js')
  }
})

fastify.route({
  method: 'POST',
  url: '/',
  schema: {
    body: {
      url: { type: 'string' }
    },
    response: {
      200: {
        type: 'object',
        properties: {
          short: { type: 'string' }
        }
      }
    }
  },
  handler: async function (request, reply) {
    try {
      const url = new URL(request.body.url)
      const shortUrl = shortid.generate()

      await storage.set(shortUrl, url.href)

      return {
        short: `${baseUrl}/${shortUrl}`
      }
    } catch (err) {
      reply.code(400)

      return err
    }
  }
})

fastify.listen(3000, function (err) {
  if (err) throw err
  console.log(`server listening on ${fastify.server.address().port}`)
})
<|endoftext|>


<commit_before>window.localStorage.clear();

var module = angular.module('OhHell', []);

// bootstrap angular into the page
angular.element(document).ready(() => {
	angular.bootstrap(document.body, [module.name], {
		strictDi: true
	});
});

class AppController {
	constructor ($scope) {
		this.settings = this.getSettings();
		this.game = this.getGame();
		this.showFullScore = false;

		$scope.$watch('App.settings', (new_val, old_val) => {
			this.saveSettings();
		}, true);

		$scope.$watch('App.game', (new_val, old_val) => {
			this.saveGame();
			this.updateStats();
		}, true);

		this.updateStats();
	}

	addNewPlayer () {
		if (this.newPlayerName && this.settings.players.indexOf(this.newPlayerName) === -1) {
			this.settings.players.push(this.newPlayerName);
			this.newPlayerName = '';
		}
	}

	removePlayer (index) {
		this.settings.players.splice(index, 1);
	}

	startGame () {
		var rounds = [];
		var roundRange = this.roundRange(this.settings.cardsInFirstRound, this.settings.cardsInLastRound, this.settings.mirrorRounds);
		var dealer = this.generateRandomNumber(0, this.settings.players.length - 1);

		for (var i = 0; i < roundRange.length; i++) {
			if (i > 0) {
				dealer++;

				if (dealer >= this.settings.players.length) {
					dealer = 0;
				}
			}

			var round = {
				suit: this.generateRandomSuit(i === 0 ? null : rounds[i - 1].suit),
				cards: roundRange[i],
				dealer: dealer,
				players: [],
			};

			for (var j = 0; j < this.settings.players.length; j++) {
				round.players.push({
					bid: null,
					tricks: null,
				});
			}
			rounds.push(round);
		}

		this.game = {
			settings: this.settings,
			rounds: rounds,
			isFinished: false,
			currentRound: {
				index: 0,
				started: false,
			},
		};
	}

	getSettings () {
		var settings = localStorage.getItem('oh-hell-settings');

		try {
			settings = JSON.parse(settings);
		} catch (err) {
			settings = null;
		}

		if (!settings) {
			settings = this.getDefaultSettings();
		}

		return settings;
	}

	getDefaultSettings () {
		return {
			players: [],
		};
	}

	saveSettings () {
		localStorage.setItem('oh-hell-settings', JSON.stringify(this.settings));
	}

	getGame () {
		var game = localStorage.getItem('oh-hell-game');

		try {
			game = JSON.parse(game);
		} catch (err) {
			game = null;
		}

		return game;
	}

	saveGame () {
		localStorage.setItem('oh-hell-game', JSON.stringify(this.game));
	}

	roundRange (start, end, mirror) {
		var input = [];

		if (start < end) {
			for (var i = start; i <= end; i += 1) {
		        input.push(i);
		    }
		} else {
			for (var i = start; i >= end; i -= 1) {
		        input.push(i);
		    }
		}

		if (mirror) {
			input = input.concat(this.roundRange(end, start, false));
		}

	    return input;
	}

	calculateRoundPoints (playerIndex, roundIndex) {
		var cards = this.game.rounds[roundIndex].cards;
		var bid = parseInt(this.game.rounds[roundIndex].players[playerIndex].bid);
		var tricks = parseInt(this.game.rounds[roundIndex].players[playerIndex].tricks);
		var successful = tricks === bid;

		if (isNaN(bid) || isNaN(tricks)) {
			return null;
		}

		var points = 0;

		// award points per trick

		if (this.game.settings.winPointsPerTrick) {
			if (successful || !this.game.settings.winPointsPerTrickIfSuccessful) {
				if (tricks === 0 && this.game.settings.winPointsPerTrickIfZero) {
					points += 0.5;
				} else {
					points += tricks;
				}
			}
		}

		// lose points per trick different

		if (this.game.settings.losePointsPerDifference) {
			points -= Math.abs(tricks - bid);
		}

		// bonus points on successful bid

		var bonusSuccessful = parseInt(this.game.settings.pointsSuccessfulBid);
		if (successful && !isNaN(bonusSuccessful) ) {
			points += bonusSuccessful;
		}

		if (successful && this.game.settings.pointsSuccessfulVariable) {
			points += cards;
		}

		if (successful && this.game.settings.pointsSuccessfulInverse) {
			points += (this.getHighestCardCount() - cards + 1);
		}

		// negative points on unsuccessful bid

		var bonusUnsuccessful = parseInt(this.game.settings.pointsUnsuccessfulBid);
		if (!successful && !isNaN(bonusUnsuccessful)) {
			points -= bonusUnsuccessful;
		}

		if (!successful && this.game.settings.pointsUnsuccessfulVariable) {
			points -= cards;
		}

		if (!successful && this.game.settings.pointsUnsuccessfulInverse) {
			points -= (this.getHighestCardCount() - cards + 1);
		}

		// blind bid

		var blindBidBonus = parseInt(this.game.settings.blindBidBonus);
		if (successful && this.game.rounds[roundIndex].players[playerIndex].blind && !isNaN(blindBidBonus)) {
			points += blindBidBonus;
		}

		if (successful && this.game.rounds[roundIndex].players[playerIndex].blind && this.game.settings.blindBidDouble) {
			points *= 2;
		}

		// set the points

		this.game.rounds[roundIndex].players[playerIndex].points = points;

		return points;
	}

	calculateTotalPoints (playerIndex, roundIndex) {
		var totalPoints = 0;

		this.game.rounds.forEach((round, i) => {
			if (roundIndex && i >= roundIndex) {
				return true;
			}

			var roundPoints = this.calculateRoundPoints(playerIndex, i);

			if (roundPoints) {
				totalPoints += roundPoints;
			}
		});

		return totalPoints;
	}

	generateRandomSuit (previousSuit) {
		var suits = ['S', 'C', 'D', 'H'];
		var index = this.generateRandomNumber(0, 3);

		if (suits[index] === previousSuit) {
			return 'N';
		}

		return suits[index];
	}

	generateRandomNumber (first, last) {
		return Math.round(Math.random() * last) + first;
	}

	updateStats () {
		if (this.game && this.game.rounds) {
			this.updateBidAccuracyChart();
			this.updateBidCountChart();
			this.updateScoresChart();
		}
	}

	updateBidAccuracyChart () {
		var labels = [];

		this.game.settings.players.forEach((player) => {
			labels.push(player);
		});

		var datasets = [{
			label: 'Accurate Bid',
			backgroundColor: '#5cb85c',
			stack: 1,
			data: this.game.settings.players.map((player) => {
				return 0;
			}),
		}, {
			label: 'Underbid',
			backgroundColor: '#f0ad4e',
			stack: 1,
			data: this.game.settings.players.map((player) => {
				return 0;
			}),
		}, {
			label: 'Overbid',
			backgroundColor: '#c9302c',
			stack: 1,
			data: this.game.settings.players.map((player) => {
				return 0;
			}),
		}];

		this.game.rounds.forEach((round, roundIndex) => {
			round.players.forEach((player, playerIndex) => {
				var tricks = parseInt(player.tricks);
				var bid = parseInt(player.bid);

				if (!isNaN(tricks) && !isNaN(bid)) {
					if (tricks > bid) {
						datasets[1].data[playerIndex]++;
					} else if (tricks === bid) {
						datasets[0].data[playerIndex]++;
					} else if (tricks < bid) {
						datasets[2].data[playerIndex]++;
					}
				}
			});
		});

		if (this.chartBidAccuracy) {
			this.chartBidAccuracy.destroy();
		}

		this.chartBidAccuracy = new Chart(document.getElementById('chart-bid-accuracy'), {
		    type: 'bar',
		    data: {
		        labels: labels,
		        datasets: datasets
		    },
		    options: {
				legend: {
					display: false
				},
		        scales: {
		            yAxes: [{
		                ticks: {
		                    beginAtZero: true
		                }
		            }]
		        }
		    }
		});
	}

	updateBidCountChart () {
		var labels = [];
		var highestCardCount = this.getHighestCardCount();

		for (var i = 0; i <= highestCardCount; i++) {
			labels.push(i + ' Bid');
		}

		var datasets = [];

		this.game.rounds.forEach((round, roundIndex) => {
			round.players.forEach((player, playerIndex) => {
				var tricks = parseInt(player.tricks);
				var bid = parseInt(player.bid);

				if (!datasets[playerIndex]) {
					var data = [];
					labels.forEach((label) => {
						data.push(0);
					});

					datasets[playerIndex] = {
						label: this.game.settings.players[playerIndex],
						backgroundColor: this.getPlayerColour(playerIndex),
						borderColor: this.getPlayerColour(playerIndex),
						fill: false,
						data: data,
					}
				}

				if (!isNaN(bid)) {
					datasets[playerIndex].data[bid]++;
				}
			});
		});

		if (this.chartBidCounts) {
			this.chartBidCounts.destroy();
		}

		this.chartBidCounts = new Chart(document.getElementById('chart-bid-counts'), {
		    type: 'line',
		    data: {
		        labels: labels,
		        datasets: datasets
		    },
		    options: {
		        scales: {
		            yAxes: [{
		                ticks: {
		                    beginAtZero: true,
		                }
		            }]
		        }
		    }
		});
	}

	updateScoresChart() {
		var labels = [];

		for (var i = 1; i <= this.game.rounds.length; i++) {
			labels.push('Round ' + i);
		}
		console.log(labels);
		var datasets = [];

		this.game.rounds.forEach((round, roundIndex) => {
			round.players.forEach((player, playerIndex) => {
				if (!datasets[playerIndex]) {
					datasets[playerIndex] = {
						label: this.game.settings.players[playerIndex],
						backgroundColor: this.getPlayerColour(playerIndex),
						borderColor: this.getPlayerColour(playerIndex),
						fill: false,
						data: [],
					}
				}

				var points = parseInt(player.points);
				if (!isNaN(points)) {
					if (roundIndex === 0) {
						datasets[playerIndex].data.push(points);
					} else {
						datasets[playerIndex].data.push(datasets[playerIndex].data[roundIndex - 1] + points);
					}
				}
			});
		});

		if (this.chartBidScores) {
			this.chartBidScores.destroy();
		}
		console.log(this.game.rounds.length);
		this.chartBidScores = new Chart(document.getElementById('chart-bid-scores'), {
		    type: 'line',
		    data: {
		        labels: labels,
		        datasets: datasets
		    },
		    options: {
		        scales: {
		            yAxes: [{
		                ticks: {
							beginAtZero: true,
		                }
		            }]
		        }
		    }
		});
	}

	getPlayerColour (playerIndex) {
		return [
            '#EE2E2F',
            '#F47D23',
            '#008C48',
            '#185AA9',
            '#662C91',
            '#E76BC7',
        ][playerIndex];
	}

	getColumnWidth () {
		var columnCount = this.game.settings.players.length;

		if (this.showFullScore) {
			columnCount++;
		}

		return (100 / columnCount) + '%';
	}

	toggleStoreView () {
		this.showFullScore = !this.showFullScore;
	}

	startRound () {
		this.game.currentRound.started = true;
	}

	nextRound () {
		if (this.game.currentRound.index === (this.game.rounds.length - 1)) {
			this.game.leaderboard = this.getLeaderboard();
			this.game.isFinished = true;
		} else {
			this.game.currentRound.index++;
			this.game.currentRound.started = false;
		}
	}

	eligibleForBlindBid (playerIndex, roundIndex) {
		var playerPoints = [];
		var leader = 0;

		this.game.settings.players.forEach((player, i) => {
			playerPoints[i] = this.calculateTotalPoints(i, roundIndex);

			if (playerPoints[i] >= playerPoints[leader]) {
				leader = i;
			}
		});

		var threshold = parseInt(this.game.settings.blindBidThreshold);
		var canBlindBid = !isNaN(threshold) && (playerPoints[playerIndex] + threshold) <= playerPoints[leader];

		this.game.rounds[roundIndex].players[playerIndex].canBlindBid = canBlindBid;

		return canBlindBid;
	}

	getLeaderboard() {
		var leaderboard = [];

		this.game.settings.players.forEach((player, playerIndex) => {
			leaderboard[playerIndex] = {
				player: player,
				points: this.calculateTotalPoints(playerIndex),
			};
		});

		leaderboard.sort((a, b) => {
			return b.points - a.points;
		});

		return leaderboard;
	}

	calculateBidderRestriction(roundIndex) {
		let bid = this.game.rounds[roundIndex].cards - this.calculateTotalBids(roundIndex, this.game.rounds[roundIndex].dealer);

		if (bid < 0) {
			return 'Can bid anything';
		} else {
			return 'Cannot bid ' + bid;
		}
	}

	calculateTotalBids(roundIndex, excludeDealer) {
		var bids = 0;

		for (var i = 0; i < this.game.rounds[roundIndex].players.length; i++) {
			if (i === excludeDealer) {
				continue;
			}

			bids += this.game.rounds[roundIndex].players[i].bid;
		}

		return bids;
	}

	getHighestCardCount() {
		return Math.max(this.game.settings.cardsInFirstRound, this.game.settings.cardsInLastRound);
	}
}

AppController.$inject = ['$scope'];

module.controller('AppController', AppController);<commit_msg>- clear local storage question on reload<commit_after>
if (confirm("Clear Local Storage?") == true) {
	window.localStorage.clear();
}

var module = angular.module('OhHell', []);

// bootstrap angular into the page
angular.element(document).ready(() => {
	angular.bootstrap(document.body, [module.name], {
		strictDi: true
	});
});

class AppController {
	constructor ($scope) {
		this.settings = this.getSettings();
		this.game = this.getGame();
		this.showFullScore = false;

		$scope.$watch('App.settings', (new_val, old_val) => {
			this.saveSettings();
		}, true);

		$scope.$watch('App.game', (new_val, old_val) => {
			this.saveGame();
			this.updateStats();
		}, true);

		this.updateStats();
	}

	addNewPlayer () {
		if (this.newPlayerName && this.settings.players.indexOf(this.newPlayerName) === -1) {
			this.settings.players.push(this.newPlayerName);
			this.newPlayerName = '';
		}
	}

	removePlayer (index) {
		this.settings.players.splice(index, 1);
	}

	startGame () {
		var rounds = [];
		var roundRange = this.roundRange(this.settings.cardsInFirstRound, this.settings.cardsInLastRound, this.settings.mirrorRounds);
		var dealer = this.generateRandomNumber(0, this.settings.players.length - 1);

		for (var i = 0; i < roundRange.length; i++) {
			if (i > 0) {
				dealer++;

				if (dealer >= this.settings.players.length) {
					dealer = 0;
				}
			}

			var round = {
				suit: this.generateRandomSuit(i === 0 ? null : rounds[i - 1].suit),
				cards: roundRange[i],
				dealer: dealer,
				players: [],
			};

			for (var j = 0; j < this.settings.players.length; j++) {
				round.players.push({
					bid: null,
					tricks: null,
				});
			}
			rounds.push(round);
		}

		this.game = {
			settings: this.settings,
			rounds: rounds,
			isFinished: false,
			currentRound: {
				index: 0,
				started: false,
			},
		};
	}

	getSettings () {
		var settings = localStorage.getItem('oh-hell-settings');

		try {
			settings = JSON.parse(settings);
		} catch (err) {
			settings = null;
		}

		if (!settings) {
			settings = this.getDefaultSettings();
		}

		return settings;
	}

	getDefaultSettings () {
		return {
			players: [],
		};
	}

	saveSettings () {
		localStorage.setItem('oh-hell-settings', JSON.stringify(this.settings));
	}

	getGame () {
		var game = localStorage.getItem('oh-hell-game');

		try {
			game = JSON.parse(game);
		} catch (err) {
			game = null;
		}

		return game;
	}

	saveGame () {
		localStorage.setItem('oh-hell-game', JSON.stringify(this.game));
	}

	roundRange (start, end, mirror) {
		var input = [];

		if (start < end) {
			for (var i = start; i <= end; i += 1) {
		        input.push(i);
		    }
		} else {
			for (var i = start; i >= end; i -= 1) {
		        input.push(i);
		    }
		}

		if (mirror) {
			input = input.concat(this.roundRange(end, start, false));
		}

	    return input;
	}

	calculateRoundPoints (playerIndex, roundIndex) {
		var cards = this.game.rounds[roundIndex].cards;
		var bid = parseInt(this.game.rounds[roundIndex].players[playerIndex].bid);
		var tricks = parseInt(this.game.rounds[roundIndex].players[playerIndex].tricks);
		var successful = tricks === bid;

		if (isNaN(bid) || isNaN(tricks)) {
			return null;
		}

		var points = 0;

		// award points per trick

		if (this.game.settings.winPointsPerTrick) {
			if (successful || !this.game.settings.winPointsPerTrickIfSuccessful) {
				if (tricks === 0 && this.game.settings.winPointsPerTrickIfZero) {
					points += 0.5;
				} else {
					points += tricks;
				}
			}
		}

		// lose points per trick different

		if (this.game.settings.losePointsPerDifference) {
			points -= Math.abs(tricks - bid);
		}

		// bonus points on successful bid

		var bonusSuccessful = parseInt(this.game.settings.pointsSuccessfulBid);
		if (successful && !isNaN(bonusSuccessful) ) {
			points += bonusSuccessful;
		}

		if (successful && this.game.settings.pointsSuccessfulVariable) {
			points += cards;
		}

		if (successful && this.game.settings.pointsSuccessfulInverse) {
			points += (this.getHighestCardCount() - cards + 1);
		}

		// negative points on unsuccessful bid

		var bonusUnsuccessful = parseInt(this.game.settings.pointsUnsuccessfulBid);
		if (!successful && !isNaN(bonusUnsuccessful)) {
			points -= bonusUnsuccessful;
		}

		if (!successful && this.game.settings.pointsUnsuccessfulVariable) {
			points -= cards;
		}

		if (!successful && this.game.settings.pointsUnsuccessfulInverse) {
			points -= (this.getHighestCardCount() - cards + 1);
		}

		// blind bid

		var blindBidBonus = parseInt(this.game.settings.blindBidBonus);
		if (successful && this.game.rounds[roundIndex].players[playerIndex].blind && !isNaN(blindBidBonus)) {
			points += blindBidBonus;
		}

		if (successful && this.game.rounds[roundIndex].players[playerIndex].blind && this.game.settings.blindBidDouble) {
			points *= 2;
		}

		// set the points

		this.game.rounds[roundIndex].players[playerIndex].points = points;

		return points;
	}

	calculateTotalPoints (playerIndex, roundIndex) {
		var totalPoints = 0;

		this.game.rounds.forEach((round, i) => {
			if (roundIndex && i >= roundIndex) {
				return true;
			}

			var roundPoints = this.calculateRoundPoints(playerIndex, i);

			if (roundPoints) {
				totalPoints += roundPoints;
			}
		});

		return totalPoints;
	}

	generateRandomSuit (previousSuit) {
		var suits = ['S', 'C', 'D', 'H'];
		var index = this.generateRandomNumber(0, 3);

		if (suits[index] === previousSuit) {
			return 'N';
		}

		return suits[index];
	}

	generateRandomNumber (first, last) {
		return Math.round(Math.random() * last) + first;
	}

	updateStats () {
		if (this.game && this.game.rounds) {
			this.updateBidAccuracyChart();
			this.updateBidCountChart();
			this.updateScoresChart();
		}
	}

	updateBidAccuracyChart () {
		var labels = [];

		this.game.settings.players.forEach((player) => {
			labels.push(player);
		});

		var datasets = [{
			label: 'Accurate Bid',
			backgroundColor: '#5cb85c',
			stack: 1,
			data: this.game.settings.players.map((player) => {
				return 0;
			}),
		}, {
			label: 'Underbid',
			backgroundColor: '#f0ad4e',
			stack: 1,
			data: this.game.settings.players.map((player) => {
				return 0;
			}),
		}, {
			label: 'Overbid',
			backgroundColor: '#c9302c',
			stack: 1,
			data: this.game.settings.players.map((player) => {
				return 0;
			}),
		}];

		this.game.rounds.forEach((round, roundIndex) => {
			round.players.forEach((player, playerIndex) => {
				var tricks = parseInt(player.tricks);
				var bid = parseInt(player.bid);

				if (!isNaN(tricks) && !isNaN(bid)) {
					if (tricks > bid) {
						datasets[1].data[playerIndex]++;
					} else if (tricks === bid) {
						datasets[0].data[playerIndex]++;
					} else if (tricks < bid) {
						datasets[2].data[playerIndex]++;
					}
				}
			});
		});

		if (this.chartBidAccuracy) {
			this.chartBidAccuracy.destroy();
		}

		this.chartBidAccuracy = new Chart(document.getElementById('chart-bid-accuracy'), {
		    type: 'bar',
		    data: {
		        labels: labels,
		        datasets: datasets
		    },
		    options: {
				legend: {
					display: false
				},
		        scales: {
		            yAxes: [{
		                ticks: {
		                    beginAtZero: true
		                }
		            }]
		        }
		    }
		});
	}

	updateBidCountChart () {
		var labels = [];
		var highestCardCount = this.getHighestCardCount();

		for (var i = 0; i <= highestCardCount; i++) {
			labels.push(i + ' Bid');
		}

		var datasets = [];

		this.game.rounds.forEach((round, roundIndex) => {
			round.players.forEach((player, playerIndex) => {
				var tricks = parseInt(player.tricks);
				var bid = parseInt(player.bid);

				if (!datasets[playerIndex]) {
					var data = [];
					labels.forEach((label) => {
						data.push(0);
					});

					datasets[playerIndex] = {
						label: this.game.settings.players[playerIndex],
						backgroundColor: this.getPlayerColour(playerIndex),
						borderColor: this.getPlayerColour(playerIndex),
						fill: false,
						data: data,
					}
				}

				if (!isNaN(bid)) {
					datasets[playerIndex].data[bid]++;
				}
			});
		});

		if (this.chartBidCounts) {
			this.chartBidCounts.destroy();
		}

		this.chartBidCounts = new Chart(document.getElementById('chart-bid-counts'), {
		    type: 'line',
		    data: {
		        labels: labels,
		        datasets: datasets
		    },
		    options: {
		        scales: {
		            yAxes: [{
		                ticks: {
		                    beginAtZero: true,
		                }
		            }]
		        }
		    }
		});
	}

	updateScoresChart() {
		var labels = [];

		for (var i = 1; i <= this.game.rounds.length; i++) {
			labels.push('Round ' + i);
		}
		console.log(labels);
		var datasets = [];

		this.game.rounds.forEach((round, roundIndex) => {
			round.players.forEach((player, playerIndex) => {
				if (!datasets[playerIndex]) {
					datasets[playerIndex] = {
						label: this.game.settings.players[playerIndex],
						backgroundColor: this.getPlayerColour(playerIndex),
						borderColor: this.getPlayerColour(playerIndex),
						fill: false,
						data: [],
					}
				}

				var points = parseInt(player.points);
				if (!isNaN(points)) {
					if (roundIndex === 0) {
						datasets[playerIndex].data.push(points);
					} else {
						datasets[playerIndex].data.push(datasets[playerIndex].data[roundIndex - 1] + points);
					}
				}
			});
		});

		if (this.chartBidScores) {
			this.chartBidScores.destroy();
		}
		console.log(this.game.rounds.length);
		this.chartBidScores = new Chart(document.getElementById('chart-bid-scores'), {
		    type: 'line',
		    data: {
		        labels: labels,
		        datasets: datasets
		    },
		    options: {
		        scales: {
		            yAxes: [{
		                ticks: {
							beginAtZero: true,
		                }
		            }]
		        }
		    }
		});
	}

	getPlayerColour (playerIndex) {
		return [
            '#EE2E2F',
            '#F47D23',
            '#008C48',
            '#185AA9',
            '#662C91',
            '#E76BC7',
        ][playerIndex];
	}

	getColumnWidth () {
		var columnCount = this.game.settings.players.length;

		if (this.showFullScore) {
			columnCount++;
		}

		return (100 / columnCount) + '%';
	}

	toggleStoreView () {
		this.showFullScore = !this.showFullScore;
	}

	startRound () {
		this.game.currentRound.started = true;
	}

	nextRound () {
		if (this.game.currentRound.index === (this.game.rounds.length - 1)) {
			this.game.leaderboard = this.getLeaderboard();
			this.game.isFinished = true;
		} else {
			this.game.currentRound.index++;
			this.game.currentRound.started = false;
		}
	}

	eligibleForBlindBid (playerIndex, roundIndex) {
		var playerPoints = [];
		var leader = 0;

		this.game.settings.players.forEach((player, i) => {
			playerPoints[i] = this.calculateTotalPoints(i, roundIndex);

			if (playerPoints[i] >= playerPoints[leader]) {
				leader = i;
			}
		});

		var threshold = parseInt(this.game.settings.blindBidThreshold);
		var canBlindBid = !isNaN(threshold) && (playerPoints[playerIndex] + threshold) <= playerPoints[leader];

		this.game.rounds[roundIndex].players[playerIndex].canBlindBid = canBlindBid;

		return canBlindBid;
	}

	getLeaderboard() {
		var leaderboard = [];

		this.game.settings.players.forEach((player, playerIndex) => {
			leaderboard[playerIndex] = {
				player: player,
				points: this.calculateTotalPoints(playerIndex),
			};
		});

		leaderboard.sort((a, b) => {
			return b.points - a.points;
		});

		return leaderboard;
	}

	calculateBidderRestriction(roundIndex) {
		let bid = this.game.rounds[roundIndex].cards - this.calculateTotalBids(roundIndex, this.game.rounds[roundIndex].dealer);

		if (bid < 0) {
			return 'Can bid anything';
		} else {
			return 'Cannot bid ' + bid;
		}
	}

	calculateTotalBids(roundIndex, excludeDealer) {
		var bids = 0;

		for (var i = 0; i < this.game.rounds[roundIndex].players.length; i++) {
			if (i === excludeDealer) {
				continue;
			}

			bids += this.game.rounds[roundIndex].players[i].bid;
		}

		return bids;
	}

	getHighestCardCount() {
		return Math.max(this.game.settings.cardsInFirstRound, this.game.settings.cardsInLastRound);
	}
}

AppController.$inject = ['$scope'];

module.controller('AppController', AppController);<|endoftext|>


<commit_before>'use strict';
const instance_url = process.env.INSTANCE_URL;
let app = instance_url ? instance_url : require('../../../src/backend/app');
let request = require('supertest-as-promised');
let integrationTestHelpers = require('./integrationTestHelpers.js');

describe('SuperAdminOnlyValidator Integration tests', () => {
    let agent;

    beforeEach(() => {
        agent = request.agent(app);
    });

    it('should respond with 401 when users try to access something they are NOT entitled to see', (done) => {
            integrationTestHelpers.createBranch()
            .then(integrationTestHelpers.createBranchAdmin)
            .then(integrationTestHelpers.authenticateOrganiser(agent))
            .then(() => {
                return agent.post(`/branches`)
                .set('Content-Type', 'application/json')
                .send({
                    name: 'Melbourne',
                    notes: 'organiser',
                    contact: 'hey i\'m a contact',
                })
                .expect(401);
            })
            .then(done, done.fail);
    });

    it('should respond with 200 when a super admin tries to access a superadmin only resource', (done) => {
        integrationTestHelpers.createSuperAdmin()
        .then(integrationTestHelpers.authenticateSuperAdmin(agent))
        .then(() => {
            return agent.post(`/branches`)
                .set('Content-Type', 'application/json')
                .send({
                    name: 'Melbourne',
                    notes: 'organiser',
                    contact: 'hey i\'m a contact',
                })
                .expect(200);
    })
    .then(done, done.fail);
    });
});
<commit_msg>tests for super admin validator<commit_after>'use strict';

require('../../support/specHelper');
const instance_url = process.env.INSTANCE_URL;
let app = instance_url ? instance_url : require('../../../src/backend/app');
let request = require('supertest-as-promised');
let integrationTestHelpers = require('./integrationTestHelpers.js');

describe('SuperAdminOnlyValidator Integration tests', () => {
    let agent;

    beforeEach(() => {
        agent = request.agent(app);
    });

    it('should respond with 401 when users try to access something they are NOT entitled to see', (done) => {
            integrationTestHelpers.createBranch()
            .then(integrationTestHelpers.createBranchAdmin)
            .then(integrationTestHelpers.authenticateOrganiser(agent))
            .then(() => {
                return agent.post(`/branches`)
                .set('Content-Type', 'application/json')
                .send({
                    name: 'Melbourne',
                    notes: 'organiser',
                    contact: 'hey i\'m a contact',
                })
                .expect(401);
            })
            .then(done, done.fail);
    });

    it('should respond with 200 when a super admin tries to access a superadmin only resource', (done) => {
        integrationTestHelpers.createSuperAdmin()
        .then(integrationTestHelpers.authenticateSuperAdmin(agent))
        .then(() => {
            return agent.post(`/branches`)
                .set('Content-Type', 'application/json')
                .send({
                    name: 'Melbourne',
                    notes: 'organiser',
                    contact: 'hey i\'m a contact',
                })
                .expect(200);
    })
    .then(done, done.fail);
    });
});
<|endoftext|>


<commit_before>/**
 * Wrapper around brackets pref system to ensure preferences are stored in in one single object instead of using multiple keys.
 * This is to make it easy for the user who edits their preferences file to easily manage the potentially numerous lines of preferences generated by the persisting code-folding state.
 * @author Patrick Oladimeji
 * @date 3/22/14 20:39:53 PM
 */
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, brackets*/
define(function (require, exports, module) {
    "use strict";
    var PreferencesManager          = brackets.getModule("preferences/PreferencesManager"),
        prefs                       = PreferencesManager.getExtensionPrefs("code-folding"),
        foldsKey                    = "code-folding.folds",
        // preference key strings are here for now since they are not used in any UI
        ENABLE_CODE_FOLDING         = "Enable code folding",
        MIN_FOLD_SIZE               = "Minimum fold size",
        MIN_FOLD_SIZE_HELP          = "Minimum number of lines to allow in a foldable range",
        SAVE_FOLD_STATES            = "Save fold states",
        SAVE_FOLD_STATES_HELP       = "Save fold states to disk when editor is closed and restore the folds when reopened",
        ALWAYS_USE_INDENT_FOLD      = "Always use indent fold",
        ALWAYS_USE_INDENT_FOLD_HELP = "Fall back to using level of indentation as a folding guideline if no range finder is found for the current mode.",
        HIDE_FOLD_BUTTONS           = "Hide fold triangles",
        HIDE_FOLD_BUTTONS_HELP      = "Hide fold triangles unless the mouse is over the gutter",
        MAX_FOLD_LEVEL              = "Max fold level",
        MAX_FOLD_LEVEL_HELP         = "Used to limit the number of nested folds to find and collapse when View -> Collapse All is called or Alt is held down when collapsing. Should improve performance for large files.";

    //default preference values
    prefs.definePreference("enabled", "boolean", true,
                           {name: ENABLE_CODE_FOLDING, description: ENABLE_CODE_FOLDING});
    prefs.definePreference("minFoldSize", "number", 2,
                           {name: MIN_FOLD_SIZE, description: MIN_FOLD_SIZE_HELP});
    prefs.definePreference("saveFoldStates", "boolean", true,
                           {name: SAVE_FOLD_STATES, description: SAVE_FOLD_STATES_HELP});
    prefs.definePreference("alwaysUseIndentFold", "boolean", false,
                           {name: ALWAYS_USE_INDENT_FOLD, description: ALWAYS_USE_INDENT_FOLD_HELP});
    prefs.definePreference("hideUntilMouseover", "boolean", false,
                           {name: HIDE_FOLD_BUTTONS, description: HIDE_FOLD_BUTTONS_HELP});
    prefs.definePreference("maxFoldLevel", "number", 2,
                           {name: MAX_FOLD_LEVEL, description: MAX_FOLD_LEVEL_HELP});
    PreferencesManager.stateManager.definePreference(foldsKey, "object", {});

    /**
      * Simplifies the fold ranges into an array of pairs of numbers.
      * @param {!Object} folds the raw fold ranges indexed by line numbers
      * @return {Object} an object whose keys are line numbers and the values are array
      * of two 2-element arrays. First array contains [from.line, from.ch] and the second contains [to.line, to.ch]
      */
    function simplify(folds) {
        if (!folds) {
            return;
        }
        var res = {}, range;
        Object.keys(folds).forEach(function (line) {
            range = folds[line];
            res[line] = Array.isArray(range) ? range : [[range.from.line, range.from.ch], [range.to.line, range.to.ch]];
        });
        return res;
    }

    /**
      * Inflates the fold ranges stored as simplified numeric arrays. The inflation converts the data into
      * objects whose keys are line numbers and whose values are objects in the format {from: {line, ch}, to: {line, ch}}.
      * @param {Object}  folds the simplified fold ranges
      * @return {Object} the converted fold ranges
      */
    function inflate(folds) {
        if (!folds) {
            return;
        }
         //transform the folds into objects with from and to properties
        var ranges = {}, obj;
        Object.keys(folds).forEach(function (line) {
            obj = folds[line];
            ranges[line] = {from: {line: obj[0][0], ch: obj[0][1]}, to: {line: obj[1][0], ch: obj[1][1]}};
        });

        return ranges;
    }

    /**
      * Gets the line folds saved for the specified path.
      * @param {string} path the document path
      * @return {Object} the line folds for the document at the specified path
      */
    function getFolds(path) {
        var folds = PreferencesManager.getViewState(foldsKey);
        return inflate(folds[path]);
    }

    /**
      * Saves the line folds for the specified path
      * @param {!string} path the path to the document
      * @param {Object} folds the fold ranges to save for the current document
      */
    function setFolds(path, folds) {
        var allFolds = PreferencesManager.getViewState(foldsKey);
        allFolds[path] = simplify(folds);
        PreferencesManager.setViewState(foldsKey, allFolds);
    }

    /**
      * Get the code folding setting with the specified key from the store
      * @param {!string} key The key for the setting to retrieve
      * @return {string} the setting with the specified key
      */
    function getSetting(key) {
        return prefs.get(key);
    }

    /**
      * Clears all the saved line folds for all documents.
      */
    function clearAllFolds() {
        PreferencesManager.setViewState(foldsKey, {});
    }

    module.exports.getFolds = getFolds;
    module.exports.setFolds = setFolds;
    module.exports.getSetting = getSetting;
    module.exports.clearAllFolds = clearAllFolds;
    module.exports.prefsObject = prefs;
});
<commit_msg>Store code-folding view state in project-specific buckets for cleaner organization. If we later offer a way for users to delete stored data for a project, this ensures code folding data will be cleaned up along with everything else. (This is also how we store Quick Edit expand/collapse state, which is very similar).<commit_after>/**
 * Wrapper around brackets pref system to ensure preferences are stored in in one single object instead of using multiple keys.
 * This is to make it easy for the user who edits their preferences file to easily manage the potentially numerous lines of preferences generated by the persisting code-folding state.
 * @author Patrick Oladimeji
 * @date 3/22/14 20:39:53 PM
 */
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, brackets*/
define(function (require, exports, module) {
    "use strict";

    var ProjectManager              = brackets.getModule("project/ProjectManager"),
        PreferencesManager          = brackets.getModule("preferences/PreferencesManager"),
        prefs                       = PreferencesManager.getExtensionPrefs("code-folding"),
        FOLDS_PREF_KEY              = "code-folding.folds",
        // preference key strings are here for now since they are not used in any UI
        ENABLE_CODE_FOLDING         = "Enable code folding",
        MIN_FOLD_SIZE               = "Minimum fold size",
        MIN_FOLD_SIZE_HELP          = "Minimum number of lines to allow in a foldable range",
        SAVE_FOLD_STATES            = "Save fold states",
        SAVE_FOLD_STATES_HELP       = "Save fold states to disk when editor is closed and restore the folds when reopened",
        ALWAYS_USE_INDENT_FOLD      = "Always use indent fold",
        ALWAYS_USE_INDENT_FOLD_HELP = "Fall back to using level of indentation as a folding guideline if no range finder is found for the current mode.",
        HIDE_FOLD_BUTTONS           = "Hide fold triangles",
        HIDE_FOLD_BUTTONS_HELP      = "Hide fold triangles unless the mouse is over the gutter",
        MAX_FOLD_LEVEL              = "Max fold level",
        MAX_FOLD_LEVEL_HELP         = "Used to limit the number of nested folds to find and collapse when View -> Collapse All is called or Alt is held down when collapsing. Should improve performance for large files.";

    //default preference values
    prefs.definePreference("enabled", "boolean", true,
                           {name: ENABLE_CODE_FOLDING, description: ENABLE_CODE_FOLDING});
    prefs.definePreference("minFoldSize", "number", 2,
                           {name: MIN_FOLD_SIZE, description: MIN_FOLD_SIZE_HELP});
    prefs.definePreference("saveFoldStates", "boolean", true,
                           {name: SAVE_FOLD_STATES, description: SAVE_FOLD_STATES_HELP});
    prefs.definePreference("alwaysUseIndentFold", "boolean", false,
                           {name: ALWAYS_USE_INDENT_FOLD, description: ALWAYS_USE_INDENT_FOLD_HELP});
    prefs.definePreference("hideUntilMouseover", "boolean", false,
                           {name: HIDE_FOLD_BUTTONS, description: HIDE_FOLD_BUTTONS_HELP});
    prefs.definePreference("maxFoldLevel", "number", 2,
                           {name: MAX_FOLD_LEVEL, description: MAX_FOLD_LEVEL_HELP});

    PreferencesManager.stateManager.definePreference(FOLDS_PREF_KEY, "object", {});

    /**
      * Simplifies the fold ranges into an array of pairs of numbers.
      * @param {!Object} folds the raw fold ranges indexed by line numbers
      * @return {Object} an object whose keys are line numbers and the values are array
      * of two 2-element arrays. First array contains [from.line, from.ch] and the second contains [to.line, to.ch]
      */
    function simplify(folds) {
        if (!folds) {
            return;
        }
        var res = {}, range;
        Object.keys(folds).forEach(function (line) {
            range = folds[line];
            res[line] = Array.isArray(range) ? range : [[range.from.line, range.from.ch], [range.to.line, range.to.ch]];
        });
        return res;
    }

    /**
      * Inflates the fold ranges stored as simplified numeric arrays. The inflation converts the data into
      * objects whose keys are line numbers and whose values are objects in the format {from: {line, ch}, to: {line, ch}}.
      * @param {Object}  folds the simplified fold ranges
      * @return {Object} the converted fold ranges
      */
    function inflate(folds) {
        if (!folds) {
            return;
        }
         //transform the folds into objects with from and to properties
        var ranges = {}, obj;
        Object.keys(folds).forEach(function (line) {
            obj = folds[line];
            ranges[line] = {from: {line: obj[0][0], ch: obj[0][1]}, to: {line: obj[1][0], ch: obj[1][1]}};
        });

        return ranges;
    }

    /**
     * Returns a 'context' object for getting/setting project-specific view state preferences.
     * Similar to code in MultiRangeInlineEditor._getPrefsContext()...
     */
    function getViewStateContext() {
        var projectRoot = ProjectManager.getProjectRoot();  // note: null during unit tests!
        return { location : { scope: "user",
                              layer: "project",
                              layerID: projectRoot && projectRoot.fullPath } };
    }

    /**
      * Gets the line folds saved for the specified path.
      * @param {string} path the document path
      * @return {Object} the line folds for the document at the specified path
      */
    function getFolds(path) {
        var context = getViewStateContext();
        var folds = PreferencesManager.getViewState(FOLDS_PREF_KEY, context);
        return inflate(folds[path]);
    }

    /**
      * Saves the line folds for the specified path
      * @param {!string} path the path to the document
      * @param {Object} folds the fold ranges to save for the current document
      */
    function setFolds(path, folds) {
        var context = getViewStateContext();
        var allFolds = PreferencesManager.getViewState(FOLDS_PREF_KEY, context);
        allFolds[path] = simplify(folds);
        PreferencesManager.setViewState(FOLDS_PREF_KEY, allFolds, context);
    }

    /**
      * Get the code folding setting with the specified key from the store
      * @param {!string} key The key for the setting to retrieve
      * @return {string} the setting with the specified key
      */
    function getSetting(key) {
        return prefs.get(key);
    }

    /**
      * Clears all the saved line folds for all documents.
      */
    function clearAllFolds() {
        PreferencesManager.setViewState(FOLDS_PREF_KEY, {});
    }

    module.exports.getFolds = getFolds;
    module.exports.setFolds = setFolds;
    module.exports.getSetting = getSetting;
    module.exports.clearAllFolds = clearAllFolds;
    module.exports.prefsObject = prefs;
});
<|endoftext|>


<commit_before>/* jslint node: true */
"use strict";

module.exports = ObjectArray;
function ObjectArray(){
  var args = Array.prototype.slice.call(arguments);
  this.splice.apply(this,[0,0].concat(args));
}
ObjectArray.prototype = [];

ObjectArray.prototype.constructor = ObjectArray;

ObjectArray.prototype.insert = function(element,index,pid){
  if(typeof index === 'string'){index = this.search(index,pid);}
  if(Math.floor(index) === parseFloat(index,10) && index>=0 && index<=this.length){
    this.splice(index,0,element);
  } else {
    this.push(element);
  }
  return this;
};
ObjectArray.prototype.insertAfter = function(element,index,pid){
  if(typeof index === 'string'){index = this.search(index,pid);}
  index++;
  if(Math.floor(index) === parseFloat(index,10) && index>=0 && index<=this.length){
    this.splice(index,0,element);
  } else {
    this.push(element);
  }
  return this;
};
ObjectArray.prototype.get = function(index,pid){
  if(typeof index === 'string'){index = this.search(index,pid);}
  if(Math.floor(index) === parseFloat(index,10) && index>=0 && index<=this.length){
    return this[index];
  }
};
ObjectArray.prototype.search = function(index,pid){
  pid = pid || 'id';
  for(var i=0,l=this.length;i<l;i++){
    if(this[i][pid] === index){
      return i;
    }
  }
};
ObjectArray.prototype.move = function(index,indexTo,pid){
  if(typeof index === 'string'){index = this.search(index,pid);}
  if(!(Math.floor(index) === parseFloat(index,10) && index>=0 && index<this.length)){
    return;
  }
  var copy = this[index];
  if(typeof indexTo === 'string'){indexTo = this.search(indexTo,pid);}
  if(index == indexTo || index==indexTo-1){
    return;
  }
  if(Math.floor(indexTo) === parseFloat(indexTo,10) && indexTo>=0 && indexTo<=this.length){
    this.splice(indexTo, 0, copy);
    this.splice(index > indexTo ? index+1 : index, 1);
  } else {
    this.push(copy);
    this.splice(index, 1);
  }
  return true;
};
ObjectArray.prototype.moveAfter = function(index,indexTo,pid){
  if(typeof index === 'string'){index = this.search(index,pid);}
  if(!(Math.floor(index) === parseFloat(index,10) && index>=0 && index<this.length)){
    return;
  }
  var copy = this[index];
  if(typeof indexTo === 'string'){indexTo = this.search(indexTo,pid);}
  if(index == indexTo || index==indexTo+1){
    return;
  }
  if(Math.floor(indexTo) === parseFloat(indexTo,10) && indexTo>=0 && indexTo<=this.length){
    indexTo++;
    this.splice(indexTo, 0, copy);
    this.splice(index > indexTo ? index+1 : index, 1);
  } else {
    this.push(copy);
    this.splice(index, 1);
  }
  return true;
};
ObjectArray.prototype.remove = function(index,pid){
  if(typeof index === 'string'){index = this.search(index,pid);}
  if(Math.floor(index) === parseFloat(index,10) && index>=0 && index<=this.length){
    this.splice(index, 1);
    return true;
  } else {
    return undefined;
  }
};
<commit_msg>fixes from test<commit_after>/* jslint node: true */
"use strict";

module.exports = ObjectArray;
function ObjectArray(){
  var args = Array.prototype.slice.call(arguments);
  this.splice.apply(this,[0,0].concat(args));
  this.pid = 'id';
}
  ObjectArray.prototype = [];
  ObjectArray.prototype.constructor = Array;

  ObjectArray.prototype.insert = function(element,index,pid,after){
    index = typeof index === 'string' ? this.search(index,pid) : index === -1 ? this.length : index;
    index += after ? 1 : 0;
    if(Math.floor(index) !== parseFloat(index,10) || index<0 || index>this.length){
      this.push(element);
    } else {
      this.splice(index,0,element);
    }
    return this;
  };

  ObjectArray.prototype.insertAfter = function(element,index,pid){
    return this.insert(element,index,pid,true);
  };

  ObjectArray.prototype.add = ObjectArray.prototype.insert;

  ObjectArray.prototype.addAfter = ObjectArray.prototype.insertAfter;

  ObjectArray.prototype.get = function(index,pid){
    index = typeof index === 'string' ? this.search(index,pid) : index === -1 ? this.length : index;
    if(Math.floor(index) !== parseFloat(index,10) || index<0 || index>this.length){
      return;
    } else {
      return this[index];
    }
  };

  ObjectArray.prototype.search = function(index,pid){
    pid = pid || this.pid || 'id';
    for(var i=0,l=this.length;i<l;i++){
      if(this[i][pid] === index){
        return i;
      }
    }
  };

  ObjectArray.prototype.move = function(index,indexTo,pid,after){
    index = typeof index === 'string' ? this.search(index,pid) : index === -1 ? this.length : index;
    if(Math.floor(index) !== parseFloat(index,10) || index<0 || index>this.length){
      return false;
    }
    indexTo = typeof indexTo === 'string' ? indexTo.search(indexTo,pid) : indexTo === -1 ? this.length : indexTo;
    if(Math.floor(indexTo) !== parseFloat(indexTo,10) || indexTo<0 || indexTo>this.length){
      return false;
    }
    indexTo += after ? 1 : 0;
    if(index == indexTo || index==indexTo-1){
      return true;
    }
    var copy = this[index];
    this.splice(indexTo, 0, copy);
    this.splice(index > indexTo ? index+1 : index, 1);
    return true;
  };

  ObjectArray.prototype.moveAfter = function(index,indexTo,pid){
    this.move(index,indexTo,pid,true);
  };

  ObjectArray.prototype.remove = function(index,pid){
    index = typeof index === 'string' ? this.search(index,pid) : index === -1 ? this.length : index;
    if(Math.floor(index) !== parseFloat(index,10) || index<0 || index>this.length){
      return false;
    } else {
      this.splice(index, 1);
    }
  };
<|endoftext|>


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

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4,
maxerr: 50, browser: true */
/*global $, define, brackets */

define(function (require, exports, module) {
    "use strict";

    var AppInit              = brackets.getModule("utils/AppInit"),
        ExtensionUtils       = brackets.getModule("utils/ExtensionUtils"),
        FileUtils            = brackets.getModule("file/FileUtils"),
        LiveDevServerManager = brackets.getModule("LiveDevelopment/LiveDevServerManager"),
        NodeConnection       = brackets.getModule("utils/NodeConnection"),
        ProjectManager       = brackets.getModule("project/ProjectManager");

    /**
     * @const
     * Amount of time to wait before automatically rejecting the connection
     * deferred. If we hit this timeout, we'll never have a node connection
     * for the static server in this run of Brackets.
     */
    var NODE_CONNECTION_TIMEOUT = 30000; // 30 seconds

    /**
     * @private
     * @type{jQuery.Deferred.<NodeConnection>}
     * A deferred which is resolved with a NodeConnection or rejected if
     * we are unable to connect to Node.
     */
    var _nodeConnectionDeferred = $.Deferred();

    var _baseUrl = "";

    /**
     * @constructor
     */
    function StaticServerProvider() {}

    /**
     * Determines whether we can serve local file.
     *
     * @param {String} localPath
     * A local path to file being served.
     *
     * @return {Boolean}
     * true for yes, otherwise false.
     */
    StaticServerProvider.prototype.canServe = function (localPath) {

        if (_nodeConnectionDeferred.isRejected()) {
            return false;
        }

        if (!ProjectManager.isWithinProject(localPath)) {
            return false;
        }

        // Url ending in "/" implies default file, which is usually index.html.
        // Return true to indicate that we can serve it.
        if (localPath.match(/\/$/)) {
            return true;
        }

        // FUTURE: do a MIME Type lookup on file extension
        return FileUtils.isStaticHtmlFileExt(localPath);
    };

    /**
     * Returns a base url for current project.
     *
     * @return {String}
     * Base url for current project.
     */
    StaticServerProvider.prototype.getBaseUrl = function () {
        return _baseUrl;
    };

    /**
     * # LiveDevServerProvider.readyToServe()
     *
     * Gets the server details from the StaticServerDomain in node.
     * The domain itself handles starting a server if necessary (when
     * the staticServer.getServer command is called).
     *
     * @return {jQuery.Promise} A promise that resolves/rejects when
     *     the server is ready/failed.
     */
    StaticServerProvider.prototype.readyToServe = function () {
        var readyToServeDeferred = $.Deferred();

        _nodeConnectionDeferred.done(function (nodeConnection) {
            if (nodeConnection.connected()) {
                var projectPath = ProjectManager.getProjectRoot().fullPath;
                nodeConnection.domains.staticServer.getServer(
                    projectPath
                ).done(function (address) {
                    _baseUrl = "http://" + address.address + ":" + address.port + "/";
                    readyToServeDeferred.resolve();
                }).fail(function () {
                    _baseUrl = "";
                    readyToServeDeferred.reject();
                });
            } else { // nodeConnection not currently connected
                // If we are in this case, then the node process has crashed
                // and is in the process of restarting. Once that happens, the
                // node connection will automatically reconnect and reload the
                // domain. Unfortunately, we don't have any promise to wait on
                // to know when that happens. The best we can do is reject this
                // readyToServe so that the user gets an error message to try
                // again later.
                readyToServeDeferred.reject();
            }
        });

        _nodeConnectionDeferred.fail(function () {
            readyToServeDeferred.reject();
        });

        return readyToServeDeferred.promise();
    };

    /**
     * @private
     * @type{StaticServerProvider}
     * Stores the singleton StaticServerProvider for use in unit testing.
     */
    var _staticServerProvider = new StaticServerProvider();

    /**
     * @private
     * @return {StaticServerProvider} The singleton StaticServerProvider initialized
     * on app ready.
     */
    function _getStaticServerProvider() {
        return _staticServerProvider;
    }

    AppInit.appReady(function () {
        // Register as a Live Development server provider
        LiveDevServerManager.registerProvider(_staticServerProvider, 5);

        // Start up the node connection, which is held in the
        // _nodeConnectionDeferred module variable. (Use
        // _nodeConnectionDeferred.done() to access it.
        var connectionTimeout = setTimeout(function () {
            console.error("[StaticServer] Timed out while trying to connect to node");
            _nodeConnectionDeferred.reject();
        }, NODE_CONNECTION_TIMEOUT);

        var _nodeConnection = new NodeConnection();
        _nodeConnection.connect(true).then(function () {
            _nodeConnection.loadDomains(
                [ExtensionUtils.getModulePath(module, "node/StaticServerDomain")],
                true
            ).then(
                function () {
                    clearTimeout(connectionTimeout);
                    _nodeConnectionDeferred.resolveWith(null, [_nodeConnection]);
                },
                function () { // Failed to connect
                    console.error("[StaticServer] Failed to connect to node", arguments);
                    _nodeConnectionDeferred.reject();
                }
            );
        });
    });

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

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4,
maxerr: 50, browser: true */
/*global $, define, brackets */

define(function (require, exports, module) {
    "use strict";

    var AppInit              = brackets.getModule("utils/AppInit"),
        ExtensionUtils       = brackets.getModule("utils/ExtensionUtils"),
        FileUtils            = brackets.getModule("file/FileUtils"),
        LiveDevServerManager = brackets.getModule("LiveDevelopment/LiveDevServerManager"),
        NodeConnection       = brackets.getModule("utils/NodeConnection"),
        ProjectManager       = brackets.getModule("project/ProjectManager");

    /**
     * @const
     * Amount of time to wait before automatically rejecting the connection
     * deferred. If we hit this timeout, we'll never have a node connection
     * for the static server in this run of Brackets.
     */
    var NODE_CONNECTION_TIMEOUT = 30000; // 30 seconds

    /**
     * @private
     * @type{jQuery.Deferred.<NodeConnection>}
     * A deferred which is resolved with a NodeConnection or rejected if
     * we are unable to connect to Node.
     */
    var _nodeConnectionDeferred = $.Deferred();

    var _baseUrl = "";

    /**
     * @constructor
     */
    function StaticServerProvider() {}

    /**
     * Determines whether we can serve local file.
     *
     * @param {String} localPath
     * A local path to file being served.
     *
     * @return {Boolean}
     * true for yes, otherwise false.
     */
    StaticServerProvider.prototype.canServe = function (localPath) {

        if (!_nodeConnectionDeferred.isResolved()) {
            return false;
        }

        if (!ProjectManager.isWithinProject(localPath)) {
            return false;
        }

        // Url ending in "/" implies default file, which is usually index.html.
        // Return true to indicate that we can serve it.
        if (localPath.match(/\/$/)) {
            return true;
        }

        // FUTURE: do a MIME Type lookup on file extension
        return FileUtils.isStaticHtmlFileExt(localPath);
    };

    /**
     * Returns a base url for current project.
     *
     * @return {String}
     * Base url for current project.
     */
    StaticServerProvider.prototype.getBaseUrl = function () {
        return _baseUrl;
    };

    /**
     * # LiveDevServerProvider.readyToServe()
     *
     * Gets the server details from the StaticServerDomain in node.
     * The domain itself handles starting a server if necessary (when
     * the staticServer.getServer command is called).
     *
     * @return {jQuery.Promise} A promise that resolves/rejects when
     *     the server is ready/failed.
     */
    StaticServerProvider.prototype.readyToServe = function () {
        var readyToServeDeferred = $.Deferred();

        _nodeConnectionDeferred.done(function (nodeConnection) {
            if (nodeConnection.connected()) {
                nodeConnection.domains.staticServer.getServer(
                    ProjectManager.getProjectRoot().fullPath
                ).done(function (address) {
                    _baseUrl = "http://" + address.address + ":" + address.port + "/";
                    readyToServeDeferred.resolve();
                }).fail(function () {
                    _baseUrl = "";
                    readyToServeDeferred.reject();
                });
            } else {
                // nodeConnection has been connected once (because the deferred
                // resolved, but is not currently connected).
                //
                // If we are in this case, then the node process has crashed
                // and is in the process of restarting. Once that happens, the
                // node connection will automatically reconnect and reload the
                // domain. Unfortunately, we don't have any promise to wait on
                // to know when that happens. The best we can do is reject this
                // readyToServe so that the user gets an error message to try
                // again later.
                //
                // The user will get the error immediately in this state, and
                // the new node process should start up in a matter of seconds
                // (assuming there isn't a more widespread error). So, asking
                // them to retry in a second is reasonable.
                readyToServeDeferred.reject();
            }
        });

        _nodeConnectionDeferred.fail(function () {
            readyToServeDeferred.reject();
        });

        return readyToServeDeferred.promise();
    };

    /**
     * @private
     * @type{StaticServerProvider}
     * Stores the singleton StaticServerProvider for use in unit testing.
     */
    var _staticServerProvider = new StaticServerProvider();

    /**
     * @private
     * @return {StaticServerProvider} The singleton StaticServerProvider initialized
     * on app ready.
     */
    function _getStaticServerProvider() {
        return _staticServerProvider;
    }

    AppInit.appReady(function () {
        // Register as a Live Development server provider
        LiveDevServerManager.registerProvider(_staticServerProvider, 5);

        // Start up the node connection, which is held in the
        // _nodeConnectionDeferred module variable. (Use
        // _nodeConnectionDeferred.done() to access it.
        var connectionTimeout = setTimeout(function () {
            console.error("[StaticServer] Timed out while trying to connect to node");
            _nodeConnectionDeferred.reject();
        }, NODE_CONNECTION_TIMEOUT);

        var _nodeConnection = new NodeConnection();
        _nodeConnection.connect(true).then(function () {
            _nodeConnection.loadDomains(
                [ExtensionUtils.getModulePath(module, "node/StaticServerDomain")],
                true
            ).then(
                function () {
                    clearTimeout(connectionTimeout);
                    _nodeConnectionDeferred.resolveWith(null, [_nodeConnection]);
                },
                function () { // Failed to connect
                    console.error("[StaticServer] Failed to connect to node", arguments);
                    _nodeConnectionDeferred.reject();
                }
            );
        });
    });

    // For unit tests only
    exports._getStaticServerProvider = _getStaticServerProvider;
});
<|endoftext|>


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

/**
 * Module dependencies.
 */
require('shelljs/global');

var moment                = require('moment');
var tpl                   = require('tpl_apply');
var Promise               = require("bluebird");
var fs                    = Promise.promisifyAll(require("fs"));
var program               = require('commander');
var get_collection_names  = require('get_collection_names');
var child_process         = require('child_process');
var current_path          = process.cwd();

if (!which('mongoexport')) {
  echo('Sorry, this script requires mongoexport');
  exit(1);
}

if (!which('git')) {
  echo('Sorry, this script requires git');
  exit(1);
}

var config_file = current_path + '/mongo.config.json';
var source = __dirname + '/tpl.js'
var dest = process.cwd() + '/export.sh'

program
  .version('1.0.0')
  .option('-i, --init', 'init')
  .parse(process.argv);

console.log('moa mongodb-backup');

if(program.init){
  console.log('init config...');

  // Copy files to release dir
  cp('-f', __dirname +  '/mongo.config.json', current_path + '');
}else{
  if(fs.existsSync(config_file) == true) {
    fs.readFileAsync(config_file, {
      encoding: 'utf-8'
    }).then(function(str){
    		var _new_json_string = JSON.parse(JSON.stringify(str));
    		var obj = JSON.parse(_new_json_string);
    		return Promise.resolve(obj);
    	}).then(function(config){
        var host  = config.host;
        var port  = config.port;
        var db    = config.db;

        get_collection_names(host, port, db, function(err, collection_names){
          console.log(collection_names);
          generate_shell(config, collection_names)
        })
    	}).catch(function(err){
    	  console.log(err);
    	});
  }
}

function generate_shell (config, collection_names) {
  tpl.tpl_apply(source, {
    config            : config,
  	collection_names  : collection_names
  }, dest);

  var generated_dirname = moment().format(config.dirname);

  setTimeout(function(){
    chmod('u+x', dest);
    // execFile: executes a file with the specified arguments
    child_process.execFile(dest, [generated_dirname],
      {cwd:current_path}, function (error, stdout, stderr) {
        if (error !== null) {
          console.log('exec error: ' + error);
        }else{
          console.log('exec sucess!');
        }
    });
  }, 200);
}
<commit_msg>fixed when config.dirname = YYYY-MM-DD HH:mm:ss<commit_after>#!/usr/bin/env node

/**
 * Module dependencies.
 */
require('shelljs/global');

var moment                = require('moment');
var tpl                   = require('tpl_apply');
var Promise               = require("bluebird");
var fs                    = Promise.promisifyAll(require("fs"));
var program               = require('commander');
var get_collection_names  = require('get_collection_names');
var child_process         = require('child_process');
var current_path          = process.cwd();

if (!which('mongoexport')) {
  echo('Sorry, this script requires mongoexport');
  exit(1);
}

if (!which('git')) {
  echo('Sorry, this script requires git');
  exit(1);
}

var config_file = current_path + '/mongo.config.json';
var source = __dirname + '/tpl.js'
var dest = process.cwd() + '/export.sh'

program
  .version('1.0.0')
  .option('-i, --init', 'init')
  .parse(process.argv);

console.log('moa mongodb-backup');

if(program.init){
  console.log('init config...');

  // Copy files to release dir
  cp('-f', __dirname +  '/mongo.config.json', current_path + '');
}else{
  if(fs.existsSync(config_file) == true) {
    fs.readFileAsync(config_file, {
      encoding: 'utf-8'
    }).then(function(str){
    		var _new_json_string = JSON.parse(JSON.stringify(str));
    		var obj = JSON.parse(_new_json_string);
    		return Promise.resolve(obj);
    	}).then(function(config){
        var host  = config.host;
        var port  = config.port;
        var db    = config.db;

        get_collection_names(host, port, db, function(err, collection_names){
          console.log(collection_names);
          generate_shell(config, collection_names)
        })
    	}).catch(function(err){
    	  console.log(err);
    	});
  }
}

function generate_shell (config, collection_names) {
  tpl.tpl_apply(source, {
    config            : config,
  	collection_names  : collection_names
  }, dest);

  var generated_dirname = moment().format(config.dirname);
  if(generated_dirname.split(' ').length > 0){
    generated_dirname = generated_dirname.split(' ').join('_');
  }

  setTimeout(function(){
    chmod('u+x', dest);
    // execFile: executes a file with the specified arguments
    child_process.execFile(dest, [generated_dirname],
      {cwd:current_path}, function (error, stdout, stderr) {
        if (error !== null) {
          console.log('exec error: ' + error);
        }else{
          console.log('exec sucess!');
        }
    });
  }, 200);
}
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var Readable = require('stream').Readable;

var base64 = require('base64-stream');

module.exports = function (filePathOrStream, callback) {
  var metadata = {};
  var outputStream = process.stdout;
  var inputStream;

  if (typeof filePathOrStream === 'string') {
    var stat = fs.statSync(filePathOrStream);
    inputStream  = fs.createReadStream(filePathOrStream);
    metadata.size = stat.size;
    metadata.name = new Buffer(path.basename(filePathOrStream, true)).toString('base64');
  } else if (filePathOrStream instanceof Readable) {
    inputStream = filePathOrStream;
  } else {
    throw new Error('Parameter should be either a filepath or stream');
  }

  // TODO Parametrize me
  metadata.inline = 1;

  outputStream.write('\033]1337;');

  var s = 'File=';

  Object.keys(metadata).forEach(function (key) {
    var value = metadata[key];
    s += key + '=' + value + ';';
  });

  s = s.slice(0, -1) + ':';

  outputStream.write(s);

  var x = inputStream.pipe(base64.encode()).pipe(outputStream);
  inputStream.on('end', function () {
    outputStream.write('\07\n');
    if (callback) {
      callback();
    }
  });
};
<commit_msg>Fixes valid streams not recognized as streams.<commit_after>var fs = require('fs');
var path = require('path');
var Readable = require('stream').Readable;

var base64 = require('base64-stream');

module.exports = function (filePathOrStream, callback) {
  var metadata = {};
  var outputStream = process.stdout;
  var inputStream;

  if (typeof filePathOrStream === 'string') {
    var stat = fs.statSync(filePathOrStream);
    inputStream  = fs.createReadStream(filePathOrStream);
    metadata.size = stat.size;
    metadata.name = new Buffer(path.basename(filePathOrStream, true)).toString('base64');
  } else if (filePathOrStream) {
    // TODO better input validation
    inputStream = filePathOrStream;
  }

  // TODO Parametrize me
  metadata.inline = 1;

  outputStream.write('\033]1337;');

  var s = 'File=';

  Object.keys(metadata).forEach(function (key) {
    var value = metadata[key];
    s += key + '=' + value + ';';
  });

  s = s.slice(0, -1) + ':';

  outputStream.write(s);

  var x = inputStream.pipe(base64.encode()).pipe(outputStream);
  inputStream.on('end', function () {
    outputStream.write('\07\n');
    if (callback) {
      callback();
    }
  });
};
<|endoftext|>