<commit_before>import * as d3 from 'd3';
import {
  generateRandom as _generateRandom,
  generateOneDimensionRandom
} from './utils';

const INTERVAL = 500;
const width = 400;
const height = 400;
const generateRandom = _generateRandom.bind(this, height);
const data = generateOneDimensionRandom(10, height);
const rectWidth = 25;
const margin = 10;
const svg = d3.select('body').append('svg')
              .attr('width', width)
              .attr('height', height);
let timeoutRef;
const output = d3.select('#data');

function drawRect() {
  const elements = svg.selectAll('.rect')
    .data(data);
  const enter = elements.enter();
  const exit = elements.exit();
  // update
  elements
    .transition()
    .attr('height', (d) => d);
  // enter
  enter.append('rect')
    .attr('class', 'rect')
    .attr('x', (d, i) => (rectWidth + margin) * i)
    .attr('width', rectWidth)
    .attr('height', 0)
    .transition()
    .attr('height', (d) => d);
  // exit
  exit.remove();
}

function outputData() {
  output.text(data.join(' , '));
}

const reDrawRect = drawRect;

outputData();
drawRect();

d3.select('#push').on('click', () => {
  data.push(generateRandom());
  outputData();
  reDrawRect();
});
d3.select('#shift').on('click', () => {
  data.shift();
  outputData();
  reDrawRect();
});
d3.select('#splice').on('click', () => {
  data.splice(1, 1, generateRandom());
  outputData();
  reDrawRect();
});

let run = false;

function draw() {
  run = true;
  data.push(generateRandom());
  data.shift();
  outputData();
  reDrawRect();
  timeoutRef = window.setTimeout(draw, INTERVAL);
}

draw();

d3.select('#auto').on('click', () => {
  if (!run) {
    draw();
  }
});

d3.select('#stop').on('click', () => {
  if (!!timeoutRef) {
    window.clearTimeout(timeoutRef);
  }
  run = false;
});

d3.select('#loadOndemand').on('click', () => {
  require.ensure([], (require) => {
    require('./load-on-demand');
  });
});
<commit_msg>add lable for bar chart<commit_after>import * as d3 from 'd3';
import {
  generateRandom as _generateRandom,
  generateOneDimensionRandom
} from './utils';

const INTERVAL = 1000;
const width = 400;
const height = 400;
const generateRandom = _generateRandom.bind(this, height);
const data = generateOneDimensionRandom(10, height);
const rectWidth = 30;
const margin = 10;
const svg = d3.select('body').append('svg')
              .attr('width', width)
              .attr('height', height);
let timeoutRef;
const output = d3.select('#data');

function drawRect() {
  const elements = svg.selectAll('.rect').data(data);
  const enter = elements.enter();
  const exit = elements.exit();
  // update
  elements.select('rect')
    .transition()
    .attr('height', (d) => d);

  elements.select('text')
    .transition()
    .attr('transform', (d) => `translate(${rectWidth / 2}, ${d})`)
    .text((d) => d);

  // enter
  const rectGroup = enter.append('g')
    .attr('class', 'rect')
    .attr('transform', (d, i) => `translate(${(rectWidth + margin) * i}, 0)`);

  rectGroup.append('rect')
    .attr('width', rectWidth)
    .attr('height', 0)
    .transition()
    .attr('height', (d) => d);

  rectGroup.append('text')
    .attr('fill', '#d62728')
    .attr('width', rectWidth + margin)
    .attr('text-anchor', 'middle')
    .attr('transform', 'translate(0, 0)')
    .transition()
    .attr('transform', (d) => `translate(${rectWidth / 2}, ${d})`)
    .text((d) => d);

  // exit
  exit.remove();
}

function outputData() {
  output.text(data.join(' , '));
}

const reDrawRect = drawRect;

outputData();
drawRect();

d3.select('#push').on('click', () => {
  data.push(generateRandom());
  outputData();
  reDrawRect();
});
d3.select('#shift').on('click', () => {
  data.shift();
  outputData();
  reDrawRect();
});
d3.select('#splice').on('click', () => {
  data.splice(1, 1, generateRandom());
  outputData();
  reDrawRect();
});

let run = false;

function draw() {
  run = true;
  data.push(generateRandom());
  data.shift();
  outputData();
  reDrawRect();
  timeoutRef = window.setTimeout(draw, INTERVAL);
}

draw();

d3.select('#auto').on('click', () => {
  if (!run) {
    draw();
  }
});

d3.select('#stop').on('click', () => {
  if (!!timeoutRef) {
    window.clearTimeout(timeoutRef);
  }
  run = false;
});

d3.select('#loadOndemand').on('click', () => {
  require.ensure([], (require) => {
    require('./load-on-demand');
  });
});
<|endoftext|>


