<commit_before>(function(window, document, undefined) {

	// data specifically for the jobs page
	var jobsData = {
		header: "Job Postings",
		description: "Opportunities to work in sports analytics",
		navbarTitle: "Job Postings",
		jobs: [
			{
				company: "Toronto Blue Jays",
				title: "Baseball Operations Analytics Intern",
				location: "Toronto, ON, CA",
				description: "A Baseball Operations Analytics Intern is primarily responsible for assisting with day-to-day tasks within Baseball Operations.  Responsibilities vary dependent on the baseball calendar and internal sub-department needs (Amateur Scouting, Player Development, Pro Scouting and Baseball Information), with a heavy focus on analytics and research.",
				link: "https://jobs.rogers.com/job/Toronto-Baseball-Operations-Analytics-Intern-ON/302799300/",
				logo: "bluejays.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 30
					},
					due   : {
						year: 2015,
						month: 11,
						day: 13
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Houston Astros",
				title: "Analyst, Baseball Research and Development",
				location: "Houston, TX",
				description: "The Houston Astros are seeking an Analyst for the team's Baseball Research and Development group. The Analyst will work closely with the Director of R&D and the analytics team to conduct research and develop methods that encourage the effective understanding and application of information throughout Baseball Operations.",
				link: "http://www.baseballprospectus.com/article.php?articleid=27776",
				logo: "astros.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 28
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Second Spectrum",
				title: "Machine Learning Engineer",
				location: "Los Angeles, CA or Boston, MA",
				description: "Second Spectrum is seeking a Machine Learning Software Engineer to join our Data team.  At Second Spectrum the machine understanding of sports forms the foundation of all the products we deliver.  Machine Learning engineers have the opportunity to develop state of the art models whose results are used by coaches, broadcasters, and fans throughout the world.",
				link: "http://www.secondspectrum.com/careers-ml",
				logo: "second-spectrum.jpg",
				date: {},
				active: true,
				isTeam: false
			},
			{
				company: "Second Spectrum",
				title: "Full-Stack Software Engineer",
				location: "Los Angeles, CA or Shanghai",
				description: "Second Spectrum is seeking solid full-stack engineers to join our team and help build out infrastructure to support highly interactive applications. Full-stack engineers can range from specializing at systems engineering to UI/UX development.",
				link: "http://www.secondspectrum.com/careers-full-stack",
				logo: "second-spectrum.jpg",
				date: {},
				active: true,
				isTeam: false
			},
			{
				company: "Los Angeles Dodgers",
				title: "Analysis Associate",
				location: "Los Angeles, CA",
				description: "The Los Angeles Dodgers are seeking an Analysis Associate to join the team's Baseball Operations group starting in the fall of 2015. We consider our internship program to be a critical pipeline for recruiting full-time employees, though there is no guarantee of receiving a full-time offer after the internship is completed. Our current focus is on identifying highly-talented, mathematically-oriented candidates as we seek to build and develop our baseball analytics team.",
				link: "http://baseballjobs.teamworkonline.com/teamwork/r.cfm?i=88159",
				logo: "dodgers.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 21
					},
					due: {
						year: 2015,
						month: 11,
						day: 13
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Boston Red Sox",
				title: "Software Engineer",
				location: "Boston, MA",
				description: "The software engineer will be a member of the Application Development team involved in all aspects of the application development process.  This individual will work closely with team members to understand business requirements that drive the analysis, design and coding of quality business and baseball applications that meet our customer’s needs.",
				link: "http://baseballjobs.teamworkonline.com/teamwork/r.cfm?i=88111",
				logo: "redsox.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 21
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Los Angeles Angels of Anaheim",
				title: "Director, Quantitative Analysis",
				location: "Anaheim, CA",
				description: "Responsible for developing and overseeing the research and analytics initiative within Baseball Operations, reporting to the General Manager and Assistant General Manager.",
				link: "http://baseballjobs.teamworkonline.com/teamwork/r.cfm?i=88100",
				logo: "angels.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 20
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "TruMedia Networks",
				title: "Principal / Senior / QA Software",
				location: "Boston, MA (remote possible)",
				description: "TruMedia is looking for Principal, Senior and QA Software Engineers to help build tier one sports analytics and scouting solutions. The ideal candidates will be passionate sports fans, have a strong interest in data science and have the ability to work on the full software stack with a focus on web development and user interface design. Interfaces will be needed for web based solutions as well as mobile platforms.",
				link: "http://www.fangraphs.com/blogs/instagraphs/job-posting-trumedia-networks-principal-senior-qa-software-engineer/",
				logo: "trumedia.jpg",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 14
					}
				},
				active: true,
				isTeam: false
			},
			{
				company: "Charlotte Hornets",
				title: "Business Analytics Internship",
				location: "Charlotte, NC",
				description: "The Business Analytics and Database Marketing Intern will be interning in our offices here in Charlotte, NC. The primary responsibility of this intern will be to assist the Business Intelligence department’s needs with business analytics.",
				link: "http://nbateamjobs.teamworkonline.com/teamwork/r.cfm?i=87460",
				logo: "hornets.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 5
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "San Francisco 49ers",
				title: "Data Science Internship",
				location: "San Francisco, CA",
				description: "We are looking for a Data Science Intern to play a critical role in our use and understanding of data across various 49ers technology efforts and fan interaction and touch points.",
				link: "http://49ers.teamworkonline.com/teamwork/r.cfm?i=83653",
				logo: "49ers.gif",
				date: {
					posted: {
						year: 2015,
						month: 9,
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Columbus Crew SC",
				title: "Database & Analytics Internship",
				location: "Columbus, OH",
				description: "Columbus Crew SC is offering a Database and Analytics Internship designed to offer experience in reviewing and analyzing data within our Sales & Marketing Department.",
				link: "http://mls.teamworkonline.com/teamwork/r.cfm?i=87042",
				logo: "columbus-crew.gif",
				date: {
					posted: {
						year: 2015,
						month: 9,
						day: 28
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Baseball Info Solutions",
				title: "Research & Development Associate",
				location: "Allentown, PA",
				description: "Baseball Info Solutions (BIS) is looking for candidates to fill a full-time position in our R&D Department. The R&D Associate will work out of our office near Allentown, Pa., and will contribute as a member of our R&D team, supporting research for publications and future products.",
				link: "http://www.fangraphs.com/blogs/instagraphs/job-posting-baseball-info-solutions-research-development-associate/",
				logo: "bis.gif",
				date: {
					posted: {
						year: 2015,
						month: 9,
						day: 28
					}
				},
				active: true,
				isTeam: false
			},
			{
				company: "Carolina Hurricanes",
				title: "Java Developer/Database Administrator",
				location: "Raleigh, NC",
				description: "The Carolina Hurricanes and PNC Arena are seeking a Java Developer to continue development of existing systems and write new applications as needed.",
				link: "http://hockeyjobs.nhl.com/teamwork/r.cfm?i=85191",
				logo: "hurricanes.gif",
				date: {
					posted: {
						year: 2015,
						month: 9,
					}
				},
				active: false,
				isTeam: true
			},
			{
				company: "Atlanta Braves",
				title: "Baseball Operations Analyst",
				location: "Atlanta, GA",
				description: "Responsibilities: Oversee the in-house technological efforts associated with the development of Braves’ new internal player evaluation application, Development and on-going adjustment of proprietary statistics and systems, etc.",
				link: "http://www.fangraphs.com/blogs/instagraphs/job-posting-atlanta-braves-baseball-operations-analyst/",
				logo: "braves.gif",
				date: {
					posted: {
						year: 2015,
						month: 7,
						day: 23
					}
				},
				active: false,
				isTeam: true
			},
			{
				company: "St. Louis Cardinals",
				title: "Analyst, Baseball Development",
				location: "St. Louis, MO",
				description: "This position is responsible for conducting quantitative research to provide timely recommendations to decision makers within Baseball Operations.",
				link: "http://www.fangraphs.com/blogs/jop-posting-cardinals-openings/",
				logo: "cardinals.gif",
				date: {
					posted: {
						year: 2015,
						month: 1,
						day: 14
					}
				},
				active: false,
				isTeam: true
			},
			{
				company: "St. Louis Cardinals",
				title: "Developer, Baseball Development",
				location: "St. Louis, MO",
				description: "This position is responsible for designing, implementing and maintaining analytic and technical systems to provide timely, baseball-related information to decision makers within Baseball Operations.",
				link: "http://www.fangraphs.com/blogs/jop-posting-cardinals-openings/",
				logo: "cardinals.gif",
				date: {
					posted: {
						year: 2015,
						month: 1,
						day: 14
					}
				},
				active: false,
				isTeam: true
			},
		]
	};

	Handlebars.registerHelper("job", function(job, active) {
		var result = "";
		result += '
'; // JOB POSTING

		// add job logo
		result += '
';
		result += '';
		result += '
';

		// add company name, location, title, and date posted
		result += '
';
		result += '
' + job.company + '
';
		result += '
' + job.location + '
';
		result += '
' + job.title + '
';
		if (job.date.posted) {
			result += '
Posted ' + Handlebars.helpers.textualDate(job.date.posted) + '
';
		}
		if (job.date.due) {
			result += '
Due ' + Handlebars.helpers.textualDate(job.date.due) + '
';
		}
		result += '
';

		// add the description and link
		result += '
';
		result += '
' + job.description + '
';
		result += 'Link to the ' + job.title + ' job with ' + (job.isTeam ? 'the ' : '') + job.company + '';
		if (!active) {
			result += '
Please note that this job is now closed.
';
		}
		result += '
';

		result += '
'; // / JOB POSTING
		return new Handlebars.SafeString(result);
	});

	Handlebars.registerHelper("job-listings", function(jobs) {
		var result = "";

		activeJobs = '
Active Jobs
';
		closedJobs = '
Closed Jobs
';

		$.each(jobs, function(index, job) {
			if (job.active) {
				activeJobs += Handlebars.helpers.job(job, true);
			} else {
				closedJobs += Handlebars.helpers.job(job, false);
			}
		});

		result += '
';
		result += activeJobs;
		result += closedJobs;
		result += '
';

		return new Handlebars.SafeString(result);
	});

	Handlebars.registerHelper('job-overview', function() {
		var overview = 'If you have found a job listing that would fit on this page, please send it to ';
		var email = 'stanfordsportsanalytics@gmail.com';
		var subject = 'A New SSAC Job Posting';
		var body = 'Here is a job listing that would fit well on the SSAC job postings: ';

		var result = '';

		result += '
';
		result += overview;
		result += '' + email + '';
		result += '!
';

    	return new Handlebars.SafeString(result);
	});

	// Handlebars template for the jobs page
	jobsTemplate = [
		'{{job-overview}}',
		'{{job-listings pageData.jobs}}'
	].join('\n');

	// populate page with the above data
	populatePage(jobsTemplate, jobsData);

})(this, this.document);
<commit_msg>Reorder jobs<commit_after>(function(window, document, undefined) {

	// data specifically for the jobs page
	var jobsData = {
		header: "Job Postings",
		description: "Opportunities to work in sports analytics",
		navbarTitle: "Job Postings",
		jobs: [
			{
				company: "Toronto Blue Jays",
				title: "Baseball Operations Analytics Intern",
				location: "Toronto, ON, CA",
				description: "A Baseball Operations Analytics Intern is primarily responsible for assisting with day-to-day tasks within Baseball Operations.  Responsibilities vary dependent on the baseball calendar and internal sub-department needs (Amateur Scouting, Player Development, Pro Scouting and Baseball Information), with a heavy focus on analytics and research.",
				link: "https://jobs.rogers.com/job/Toronto-Baseball-Operations-Analytics-Intern-ON/302799300/",
				logo: "bluejays.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 30
					},
					due   : {
						year: 2015,
						month: 11,
						day: 13
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Houston Astros",
				title: "Analyst, Baseball Research and Development",
				location: "Houston, TX",
				description: "The Houston Astros are seeking an Analyst for the team's Baseball Research and Development group. The Analyst will work closely with the Director of R&D and the analytics team to conduct research and develop methods that encourage the effective understanding and application of information throughout Baseball Operations.",
				link: "http://www.baseballprospectus.com/article.php?articleid=27776",
				logo: "astros.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 28
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Los Angeles Dodgers",
				title: "Analysis Associate",
				location: "Los Angeles, CA",
				description: "The Los Angeles Dodgers are seeking an Analysis Associate to join the team's Baseball Operations group starting in the fall of 2015. We consider our internship program to be a critical pipeline for recruiting full-time employees, though there is no guarantee of receiving a full-time offer after the internship is completed. Our current focus is on identifying highly-talented, mathematically-oriented candidates as we seek to build and develop our baseball analytics team.",
				link: "http://baseballjobs.teamworkonline.com/teamwork/r.cfm?i=88159",
				logo: "dodgers.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 21
					},
					due: {
						year: 2015,
						month: 11,
						day: 13
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Boston Red Sox",
				title: "Software Engineer",
				location: "Boston, MA",
				description: "The software engineer will be a member of the Application Development team involved in all aspects of the application development process.  This individual will work closely with team members to understand business requirements that drive the analysis, design and coding of quality business and baseball applications that meet our customer’s needs.",
				link: "http://baseballjobs.teamworkonline.com/teamwork/r.cfm?i=88111",
				logo: "redsox.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 21
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Los Angeles Angels of Anaheim",
				title: "Director, Quantitative Analysis",
				location: "Anaheim, CA",
				description: "Responsible for developing and overseeing the research and analytics initiative within Baseball Operations, reporting to the General Manager and Assistant General Manager.",
				link: "http://baseballjobs.teamworkonline.com/teamwork/r.cfm?i=88100",
				logo: "angels.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 20
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Charlotte Hornets",
				title: "Business Analytics Internship",
				location: "Charlotte, NC",
				description: "The Business Analytics and Database Marketing Intern will be interning in our offices here in Charlotte, NC. The primary responsibility of this intern will be to assist the Business Intelligence department’s needs with business analytics.",
				link: "http://nbateamjobs.teamworkonline.com/teamwork/r.cfm?i=87460",
				logo: "hornets.gif",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 5
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "San Francisco 49ers",
				title: "Data Science Internship",
				location: "San Francisco, CA",
				description: "We are looking for a Data Science Intern to play a critical role in our use and understanding of data across various 49ers technology efforts and fan interaction and touch points.",
				link: "http://49ers.teamworkonline.com/teamwork/r.cfm?i=83653",
				logo: "49ers.gif",
				date: {
					posted: {
						year: 2015,
						month: 9,
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Columbus Crew SC",
				title: "Database & Analytics Internship",
				location: "Columbus, OH",
				description: "Columbus Crew SC is offering a Database and Analytics Internship designed to offer experience in reviewing and analyzing data within our Sales & Marketing Department.",
				link: "http://mls.teamworkonline.com/teamwork/r.cfm?i=87042",
				logo: "columbus-crew.gif",
				date: {
					posted: {
						year: 2015,
						month: 9,
						day: 28
					}
				},
				active: true,
				isTeam: true
			},
			{
				company: "Second Spectrum",
				title: "Machine Learning Engineer",
				location: "Los Angeles, CA or Boston, MA",
				description: "Second Spectrum is seeking a Machine Learning Software Engineer to join our Data team.  At Second Spectrum the machine understanding of sports forms the foundation of all the products we deliver.  Machine Learning engineers have the opportunity to develop state of the art models whose results are used by coaches, broadcasters, and fans throughout the world.",
				link: "http://www.secondspectrum.com/careers-ml",
				logo: "second-spectrum.jpg",
				date: {},
				active: true,
				isTeam: false
			},
			{
				company: "Second Spectrum",
				title: "Full-Stack Software Engineer",
				location: "Los Angeles, CA or Shanghai",
				description: "Second Spectrum is seeking solid full-stack engineers to join our team and help build out infrastructure to support highly interactive applications. Full-stack engineers can range from specializing at systems engineering to UI/UX development.",
				link: "http://www.secondspectrum.com/careers-full-stack",
				logo: "second-spectrum.jpg",
				date: {},
				active: true,
				isTeam: false
			},
			{
				company: "TruMedia Networks",
				title: "Principal / Senior / QA Software",
				location: "Boston, MA (remote possible)",
				description: "TruMedia is looking for Principal, Senior and QA Software Engineers to help build tier one sports analytics and scouting solutions. The ideal candidates will be passionate sports fans, have a strong interest in data science and have the ability to work on the full software stack with a focus on web development and user interface design. Interfaces will be needed for web based solutions as well as mobile platforms.",
				link: "http://www.fangraphs.com/blogs/instagraphs/job-posting-trumedia-networks-principal-senior-qa-software-engineer/",
				logo: "trumedia.jpg",
				date: {
					posted: {
						year: 2015,
						month: 10,
						day: 14
					}
				},
				active: true,
				isTeam: false
			},
			{
				company: "Baseball Info Solutions",
				title: "Research & Development Associate",
				location: "Allentown, PA",
				description: "Baseball Info Solutions (BIS) is looking for candidates to fill a full-time position in our R&D Department. The R&D Associate will work out of our office near Allentown, Pa., and will contribute as a member of our R&D team, supporting research for publications and future products.",
				link: "http://www.fangraphs.com/blogs/instagraphs/job-posting-baseball-info-solutions-research-development-associate/",
				logo: "bis.gif",
				date: {
					posted: {
						year: 2015,
						month: 9,
						day: 28
					}
				},
				active: true,
				isTeam: false
			},
			{
				company: "Carolina Hurricanes",
				title: "Java Developer/Database Administrator",
				location: "Raleigh, NC",
				description: "The Carolina Hurricanes and PNC Arena are seeking a Java Developer to continue development of existing systems and write new applications as needed.",
				link: "http://hockeyjobs.nhl.com/teamwork/r.cfm?i=85191",
				logo: "hurricanes.gif",
				date: {
					posted: {
						year: 2015,
						month: 9,
					}
				},
				active: false,
				isTeam: true
			},
			{
				company: "Atlanta Braves",
				title: "Baseball Operations Analyst",
				location: "Atlanta, GA",
				description: "Responsibilities: Oversee the in-house technological efforts associated with the development of Braves’ new internal player evaluation application, Development and on-going adjustment of proprietary statistics and systems, etc.",
				link: "http://www.fangraphs.com/blogs/instagraphs/job-posting-atlanta-braves-baseball-operations-analyst/",
				logo: "braves.gif",
				date: {
					posted: {
						year: 2015,
						month: 7,
						day: 23
					}
				},
				active: false,
				isTeam: true
			},
			{
				company: "St. Louis Cardinals",
				title: "Analyst, Baseball Development",
				location: "St. Louis, MO",
				description: "This position is responsible for conducting quantitative research to provide timely recommendations to decision makers within Baseball Operations.",
				link: "http://www.fangraphs.com/blogs/jop-posting-cardinals-openings/",
				logo: "cardinals.gif",
				date: {
					posted: {
						year: 2015,
						month: 1,
						day: 14
					}
				},
				active: false,
				isTeam: true
			},
			{
				company: "St. Louis Cardinals",
				title: "Developer, Baseball Development",
				location: "St. Louis, MO",
				description: "This position is responsible for designing, implementing and maintaining analytic and technical systems to provide timely, baseball-related information to decision makers within Baseball Operations.",
				link: "http://www.fangraphs.com/blogs/jop-posting-cardinals-openings/",
				logo: "cardinals.gif",
				date: {
					posted: {
						year: 2015,
						month: 1,
						day: 14
					}
				},
				active: false,
				isTeam: true
			},
		]
	};

	Handlebars.registerHelper("job", function(job, active) {
		var result = "";
		result += '
'; // JOB POSTING

		// add job logo
		result += '
';
		result += '';
		result += '
';

		// add company name, location, title, and date posted
		result += '
';
		result += '
' + job.company + '
';
		result += '
' + job.location + '
';
		result += '
' + job.title + '
';
		if (job.date.posted) {
			result += '
Posted ' + Handlebars.helpers.textualDate(job.date.posted) + '
';
		}
		if (job.date.due) {
			result += '
Due ' + Handlebars.helpers.textualDate(job.date.due) + '
';
		}
		result += '
';

		// add the description and link
		result += '
';
		result += '
' + job.description + '
';
		result += 'Link to the ' + job.title + ' job with ' + (job.isTeam ? 'the ' : '') + job.company + '';
		if (!active) {
			result += '
Please note that this job is now closed.
';
		}
		result += '
';

		result += '
'; // / JOB POSTING
		return new Handlebars.SafeString(result);
	});

	Handlebars.registerHelper("job-listings", function(jobs) {
		var result = "";

		activeJobs = '
Active Jobs
';
		closedJobs = '
Closed Jobs
';

		$.each(jobs, function(index, job) {
			if (job.active) {
				activeJobs += Handlebars.helpers.job(job, true);
			} else {
				closedJobs += Handlebars.helpers.job(job, false);
			}
		});

		result += '
';
		result += activeJobs;
		result += closedJobs;
		result += '
';

		return new Handlebars.SafeString(result);
	});

	Handlebars.registerHelper('job-overview', function() {
		var overview = 'If you have found a job listing that would fit on this page, please send it to ';
		var email = 'stanfordsportsanalytics@gmail.com';
		var subject = 'A New SSAC Job Posting';
		var body = 'Here is a job listing that would fit well on the SSAC job postings: ';

		var result = '';

		result += '
';
		result += overview;
		result += '' + email + '';
		result += '!
';

    	return new Handlebars.SafeString(result);
	});

	// Handlebars template for the jobs page
	jobsTemplate = [
		'{{job-overview}}',
		'{{job-listings pageData.jobs}}'
	].join('\n');

	// populate page with the above data
	populatePage(jobsTemplate, jobsData);

})(this, this.document);
<|endoftext|>


<commit_before><commit_msg>hotkey for search<commit_after><|endoftext|>


<commit_before>/*
 * dump
 * https://github.com/tnightingale/dump
 *
 * Copyright (c) 2013 tnightingale
 * Licensed under the MIT license.
 */

'use strict';

var restify = require('restify');

var storage = require('./storage'),
    storage_redis = require('./storage-redis');

var port = 8080;

function Dump () {
    var server = this.server = restify.createServer(),
        store = this.store = new storage(new storage_redis());

    server.get('/storage/:id', function (req, res, next) {
        var success = function (doc) {
                res.send(doc);
                return next();
            },
            error = function (err) {
                return next(err);
            };

        store.load(req.params.id).then(success, error);
    });

    server.post('/storage', function (req, res, next) {
        req.setEncoding('utf-8');

        var chunks = [],
            success = function (doc) {
                res.send(doc);
                return next();
            },
            error = function (err) {
                return next(err);
            };

        req.on('data', function (chunk) {
            chunks.push(chunk);
        });

        req.on('end', function () {
            try {
                var data = JSON.parse(chunks.join());
                store.save(data).then(success, error);
            }
            catch (err) {
                error(err);
            }
        });
    });
}

Dump.prototype.start = function () {
    var server = this.server;

    server.listen(port, function() {
        console.log('%s listening at %s', server.name, server.url);
    });
};

exports.createServer = function () {
    return new Dump();
};
<commit_msg>added support for redistogo<commit_after>/*
 * dump
 * https://github.com/tnightingale/dump
 *
 * Copyright (c) 2013 tnightingale
 * Licensed under the MIT license.
 */

'use strict';

var Url = require("url"),
    restify = require('restify');

var storage = require('./storage'),
    storage_redis = require('./storage-redis');

// TODO: These config items should be defined externally.
//       Likewise the specific storage adapter should also be configurable.
var port = 8080,
    redis_info = Url.parse(process.env.REDISTOGO_URL || 'redis://localhost:6379');

function Dump () {
    var server = this.server = restify.createServer(),
        store = this.store = new storage(new storage_redis());

    server.get('/storage/:id', function (req, res, next) {
        var success = function (doc) {
                res.send(doc);
                return next();
            },
            error = function (err) {
                return next(err);
            };

        store.load(req.params.id).then(success, error);
    });

    server.post('/storage', function (req, res, next) {
        req.setEncoding('utf-8');

        var chunks = [],
            success = function (doc) {
                res.send(doc);
                return next();
            },
            error = function (err) {
                return next(err);
            };

        req.on('data', function (chunk) {
            chunks.push(chunk);
        });

        req.on('end', function () {
            try {
                var data = JSON.parse(chunks.join());
                store.save(data).then(success, error);
            }
            catch (err) {
                error(err);
            }
        });
    });
}

Dump.prototype.start = function () {
    var server = this.server;

    server.listen(port, function() {
        console.log('%s listening at %s', server.name, server.url);
    });
};

exports.createServer = function () {
    return new Dump();
};
<|endoftext|>


<commit_before>'use strict'

var co = require('co')
var path = require('path')
var util = require('util')
var debug = require('debug')
var mkdirp = require('mkdirp')
var chokidar = require('chokidar')
var Cat = require('concat-with-sourcemaps')
var assign = require('object-assign')
var flatten = require('flatten')
var expand = require('globby')
var arrify = require('arrify')
var rimraf = require('rimraf')
// locals
var utils = require('./utils')
var Emitter = require('./emitter')
// shorthands
var sep = path.sep
var _ = debug('fly')

function Fly(options) {
	var self = this

	if (!(self instanceof Fly)) {
		throw new TypeError('Fly cannot be invoked without \'new\'')
	}

	options = assign({
		file: process.cwd(),
		host: {},
		plugins: []
	}, options || {})

	// shorter aliases
	var host = options.host
	var file = options.file
	var plugins = options.plugins

	// ~ `super()`
	Emitter.call(self)

	// attach files & funcs into the curr instance
	assign(self, {
		file: file,
		plugins: plugins,
		root: path.dirname(file),
		alert: utils.alert,
		error: utils.error,
		defer: utils.defer,
		log: utils.log,
		host: (typeof host === 'function') ? assign(host, {default: host}) : host,
		debug: _,
		_: {
			filters: []
		},
		tasks: Object.keys(host).reduce(function (_, key) {
			var obj = {}
			obj[key] = host[key].bind(self)
			return assign(_, obj)
		}, {})
	})

	plugins.forEach(function (el) {
		if (!el.plugin) {
			throw new Error('Did you forget to `npm i -D ' + el.name + '`?')
		}
		// if (plugin.default) plugin = plugin.default
		el.plugin.call(self, debug(el.name.replace('-', ':')), _('load %o', el.name))
	})

	_('chdir %o', self.root)
	process.chdir(self.root)
}

// `Fly extends Emitter`...
util.inherits(Fly, Emitter)
module.exports = Fly

/**
 * Compose a new, yeildable sequence.
 * Resets instance's glob, filters, and writer.
 *
 * @param  {String|Array} globs   The glob selection(s)
 * @param  {Object}       options Any options to pass as `node-glob` config.
 * @return                        The current Fly instance.
 */
Fly.prototype.source = function (globs, options) {
	globs = flatten(arrify(globs))

	assign(this, {
		_: {
			filters: [],
			globs: globs,
			files: Promise.all(globs.map(function (glob) {
				return expand(glob, options)
			}))
		}
	})

	this._.cat = undefined
	_('source %o', this._.globs)
	return this
}

/**
 * Add filter / transform function.
 * Create a closure bound to the current Fly instance.
 *
 * @param {String|Function} name 		The name of filter || the callback
 * @param {Function}        cb      The function: (cb, options) => {}
*/
Fly.prototype.filter = function (name, cb) {
	var type = typeof name

	if (type === 'function') {
		this.filter({cb: name})
	} else if (type === 'object') {
		this._.filters.push(name)
	} else {
		if (typeof this[name] === 'function') {
			throw new RangeError(name + ' method is already defined!')
		}

		this[name] = function (options) {
			var rest = [].slice.call(arguments)
			rest.shift() // remove `options` argument

			debug('fly')(name + ' %o, %o', options, rest)

			return this.filter({
				cb: cb,
				options: options,
				rest: rest
			})
		}
	}

	return this
}

/**
 * Watch IO events within glob selections & run tasks
 * @param  {String} globs   The glob patterns to observe
 * @param  {String} tasks   The list of tasks to run on file changes
 * @param  {Object} options The options for `Fly.proto.start`
 * @return {void}
 */
Fly.prototype.watch = function (globs, tasks, options) {
	options = options || {}
	globs = arrify(globs)

	_('watch %o', globs)

	var self = this
	return self.emit('fly_watch').start(tasks, options).then(function () {
		return chokidar
			.watch(flatten(globs), {ignoreInitial: true})
			.on('all', function (type, file) {
				options.value = null
				self.emit('fly_watch_event', {type: type, file: file})

				// if a single file was passed, then pass in the file to the tasks
				if (path.extname(file)) {
					options.value = file
				}

				return self.start(tasks, options)
			})
			.on('error', self.error)
	})
}

/**
 * Unwrap/Expand source globs as single files, then run fn.
 * @param  {Function} onResolved  The callback to run on 'success'.
 * @param  {Function} onRejected  The callback to run on 'error'.
 * @return {Promise}
 */
Fly.prototype.unwrap = function (onResolved, onRejected) {
	return this._.files.then(flatten).then(onResolved).catch(onRejected)
}

/**
 * Execute a single task.
 * @param  {String} task     The name of the task
 * @param  {Mixed}  value    The initial value to pass into `task`
 * @param  {Object} instance The Fly instance `task` should be bound to
 * @return {Mixed}           The task's resulting value.
 */
Fly.prototype.exec = function * (task, value, instance) {
	instance = instance || this
	value = arrify(value)
	_('run %o', task)

	try {
		var start = getTime()

		this.emit('task_start', {
			task: task
		})

		value = (yield this.host[task].apply(instance, value)) || value

		this.emit('task_complete', {
			task: task,
			duration: getTime() - start
		})
	} catch (e) {
		this.emit('task_error', {
			task: task,
			error: e
		})
	}

	return value
}

/**
 * Run a task sequence of 1 or more.
 * Each task's return value is piped into the next task of sequence.
 *
 * @param  {Array}  tasks   The list of tasks to start
 * @param  {Object} options The options to begin.
 * @return {Promise}
 */
Fly.prototype.start = function (tasks, options) {
	tasks = arrify(tasks.length ? tasks : 'default')

	options = assign({
		parallel: false,
		value: null
	}, options || {})

	_('start %o in ' + (options.parallel ? 'parallel' : 'sequence'), tasks)

	var self = this
	var value = options.value
	var inst = Object.create(self)

	return co.call(self, function * (tasks) {
		if (options.parallel) {
			yield tasks.map(function * (task) {
				yield self.exec(task, value, inst)
			})
		} else {
			for (var task of tasks) {
				value = yield self.exec(task, value, inst)
			}
		}
		return value
	}, [].concat(tasks).filter(function (task) {
		return Object.keys(self.host).indexOf(task) !== -1 || !self.emit('task_not_found', {task: task})
	}))
}

/**
 * Deferred `rimraf` wrapper
 * @param  {String|Array} globs  The glob selection(s) to delete
 * @return {void}
 */
Fly.prototype.clear = function (globs) {
	globs = flatten(arrify(globs))

	_('clear %o', globs)

	return globs.map(function (p) {
		utils.defer(rimraf)(p)
	})
}

/**
 * Concatenate active `files` to single file.
 * @param  {String} filename  The single output file
 * @return {Fly}      				The current Fly instance.
 */
Fly.prototype.concat = function (filename) {
	this._.cat = new Cat(false, filename, '\n')
	this._.cat.base = filename
	return this
}

/**
 * Resolve a yieldable sequence.
 * Reduces `source` with filters and invokes writer.
 *
 * @param  {Array}  dirs    The target/destination directories
 * @param  {Object} options Target options. Depth refers to path retention
 * @return {Promise}
 */
Fly.prototype.target = function (dirs, options) {
	dirs = arrify(dirs)
	options = assign({}, {depth: -1}, options || {})

	var self = this
	var _cat = self._.cat
	var _filters = self._.filters

	return co(function * () {
		var globs = self._.globs
		var files = yield self._.files

		for (var i = 0; i < globs.length; i++) {
			var glob = globs[i]
			// run thru all files of each glob
			yield files[i].map(function * (file) {
				// get data & stats
				var f = path.parse(file)
				var data = yield utils.read(file)

				// had no data (empty file || attempted a directory read)
				if (!data) {
					return // exit
				}

				// pass files' data thru attached filters
				for (var filter of _filters) {
					// run the filter's closure fn w/data
					var res = yield Promise.resolve(filter.cb.apply(
						self, [data, assign({file: f}, filter.options)].concat(filter.rest)
					))

					// once done, retrieve the final `data` & `ext` of output
					data = res.code || res.js || res.css || res.data || res || data
					f.ext = res.ext || res.extension || f.ext
				}

				if (_cat) {
					_cat.add(f.base, data)
				} else {
					// get shared dir between glob & current filepath
					var dir = path.join.apply(null, f.dir.split(sep).filter(function (filepath) {
						return glob.split(sep).indexOf(filepath) === -1
					}))

					// complete the promise & write the output
					yield resolve(dirs, {
						data: data,
						base: path.join(dir, f.name + f.ext),
						depth: options.depth
					})
				}
			})
		}

		if (_cat) {
			yield resolve(dirs, {
				data: _cat.content,
				base: _cat.base,
				depth: options.depth
			})
		}
	})
}

/**
 * Write utility to help concat and target.
 * @param {String}   dirs           parent directory
 * @param {String}   options.base   directory/file
 * @param {Mixed}    options.data
 * @param {Integer}  options.depth  number of parent directories to keep
 * @param {Function} options.write  promisified writer function
 */
function * resolve(dirs, options) {
	var opts = options || {}
	var writer = opts.hasOwnProperty('writer') ? opts.writer : utils.write

	if (opts.depth > -1) {
		opts.base = dirpaths(opts.base, opts.depth)
	}

	yield flatten(dirs).map(function * (dir) {
		var file = path.join(dir, opts.base)
		mkdirp.sync(path.dirname(file))
		yield writer(file, opts.data)
	})
}

/**
 * Shorten a directory string to # of parent dirs
 * @param  {String}  	full    The original full path
 * @param  {Integer}  depth   The number of levels to retain
 * @return {String}
 */
function dirpaths(full, depth) {
	var arr = full.split(sep)
	var len = arr.length

	if (depth === 0) {
		return arr[len - 1]
	} else if (depth >= len) {
		return full
	}

	return arr.slice(len - 1 - depth).join(sep)
}

/**
 * Get the current timestamp
 * @return {Integer}
 */
function getTime() {
	return (new Date()).getTime()
}
<commit_msg>fix fly.clear; resolves #193<commit_after>'use strict'

var co = require('co')
var path = require('path')
var util = require('util')
var debug = require('debug')
var mkdirp = require('mkdirp')
var chokidar = require('chokidar')

var Cat = require('concat-with-sourcemaps')
var assign = require('object-assign')
var flatten = require('flatten')
var expand = require('globby')
var arrify = require('arrify')
var rimraf = require('rimraf')
// locals
var utils = require('./utils')
var Emitter = require('./emitter')
// shorthands
var sep = path.sep
var _ = debug('fly')

function Fly(options) {
	var self = this

	if (!(self instanceof Fly)) {
		throw new TypeError('Fly cannot be invoked without \'new\'')
	}

	options = assign({
		file: process.cwd(),
		host: {},
		plugins: []
	}, options || {})

	// shorter aliases
	var host = options.host
	var file = options.file
	var plugins = options.plugins

	// ~ `super()`
	Emitter.call(self)

	// attach files & funcs into the curr instance
	assign(self, {
		file: file,
		plugins: plugins,
		root: path.dirname(file),
		alert: utils.alert,
		error: utils.error,
		defer: utils.defer,
		log: utils.log,
		host: (typeof host === 'function') ? assign(host, {default: host}) : host,
		debug: _,
		_: {
			filters: []
		},
		tasks: Object.keys(host).reduce(function (_, key) {
			var obj = {}
			obj[key] = host[key].bind(self)
			return assign(_, obj)
		}, {})
	})

	plugins.forEach(function (el) {
		if (!el.plugin) {
			throw new Error('Did you forget to `npm i -D ' + el.name + '`?')
		}
		// if (plugin.default) plugin = plugin.default
		el.plugin.call(self, debug(el.name.replace('-', ':')), _('load %o', el.name))
	})

	_('chdir %o', self.root)
	process.chdir(self.root)
}

// `Fly extends Emitter`...
util.inherits(Fly, Emitter)
module.exports = Fly

/**
 * Compose a new, yeildable sequence.
 * Resets instance's glob, filters, and writer.
 *
 * @param  {String|Array} globs   The glob selection(s)
 * @param  {Object}       options Any options to pass as `node-glob` config.
 * @return                        The current Fly instance.
 */
Fly.prototype.source = function (globs, options) {
	globs = flatten(arrify(globs))

	assign(this, {
		_: {
			filters: [],
			globs: globs,
			files: Promise.all(globs.map(function (glob) {
				return expand(glob, options)
			}))
		}
	})

	this._.cat = undefined
	_('source %o', this._.globs)
	return this
}

/**
 * Add filter / transform function.
 * Create a closure bound to the current Fly instance.
 *
 * @param {String|Function} name 		The name of filter || the callback
 * @param {Function}        cb      The function: (cb, options) => {}
*/
Fly.prototype.filter = function (name, cb) {
	var type = typeof name

	if (type === 'function') {
		this.filter({cb: name})
	} else if (type === 'object') {
		this._.filters.push(name)
	} else {
		if (typeof this[name] === 'function') {
			throw new RangeError(name + ' method is already defined!')
		}

		this[name] = function (options) {
			var rest = [].slice.call(arguments)
			rest.shift() // remove `options` argument

			debug('fly')(name + ' %o, %o', options, rest)

			return this.filter({
				cb: cb,
				options: options,
				rest: rest
			})
		}
	}

	return this
}

/**
 * Watch IO events within glob selections & run tasks
 * @param  {String} globs   The glob patterns to observe
 * @param  {String} tasks   The list of tasks to run on file changes
 * @param  {Object} options The options for `Fly.proto.start`
 * @return {void}
 */
Fly.prototype.watch = function (globs, tasks, options) {
	options = options || {}
	globs = arrify(globs)

	_('watch %o', globs)

	var self = this
	return self.emit('fly_watch').start(tasks, options).then(function () {
		return chokidar
			.watch(flatten(globs), {ignoreInitial: true})
			.on('all', function (type, file) {
				options.value = null
				self.emit('fly_watch_event', {type: type, file: file})

				// if a single file was passed, then pass in the file to the tasks
				if (path.extname(file)) {
					options.value = file
				}

				return self.start(tasks, options)
			})
			.on('error', self.error)
	})
}

/**
 * Unwrap/Expand source globs as single files, then run fn.
 * @param  {Function} onResolved  The callback to run on 'success'.
 * @param  {Function} onRejected  The callback to run on 'error'.
 * @return {Promise}
 */
Fly.prototype.unwrap = function (onResolved, onRejected) {
	return this._.files.then(flatten).then(onResolved).catch(onRejected)
}

/**
 * Execute a single task.
 * @param  {String} task     The name of the task
 * @param  {Mixed}  value    The initial value to pass into `task`
 * @param  {Object} instance The Fly instance `task` should be bound to
 * @return {Mixed}           The task's resulting value.
 */
Fly.prototype.exec = function * (task, value, instance) {
	instance = instance || this
	value = arrify(value)
	_('run %o', task)

	try {
		var start = getTime()

		this.emit('task_start', {
			task: task
		})

		value = (yield this.host[task].apply(instance, value)) || value

		this.emit('task_complete', {
			task: task,
			duration: getTime() - start
		})
	} catch (e) {
		this.emit('task_error', {
			task: task,
			error: e
		})
	}

	return value
}

/**
 * Run a task sequence of 1 or more.
 * Each task's return value is piped into the next task of sequence.
 *
 * @param  {Array}  tasks   The list of tasks to start
 * @param  {Object} options The options to begin.
 * @return {Promise}
 */
Fly.prototype.start = function (tasks, options) {
	tasks = arrify(tasks.length ? tasks : 'default')

	options = assign({
		parallel: false,
		value: null
	}, options || {})

	_('start %o in ' + (options.parallel ? 'parallel' : 'sequence'), tasks)

	var self = this
	var value = options.value
	var inst = Object.create(self)

	return co.call(self, function * (tasks) {
		if (options.parallel) {
			yield tasks.map(function * (task) {
				yield self.exec(task, value, inst)
			})
		} else {
			for (var task of tasks) {
				value = yield self.exec(task, value, inst)
			}
		}
		return value
	}, [].concat(tasks).filter(function (task) {
		return Object.keys(self.host).indexOf(task) !== -1 || !self.emit('task_not_found', {task: task})
	}))
}

/**
 * Deferred `rimraf` wrapper
 * @param  {String|Array} globs  The glob selection(s) to delete
 * @return {void}
 */
Fly.prototype.clear = function (globs) {
	globs = flatten(arrify(globs))

	_('clear %o', globs)

	return globs.map(function (p) {
		return utils.defer(rimraf)(p)
	})
}

/**
 * Concatenate active `files` to single file.
 * @param  {String} filename  The single output file
 * @return {Fly}      				The current Fly instance.
 */
Fly.prototype.concat = function (filename) {
	this._.cat = new Cat(false, filename, '\n')
	this._.cat.base = filename
	return this
}

/**
 * Resolve a yieldable sequence.
 * Reduces `source` with filters and invokes writer.
 *
 * @param  {Array}  dirs    The target/destination directories
 * @param  {Object} options Target options. Depth refers to path retention
 * @return {Promise}
 */
Fly.prototype.target = function (dirs, options) {
	dirs = arrify(dirs)
	options = assign({}, {depth: -1}, options || {})

	var self = this
	var _cat = self._.cat
	var _filters = self._.filters

	return co(function * () {
		var globs = self._.globs
		var files = yield self._.files

		for (var i = 0; i < globs.length; i++) {
			var glob = globs[i]
			// run thru all files of each glob
			yield files[i].map(function * (file) {
				// get data & stats
				var f = path.parse(file)
				var data = yield utils.read(file)

				// had no data (empty file || attempted a directory read)
				if (!data) {
					return // exit
				}

				// pass files' data thru attached filters
				for (var filter of _filters) {
					// run the filter's closure fn w/data
					var res = yield Promise.resolve(filter.cb.apply(
						self, [data, assign({file: f}, filter.options)].concat(filter.rest)
					))

					// once done, retrieve the final `data` & `ext` of output
					data = res.code || res.js || res.css || res.data || res || data
					f.ext = res.ext || res.extension || f.ext
				}

				if (_cat) {
					_cat.add(f.base, data)
				} else {
					// get shared dir between glob & current filepath
					var dir = path.join.apply(null, f.dir.split(sep).filter(function (filepath) {
						return glob.split(sep).indexOf(filepath) === -1
					}))

					// complete the promise & write the output
					yield resolve(dirs, {
						data: data,
						base: path.join(dir, f.name + f.ext),
						depth: options.depth
					})
				}
			})
		}

		if (_cat) {
			yield resolve(dirs, {
				data: _cat.content,
				base: _cat.base,
				depth: options.depth
			})
		}
	})
}

/**
 * Write utility to help concat and target.
 * @param {String}   dirs           parent directory
 * @param {String}   options.base   directory/file
 * @param {Mixed}    options.data
 * @param {Integer}  options.depth  number of parent directories to keep
 * @param {Function} options.write  promisified writer function
 */
function * resolve(dirs, options) {
	var opts = options || {}
	var writer = opts.hasOwnProperty('writer') ? opts.writer : utils.write

	if (opts.depth > -1) {
		opts.base = dirpaths(opts.base, opts.depth)
	}

	yield flatten(dirs).map(function * (dir) {
		var file = path.join(dir, opts.base)
		mkdirp.sync(path.dirname(file))
		yield writer(file, opts.data)
	})
}

/**
 * Shorten a directory string to # of parent dirs
 * @param  {String}  	full    The original full path
 * @param  {Integer}  depth   The number of levels to retain
 * @return {String}
 */
function dirpaths(full, depth) {
	var arr = full.split(sep)
	var len = arr.length

	if (depth === 0) {
		return arr[len - 1]
	} else if (depth >= len) {
		return full
	}

	return arr.slice(len - 1 - depth).join(sep)
}

/**
 * Get the current timestamp
 * @return {Integer}
 */
function getTime() {
	return (new Date()).getTime()
}
<|endoftext|>


<commit_before>
/*!
 * Ext JS Connect
 * Copyright(c) 2010 Sencha Inc.
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var parse = require('url').parse;

/**
 * Provides Sinatra and Express like routing capabilities.
 *
 * Examples:
 *
 *     connect.router(function(app){
 *         app.get('/user/:id', function(req, res, params){
 *             // populates params.id
 *         });
 *     })
 *
 * @param {Function} fn
 * @return {Function}
 * @api public
 */

module.exports = function router(fn){
    var routes;

    if (fn) {
        routes = {};
        fn.call(this, {
            post: method.call(this, 'post'),
            get: method.call(this, 'get'),
            put: method.call(this, 'put'),
            del: method.call(this, 'del')
        });
    } else {
        throw new Error('router provider requires a callback function');
    }

    function method(name) {
        var self = this,
            localRoutes = routes[name] = routes[name] || [];
        return function(path, fn){
            var keys = [];
            path = path instanceof RegExp
                ? path
                : normalizePath(path, keys);
            localRoutes.push(fn, path, keys);
            return self;
        };
    }

    return function router(req, res, next){
        var route,
            self = this;
        (function pass(i){
            if (route = match(req, routes, i)) {
                req.params = route._params;
                try {
                    route.call(self, req, res, function(err){
                        if (err === true) {
                            next();
                        } else if (err) {
                            next(err);
                        } else {
                            pass(++route._index);
                        }
                    });
                } catch (err) {
                    next(err);
                }
            } else {
                next();
            }
        })();
    };
}

/**
 * Normalize the given path string,
 * returning a regular expression.
 *
 * An empty array should be passed,
 * which will contain the placeholder
 * key names. For example "/user/:id" will
 * then contain ["id"].
 *
 * @param  {String} path
 * @param  {Array} keys
 * @return {RegExp}
 * @api private
 */

function normalizePath(path, keys) {
    path = path
        .concat('/?')
        .replace(/\/\(/g, '(?:/')
        .replace(/(\/)?(\.)?:(\w+)(\?)?/g, function(_, slash, format, key, optional){
            keys.push(key);
            slash = slash || '';
            return ''
                + (optional ? '' : slash)
                + '(?:'
                + (optional ? slash : '')
                + (format || '') + '([^/]+))'
                + (optional || '');
        })
        .replace(/([\/.-])/g, '\\$1')
        .replace(/\*/g, '(.+)');
    return new RegExp('^' + path + '$', 'i');
}

/**
 * Attempt to match the given request to
 * one of the routes. When successful
 * a route function is returned.
 *
 * @param  {ServerRequest} req
 * @param  {Object} routes
 * @return {Function}
 * @api private
 */

function match(req, routes, i) {
    var captures,
        method = req.method.toLowerCase(),
        i = i || 0;
    if (method === 'delete') {
        method = 'del';
    }
    if (routes = routes[method]) {
        var url = parse(req.url),
            pathname = url.pathname;
        for (var len = routes.length; i < len; ++i) {
            var fn = routes[i++],
                path = routes[i++],
                keys = routes[i];
            if (captures = path.exec(pathname)) {
                fn._params = [];
                for (var j = 1, len = captures.length; j < len; ++j) {
                    var key = keys[j-1];
                    if (key) {
                        fn._params[key] = captures[j];
                    } else {
                        fn._params.push(captures[j]);
                    }
                }
                fn._index = i;
                return fn;
            }
        }
    }
}<commit_msg>try stupidly debugging in the log for now<commit_after>
/*!
 * Ext JS Connect
 * Copyright(c) 2010 Sencha Inc.
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var parse = require('url').parse;

/**
 * Provides Sinatra and Express like routing capabilities.
 *
 * Examples:
 *
 *     connect.router(function(app){
 *         app.get('/user/:id', function(req, res, params){
 *             // populates params.id
 *         });
 *     })
 *
 * @param {Function} fn
 * @return {Function}
 * @api public
 */

module.exports = function router(fn){
    var routes;

    if (fn) {
        routes = {};
        fn.call(this, {
            post: method.call(this, 'post'),
            get: method.call(this, 'get'),
            put: method.call(this, 'put'),
            del: method.call(this, 'del')
        });
    } else {
        throw new Error('router provider requires a callback function');
    }

    function method(name) {
        var self = this,
            localRoutes = routes[name] = routes[name] || [];
        return function(path, fn){
            var keys = [];
            path = path instanceof RegExp
                ? path
                : normalizePath(path, keys);
            localRoutes.push(fn, path, keys);
            return self;
        };
    }

    return function router(req, res, next){
        var route,
            self = this;
        (function pass(i){
            if (route = match(req, routes, i)) {
                req.params = route._params;
                try {
                    route.call(self, req, res, function(err){
                        if (err === true) {
                            next();
                        } else if (err) {
                            next(err);
                        } else {
                            pass(++route._index);
                        }
                    });
                } catch (err) {
                    next(err);
                }
            } else {
                next();
            }
        })();
    };
}

/**
 * Normalize the given path string,
 * returning a regular expression.
 *
 * An empty array should be passed,
 * which will contain the placeholder
 * key names. For example "/user/:id" will
 * then contain ["id"].
 *
 * @param  {String} path
 * @param  {Array} keys
 * @return {RegExp}
 * @api private
 */

function normalizePath(path, keys) {
    path = path
        .concat('/?')
        .replace(/\/\(/g, '(?:/')
        .replace(/(\/)?(\.)?:(\w+)(\?)?/g, function(_, slash, format, key, optional){
            keys.push(key);
            slash = slash || '';
            return ''
                + (optional ? '' : slash)
                + '(?:'
                + (optional ? slash : '')
                + (format || '') + '([^/]+))'
                + (optional || '');
        })
        .replace(/([\/.-])/g, '\\$1')
        .replace(/\*/g, '(.+)');
    return new RegExp('^' + path + '$', 'i');
}

/**
 * Attempt to match the given request to
 * one of the routes. When successful
 * a route function is returned.
 *
 * @param  {ServerRequest} req
 * @param  {Object} routes
 * @return {Function}
 * @api private
 */

function match(req, routes, i) {
    var captures,
        method = req.method.toLowerCase(),
        i = i || 0;
    if (method === 'delete') {
        method = 'del';
    }
    if (routes = routes[method]) {
        var url = parse(req.url),
            pathname = url.pathname;
        for (var len = routes.length; i < len; ++i) {
            var fn = routes[i++],
                path = routes[i++],
                keys = routes[i];
            if (!('exec' in path)) {
              var sys = require('sys');
              sys.log(sys.inspect(req));
            }
            if (captures = path.exec(pathname)) {
                fn._params = [];
                for (var j = 1, len = captures.length; j < len; ++j) {
                    var key = keys[j-1];
                    if (key) {
                        fn._params[key] = captures[j];
                    } else {
                        fn._params.push(captures[j]);
                    }
                }
                fn._index = i;
                return fn;
            }
        }
    }
}
<|endoftext|>


<commit_before>var assert = require("assert");

var dateFormat = require("./../lib/dateformat");

describe("dayOfWeek", function () {
  it("should correctly format the timezone part", function (done) {
    var start = 10; // the 10 of March 2013 is a Sunday
    for (var dow = 1; dow <= 7; dow++) {
      var date = new Date("2013-03-" + (start + dow));
      var N = dateFormat(date, "N");
      assert.strictEqual(N, String(dow));
    }
    done();
  });
});
<commit_msg>Revert "Minor Formatting Changes for Day of Week Test"<commit_after>var assert = require('assert');

var dateFormat = require('./../lib/dateformat');

describe('dayOfWeek', function() {
  it('should correctly format the timezone part', function(done) {
    var start = 10; // the 10 of March 2013 is a Sunday
    for(var dow = 1; dow <= 7; dow++){
      var date = new Date('2013-03-' + (start + dow));
      var N = dateFormat(date, 'N');
      assert.strictEqual(N, String(dow));
    }
    done();
  });
});
<|endoftext|>


<commit_before>// @flow
/**
 * All About Olaf
 * StudentOrgs page
 */

import React from 'react'
import {StyleSheet, View, Text, Platform} from 'react-native'
import {StyledAlphabetListView} from '../components/alphabet-listview'
import debounce from 'lodash/debounce'
import type {TopLevelViewPropsType} from '../types'
import LoadingView from '../components/loading'
import delay from 'delay'
import {NoticeView} from '../components/notice'
import {Row, Column} from '../components/layout'
import {
  ListRow,
  ListSectionHeader,
  ListSeparator,
  Detail,
  Title,
} from '../components/list'
import {tracker} from '../../analytics'
import bugsnag from '../../bugsnag'
import size from 'lodash/size'
import sortBy from 'lodash/sortBy'
import groupBy from 'lodash/groupBy'
import head from 'lodash/head'
import uniq from 'lodash/uniq'
import words from 'lodash/words'
import deburr from 'lodash/deburr'
import filter from 'lodash/filter'
import isString from 'lodash/isString'
import * as c from '../components/colors'
import startCase from 'lodash/startCase'
import {SearchBar} from '../components/searchbar'
import type {StudentOrgType} from './types'

const orgsUrl =
  'https://www.stolaf.edu/orgs/list/index.cfm?fuseaction=getall&nostructure=1'
const leftSideSpacing = 20
const rowHeight = Platform.OS === 'ios' ? 58 : 74
const headerHeight = Platform.OS === 'ios' ? 33 : 41

const styles = StyleSheet.create({
  wrapper: {
    flex: 1,
  },
  row: {
    height: rowHeight,
    paddingRight: 2,
  },
  rowSectionHeader: {
    height: headerHeight,
  },
  badgeContainer: {
    alignItems: 'center',
    justifyContent: 'center',
    alignSelf: 'flex-start',
    width: leftSideSpacing,
  },
  badge: {
    fontSize: Platform.OS === 'ios' ? 24 : 28,
    color: c.transparent,
  },
})

export class StudentOrgsView extends React.Component {
  static navigationOptions = {
    title: 'Student Orgs',
    headerBackTitle: 'Orgs',
  }

  props: TopLevelViewPropsType
  searchBar: any

  state: {
    orgs: {[key: string]: StudentOrgType[]},
    results: {[key: string]: StudentOrgType[]},
    refreshing: boolean,
    error: boolean,
    loaded: boolean,
  } = {
    orgs: {},
    results: {},
    refreshing: false,
    loaded: false,
    error: false,
  }

  componentWillMount() {
    this.fetchData()
  }

  fetchData = async () => {
    try {
      const responseData: StudentOrgType[] = await fetchJson(orgsUrl)
      const sortableRegex = /^(St\.? Olaf(?: College)?|The) +/i
      const withSortableNames = responseData.map(item => {
        const sortableName = item.name.replace(sortableRegex, '')

        return {
          ...item,
          $sortableName: sortableName,
          $groupableName: head(startCase(sortableName)),
        }
      })

      const sorted = sortBy(withSortableNames, '$sortableName')
      const grouped = groupBy(sorted, '$groupableName')
      this.setState(() => ({orgs: sorted, results: grouped}))
    } catch (err) {
      tracker.trackException(err.message)
      bugsnag.notify(err)
      this.setState(() => ({error: true}))
      console.error(err)
    }

    this.setState(() => ({loaded: true}))
  }

  refresh = async () => {
    const start = Date.now()
    this.setState(() => ({refreshing: true}))

    await this.fetchData()

    // wait 0.5 seconds – if we let it go at normal speed, it feels broken.
    const elapsed = Date.now() - start
    if (elapsed < 500) {
      await delay(500 - elapsed)
    }
    this.setState(() => ({refreshing: false}))
  }

  renderSectionHeader = ({title}: {title: string}) => {
    return (
      <ListSectionHeader
        title={title}
        spacing={{left: leftSideSpacing}}
        style={styles.rowSectionHeader}
      />
    )
  }

  renderRow = ({item}: {item: StudentOrgType}) => {
    return (
      <ListRow
        onPress={() => this.onPressRow(item)}
        contentContainerStyle={[styles.row]}
        arrowPosition="none"
        fullWidth={true}
      >
        <Row alignItems="flex-start">
          <View style={styles.badgeContainer}>
            <Text style={styles.badge}>•</Text>
          </View>

          <Column flex={1}>
            <Title lines={1}>{item.name}</Title>
            <Detail lines={1}>{item.category}</Detail>
          </Column>
        </Row>
      </ListRow>
    )
  }

  renderSeparator = (sectionId: string, rowId: string) => {
    return (
      <ListSeparator
        key={`${sectionId}-${rowId}`}
        spacing={{left: leftSideSpacing}}
      />
    )
  }

  onPressRow = (data: StudentOrgType) => {
    tracker.trackEvent('student-org', data.name)
    this.props.navigation.navigate('StudentOrgsDetailView', {org: data})
  }

  splitToArray = (str: string) => {
    return words(deburr(str.toLowerCase()))
  }

  orgToArray = (term: StudentOrgType) => {
    return uniq([
      ...this.splitToArray(term.name),
      ...this.splitToArray(term.category),
      ...this.splitToArray(term.description),
    ])
  }

  _performSearch = (text: string) => {
    // Android clear button returns an object...
    // ...and we need to check if the query exists
    if (!isString(text) || !text) {
      this.setState(state => ({
        results: groupBy(state.orgs, '$groupableName'),
      }))
      return
    }

    this.setState(state => {
      const query = text.toLowerCase()
      const filteredResults = filter(state.orgs, org =>
        this.orgToArray(org).some(word => word.startsWith(query)),
      )
      return {results: groupBy(filteredResults, '$groupableName')}
    })
  }

  // We need to make the search run slightly behind the UI,
  // so I'm slowing it down by 50ms. 0ms also works, but seems
  // rather pointless.
  performSearch = debounce(this._performSearch, 50)

  render() {
    if (!this.state.loaded) {
      return <LoadingView />
    }

    if (!size(this.state.orgs)) {
      return <NoticeView text="No organizations found." />
    }

    return (
      <View style={styles.wrapper}>
        <SearchBar
          getRef={ref => (this.searchBar = ref)}
          onChangeText={this.performSearch}
          // if we don't use the arrow function here, searchBar ref is null...
          onSearchButtonPress={() => this.searchBar.unFocus()}
        />
        <StyledAlphabetListView
          data={this.state.results}
          cell={this.renderRow}
          // just setting cellHeight sends the wrong values on iOS.
          cellHeight={
            rowHeight +
            (Platform.OS === 'ios' ? 11 / 12 * StyleSheet.hairlineWidth : 0)
          }
          sectionHeader={this.renderSectionHeader}
          sectionHeaderHeight={headerHeight}
          renderSeparator={this.renderSeparator}
          showsVerticalScrollIndicator={false}
          keyboardDismissMode="on-drag"
          keyboardShouldPersistTaps="never"
        />
      </View>
    )
  }
}
<commit_msg>use SearchableAlphabetListView in Orgs<commit_after>// @flow

import React from 'react'
import {StyleSheet, View, Text, Platform, RefreshControl} from 'react-native'
import {SearchableAlphabetListView} from '../components/searchable-alphabet-listview'
import type {TopLevelViewPropsType} from '../types'
import LoadingView from '../components/loading'
import delay from 'delay'
import {NoticeView} from '../components/notice'
import {Row, Column} from '../components/layout'
import {
  ListRow,
  ListSectionHeader,
  ListSeparator,
  Detail,
  Title,
} from '../components/list'
import {tracker} from '../../analytics'
import {reportNetworkProblem} from '../../lib/report-network-problem'
import size from 'lodash/size'
import sortBy from 'lodash/sortBy'
import groupBy from 'lodash/groupBy'
import head from 'lodash/head'
import uniq from 'lodash/uniq'
import words from 'lodash/words'
import deburr from 'lodash/deburr'
import filter from 'lodash/filter'
import startCase from 'lodash/startCase'
import * as c from '../components/colors'
import type {StudentOrgType} from './types'

const orgsUrl =
  'https://www.stolaf.edu/orgs/list/index.cfm?fuseaction=getall&nostructure=1'
const leftSideSpacing = 20
const ROW_HEIGHT = Platform.OS === 'ios' ? 58 : 74
const SECTION_HEADER_HEIGHT = Platform.OS === 'ios' ? 33 : 41

const splitToArray = (str: string) => words(deburr(str.toLowerCase()))

const orgToArray = (term: StudentOrgType) =>
  uniq([
    ...splitToArray(term.name),
    ...splitToArray(term.category),
    ...splitToArray(term.description),
  ])

const styles = StyleSheet.create({
  wrapper: {
    flex: 1,
  },
  row: {
    height: ROW_HEIGHT,
    paddingRight: 2,
  },
  rowSectionHeader: {
    height: SECTION_HEADER_HEIGHT,
  },
  badgeContainer: {
    alignItems: 'center',
    justifyContent: 'center',
    alignSelf: 'flex-start',
    width: leftSideSpacing,
  },
  badge: {
    fontSize: Platform.OS === 'ios' ? 24 : 28,
    color: c.transparent,
  },
})

export class StudentOrgsView extends React.Component {
  static navigationOptions = {
    title: 'Student Orgs',
    headerBackTitle: 'Orgs',
  }

  props: TopLevelViewPropsType
  searchBar: any

  state: {
    orgs: {[key: string]: StudentOrgType[]},
    results: {[key: string]: StudentOrgType[]},
    refreshing: boolean,
    error: boolean,
    loading: boolean,
  } = {
    orgs: {},
    results: {},
    refreshing: false,
    loading: true,
    error: false,
  }

  componentWillMount() {
    this.fetchData()
  }

  fetchData = async () => {
    this.setState(() => ({loading: true}))

    const responseData: StudentOrgType[] = await fetchJson(
      orgsUrl,
    ).catch(err => {
      reportNetworkProblem(err)
      this.setState(() => ({error: true}))
      return []
    })

    const sortableRegex = /^(St\.? Olaf(?: College)?|The) +/i
    const withSortableNames = responseData.map(item => {
      const sortableName = item.name.replace(sortableRegex, '')

      return {
        ...item,
        $sortableName: sortableName,
        $groupableName: head(startCase(sortableName)),
      }
    })

    const sorted = sortBy(withSortableNames, '$sortableName')
    const grouped = groupBy(sorted, '$groupableName')
    this.setState(() => ({orgs: sorted, results: grouped}))

    this.setState(() => ({loading: false}))
  }

  refresh = async () => {
    const start = Date.now()
    this.setState(() => ({refreshing: true}))

    await this.fetchData()

    // wait 0.5 seconds – if we let it go at normal speed, it feels broken.
    const elapsed = Date.now() - start
    if (elapsed < 500) {
      await delay(500 - elapsed)
    }
    this.setState(() => ({refreshing: false}))
  }

  renderSectionHeader = ({title}: {title: string}) =>
    <ListSectionHeader
      title={title}
      spacing={{left: leftSideSpacing}}
      style={styles.rowSectionHeader}
    />

  renderRow = ({item}: {item: StudentOrgType}) =>
    <ListRow
      onPress={() => this.onPressRow(item)}
      contentContainerStyle={[styles.row]}
      arrowPosition="none"
      fullWidth={true}
    >
      <Row alignItems="flex-start">
        <View style={styles.badgeContainer}>
          <Text style={styles.badge}>•</Text>
        </View>

        <Column flex={1}>
          <Title lines={1}>{item.name}</Title>
          <Detail lines={1}>{item.category}</Detail>
        </Column>
      </Row>
    </ListRow>

  renderSeparator = (sectionId: string, rowId: string) =>
    <ListSeparator
      key={`${sectionId}-${rowId}`}
      spacing={{left: leftSideSpacing}}
    />

  onPressRow = (data: StudentOrgType) => {
    tracker.trackEvent('student-org', data.name)
    this.props.navigation.navigate('StudentOrgsDetailView', {org: data})
  }

  performSearch = (text: ?string) => {
    if (!text) {
      this.setState(state => ({
        results: groupBy(state.orgs, '$groupableName'),
      }))
      return
    }

    this.setState(state => {
      const query = text.toLowerCase()
      const filteredResults = filter(state.orgs, org =>
        orgToArray(org).some(word => word.startsWith(query)),
      )
      return {results: groupBy(filteredResults, '$groupableName')}
    })
  }

  render() {
    if (this.state.loading) {
      return <LoadingView />
    }

    if (!size(this.state.orgs)) {
      return <NoticeView text="No organizations found." />
    }

    const refreshControl = (
      <RefreshControl
        refreshing={this.state.loading}
        onRefresh={this.refresh}
      />
    )

    return (
      <SearchableAlphabetListView
        cell={this.renderRow}
        cellHeight={
          ROW_HEIGHT +
          (Platform.OS === 'ios' ? 11 / 12 * StyleSheet.hairlineWidth : 0)
        }
        data={this.state.results}
        onSearch={this.performSearch}
        refreshControl={refreshControl}
        renderSeparator={this.renderSeparator}
        sectionHeader={this.renderSectionHeader}
        sectionHeaderHeight={SECTION_HEADER_HEIGHT}
        style={styles.wrapper}
      />
    )
  }
}
<|endoftext|>


<commit_before>define(["dojo/main", "ppwcode/contracts/doh",
        "../_Cache",
        "./mock/Person", "ppwcode/collections/StoreOfStateful",
        "ppwcode/oddsAndEnds/typeOf"],
    function(dojo, doh,
             _Cache,
             Person, StoreOfStateful,
             typeOf) {

      var personId = 898942;
      var personJson = {
        "persistenceId":personId,
        "name":"Pete Peeters",
        "street":"Avenue de rue 93",
        "zip":"1040 CAA",
        "city":"Cité de Beauté",
        "tel":"0322 44 442 22"
      };

      function createPerson() {
        var person = new Person();
        person.reload(personJson);
        return person;
      }

      doh.register("_Cache", [

        function testConstructor() {
          var subject = new _Cache();
          doh.invars(subject);
          doh.t(subject._data);
          doh.t(typeOf(subject._data) === "object");
          doh.is(0, Object.keys(subject._data).length);
        },

        {
          name: "trackPo once",
          setUp: function() {
            this.person = createPerson();
            this.subject = new _Cache();
          },
          runTest: function() {
            this.subject.trackPo(this.person, this);
            var tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId);
            doh.is(this.person, tracked);
            tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(1, this.subject._data[this.person.get("persistenceType") + "@" + personId].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));
          },
          tearDown: function() {
            delete this.person;
            delete this.subject;
          }
        },

        {
          name: "trackPo trice",
          setUp: function() {
            this.person = createPerson();
            this.subject = new _Cache();
          },
          runTest: function() {
            this.subject.trackPo(this.person, this);
            this.subject.trackPo(this.person, {});
            this.subject.trackPo(this.person, {});
            var tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId);
            doh.is(this.person, tracked);
            tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(3, this.subject._data[this.person.get("persistenceType") + "@" + personId].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));
          },
          tearDown: function() {
            delete this.person;
            delete this.subject;
          }
        },

        {
          name: "trackPo quatro",
          setUp: function() {
            this.person = createPerson();
            this.subject = new _Cache();
            this.referer1 = {};
            this.referer2 = {};
          },
          runTest: function() {
            this.subject.trackPo(this.person, this);
            this.subject.trackPo(this.person, this.referer1);
            this.subject.trackPo(this.person, this.referer1);
            this.subject.trackPo(this.person, this.referer2);
            var tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId);
            doh.is(this.person, tracked);
            tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(3, this.subject._data[this.person.get("persistenceType") + "@" + personId].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));
          },
          tearDown: function() {
            delete this.person;
            delete this.subject;
            delete this.referer1;
            delete this.referer2;
          }
        },

        {
          name: "stopTracking",
          setUp: function() {
            this.person = createPerson();
            this.subject = new _Cache();
            this.referer1 = {};
            this.referer2 = {};
          },
          runTest: function() {
            this.subject.trackPo(this.person, this);
            this.subject.trackPo(this.person, this.referer1);
            this.subject.trackPo(this.person, this.referer1);
            this.subject.trackPo(this.person, this.referer2);
            var tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(3, this.subject._data[this.person.get("persistenceType") + "@" + personId].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.stopTracking(this.person, {});
            tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(3, this.subject._data[this.person.get("persistenceType") + "@" + personId].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.stopTracking(this.person, this.referer1);
            tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(2, this.subject._data[this.person.get("persistenceType") + "@" + personId].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.stopTracking(this.person, this.referer2);
            tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(1, this.subject._data[this.person.get("persistenceType") + "@" + personId].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.trackPo(this.person, this.referer1);
            tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(2, this.subject._data[this.person.get("persistenceType") + "@" + personId].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.stopTracking(this.person, this.referer1);
            tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(1, this.subject._data[this.person.get("persistenceType") + "@" + personId].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.stopTracking(this.person, this);
            tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId);
            doh.f(tracked);
            console.log(JSON.stringify(this.subject.report()));
          },
          tearDown: function() {
            delete this.person;
            delete this.subject;
            delete this.referer1;
            delete this.referer2;
          }
        }

      ]);
    }
);
<commit_msg>yep<commit_after>define(["dojo/main", "ppwcode/contracts/doh",
        "../_Cache",
        "./mock/Person", "ppwcode/collections/StoreOfStateful",
        "ppwcode/oddsAndEnds/typeOf"],
    function(dojo, doh,
             _Cache,
             Person, StoreOfStateful,
             typeOf) {

      var personId1 = 898942;
      var personJson = {
        "name":"Pete Peeters",
        "street":"Avenue de rue 93",
        "zip":"1040 CAA",
        "city":"Cité de Beauté",
        "tel":"0322 44 442 22"
      };

      function createPerson(persistenceId) {
        var person = new Person();
        person.persistenceId = persistenceId;
        person.reload(personJson);
        return person;
      }

      doh.register("_Cache", [

        function testConstructor() {
          var subject = new _Cache();
          doh.invars(subject);
          doh.t(subject._data);
          doh.t(typeOf(subject._data) === "object");
          doh.is(0, Object.keys(subject._data).length);
        },

        {
          name: "trackPo once",
          setUp: function() {
            this.person = createPerson(personId1);
            this.subject = new _Cache();
          },
          runTest: function() {
            this.subject.trackPo(this.person, this);
            var tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId1);
            doh.is(this.person, tracked);
            tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(1, this.subject._data[this.person.get("persistenceType") + "@" + personId1].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));
          },
          tearDown: function() {
            delete this.person;
            delete this.subject;
          }
        },

        {
          name: "trackPo trice",
          setUp: function() {
            this.person = createPerson(personId1);
            this.subject = new _Cache();
          },
          runTest: function() {
            this.subject.trackPo(this.person, this);
            this.subject.trackPo(this.person, {});
            this.subject.trackPo(this.person, {});
            var tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId1);
            doh.is(this.person, tracked);
            tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(3, this.subject._data[this.person.get("persistenceType") + "@" + personId1].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));
          },
          tearDown: function() {
            delete this.person;
            delete this.subject;
          }
        },

        {
          name: "trackPo quatro",
          setUp: function() {
            this.person = createPerson(personId1);
            this.subject = new _Cache();
            this.referer1 = {};
            this.referer2 = {};
          },
          runTest: function() {
            this.subject.trackPo(this.person, this);
            this.subject.trackPo(this.person, this.referer1);
            this.subject.trackPo(this.person, this.referer1);
            this.subject.trackPo(this.person, this.referer2);
            var tracked = this.subject.getPoByTypeAndId(this.person.get("persistenceType"), personId1);
            doh.is(this.person, tracked);
            tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(3, this.subject._data[this.person.get("persistenceType") + "@" + personId1].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));
          },
          tearDown: function() {
            delete this.person;
            delete this.subject;
            delete this.referer1;
            delete this.referer2;
          }
        },

        {
          name: "stopTracking",
          setUp: function() {
            this.person = createPerson(personId1);
            this.subject = new _Cache();
            this.referer1 = {};
            this.referer2 = {};
          },
          runTest: function() {
            this.subject.trackPo(this.person, this);
            this.subject.trackPo(this.person, this.referer1);
            this.subject.trackPo(this.person, this.referer1);
            this.subject.trackPo(this.person, this.referer2);
            var tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(3, this.subject._data[this.person.get("persistenceType") + "@" + personId1].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.stopTracking(this.person, {});
            tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(3, this.subject._data[this.person.get("persistenceType") + "@" + personId1].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.stopTracking(this.person, this.referer1);
            tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(2, this.subject._data[this.person.get("persistenceType") + "@" + personId1].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.stopTracking(this.person, this.referer2);
            tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(1, this.subject._data[this.person.get("persistenceType") + "@" + personId1].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.trackPo(this.person, this.referer1);
            tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(2, this.subject._data[this.person.get("persistenceType") + "@" + personId1].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.stopTracking(this.person, this.referer1);
            tracked = this.subject.getPo(this.person);
            doh.is(this.person, tracked);
            // IDEA test breaks encapsulation -- whenever this fails, just remove the test
            doh.is(1, this.subject._data[this.person.get("persistenceType") + "@" + personId1].getNrOfReferers());
            console.log(JSON.stringify(this.subject.report()));

            this.subject.stopTracking(this.person, this);
            tracked = this.subject.getPo(this.person);
            doh.f(tracked);
            console.log(JSON.stringify(this.subject.report()));
          },
          tearDown: function() {
            delete this.person;
            delete this.subject;
            delete this.referer1;
            delete this.referer2;
          }
        },

        {
          name: "recursiveStopTracking",
          setUp: function() {
            this.person1 = createPerson(personId1);
            this.person2 = createPerson(85029859025);
            this.person3 = createPerson(752890);
            this.person4 = createPerson(578059230);
            this.person5 = createPerson(74924902890);
            this.person6 = createPerson(524523523);
            this.subject = new _Cache();
            this.referer1 = {};
            this.referer2 = {};
          },
          runTest: function() {
            this.subject.trackPo(this.person1, this);
            this.subject.trackPo(this.person1, this.referer1);
            this.subject.trackPo(this.person1, this.referer2);

            this.subject.trackPo(this.person2, this.referer1);
            this.subject.trackPo(this.person3, this.person2);
            this.subject.trackPo(this.person5, this.person4);
            this.subject.trackPo(this.person4, this.person1);
            this.subject.trackPo(this.person6, this.person5);
            this.subject.trackPo(this.person6, this.referer1);

            this.subject.stopTracking(this.person1, this.referer1);
            this.subject.stopTracking(this.person1, this.referer2);
            this.subject.stopTracking(this.person1, this);

            tracked = this.subject.getPo(this.person1);
            doh.f(tracked);
            tracked = this.subject.getPo(this.person4);
            doh.f(tracked);
            tracked = this.subject.getPo(this.person5);
            doh.f(tracked);
            tracked = this.subject.getPo(this.person2);
            doh.t(tracked);
            tracked = this.subject.getPo(this.person3);
            doh.t(tracked);
            tracked = this.subject.getPo(this.person6);
            doh.t(tracked);

            this.subject.stopTracking(this.person6, this.referer1);
            tracked = this.subject.getPo(this.person6);
            doh.f(tracked);
            tracked = this.subject.getPo(this.person2);
            doh.t(tracked);
            tracked = this.subject.getPo(this.person3);
            doh.t(tracked);

            this.subject.stopTracking(this.person2, this.referer1);
            tracked = this.subject.getPo(this.person2);
            doh.f(tracked);
            tracked = this.subject.getPo(this.person3);
            doh.f(tracked);

            console.log(JSON.stringify(this.subject.report()));
          },
          tearDown: function() {
            delete this.person1;
            delete this.person2;
            delete this.person3;
            delete this.person4;
            delete this.person5;
            delete this.person6;
            delete this.subject;
            delete this.referer1;
            delete this.referer2;
          }
        }

      ]);
    }
);
<|endoftext|>