<commit_before>var Editor = function() {
	var MAX_FILE_SIZE = 5 * 1024 * 1024;

	var mdjs = new Mdjs(getCustomMdjsRenderer());

	var Fs = new LocalFileSystem();
	var dlgBrowserFiles = browserStorageDialog;
	dlgBrowserFiles.onload(openFileInBrowserStorage);
	dlgBrowserFiles.ondel(list => toastInfo(`已删除 <b>${list.length}</b> 个浏览器存储的文件!`));

	var $container = $('#editorContainer'),
		$fname = $container.find('.editor-filename')
			.click(() => showRenameDialog(currentFileInfo.title)),
		$dndTip = $container.find('.editor-dnd-tip'),
		$navbar = $('#editorNavbar'),
		$fileDialog = $('#editorFileDialog'),
		$fileSaver = $('#editorFileSaver'),
		$editor = $('#editor'),
		$editorWrapper = $container.find('.editor-wrapper'),
		$outputWrapper = $container.find('.output-wrapper'),
		$output = $('#output');

	var $dlgFileName = $('#dlgNewFile'),
		$dlgFileNameInput = $dlgFileName.find('input'),
		isCreatingNewFile = false,
		loadingFileName = '';

	var $toastContainer = $container.find('.editor-toast');

	var currentFileInfo = {
		id: 0,
		title: '',
		content: '',
		timestamp: 0
	};

	var outputTmpl = $('#editorOutputTmpl').html();

	$editor.keydown(e => {
		//按下Tab键 插入Tab
		if (e.which == 9) {
			insertText('\t');
			return e.preventDefault();
		}
		if (e.which == 13) { //回车
			//TODO 自动对齐缩进
		}

	}).bind('input', () => {
		preview();
	});
	$editorWrapper.scroll(function () {//预览区域滚动
		var ih = $editorWrapper[0].scrollHeight - $editorWrapper.height(),
			oh = $outputWrapper[0].scrollHeight - $outputWrapper.height();
		var ipn = this.scrollTop;
		$outputWrapper[0].scrollTop = ipn/ih*oh;
	});
	//窗口尺寸调整重新预览(防止出现滚动条问题)
	$(document).resize(() => {
		preview();
	});

	//绑定本地文件读取回调
	Fs.on('load', content => openFile(loadingFileName, content))
		.on('error', err => toastError('读取本地文件出错:
' + err))
		.on('abort', () => toastWarn('读取本地文件操作被中断!'));

	//初始化文件拖入功能
	initFileDragAndDrop(document, {
		enter: () => $dndTip.show(),
		leave: () => $dndTip.hide(),
		drop: (file) => file ?
			Fs.readFile(file, 'utf8', $dndTip.hide(), loadingFileName = file.name) :
			$dndTip.hide()
	});
	//初始化导航栏的按钮事件
	initNavbarEvent();
	//初始化快捷键
	initShortcut();
	//初始化对话框相关
	initDialog();
	//恢复上次编辑内容
	restoreLastEditFile();

	function restoreLastEditFile() {
		var file = browserStorage.getLastEditFile();
		if (!file) return newFile();
		newFile(file.title, file.content, file.id);
		toastInfo(`已从浏览器存储内恢复了上次编辑文件<br><b>${file.title}</b>`, 2000);
	}

	function preview() {
		var markdown = $editor.val();
		currentFileInfo.content = markdown;
		//保存到localStorage(在内容不为空 或者 本来就存在于localstorage的情况)
		(markdown.trim() || browserStorage.exists(currentFileInfo.id) ) &&
			browserStorage.saveFile(currentFileInfo);

		//动态调整高度
		var ele = $editor[0], baseRow = markdown.split('\n').length;
		do {
			ele.rows = Math.max(baseRow, 20);
			baseRow += 5;
		} while(ele.scrollHeight > ele.clientHeight);
		$output.html(mdjs.md2html(markdown));
	}

	function setEditorSelection(start, end) {
		$editor[0].selectionStart = start;
		$editor[0].selectionEnd = end;
	}
	function getEditorSelection() {
		return { start: $editor[0].selectionStart, end: $editor[0].selectionEnd };
	}
	function insertText(text) {
		document.execCommand('insertText', false, text);
	}

	/**
	 * @param {String} [fname]
	 * @param {String} [content]
	 * @param {Number} [id]
	 */
	function newFile(fname, content, id) {
		$editor.val(content || '');
		currentFileInfo = { id: id || Date.now(), title: fname || '空白文档', content: content };
		_updateFileNameInThePage();
		preview();
	}
	function renameFile(fname) {
		currentFileInfo.title = fname;
		_updateFileNameInThePage();
	}
	function openFile(fname, content) {
		var match = fname.match(/^(.+)\./);
		fname = match ? match[1] : fname;
		newFile(fname, content);
		toastSuccess(`读取本地文件成功!<br/><b>${fname}</b>`);
	}
	function openFileInBrowserStorage(file) {
		newFile(file.title, file.content, file.id);
		toastInfo(`加载成功!<br/><b>${file.title}</b>`, 2000);
	}
	function exportMarkdown() {
		Fs.saveFile($fileSaver[0], currentFileInfo.title + '.md', $editor.val());
	}
	function exportHTML() {
		var obj = { title: getDocTitle(), body: $output.html(), toc: $output.find('#md_toc_content').html()},
			html = outputTmpl.replace(/\{\{\s+(\w+)\s+\}\}/g, (_, name) => obj[name] || '');
		//展开TOC
		html = html.replace('__show_if_export__', 'show');
		Fs.saveFile($fileSaver[0], currentFileInfo.title + '.html', html);
		function getDocTitle() {
			return ($output.find('h1,h2,h3,h4,h5,h6').eq(0).text()
				|| $output.find('p:eq(0)').text()).replace(/[\s\\\/\.\?\*\<\>\(\)\|\:\'\"]+/g, ' ');
		}
	}

	function _updateFileNameInThePage() {$fname.text(currentFileInfo.title)}

	function clickOpenLocalFile() {
		$fileDialog.off('change').on('change', () => {
			var file = $fileDialog[0].files[0], err;
			if (!file) return;
			if (!(err = _checkFileObj(file) ))
				return Fs.readFile(file, 'utf8', loadingFileName = file.name);
			toastError(err.error);
		}).click();
	}

	/**
	 * @description 检查一个文件对象是否合规(文件名和尺寸)
	 * @param {File} file
	 * @return {Object|void}
	 */
	function _checkFileObj(file) {
		var fname = file.name.toLowerCase();
		if(!fname.endsWith('.md') && !fname.endsWith('.markdown'))
			return { error: '你选择的文件不是Markdown文件' };
		if(file.size > MAX_FILE_SIZE)
			return { error: '你选择的文件过大,无法打开!' };
		return;
	}

// Navbar button ====================
	function initNavbarEvent() {
		var eventMap = {
			"new": showNewFileDialog,
			open_local: clickOpenLocalFile,
			open_browser: dlgBrowserFiles.open,
			export_markdown: exportMarkdown,
			export_html: exportHTML
		};
		$navbar.find('[data-navid]').each((i, e) => $(e).bind('click', eventMap[$(e).data('navid')]));
	}
//===================== Navbar button

// Dialog ===========================
	function initDialog() {
		$dlgFileName.on('shown.bs.modal', () => {
			$dlgFileNameInput.focus().select();
			$dlgFileNameInput[0].selectionStart = 0;
			$dlgFileNameInput[0].selectionEnd = $dlgFileNameInput.val().length;
		}).find('.btn-ok').click(() => {
			var fname = $dlgFileNameInput.val().trim();
			if (!fname)
				return $dlgFileNameInput.addClass('form-control-danger')
					.parents('.input-group').addClass('has-danger');
			$dlgFileName.modal('hide');
			isCreatingNewFile ? newFile(fname) : renameFile(fname);
		}).end().find('input').focusin(() => {
			$dlgFileNameInput.removeClass('form-control-danger')
				.parents('.input-group').removeClass('has-danger');
		}).keydown(event => void (event.which == 13 && $dlgFileName.find('.btn-ok').click()) );
	}
	function showRenameDialog() { isCreatingNewFile = false;_showFileNameDialog('修改名称', currentFileInfo.title); }
	function showNewFileDialog() { isCreatingNewFile = true; _showFileNameDialog('新建文件', '空白文档'); }
	function _showFileNameDialog(title, filename) {
		$dlgFileName.modal().find('.modal-title').text(title).end().find('input').val(filename);
	}

//============================ Dialog

//  Toast ===========================
	function toast(type, msg, time) {
		var $alert = $toastContainer.find('.alert').hide().end()
			.find(`.alert-${type}`);
		$alert.fadeIn().find('span').html(msg);
		setTimeout(() => $alert.fadeOut(), time || 4000);
	}
	function toastError(msg, time) { toast('danger', msg, time); }
	function toastWarn(msg, time) { toast('warning', msg, time); }
	function toastSuccess(msg, time) { toast('success', msg, time); }
	function toastInfo(msg, time) { toast('info', msg, time);}
//=============================  Toast

//  KeyShortcut ======================
	var shortcutFuncMap = {};
	function initShortcut() {
		document.onkeydown = e => {
			if(!e.ctrlKey || e.shiftKey || e.altKey)return true;
			if (shortcutFuncMap[e.which] == undefined) return true;
			shortcutFuncMap[e.which]();
			return false;
		};
	}
//=======================  KeyShortcut

};
window.editor = new Editor();<commit_msg>fix listen window resize event to refresh preview<commit_after>var Editor = function() {
	var MAX_FILE_SIZE = 5 * 1024 * 1024;

	var mdjs = new Mdjs(getCustomMdjsRenderer());

	var Fs = new LocalFileSystem();
	var dlgBrowserFiles = browserStorageDialog;
	dlgBrowserFiles.onload(openFileInBrowserStorage);
	dlgBrowserFiles.ondel(list => toastInfo(`已删除 <b>${list.length}</b> 个浏览器存储的文件!`));

	var $container = $('#editorContainer'),
		$fname = $container.find('.editor-filename')
			.click(() => showRenameDialog(currentFileInfo.title)),
		$dndTip = $container.find('.editor-dnd-tip'),
		$navbar = $('#editorNavbar'),
		$fileDialog = $('#editorFileDialog'),
		$fileSaver = $('#editorFileSaver'),
		$editor = $('#editor'),
		$editorWrapper = $container.find('.editor-wrapper'),
		$outputWrapper = $container.find('.output-wrapper'),
		$output = $('#output');

	var $dlgFileName = $('#dlgNewFile'),
		$dlgFileNameInput = $dlgFileName.find('input'),
		isCreatingNewFile = false,
		loadingFileName = '';

	var $toastContainer = $container.find('.editor-toast');

	var currentFileInfo = {
		id: 0,
		title: '',
		content: '',
		timestamp: 0
	};

	var outputTmpl = $('#editorOutputTmpl').html();

	$editor.keydown(e => {
		//按下Tab键 插入Tab
		if (e.which == 9) {
			insertText('\t');
			return e.preventDefault();
		}
		if (e.which == 13) { //回车
			//TODO 自动对齐缩进
		}

	}).bind('input', () => {
		preview();
	});
	$editorWrapper.scroll(function () {//预览区域滚动
		var ih = $editorWrapper[0].scrollHeight - $editorWrapper.height(),
			oh = $outputWrapper[0].scrollHeight - $outputWrapper.height();
		var ipn = this.scrollTop;
		$outputWrapper[0].scrollTop = ipn/ih*oh;
	});
	//窗口尺寸调整重新预览(防止出现滚动条问题)
	$(window).resize(() => {
		preview();
	});

	//绑定本地文件读取回调
	Fs.on('load', content => openFile(loadingFileName, content))
		.on('error', err => toastError('读取本地文件出错:
' + err))
		.on('abort', () => toastWarn('读取本地文件操作被中断!'));

	//初始化文件拖入功能
	initFileDragAndDrop(document, {
		enter: () => $dndTip.show(),
		leave: () => $dndTip.hide(),
		drop: (file) => file ?
			Fs.readFile(file, 'utf8', $dndTip.hide(), loadingFileName = file.name) :
			$dndTip.hide()
	});
	//初始化导航栏的按钮事件
	initNavbarEvent();
	//初始化快捷键
	initShortcut();
	//初始化对话框相关
	initDialog();
	//恢复上次编辑内容
	restoreLastEditFile();

	function restoreLastEditFile() {
		var file = browserStorage.getLastEditFile();
		if (!file) return newFile();
		newFile(file.title, file.content, file.id);
		toastInfo(`已从浏览器存储内恢复了上次编辑文件<br><b>${file.title}</b>`, 2000);
	}

	function preview() {
		var markdown = $editor.val();
		currentFileInfo.content = markdown;
		//保存到localStorage(在内容不为空 或者 本来就存在于localstorage的情况)
		(markdown.trim() || browserStorage.exists(currentFileInfo.id) ) &&
			browserStorage.saveFile(currentFileInfo);

		//动态调整高度
		var ele = $editor[0], baseRow = markdown.split('\n').length;
		do {
			ele.rows = Math.max(baseRow, 20);
			baseRow += 10;
		} while (ele.scrollHeight > ele.clientHeight);
		var html = mdjs.md2html(markdown);
		$output.html(html);
	}

	function setEditorSelection(start, end) {
		$editor[0].selectionStart = start;
		$editor[0].selectionEnd = end;
	}
	function getEditorSelection() {
		return { start: $editor[0].selectionStart, end: $editor[0].selectionEnd };
	}
	function insertText(text) {
		document.execCommand('insertText', false, text);
	}

	/**
	 * @param {String} [fname]
	 * @param {String} [content]
	 * @param {Number} [id]
	 */
	function newFile(fname, content, id) {
		$editor.val(content || '');
		currentFileInfo = { id: id || Date.now(), title: fname || '空白文档', content: content };
		_updateFileNameInThePage();
		preview();
	}
	function renameFile(fname) {
		currentFileInfo.title = fname;
		_updateFileNameInThePage();
	}
	function openFile(fname, content) {
		var match = fname.match(/^(.+)\./);
		fname = match ? match[1] : fname;
		newFile(fname, content);
		toastSuccess(`读取本地文件成功!<br/><b>${fname}</b>`);
	}
	function openFileInBrowserStorage(file) {
		newFile(file.title, file.content, file.id);
		toastInfo(`加载成功!<br/><b>${file.title}</b>`, 2000);
	}
	function exportMarkdown() {
		Fs.saveFile($fileSaver[0], currentFileInfo.title + '.md', $editor.val());
	}
	function exportHTML() {
		var obj = { title: getDocTitle(), body: $output.html(), toc: $output.find('#md_toc_content').html()},
			html = outputTmpl.replace(/\{\{\s+(\w+)\s+\}\}/g, (_, name) => obj[name] || '');
		//展开TOC
		html = html.replace('__show_if_export__', 'show');
		Fs.saveFile($fileSaver[0], currentFileInfo.title + '.html', html);
		function getDocTitle() {
			return ($output.find('h1,h2,h3,h4,h5,h6').eq(0).text()
				|| $output.find('p:eq(0)').text()).replace(/[\s\\\/\.\?\*\<\>\(\)\|\:\'\"]+/g, ' ');
		}
	}

	function _updateFileNameInThePage() {$fname.text(currentFileInfo.title)}

	function clickOpenLocalFile() {
		$fileDialog.off('change').on('change', () => {
			var file = $fileDialog[0].files[0], err;
			if (!file) return;
			if (!(err = _checkFileObj(file) ))
				return Fs.readFile(file, 'utf8', loadingFileName = file.name);
			toastError(err.error);
		}).click();
	}

	/**
	 * @description 检查一个文件对象是否合规(文件名和尺寸)
	 * @param {File} file
	 * @return {Object|void}
	 */
	function _checkFileObj(file) {
		var fname = file.name.toLowerCase();
		if(!fname.endsWith('.md') && !fname.endsWith('.markdown'))
			return { error: '你选择的文件不是Markdown文件' };
		if(file.size > MAX_FILE_SIZE)
			return { error: '你选择的文件过大,无法打开!' };
		return;
	}

// Navbar button ====================
	function initNavbarEvent() {
		var eventMap = {
			"new": showNewFileDialog,
			open_local: clickOpenLocalFile,
			open_browser: dlgBrowserFiles.open,
			export_markdown: exportMarkdown,
			export_html: exportHTML
		};
		$navbar.find('[data-navid]').each((i, e) => $(e).bind('click', eventMap[$(e).data('navid')]));
	}
//===================== Navbar button

// Dialog ===========================
	function initDialog() {
		$dlgFileName.on('shown.bs.modal', () => {
			$dlgFileNameInput.focus().select();
			$dlgFileNameInput[0].selectionStart = 0;
			$dlgFileNameInput[0].selectionEnd = $dlgFileNameInput.val().length;
		}).find('.btn-ok').click(() => {
			var fname = $dlgFileNameInput.val().trim();
			if (!fname)
				return $dlgFileNameInput.addClass('form-control-danger')
					.parents('.input-group').addClass('has-danger');
			$dlgFileName.modal('hide');
			isCreatingNewFile ? newFile(fname) : renameFile(fname);
		}).end().find('input').focusin(() => {
			$dlgFileNameInput.removeClass('form-control-danger')
				.parents('.input-group').removeClass('has-danger');
		}).keydown(event => void (event.which == 13 && $dlgFileName.find('.btn-ok').click()) );
	}
	function showRenameDialog() { isCreatingNewFile = false;_showFileNameDialog('修改名称', currentFileInfo.title); }
	function showNewFileDialog() { isCreatingNewFile = true; _showFileNameDialog('新建文件', '空白文档'); }
	function _showFileNameDialog(title, filename) {
		$dlgFileName.modal().find('.modal-title').text(title).end().find('input').val(filename);
	}

//============================ Dialog

//  Toast ===========================
	function toast(type, msg, time) {
		var $alert = $toastContainer.find('.alert').hide().end()
			.find(`.alert-${type}`);
		$alert.fadeIn().find('span').html(msg);
		setTimeout(() => $alert.fadeOut(), time || 4000);
	}
	function toastError(msg, time) { toast('danger', msg, time); }
	function toastWarn(msg, time) { toast('warning', msg, time); }
	function toastSuccess(msg, time) { toast('success', msg, time); }
	function toastInfo(msg, time) { toast('info', msg, time);}
//=============================  Toast

//  KeyShortcut ======================
	var shortcutFuncMap = {};
	function initShortcut() {
		document.onkeydown = e => {
			if(!e.ctrlKey || e.shiftKey || e.altKey)return true;
			if (shortcutFuncMap[e.which] == undefined) return true;
			shortcutFuncMap[e.which]();
			return false;
		};
	}
//=======================  KeyShortcut

};
window.editor = new Editor();<|endoftext|>


<commit_before>(function () {
  'use strict';

  // mihalism v1
  $.register({
    rule: {
      host: /^(pornpicuploader|imagepremium|hentai-hosting|gallery\.jpavgod|miragepics|funextra\.hostzi)\.com|freeuploadimages\.org|shareimage\.ro|bilder\.nixhelp\.de|imagecurl\.(com|org)|imagevau\.eu|img\.deli\.sh|sangjkay\.biz$/,
      path: /^\/viewer\.php$/,
      query: /^\?file=([^&]+)/,
    },
    start: function (m) {
      $.openImage('/images/' + m.query[1]);
    },
  });

  // mihalism v2
  $.register({
    rule: {
      host: /^love69\.org$/,
      path: /^\/i\/viewer\.php$/,
      query: /^\?file=([^&]+)/,
    },
    start: function (m) {
      $.openImage('/i/images/' + m.query[1]);
    },
  });

  // mihalism v3
  $.register({
    rule: {
      host: /howtohemorrhoidscure\.com|javimage\.us/,
      path: /^\/viewer\.php$/,
      query: /^\?file=([^&]+)/,
    },
    ready: function () {
      var a = $('#page_body a');
      var s = a.href;
      // the real link is diffirent from original host
      a = s.lastIndexOf('http://');
      if (a >= 0) {
        $.openLink(s.substr(a));
      }
    },
  });

  // preview.jpavgod.com
  $.register({
    rule: [
      'http://hostpornpics.net/viewer.php?*file=*',
      'http://preview.jpavgod.com/*.html',
    ],
    ready: function () {
      var i = $('#page_body div.text_align_center img');
      $.openImage(i.src);
    },
  });

  // dwimg.com
  $.register({
    rule: {
      host: /^(dwimg|imgsin)\.com$/,
      path: /^\/viewer\.php$/,
      query: /^\?file=([^&]+)/,
    },
    start: function (m) {
      $.openImage('/files/' + m.query[1]);
    },
  });

})();

// ex: ts=2 sts=2 sw=2 et
// sublime: tab_size 2; translate_tabs_to_spaces true; detect_indentation false; use_tab_stops true;
// kate: space-indent on; indent-width 2;
<commit_msg>love69.org<commit_after>(function () {
  'use strict';

  // mihalism v1
  $.register({
    rule: {
      host: /^(pornpicuploader|imagepremium|hentai-hosting|gallery\.jpavgod|miragepics|funextra\.hostzi)\.com|freeuploadimages\.org|shareimage\.ro|bilder\.nixhelp\.de|imagecurl\.(com|org)|imagevau\.eu|img\.deli\.sh|sangjkay\.biz$/,
      path: /^\/viewer\.php$/,
      query: /^\?file=([^&]+)/,
    },
    start: function (m) {
      $.openImage('/images/' + m.query[1]);
    },
  });

  // mihalism v2
  $.register({
    rule: {
      host: /^love69\.org$/,
      path: /^\/(i|eu)\/viewer\.php$/,
      query: /^\?file=([^&]+)/,
    },
    start: function (m) {
      var url = _.T('/{0}/images/{1}');
      $.openImage(url(m.path[1], m.query[1]));
    },
  });

  // mihalism v3
  $.register({
    rule: {
      host: /howtohemorrhoidscure\.com|javimage\.us/,
      path: /^\/viewer\.php$/,
      query: /^\?file=([^&]+)/,
    },
    ready: function () {
      var a = $('#page_body a');
      var s = a.href;
      // the real link is diffirent from original host
      a = s.lastIndexOf('http://');
      if (a >= 0) {
        $.openLink(s.substr(a));
      }
    },
  });

  // preview.jpavgod.com
  $.register({
    rule: [
      'http://hostpornpics.net/viewer.php?*file=*',
      'http://preview.jpavgod.com/*.html',
    ],
    ready: function () {
      var i = $('#page_body div.text_align_center img');
      $.openImage(i.src);
    },
  });

  // dwimg.com
  $.register({
    rule: {
      host: /^(dwimg|imgsin)\.com$/,
      path: /^\/viewer\.php$/,
      query: /^\?file=([^&]+)/,
    },
    start: function (m) {
      $.openImage('/files/' + m.query[1]);
    },
  });

})();

// ex: ts=2 sts=2 sw=2 et
// sublime: tab_size 2; translate_tabs_to_spaces true; detect_indentation false; use_tab_stops true;
// kate: space-indent on; indent-width 2;
<|endoftext|>


<commit_before>import Phaser from 'phaser'

export default class extends Phaser.Sprite {
  constructor (game, x, y, options = { canTurn: false, isFalling: true }) {
    super(game, x, y, 'chars_small', 165)

    this.canTurn = options.canTurn
    this.isFalling = options.isFalling

    this.anchor.setTo(0.5)

    this.game.physics.arcade.enable(this)

    this.cursors = this.game.input.keyboard.createCursorKeys()

    this.wasd = {
      up: this.game.input.keyboard.addKey(Phaser.Keyboard.W),
      down: this.game.input.keyboard.addKey(Phaser.Keyboard.S),
      left: this.game.input.keyboard.addKey(Phaser.Keyboard.A),
      right: this.game.input.keyboard.addKey(Phaser.Keyboard.D)
    }

    this.game.input.gamepad.start()

    // Add a bitchin trail because we are going supersonic
    this.playerTrail = this.game.add.emitter(this.x, this.y, 15)
    this.playerTrail.makeParticles('chars_small', 165)
    this.playerTrail.setXSpeed(0, 0)
    this.playerTrail.setYSpeed(0, 0)
    this.playerTrail.setAlpha(0.4, 0.01, 150)
    this.playerTrail.setRotation(0)
    this.playerTrail.start(false, 50, 10)

    // Default maxVelocity in 1G, this magic number is used everywhere
    this.body.maxVelocity.x = 800;
  }

  resetWithAnimation () {
    var duration = 500

    var x = this.x
    var y = this.y

    this.emitter = this.game.add.emitter(x, y, 6)
    this.emitter.makeParticles('chars_small', 200)
    this.emitter.width = 10
    this.emitter.height = 10
    this.emitter.minParticleScale = 0.5
    this.emitter.maxParticleScale = 3
    this.emitter.minParticleSpeed.set(0, 0)
    this.emitter.maxParticleSpeed.set(0, 0)
    this.emitter.gravity = 0
    this.emitter.start(false, duration, 50, 6)

    var player = this
    var world = this.game.world
    player.kill()

    setTimeout(function () {
      player.reset(50, world.centerY)
    }, duration)
  }

  update () {
    this.playerTrail.x = this.x
    this.playerTrail.y = this.y

    const accY = 800

    if (this.isMovingUp()) {
      if (this.isFalling || (!this.isFalling && this.body.onFloor())) {
        this.body.velocity.y = -accY
      }
    } else if (this.isMovingDown()) {
      if (this.isFalling) {
        this.body.velocity.y = accY
      }
    } else {
      this.body.velocity.y = 0;
    }

    const accX = 150
    if (this.isMovingLeft()) {
      this.body.velocity.x = - 3 * accX
      if (this.canTurn) {
        this.scale.setTo(-1, 1)
      }
    } else if (this.isMovingRight()) {
      if (this.body.maxVelocity.x <= 800 * 1.4) {
        this.body.maxVelocity.x += accX;
      }
      this.body.velocity.x += accX
      if (this.canTurn) {
        this.scale.setTo(1, 1)
      }
    } else {
      this.body.maxVelocity.x = 800;
    }
  }

  isMovingUp () {
    const pad1 = this.game.input.gamepad.pad1
    return this.cursors.up.isDown || this.wasd.up.isDown || pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_UP) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) < -0.1
  }

  isMovingDown () {
    const pad1 = this.game.input.gamepad.pad1
    return this.cursors.down.isDown || this.wasd.down.isDown || pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_DOWN) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) > 0.1
  }

  isMovingLeft () {
    const pad1 = this.game.input.gamepad.pad1
    return this.cursors.left.isDown || this.wasd.left.isDown || pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_LEFT) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) < -0.1
  }

  isMovingRight () {
    const pad1 = this.game.input.gamepad.pad1
    return this.cursors.right.isDown || this.wasd.right.isDown || pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_RIGHT) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) > 0.1
  }
}
<commit_msg>Revert "Player maxVelocity.x 1400 to 800."<commit_after>import Phaser from 'phaser'

export default class extends Phaser.Sprite {
  constructor (game, x, y, options = { canTurn: false, isFalling: true }) {
    super(game, x, y, 'chars_small', 165)

    this.canTurn = options.canTurn
    this.isFalling = options.isFalling

    this.anchor.setTo(0.5)

    this.game.physics.arcade.enable(this)

    this.cursors = this.game.input.keyboard.createCursorKeys()

    this.wasd = {
      up: this.game.input.keyboard.addKey(Phaser.Keyboard.W),
      down: this.game.input.keyboard.addKey(Phaser.Keyboard.S),
      left: this.game.input.keyboard.addKey(Phaser.Keyboard.A),
      right: this.game.input.keyboard.addKey(Phaser.Keyboard.D)
    }

    this.game.input.gamepad.start()

    // Add a bitchin trail because we are going supersonic
    this.playerTrail = this.game.add.emitter(this.x, this.y, 15)
    this.playerTrail.makeParticles('chars_small', 165)
    this.playerTrail.setXSpeed(0, 0)
    this.playerTrail.setYSpeed(0, 0)
    this.playerTrail.setAlpha(0.8, 0.01, 150)
    this.playerTrail.setRotation(0)
    this.playerTrail.start(false, 50, 10)

    // Default maxVelocity in 1G, this magic number is used everywhere
    this.body.maxVelocity.x = 1400;
  }

  resetWithAnimation () {
    var duration = 500

    var x = this.x
    var y = this.y

    this.emitter = this.game.add.emitter(x, y, 6)
    this.emitter.makeParticles('chars_small', 200)
    this.emitter.width = 10
    this.emitter.height = 10
    this.emitter.minParticleScale = 0.5
    this.emitter.maxParticleScale = 3
    this.emitter.minParticleSpeed.set(0, 0)
    this.emitter.maxParticleSpeed.set(0, 0)
    this.emitter.gravity = 0
    this.emitter.start(false, duration, 50, 6)

    var player = this
    var world = this.game.world
    player.kill()

    setTimeout(function () {
      player.reset(50, world.centerY)
    }, duration)
  }

  update () {
    this.playerTrail.x = this.x
    this.playerTrail.y = this.y

    const accY = 800

    if (this.isMovingUp()) {
      if (this.isFalling || (!this.isFalling && this.body.onFloor())) {
        this.body.velocity.y = -accY
      }
    } else if (this.isMovingDown()) {
      if (this.isFalling) {
        this.body.velocity.y = accY
      }
    } else {
      this.body.velocity.y = 0;
    }

    const accX = 150
    if (this.isMovingLeft()) {
      this.body.velocity.x = - 3 * accX
      if (this.canTurn) {
        this.scale.setTo(-1, 1)
      }
    } else if (this.isMovingRight()) {
      if (this.body.maxVelocity.x <= 1400 * 1.4) {
        this.body.maxVelocity.x += accX;
      }
      this.body.velocity.x += accX
      if (this.canTurn) {
        this.scale.setTo(1, 1)
      }
    } else {
      this.body.maxVelocity.x = 1400;
    }
  }

  isMovingUp () {
    const pad1 = this.game.input.gamepad.pad1
    return this.cursors.up.isDown || this.wasd.up.isDown || pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_UP) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) < -0.1
  }

  isMovingDown () {
    const pad1 = this.game.input.gamepad.pad1
    return this.cursors.down.isDown || this.wasd.down.isDown || pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_DOWN) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) > 0.1
  }

  isMovingLeft () {
    const pad1 = this.game.input.gamepad.pad1
    return this.cursors.left.isDown || this.wasd.left.isDown || pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_LEFT) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) < -0.1
  }

  isMovingRight () {
    const pad1 = this.game.input.gamepad.pad1
    return this.cursors.right.isDown || this.wasd.right.isDown || pad1.isDown(Phaser.Gamepad.XBOX360_DPAD_RIGHT) || pad1.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) > 0.1
  }
}
<|endoftext|>


<commit_before>// Replicator

Substance.Replicator = function(params) {
  this.store = params.store;
  this.user = params.user; // Current user scope

  var that = this;

  // Util
  function extractCommits(doc, start, end) {
    var skip = false;

    if (start === end) return [];
    var commit = doc.commits[start];

    if (!commit) return [];
    commit.sha = start;

    var commits = [commit];
    var prev = commit;

    while (!skip && (commit = doc.commits[commit.parent])) {
      if (end && commit.sha === end) {
        skip = true;
      } else {
        commit.sha = prev.parent;
        commits.push(commit);
        prev = commit;
      }
    }
    return commits.reverse();
  }

  // Start sync
  // -----------------

  this.sync = function(cb) {
  	this.computeJobs(function(err, jobs) {
      console.log('JOBS', jobs);
  		var index = 0;

  		function next() {
  			if (index === jobs.length) return cb(null);
  			that.processDocument(jobs[index], function(err) {
          if (err) console.log('ERROR WHILE PROCSSING JOB', jobs[index], "ERROR", err);
  				index += 1;
  				next();
  			});
  		}

  		next(); // start processing the first doc
  	});
  };

  // Process a single doc sync job
  // -----------------

  this.processDocument = function(doc, cb) {
    if (doc.action === "create") return that.create(doc, cb);
    if (doc.action === "push") return that.push(doc, cb);
    if (doc.action === "pull") return that.pull(doc, cb);
    if (doc.action === "fetch") return that.fetch(doc, cb);
  };

  // Fetch doc from remote store
  // -----------------
  //
  // TODO: create dedicated fetch method on server, returning commits in a sequence
  // so we don't have to use extractCommits

  this.fetch = function(doc, cb) {
    console.log('fetching ', doc.id, ' from server');
    _.request("GET", Substance.settings.hub + '/documents/get/'+that.user+'/'+doc.id, {}, function(err, doc) {

      console.log('THE DOC, just fetched', doc);
      // var commits = store.commits(doc.id, doc.refs.tail);
      var commits = extractCommits(doc, doc.refs.tail);
      console.log('commits to be applied locally', commits);

      // 1. create doc locally
      store.create(doc.id, function(err) {
        if (err) return cb(err);
        // 2. send commits
        console.log('storing commits');
        store.update(doc.id, commits, function(err) {
          console.log('updated local doc. ERRORS?', err);
          if (err) return cb(err);

          // TODO: Update meta accordingly.
          console.log('updating local metadata from server', doc.meta);

          store.updateMeta(doc.id, doc.meta, function(err) {
            store.setRef(doc.id, 'tail-remote', doc.refs.tail);
            store.setRef(doc.id, 'tail-master', doc.refs.master);
            // In case there are some undone commits
            store.setRef(doc.id, 'master', doc.refs.master);

            cb(err);
          });
        });
      });
    });
  };

  // Pull
  // -----------------
  //
  // TODO: Fetch metadata on pull and update locally / this overwrites pending local commits

  this.pull = function(doc, cb) {
    // Get latest synced commit
    var tailRemote = store.getRef(doc.id, 'tail-remote');
    console.log('pulling in changes... for', tailRemote);

    _.request("GET", Substance.settings.hub + '/documents/commits/'+that.user+'/'+doc.id+'/'+tailRemote, {}, function(err, data) {
      console.log('what does remote say?', data);
      console.log('remote commits', data.commits);
      // Should also give me remote refs
      // data.commits |data.refs
      if (data.commits.length > 0) {
        store.update(doc.id, data.commits, function(err) {
          console.log('applied remote commits.. Any ERRORS?', err);

          // Update references
          store.setRef(doc.id, 'master', data.refs.master);
          store.setRef(doc.id, 'tail', data.refs.tail); // now done implicitly by update

          // Tail and master are now up to date. Now set 'tail-remote' to new tail
          store.setRef(doc.id, 'tail-remote', data.refs.tail);
          store.setRef(doc.id, 'master-remote', data.refs.master);

          // Update metadata (remote version)
          store.updateMeta(doc.id, data.meta);
          cb(null);
        });
      } else {
        // Update metadata (remote version)
        store.updateMeta(doc.id, data.meta);
        cb(null);
      }
    });
  };

  // Push
  // -----------------

  this.push = function(doc, cb) {
    store.get(doc.id, function(err, doc) {
      var remoteTail = store.getRef(doc.id, 'tail-remote');
      var localTail = store.getRef(doc.id, 'tail');

      // Find all commits after synced (remote) commit
      var commits = store.commits(doc.id, localTail, remoteTail);

      console.log('LE LOCAL COMMITTES to be pushed: ', commits);

      var data = {
        username: that.user,
        id: doc.id,
        commits: commits, // may be empty
        meta: doc.meta,
        refs: doc.refs // make sure refs are updated on the server (for now master, tail is updated implicitly)
      };

      _.request("POST", Substance.settings.hub + '/documents/update', data, function (err) {
        // Set synced reference accordingly
        if (err) return cb(err);
        store.setRef(doc.id, 'tail-remote', doc.refs.tail);
        store.setRef(doc.id, 'master-remote', doc.refs.master);

        cb(null);
      });
    });
  };

  // Sync doc with remote store (bi-directional)
  // -----------------

  // this.update = function(doc, cb) {
  //   that.pull(doc, function(err, fastForward) {
  //     // For now only fast forward sync works smoothly
  //     // In case ther are local changes, they are lost (not pushed! what ever is on the server wins)
  //     if (fastForward) {
  //       that.push(doc, cb);
  //       console.log('pull successfull. no changes.. fast forwarding..');
  //     } else {
  //       console.log('pull with changes ignoring local changes');
  //       cb(null); // done
  //     }
  //   });
  // };

  // Create doc on the server
  // -----------------

  this.create = function(doc, cb) {
    console.log('creating ', doc.id, ' on the server');

    // 1. Get doc from local docstore
    store.get(doc.id, function(err, doc) {
      // extract commits
      var commits = store.commits(doc.id, doc.refs.tail);
      console.log("COMMITS OF NEW DOC", commits);
      // 2. Create empty doc on the server
      _.request("POST", Substance.settings.hub + '/documents/create', {"username": that.user, id: doc.id}, function (err) {
        console.log('created on the server..');
        if (err) return cb(err);
        // 3. Send updates to server
        _.request("POST", Substance.settings.hub + '/documents/update', {"username": that.user, id: doc.id, commits: commits, meta: doc.meta}, function (err) {
          store.setRef(doc.id, 'tail-remote', doc.refs.tail);
          store.setRef(doc.id, 'master-remote', doc.refs.master);
          cb(err);
        });
      });
    });
  };

  // Compute jobs for dirty documents
  // -----------------

  this.computeJobs = function(cb) {
  	// Status object looks like this
    var jobs = [];
    that.localDocStates(function(err, localDocs) {
      _.request("GET", Substance.settings.hub + '/documents/status/'+that.user, {}, function (err, remoteDocs) {
        console.log('diff', localDocs, remoteDocs);

        _.each(localDocs, function(doc, id) {
          var remoteDoc = remoteDocs[id];
          // New unsynced doc?
          if (!remoteDoc) {
            jobs.push({id: id, action: "create"});
            return;
          }

          // Local refs
          var masterRemote = store.getRef(id, 'master-remote');
          var tailRemote = store.getRef(id, 'tail-remote');

          if (tailRemote !== remoteDoc.refs['tail'] || masterRemote !== remoteDoc.refs['master']) {
            jobs.push({id: id, action: "pull"});
            return;
          } else if (tailRemote !== doc.refs['tail'] || doc.refs['master'] !== masterRemote) {
            // Local changes only -> Push (fast-forward)
            jobs.push({id: id, action: "push"});
            return;
          }
        });

        _.each(remoteDocs, function(remoteDoc, id) {
          var doc = localDocs[id];

          // New remote doc? -> Fetch
          if (!doc) {
            jobs.push({id: id, action: "fetch"});
            return;
          }
        });

        cb(null, jobs);
      });
    });
  };

  // Ask for status of all local documents
  // -----------------
  //
  // Returns: A hash of document status objects

  this.localDocStates = function(cb) {
    store.list(function(err, localDocs) {
      var result = {};
      _.each(localDocs, function(doc) {
        result[doc.id] = doc;
        delete result[doc.id].id;
      });
      cb(null, result);
    });
  };

};<commit_msg>Replicator, less code needed.<commit_after>// Replicator

Substance.Replicator = function(params) {
  this.store = params.store;
  this.user = params.user; // Current user scope

  var that = this;

  // Start sync
  // -----------------

  this.sync = function(cb) {
  	this.computeJobs(function(err, jobs) {
      console.log('JOBS', jobs);
  		var index = 0;

  		function next() {
  			if (index === jobs.length) return cb(null);
  			that.processDocument(jobs[index], function(err) {
          if (err) console.log('ERROR WHILE PROCSSING JOB', jobs[index], "ERROR", err);
  				index += 1;
  				next();
  			});
  		}

  		next(); // start processing the first doc
  	});
  };

  // Process a single doc sync job
  // -----------------

  this.processDocument = function(doc, cb) {
    if (doc.action === "create") return that.create(doc, cb);
    if (doc.action === "push") return that.push(doc, cb);
    if (doc.action === "pull") return that.pull(doc, cb);
    if (doc.action === "fetch") return that.fetch(doc, cb);
  };

  // Fetch doc from remote store
  // -----------------

  this.fetch = function(doc, cb) {
    // 1. create doc locally
    store.create(doc.id, function(err) {
      if (err) return cb(err);
      // 2. Pull in remote data
      that.pull(doc, cb);
    });
  };

  // Pull
  // -----------------
  //
  // TODO: Fetch metadata on pull and update locally / this overwrites pending local commits

  this.pull = function(doc, cb) {
    // Get latest synced commit
    var tailRemote = store.getRef(doc.id, 'tail-remote');
    console.log('pulling in changes... for', tailRemote);

    _.request("GET", Substance.settings.hub + '/documents/commits/'+that.user+'/'+doc.id+'/'+tailRemote, {}, function(err, data) {
      console.log('what does remote say?', data);
      console.log('remote commits', data.commits);
      // Should also give me remote refs
      // data.commits |data.refs
      if (data.commits.length > 0) {
        store.update(doc.id, data.commits, function(err) {
          console.log('applied remote commits.. Any ERRORS?', err);

          // Update references
          store.setRef(doc.id, 'master', data.refs.master);
          store.setRef(doc.id, 'tail', data.refs.tail); // now done implicitly by update

          // Tail and master are now up to date. Now set 'tail-remote' to new tail
          store.setRef(doc.id, 'tail-remote', data.refs.tail);
          store.setRef(doc.id, 'master-remote', data.refs.master);

          // Update metadata (remote version)
          store.updateMeta(doc.id, data.meta);
          cb(null);
        });
      } else {
        // Update metadata (remote version)
        store.updateMeta(doc.id, data.meta);
        cb(null);
      }
    });
  };

  // Push
  // -----------------

  this.push = function(doc, cb) {
    store.get(doc.id, function(err, doc) {
      var remoteTail = store.getRef(doc.id, 'tail-remote');
      var localTail = store.getRef(doc.id, 'tail');

      // Find all commits after synced (remote) commit
      var commits = store.commits(doc.id, localTail, remoteTail);

      console.log('LE LOCAL COMMITTES to be pushed: ', commits);

      var data = {
        username: that.user,
        id: doc.id,
        commits: commits, // may be empty
        meta: doc.meta,
        refs: doc.refs // make sure refs are updated on the server (for now master, tail is updated implicitly)
      };

      _.request("POST", Substance.settings.hub + '/documents/update', data, function (err) {
        // Set synced reference accordingly
        if (err) return cb(err);
        store.setRef(doc.id, 'tail-remote', doc.refs.tail);
        store.setRef(doc.id, 'master-remote', doc.refs.master);

        cb(null);
      });
    });
  };

  // Create doc on the server
  // -----------------

  this.create = function(doc, cb) {
    console.log('creating ', doc.id, ' on the server');

    // 1. Get doc from local docstore
    store.get(doc.id, function(err, doc) {
      // extract commits
      var commits = store.commits(doc.id, doc.refs.tail);
      console.log("COMMITS OF NEW DOC", commits);
      // 2. Create empty doc on the server
      _.request("POST", Substance.settings.hub + '/documents/create', {"username": that.user, id: doc.id}, function (err) {
        console.log('created on the server..');
        if (err) return cb(err);
        // 3. Send updates to server
        _.request("POST", Substance.settings.hub + '/documents/update', {"username": that.user, id: doc.id, commits: commits, meta: doc.meta}, function (err) {
          store.setRef(doc.id, 'tail-remote', doc.refs.tail);
          store.setRef(doc.id, 'master-remote', doc.refs.master);
          cb(err);
        });
      });
    });
  };

  // Compute jobs for dirty documents
  // -----------------

  this.computeJobs = function(cb) {
  	// Status object looks like this
    var jobs = [];
    that.localDocStates(function(err, localDocs) {
      _.request("GET", Substance.settings.hub + '/documents/status/'+that.user, {}, function (err, remoteDocs) {
        console.log('diff', localDocs, remoteDocs);

        _.each(localDocs, function(doc, id) {
          var remoteDoc = remoteDocs[id];
          // New unsynced doc?
          if (!remoteDoc) {
            jobs.push({id: id, action: "create"});
            return;
          }

          // Local refs
          var masterRemote = store.getRef(id, 'master-remote');
          var tailRemote = store.getRef(id, 'tail-remote');

          if (tailRemote !== remoteDoc.refs['tail'] || masterRemote !== remoteDoc.refs['master']) {
            jobs.push({id: id, action: "pull"});
            return;
          } else if (tailRemote !== doc.refs['tail'] || doc.refs['master'] !== masterRemote) {
            // Local changes only -> Push (fast-forward)
            jobs.push({id: id, action: "push"});
            return;
          }
        });

        _.each(remoteDocs, function(remoteDoc, id) {
          var doc = localDocs[id];

          // New remote doc? -> Fetch
          if (!doc) {
            jobs.push({id: id, action: "fetch"});
            return;
          }
        });

        cb(null, jobs);
      });
    });
  };

  // Ask for status of all local documents
  // -----------------
  //
  // Returns: A hash of document status objects

  this.localDocStates = function(cb) {
    store.list(function(err, localDocs) {
      var result = {};
      _.each(localDocs, function(doc) {
        result[doc.id] = doc;
        delete result[doc.id].id;
      });
      cb(null, result);
    });
  };

};<|endoftext|>


<commit_before>import {inject} from 'aurelia-dependency-injection';
import {Config} from 'aurelia-api';
import typer from 'typer';

/**
 * The Repository basis class
 */
@inject(Config)
export class Repository {
  transport = null;

  /**
   * Construct.
   *
   * @param {Config} clientConfig
   *
   * @constructor
   */
  constructor(clientConfig) {
    this.clientConfig = clientConfig;
  }

  /**
   * Get the transport for the resource this repository represents.
   *
   * @return {Rest}
   */
  getTransport() {
    if (this.transport === null) {
      this.transport = this.clientConfig.getEndpoint(this.getMeta().fetch('endpoint'));

      if (!this.transport) {
        throw new Error(`No transport found for '${this.getMeta().fetch('endpoint') || 'default'}'.`);
      }
    }

    return this.transport;
  }

  /**
   * Set the associated entity's meta data
   *
   * @param {{}} meta
   */
  setMeta(meta) {
    this.meta = meta;
  }

  /**
   * Get the associated entity's meta data.
   * @return {{}}
   */
  getMeta() {
    return this.meta;
  }

  /**
   * Set the resource
   *
   * @param {string} resource
   * @return {Repository} this
   * @chainable
   */
  setResource(resource) {
    this.resource = resource;

    return this;
  }

  /**
   * Get the resource
   *
   * @return {string|null}
   */
  getResource() {
    return this.resource;
  }

  /**
   * Perform a find query and populate entities with the retrieved data.
   *
   * @param {{}|number|string} criteria Criteria to add to the query. A plain string or number will be used as relative path.
   * @param {boolean}          [raw]    Set to true to get a POJO in stead of populated entities.
   *
   * @return {Promise<Entity|[Entity]>}
   */
  find(criteria, raw) {
    return this.findPath(this.resource, criteria, raw);
  }

  /**
   * Perform a find query and populate entities with the retrieved data, limited to one result.
   *
   * @param {{}|number|string} criteria Criteria to add to the query. A plain string or number will be used as relative path.
   * @param {boolean}          [raw]    Set to true to get a POJO in stead of populated entities.
   *
   * @return {Promise<Entity|[Entity]>}
   */
  findOne(criteria, raw) {
    return this.findPath(this.resource, criteria, raw, true);
  }

  /**
   * Perform a find query for `path` and populate entities with the retrieved data.
   *
   * @param {string}           path
   * @param {{}|number|string} criteria Criteria to add to the query. A plain string or number will be used as relative path.
   * @param {boolean}          [raw]    Set to true to get a POJO in stead of populated entities.
   *
   * @return {Promise<Entity|[Entity]>}
   */
  findPath(path, criteria, raw, single) {
    let transport = this.getTransport();
    let findQuery;

    if (single) {
      if (typeof criteria === 'object' && criteria !== null) {
        criteria.limit = 1;
      }

      findQuery = this.getTransport().findOne(path, criteria);
    } else {
      findQuery = this.getTransport().find(path, criteria);
    }

    if (raw) {
      return findQuery;
    }

    return findQuery
      .then(response => {
        return this.populateEntities(response);
      })
      .then(populated => {
        if (!populated) {
          return null;
        }

        if (!Array.isArray(populated)) {
          return populated.markClean();
        }

        populated.forEach(entity => entity.markClean());

        return populated;
      });
  }

  /**
   * Perform a count on the resource.
   *
   * @param {null|{}} criteria
   *
   * @return {Promise<number>}
   */
  count(criteria) {
    return this.getTransport().find(this.resource + '/count', criteria);
  }

  /**
   * Get new populated entity or entities based on supplied data including associations
   *
   * @param {{}|[{}]} data|[data] The data to populate with
   *
   * @return {Entity|[Entity]}
   */
  populateEntities(data) {
    if (!data) {
      return null;
    }

    if (!Array.isArray(data)) {
      return this.getPopulatedEntity(data);
    }

    let collection = [];

    data.forEach(source => {
      collection.push(this.getPopulatedEntity(source));
    });

    return collection;
  }

  /**
   * Populate a (new) entity including associations
   *
   * @param {{}}     data The data to populate with
   * @param {Entity} [entity] optional. if not set, a new entity is returned
   *
   * @return {Entity}
   */
  getPopulatedEntity(data, entity) {
    entity             = entity || this.getNewEntity();
    let entityMetadata = entity.getMeta();
    let populatedData  = {};
    let key;

    for (key in data) {
      if (!data.hasOwnProperty(key)) {
        continue;
      }

      let value = data[key];

      if (entityMetadata.has('types', key)) {
        populatedData[key] = typer.cast(value, entityMetadata.fetch('types', key));

        continue;
      }

      if (!entityMetadata.has('associations', key) || typeof value !== 'object') {
        // Not an association, or not an object. clean copy.
        populatedData[key] = value;

        continue;
      }

      let repository = this.entityManager.getRepository(entityMetadata.fetch('associations', key).entity);

      populatedData[key] = repository.populateEntities(value);
    }

    return entity.setData(populatedData);
  }

  /**
   * Get a new instance for entityReference.
   *
   * @return {Entity}
   */
  getNewEntity() {
    return this.entityManager.getEntity(this.resource);
  }

  /**
   * Populate a new entity with the empty associations set.
   *
   * @return {Entity}
   */
  getNewPopulatedEntity() {
    let entity       = this.getNewEntity();
    let associations = entity.getMeta().fetch('associations');

    for (let property in associations) {
      if (associations.hasOwnProperty(property)) {
        let assocMeta = associations[property];

        if (assocMeta.type !== 'entity') {
          continue;
        }

        entity[property] = this.entityManager.getRepository(assocMeta.entity).getNewEntity();
      }
    }

    return entity;
  }
}
<commit_msg>chore(Repository): update docblock<commit_after>import {inject} from 'aurelia-dependency-injection';
import {Config} from 'aurelia-api';
import typer from 'typer';

/**
 * The Repository basis class
 */
@inject(Config)
export class Repository {
  transport = null;

  /**
   * Construct.
   *
   * @param {Config} clientConfig
   *
   * @constructor
   */
  constructor(clientConfig) {
    this.clientConfig = clientConfig;
  }

  /**
   * Get the transport for the resource this repository represents.
   *
   * @return {Rest}
   */
  getTransport() {
    if (this.transport === null) {
      this.transport = this.clientConfig.getEndpoint(this.getMeta().fetch('endpoint'));

      if (!this.transport) {
        throw new Error(`No transport found for '${this.getMeta().fetch('endpoint') || 'default'}'.`);
      }
    }

    return this.transport;
  }

  /**
   * Set the associated entity's meta data
   *
   * @param {{}} meta
   */
  setMeta(meta) {
    this.meta = meta;
  }

  /**
   * Get the associated entity's meta data.
   * @return {{}}
   */
  getMeta() {
    return this.meta;
  }

  /**
   * Set the resource
   *
   * @param {string} resource
   * @return {Repository} this
   * @chainable
   */
  setResource(resource) {
    this.resource = resource;

    return this;
  }

  /**
   * Get the resource
   *
   * @return {string|null}
   */
  getResource() {
    return this.resource;
  }

  /**
   * Perform a find query and populate entities with the retrieved data.
   *
   * @param {{}|number|string} criteria Criteria to add to the query. A plain string or number will be used as relative path.
   * @param {boolean}          [raw]    Set to true to get a POJO in stead of populated entities.
   *
   * @return {Promise<Entity|[Entity]>}
   */
  find(criteria, raw) {
    return this.findPath(this.resource, criteria, raw);
  }

  /**
   * Perform a find query and populate entities with the retrieved data, limited to one result.
   *
   * @param {{}|number|string} criteria Criteria to add to the query. A plain string or number will be used as relative path.
   * @param {boolean}          [raw]    Set to true to get a POJO in stead of populated entities.
   *
   * @return {Promise<Entity|[Entity]>}
   */
  findOne(criteria, raw) {
    return this.findPath(this.resource, criteria, raw, true);
  }

  /**
   * Perform a find query for `path` and populate entities with the retrieved data.
   *
   * @param {string}           path
   * @param {{}|number|string} criteria Criteria to add to the query. A plain string or number will be used as relative path.
   * @param {boolean}          [raw]    Set to true to get a POJO in stead of populated entities.
   * @param {boolean}          [single] Whether or not this is a findOne.
   *
   * @return {Promise<Entity|[Entity]>}
   */
  findPath(path, criteria, raw, single) {
    let transport = this.getTransport();
    let findQuery;

    if (single) {
      if (typeof criteria === 'object' && criteria !== null) {
        criteria.limit = 1;
      }

      findQuery = this.getTransport().findOne(path, criteria);
    } else {
      findQuery = this.getTransport().find(path, criteria);
    }

    if (raw) {
      return findQuery;
    }

    return findQuery
      .then(response => {
        return this.populateEntities(response);
      })
      .then(populated => {
        if (!populated) {
          return null;
        }

        if (!Array.isArray(populated)) {
          return populated.markClean();
        }

        populated.forEach(entity => entity.markClean());

        return populated;
      });
  }

  /**
   * Perform a count on the resource.
   *
   * @param {null|{}} criteria
   *
   * @return {Promise<number>}
   */
  count(criteria) {
    return this.getTransport().find(this.resource + '/count', criteria);
  }

  /**
   * Get new populated entity or entities based on supplied data including associations
   *
   * @param {{}|[{}]} data|[data] The data to populate with
   *
   * @return {Entity|[Entity]}
   */
  populateEntities(data) {
    if (!data) {
      return null;
    }

    if (!Array.isArray(data)) {
      return this.getPopulatedEntity(data);
    }

    let collection = [];

    data.forEach(source => {
      collection.push(this.getPopulatedEntity(source));
    });

    return collection;
  }

  /**
   * Populate a (new) entity including associations
   *
   * @param {{}}     data The data to populate with
   * @param {Entity} [entity] optional. if not set, a new entity is returned
   *
   * @return {Entity}
   */
  getPopulatedEntity(data, entity) {
    entity             = entity || this.getNewEntity();
    let entityMetadata = entity.getMeta();
    let populatedData  = {};
    let key;

    for (key in data) {
      if (!data.hasOwnProperty(key)) {
        continue;
      }

      let value = data[key];

      if (entityMetadata.has('types', key)) {
        populatedData[key] = typer.cast(value, entityMetadata.fetch('types', key));

        continue;
      }

      if (!entityMetadata.has('associations', key) || typeof value !== 'object') {
        // Not an association, or not an object. clean copy.
        populatedData[key] = value;

        continue;
      }

      let repository = this.entityManager.getRepository(entityMetadata.fetch('associations', key).entity);

      populatedData[key] = repository.populateEntities(value);
    }

    return entity.setData(populatedData);
  }

  /**
   * Get a new instance for entityReference.
   *
   * @return {Entity}
   */
  getNewEntity() {
    return this.entityManager.getEntity(this.resource);
  }

  /**
   * Populate a new entity with the empty associations set.
   *
   * @return {Entity}
   */
  getNewPopulatedEntity() {
    let entity       = this.getNewEntity();
    let associations = entity.getMeta().fetch('associations');

    for (let property in associations) {
      if (associations.hasOwnProperty(property)) {
        let assocMeta = associations[property];

        if (assocMeta.type !== 'entity') {
          continue;
        }

        entity[property] = this.entityManager.getRepository(assocMeta.entity).getNewEntity();
      }
    }

    return entity;
  }
}
<|endoftext|>


<commit_before>/**
 * @fileoverview OAuth client.
 *
 */

goog.provide('ydn.client.OAuthClient');
goog.provide('ydn.client.OAuthProvider');
goog.require('goog.async.Deferred');
goog.require('ydn.client.Client');
goog.require('ydn.client.SimpleHttpRequest');

/**
 * @interface
 */
ydn.client.OAuthProvider = function() {};

/**
 * @return {goog.async.Deferred}
 */
ydn.client.OAuthProvider.prototype.getOAuthToken = goog.abstractMethod;

/**
 * OAuth client.
 * @param {ydn.client.OAuthProvider} provider
 * @param {goog.net.XhrManager} xm xhr manager.
 * @constructor
 * @implements {ydn.client.Client}
 * @const
 */
ydn.client.OAuthClient = function(provider, xm) {
  /**
   * @protected
   * @type {ydn.client.OAuthProvider}
   */
  this.provider = provider;
  /**
   * @protected
   * @type {goog.net.XhrManager}
   */
  this.xm = xm;
  /**
   * @protected
   * @type {YdnApiToken}
   */
  this.token = null;
};

/**
 * @inheritDoc
 */
ydn.client.OAuthClient.prototype.request = function(req) {
  return new ydn.client.OAuthClient.Request(req, this);
};

/**
 * Request data.
 * @param {ydn.client.HttpRequestData} args
 * @param {ydn.client.OAuthClient} parent xhr manager.
 * @constructor
 * @extends {ydn.client.SimpleHttpRequest}
 */
ydn.client.OAuthClient.Request = function(args, parent) {
  goog.base(this, args, parent.xm);
  /**
   * @final
   * @type {ydn.client.OAuthClient}
   */
  this.parent = parent;
  this.no_retry_ = false;
};
goog.inherits(ydn.client.OAuthClient.Request, ydn.client.SimpleHttpRequest);

/**
 * @const
 * @type {boolean}
 */
ydn.client.OAuthClient.USE_AUTHORIZATION_HEADER = false;

/**
 * Insert oauth header.
 * @param {function(this: T, boolean, ydn.client.HttpRespondData)} cb
 * @param {T=} opt_scope scope.
 * @template T
 * @private
 */
ydn.client.OAuthClient.Request.prototype.insertHeader_ = function(cb, opt_scope) {
  var token = this.parent.token;
  // window.console.log(token);
  if (!token || token.expires < goog.now()) {
    if (this.no_retry_) {
      cb.call(opt_scope, false, new ydn.client.HttpRespondData(0, null, null,
          'refreshing token fail'));
    } else {
      this.no_retry_ = true;
      // window.console.log('refreshing token');
      this.parent.provider.getOAuthToken().addCallbacks(function(x) {
        this.parent.token = /** @type {YdnApiToken} */ (x);
        if (ydn.client.OAuthClient.USE_AUTHORIZATION_HEADER) {
          this.req_data.headers['Authorization'] = 'Bearer ' +
              this.parent.token.access_token;
        } else {
          this.req_data.params['access_token'] = this.parent.token.access_token;
        }
        cb.call(opt_scope, true, null);
      }, function(e) {
        this.parent.token = null;
        cb.call(opt_scope, false, new ydn.client.HttpRespondData(0, null, null,
            'refreshing token fail'));
      }, this);
    }

  } else {
    if (ydn.client.OAuthClient.USE_AUTHORIZATION_HEADER) {
      this.req_data.headers['Authorization'] = 'Bearer ' + token.access_token;
    } else {
      this.req_data.params['access_token'] = token.access_token;
    }
    cb.call(opt_scope, true, null);
  }
};

/**
 * Execute the request.
 * @param {function(this: T, Object, ydn.client.HttpRespondData)?} cb
 * @param {T=} opt_scope scope.
 * @template T
 */
ydn.client.OAuthClient.Request.prototype.execute = function(cb, opt_scope) {
  this.insertHeader_(function(ok, raw) {
    if (ok) {
      ydn.client.OAuthClient.Request.superClass_.execute.call(this, cb, opt_scope);
    } else {
      if (cb) {
        cb.call(opt_scope, null, raw);
      }
    }
  }, this);
};

<commit_msg>multiple module OK.<commit_after>/**
 * @fileoverview OAuth client.
 *
 */

goog.provide('ydn.client.OAuthClient');
goog.provide('ydn.client.OAuthProvider');
goog.require('goog.async.Deferred');
goog.require('ydn.client.Client');
goog.require('ydn.client.SimpleHttpRequest');

/**
 * @interface
 */
ydn.client.OAuthProvider = function() {};

/**
 * @return {goog.async.Deferred}
 */
ydn.client.OAuthProvider.prototype.getOAuthToken = goog.abstractMethod;

/**
 * OAuth client.
 * @param {ydn.client.OAuthProvider} provider
 * @param {goog.net.XhrManager} xm xhr manager.
 * @constructor
 * @implements {ydn.client.Client}
 * @const
 */
ydn.client.OAuthClient = function(provider, xm) {
  /**
   * @protected
   * @type {ydn.client.OAuthProvider}
   */
  this.provider = provider;
  /**
   * @protected
   * @type {goog.net.XhrManager}
   */
  this.xm = xm;
  /**
   * @protected
   * @type {YdnApiToken}
   */
  this.token = null;
};

/**
 * @inheritDoc
 */
ydn.client.OAuthClient.prototype.request = function(req) {
  return new ydn.client.OAuthClient.Request(req, this);
};

/**
 * Request data.
 * @param {ydn.client.HttpRequestData} args
 * @param {ydn.client.OAuthClient} parent xhr manager.
 * @constructor
 * @extends {ydn.client.SimpleHttpRequest}
 */
ydn.client.OAuthClient.Request = function(args, parent) {
  goog.base(this, args, parent.xm);
  /**
   * @final
   * @type {ydn.client.OAuthClient}
   */
  this.parent = parent;
  this.no_retry_ = false;
};
goog.inherits(ydn.client.OAuthClient.Request, ydn.client.SimpleHttpRequest);

/**
 * @define {boolean} debug flag.
 */
ydn.client.OAuthClient.DEBUG = true;

/**
 * @const
 * @type {boolean}
 */
ydn.client.OAuthClient.USE_AUTHORIZATION_HEADER = false;

/**
 * @const
 * @type {ydn.client.HttpRespondData}
 */
ydn.client.OAuthClient.Request.ERR_RESP =
    new ydn.client.HttpRespondData(0, null, null, 'No access token');

/**
 * Execute the request.
 * @param {function(this: T, Object, ydn.client.HttpRespondData)?} cb
 * @param {T=} opt_scope scope.
 * @template T
 */
ydn.client.OAuthClient.Request.prototype.execute = function(cb, opt_scope) {

  var me = this;

  var hasValidToken = function() {
    return me.parent.token && me.parent.token.expires > goog.now();
  };

  var insertHeader = function() {
    if (ydn.client.OAuthClient.USE_AUTHORIZATION_HEADER) {
      me.req_data.headers['Authorization'] = 'Bearer ' + me.parent.token.access_token;
    } else {
      me.req_data.params['access_token'] = me.parent.token.access_token;
    }
  };

  // start
  if (hasValidToken()) {
    insertHeader();
    ydn.client.OAuthClient.Request.superClass_.execute.call(this, function(data, raw) {
      if (raw.getStatus() == 401) { // (Unauthorized)
        if (ydn.client.OAuthClient.DEBUG) {
          window.console.log(me.parent.token);
          window.console.log('Although not expires, refreshing token due to ' + raw.getStatus() + ' ' +
              raw.getStatusText());
        }
        me.parent.provider.getOAuthToken().addCallbacks(function(x) {
          me.parent.token = /** @type {YdnApiToken} */ (x);
          insertHeader();
          ydn.client.OAuthClient.Request.superClass_.execute.call(me, cb, opt_scope);
        }, function(e) {
          me.parent.token = null;
          cb.call(opt_scope, null, ydn.client.OAuthClient.Request.ERR_RESP);
        }, me);
      } else {
        cb.call(opt_scope, data, raw);
      }
    }, this);
  } else {
    this.parent.provider.getOAuthToken().addCallbacks(function(x) {
      me.parent.token = /** @type {YdnApiToken} */ (x);
      insertHeader();
      ydn.client.OAuthClient.Request.superClass_.execute.call(this, cb, opt_scope);
    }, function(e) {
      me.parent.token = null;
      cb.call(opt_scope, null, ydn.client.OAuthClient.Request.ERR_RESP);
    }, this);
  }
};

<|endoftext|>


<commit_before>var path = require('path');

var stylesheetsDir = 'assets/stylesheets';
var rendrDir = 'node_modules/rendr';
var rendrHandlebarsDir = 'node_modules/rendr-handlebars';
var rendrModulesDir = rendrDir + '/node_modules';

module.exports = function(grunt) {
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    stylus: {
      compile: {
        options: {
          paths: [stylesheetsDir],
          'include css': true
        },
        files: {
          'public/styles.css': stylesheetsDir + '/index.styl'
        }
      }
    },

    handlebars: {
      compile: {
        options: {
          namespace: false,
          commonjs: true,
          processName: function(filename) {
            return filename.replace('apps/main/app/', 'app/').replace('app/templates/', '').replace('.hbs', '');
          }
        },
        src: "apps/main/app/templates/**/*.hbs",
        dest: "apps/main/app/templates/compiledTemplates.js",
        filter: function(filepath) {
          var filename = path.basename(filepath);
          // Exclude files that begin with '__' from being sent to the client,
          // i.e. __layout.hbs.
          return filename.slice(0, 2) !== '__';
        }
      }
    },

    watch: {
      scripts: {
        files: 'apps/main/app/**/*.js',
        tasks: ['rendr_stitch'],
        options: {
          interrupt: true
        }
      },
      templates: {
        files: 'apps/main/app/**/*.hbs',
        tasks: ['handlebars'],
        options: {
          interrupt: true
        }
      },
      stylesheets: {
        files: [stylesheetsDir + '/**/*.styl', stylesheetsDir + '/**/*.css'],
        tasks: ['stylus'],
        options: {
          interrupt: true
        }
      }
    },

    rendr_stitch: {
      compile: {
        options: {
          dependencies: [
            'assets/vendor/**/*.js'
          ],
          npmDependencies: {
            underscore: '../rendr/node_modules/underscore/underscore.js',
            backbone: '../rendr/node_modules/backbone/backbone.js',
            handlebars: '../rendr-handlebars/node_modules/handlebars/dist/handlebars.runtime.js',
            async: '../rendr/node_modules/async/lib/async.js'
          },
          aliases: [
            {from: 'apps/main/app/', to: 'app/'},
            {from: rendrDir + '/client', to: 'rendr/client'},
            {from: rendrDir + '/shared', to: 'rendr/shared'},
            {from: rendrHandlebarsDir, to: 'rendr-handlebars'},
            {from: rendrHandlebarsDir + '/shared', to: 'rendr-handlebars/shared'}
          ]
        },
        files: [{
          dest: 'public/mergedAssets.js',
          src: [
            'apps/main/app/**/*.js',
            rendrDir + '/client/**/*.js',
            rendrDir + '/shared/**/*.js',
            rendrHandlebarsDir + '/index.js',
            rendrHandlebarsDir + '/shared/*.js'
          ]
        }]
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-stylus');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-handlebars');
  grunt.loadNpmTasks('grunt-rendr-stitch');

  grunt.registerTask('runNode', function () {
    grunt.util.spawn({
      cmd: 'node',
      args: ['./node_modules/nodemon/nodemon.js', 'index.js'],
      opts: {
        stdio: 'inherit'
      }
    }, function () {
      grunt.fail.fatal(new Error("nodemon quit"));
    });
  });

  grunt.registerTask('compile', ['handlebars', 'rendr_stitch', 'stylus']);

  // Run the server and watch for file changes
  grunt.registerTask('server', ['runNode', 'compile', 'watch']);

  // Default task(s).
  grunt.registerTask('default', ['compile']);
};
<commit_msg>fix template path in compile handlebars<commit_after>var path = require('path');

var stylesheetsDir = 'assets/stylesheets';
var rendrDir = 'node_modules/rendr';
var rendrHandlebarsDir = 'node_modules/rendr-handlebars';
var rendrModulesDir = rendrDir + '/node_modules';

module.exports = function(grunt) {
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    stylus: {
      compile: {
        options: {
          paths: [stylesheetsDir],
          'include css': true
        },
        files: {
          'public/styles.css': stylesheetsDir + '/index.styl'
        }
      }
    },

    handlebars: {
      compile: {
        options: {
          namespace: false,
          commonjs: true,
          processName: function(filename) {
            return filename.replace('apps/main/app/templates/', '').replace('.hbs', '');
          }
        },
        src: "apps/main/app/templates/**/*.hbs",
        dest: "apps/main/app/templates/compiledTemplates.js",
        filter: function(filepath) {
          var filename = path.basename(filepath);
          // Exclude files that begin with '__' from being sent to the client,
          // i.e. __layout.hbs.
          return filename.slice(0, 2) !== '__';
        }
      }
    },

    watch: {
      scripts: {
        files: 'apps/main/app/**/*.js',
        tasks: ['rendr_stitch'],
        options: {
          interrupt: true
        }
      },
      templates: {
        files: 'apps/main/app/**/*.hbs',
        tasks: ['handlebars'],
        options: {
          interrupt: true
        }
      },
      stylesheets: {
        files: [stylesheetsDir + '/**/*.styl', stylesheetsDir + '/**/*.css'],
        tasks: ['stylus'],
        options: {
          interrupt: true
        }
      }
    },

    rendr_stitch: {
      compile: {
        options: {
          dependencies: [
            'assets/vendor/**/*.js'
          ],
          npmDependencies: {
            underscore: '../rendr/node_modules/underscore/underscore.js',
            backbone: '../rendr/node_modules/backbone/backbone.js',
            handlebars: '../rendr-handlebars/node_modules/handlebars/dist/handlebars.runtime.js',
            async: '../rendr/node_modules/async/lib/async.js'
          },
          aliases: [
            {from: 'apps/main/app/', to: 'app/'},
            {from: rendrDir + '/client', to: 'rendr/client'},
            {from: rendrDir + '/shared', to: 'rendr/shared'},
            {from: rendrHandlebarsDir, to: 'rendr-handlebars'},
            {from: rendrHandlebarsDir + '/shared', to: 'rendr-handlebars/shared'}
          ]
        },
        files: [{
          dest: 'public/mergedAssets.js',
          src: [
            'apps/main/app/**/*.js',
            rendrDir + '/client/**/*.js',
            rendrDir + '/shared/**/*.js',
            rendrHandlebarsDir + '/index.js',
            rendrHandlebarsDir + '/shared/*.js'
          ]
        }]
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-stylus');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-handlebars');
  grunt.loadNpmTasks('grunt-rendr-stitch');

  grunt.registerTask('runNode', function () {
    grunt.util.spawn({
      cmd: 'node',
      args: ['./node_modules/nodemon/nodemon.js', 'index.js'],
      opts: {
        stdio: 'inherit'
      }
    }, function () {
      grunt.fail.fatal(new Error("nodemon quit"));
    });
  });

  grunt.registerTask('compile', ['handlebars', 'rendr_stitch', 'stylus']);

  // Run the server and watch for file changes
  grunt.registerTask('server', ['runNode', 'compile', 'watch']);

  // Default task(s).
  grunt.registerTask('default', ['compile']);
};
<|endoftext|>


<commit_before>it('Should dispatch the hashchange event', function(done) {
	window.addEventListener('hashchange', function(e) {
		expect(e.type).to.be('hashchange');
		done();
	});
	window.location.hash = 'test';
});
<commit_msg>Update hatching test<commit_after>it('Should dispatch the hashchange event', function(done) {
	window.location.hash = '';

	window.addEventListener('hashchange', function(e) {
		expect(e.type).to.be('hashchange');
		done();
	});

	window.location.hash = 'test';
});
<|endoftext|>