<commit_before>/**
 * Provides client-side equivalent to `Controller::add_notification()`.
 * Usage:
 *
 *     $.add_notification('My notification.');
 */
jQuery.add_notification = function (msg) {
	var notices = $.cookie ('elefant_notification');
	if (notices !== null) {
		msg = notices + '|' + msg;
	}
	$.cookie ('elefant_notification', msg, {path: '/'});
};

/**
 * Adds a confirmation to a link and turns its `data-*` properties
 * into a `POST` request. Usage:
 *
 *     Delete
 */
jQuery.confirm_and_post = function (el, msg) {
	if (window.event && window.event.preventDefault) {
		window.event.preventDefault ();
	}

	if (! confirm (msg)) {
		return false;
	}

	var $el = $(el),
		params = $el.data (),
		url = $el.attr ('href'),
		$form = $('<form>')
			.attr ('method', 'post')
			.attr ('action', url);

	$.each (params, function (name, value) {
		$('<input type="hidden">')
			.attr ('name', name)
			.attr ('value', value)
			.appendTo ($form);
	});

	$form.appendTo ('body');
	$form.submit ();
	return false;
};

/**
 * Turns a section of a form into an expandable/collapsible section.
 * Usage:
 *
 *
{"Extra options"}

 *

 *
 *

 *
 *
 */
jQuery.expanded_section = function (options) {
	var defaults = {
		header: '#expanded-header',
		section: '#expanded-section',
		arrowClass: 'arrow',
		arrowOffClass: 'arrow-off',
		visible: false,
		modal: false
	};

	var options = $.extend (defaults, options),
		header = $(options.header),
		section = $(options.section);

	if (options.visible) {
		header.prepend ('');
		section.css ('display', 'block');
	} else {
		header.prepend ('');
		section.css ('display', 'none');
	}

	header
		.hover (
			function () {
				$(this).css ('cursor', 'pointer');
			},
			function () {
				$(this).css ('cursor', 'default');
			}
		)
		.click (
			function (evt) {
				if (section.css ('display') === 'none') {
					section.slideDown ('fast', function () {
						if (! options.modal) {
							window.scrollTo (0, 1000);
						}
					});
					header.children ('span.' + options.arrowClass).removeClass (options.arrowOffClass);
				} else {
					section.slideUp ('fast', function () {
						section.css ('display', 'none');
					});
					header.children ('span.' + options.arrowClass).addClass (options.arrowOffClass);
				}
			}
		);
};

/**
 * Displays the update notice if one is available. This is a JSONP
 * response handler.
 */
function elefant_update_response (res) {
	var _old = $.elefant_version.split ('.'),
		_new = res.latest.split ('.'),
		is_new = false;

	for (var i = 0; i < _old.length; i++) {
		var _o = parseInt (_old[i]),
			_n = parseInt (_new[i]);

		if (_o === _n) {
			continue;
		} else if (_o < _n) {
			is_new = true;
			break;
		}
		break;
	}

	if (is_new) {
		$('#admin-bar>a').append ('Update Available: ' + res.latest + '');
	}
}

$(function () {
	// is the tools menu sliding up right now?
	var sliding_up = false;

	// fetch data for admin toolbar
	$('body').append ('

');
	$.get ('/admin/head/links', function (res) {
		$('#admin-logo').attr ('src', res.logo).attr ('alt', res.name);
		$('#admin-links').append (res.links);

		// show/hide tools menu
		if (!res.is_apps) {
			// custom tools menu
			var admin_tools = $('#admin-bar'),
				admin_tools_list = $('#admin-tools-list');

			$('#admin-bar>a').after ('');

			function toggle_custom_tools_open () {
				admin_tools_list.stop ().css ('height', 'auto').slideDown ('fast', function(){admin_tools_list.css ('overflow-y', 'auto');});
			}

			function toggle_custom_tools_close () {
				admin_tools_list.stop ().css ('overflow-y', 'hidden').slideUp ('fast');
			}

			function toggle_custom_tools (e) {
				if (e != null) e.preventDefault ();

				// fix for clicks on tools menu links
				if (e != null && $(e.target).attr ('id') !== 'admin-bar' && $(e.target).attr ('id') !== 'admin-tools-arrow') {
					window.location.href = $(e.target).attr ('href');
					return false;
				}

				if (admin_tools_list.is (':visible')) {
					admin_tools_list.stop ().css ('overflow-y', 'hidden').slideUp ('fast');
				} else {
					admin_tools_list.stop ().css ('height', 'auto').slideDown ('fast', function(){admin_tools_list.css ('overflow-y', 'auto');});
					$('#admin-tools-list a').first ().focus ();
				}

				return false;
			}

			function hide_custom_tools (e) {
				var $admin_bar = $('#admin-bar');

				if ($admin_bar.is (':visible') && ! $admin_bar[0].contains (e.target)) {
					toggle_custom_tools_close ();
				}
			}

			if (navigator.pointerEnabled) {
				$('#admin-tools-arrow').on ('pointerdown', toggle_custom_tools);
				$(window).on ('pointerdown', hide_custom_tools);
			} else if (navigator.msPointerEnabled) {
				$('#admin-tools-arrow').on ('MSPointerDown', toggle_custom_tools);
				$(window).on ('MSPointerDown', hide_custom_tools);
			} else {
				$('#admin-tools-arrow').on ('touchdown click', toggle_custom_tools);
				$(window).on ('touchdown click', hide_custom_tools);
			}

			document.onkeydown = function (z) {
				if (z.altKey && z.code === 'KeyE') {
					z.preventDefault ();
					toggle_custom_tools (null);
				}
			};

		} else {
			// default tools menu
			var admin_tools = $('#admin-tools'),
				admin_tools_list = $('#admin-tools-list');

			function toggle_tools_open () {
				admin_tools_list.stop ().css ('height', 'auto').slideDown ('fast', function(){admin_tools_list.css ('overflow-y', 'auto');});
			}

			function toggle_tools_close () {
				admin_tools_list.stop ().css ('overflow-y', 'hidden').slideUp ('slow');
			}

			function toggle_tools (e) {
				e.preventDefault ();

				// fix for clicks on tools menu links
				if ($(e.target).attr ('id') !== 'admin-tools') {
					window.location.href = $(e.target).attr ('href');
					return false;
				}

				if (admin_tools_list.is (':visible')) {
					admin_tools_list.stop ().css ('overflow-y', 'hidden').slideUp ('fast');
				} else {
					admin_tools_list.stop ().css ('height', 'auto').slideDown ('fast', function(){admin_tools_list.css ('overflow-y', 'auto');});
					$('#admin-tools-list a')[0].focus ();
				}

				return false;
			}

			if (navigator.pointerEnabled) {
				admin_tools.on ('pointerdown', toggle_tools);
			} else if (navigator.msPointerEnabled) {
				admin_tools.on ('MSPointerDown', toggle_tools);
			} else {
				admin_tools.hover (
					toggle_tools_open,
					toggle_tools_close
				);

				admin_tools.on ('touchdown click', toggle_tools);
			}

			// hide the tools menu on hover of non-tools menu toolbar links
			$('#admin-links a').not('#admin-tools-list a').bind("mouseover", toggle_tools_close);
		}

		// website link should open to the last non-admin page visited
		var last_page = $('body').data ('admin-last-page');
		if (last_page) {
			$('#admin-tools-website').attr ('href', last_page);
		} else {
			$.cookie ('elefant_last_page', window.location.pathname, { path: '/' });
			$('#admin-tools-website').attr ('href', window.location.pathname);
		}

		// toggle preview mode, shows/hides edit buttons and admin toolbar
		var toggle_preview = function () {
			var b = $('body');

			if (b.hasClass ('is-preview')) {
				b.removeClass ('is-preview');
			} else {
				b.addClass ('is-preview');
			}
			return false;
		};

		// attach preview toggle events
		$('a.admin-tools-show-preview', '#admin-bar' ).click (toggle_preview);
		$('a.admin-tools-hide-preview', '#preview-bar').click (toggle_preview);

		// add keyboard shortcuts
		$.triggers ();
	});

    $('.admin-options a').hover (
		function () {
			this.tip = this.title;
			$(this).append (
				'

' +
				'
' + this.tip + '

'
			);
			this.title = '';
			$('.admin-tooltip').fadeIn (100);
		},
		function () {
			$('.admin-tooltip').fadeOut (100);
			$('.admin-tooltip').remove ();
			this.title = this.tip;
		}
	);

	// check for and display elefant updates if available
	if ($.elefant_updates && ! $.cookie ('elefant_update_checked')) {
		var major_minor = $.elefant_version.replace (/\.[0-9]+$/, '');

		$.ajax ({
			url: '/admin/head/updates/' + major_minor + '?callback=elefant_update_response',
			type: 'GET',
			dataType: 'jsonp',
			callback: elefant_update_response
		});

		$.cookie ('elefant_update_checked', 1, { expires: 1, path: '/' });
	}

	var jgrowl_interval = function () {
		var notice = $.cookie ('elefant_notification'),
			msglist = [],
			i = 0;

		$.cookie ('elefant_notification', null, {path: '/'});

		if (notice !== null) {
			msglist = notice.split ('|');
			for (i = 0; i < msglist.length; i++) {
				if (msglist[i].length > 0) {
					$.jGrowl (msglist[i].replace (/\+/g, ' '));
				}
			}
		}
		// clear notices
		setTimeout (jgrowl_interval, 1000);
	}

	jgrowl_interval ();

	// Set left column headers for responsive tables
	if ($(window).width () <= 480) {
		var th = [];

		$('th').each (function () {
			th.push ($(this).text ());
		});

		var n = 0;
		$('td').each (function () {
			var orig = $(this).html ();
			$(this).html (
				'
' + th[n] + '
' +
				'
' + orig + '
' +
				'

'
			);
			n++;
			if (n >= th.length) {
				n = 0;
			}
		});
	}

	// focus on the first form input on load
	if (typeof elefant_focus_input !== 'undefined') {
		try {
			$('input, textarea').eq (0).focus ();
		} catch (e) {}
	}
});
<commit_msg>Only invoke menu on alt+e if no other modifiers are pressed<commit_after>/**
 * Provides client-side equivalent to `Controller::add_notification()`.
 * Usage:
 *
 *     $.add_notification('My notification.');
 */
jQuery.add_notification = function (msg) {
	var notices = $.cookie ('elefant_notification');
	if (notices !== null) {
		msg = notices + '|' + msg;
	}
	$.cookie ('elefant_notification', msg, {path: '/'});
};

/**
 * Adds a confirmation to a link and turns its `data-*` properties
 * into a `POST` request. Usage:
 *
 *     Delete
 */
jQuery.confirm_and_post = function (el, msg) {
	if (window.event && window.event.preventDefault) {
		window.event.preventDefault ();
	}

	if (! confirm (msg)) {
		return false;
	}

	var $el = $(el),
		params = $el.data (),
		url = $el.attr ('href'),
		$form = $('<form>')
			.attr ('method', 'post')
			.attr ('action', url);

	$.each (params, function (name, value) {
		$('<input type="hidden">')
			.attr ('name', name)
			.attr ('value', value)
			.appendTo ($form);
	});

	$form.appendTo ('body');
	$form.submit ();
	return false;
};

/**
 * Turns a section of a form into an expandable/collapsible section.
 * Usage:
 *
 *
{"Extra options"}

 *

 *
 *

 *
 *
 */
jQuery.expanded_section = function (options) {
	var defaults = {
		header: '#expanded-header',
		section: '#expanded-section',
		arrowClass: 'arrow',
		arrowOffClass: 'arrow-off',
		visible: false,
		modal: false
	};

	var options = $.extend (defaults, options),
		header = $(options.header),
		section = $(options.section);

	if (options.visible) {
		header.prepend ('');
		section.css ('display', 'block');
	} else {
		header.prepend ('');
		section.css ('display', 'none');
	}

	header
		.hover (
			function () {
				$(this).css ('cursor', 'pointer');
			},
			function () {
				$(this).css ('cursor', 'default');
			}
		)
		.click (
			function (evt) {
				if (section.css ('display') === 'none') {
					section.slideDown ('fast', function () {
						if (! options.modal) {
							window.scrollTo (0, 1000);
						}
					});
					header.children ('span.' + options.arrowClass).removeClass (options.arrowOffClass);
				} else {
					section.slideUp ('fast', function () {
						section.css ('display', 'none');
					});
					header.children ('span.' + options.arrowClass).addClass (options.arrowOffClass);
				}
			}
		);
};

/**
 * Displays the update notice if one is available. This is a JSONP
 * response handler.
 */
function elefant_update_response (res) {
	var _old = $.elefant_version.split ('.'),
		_new = res.latest.split ('.'),
		is_new = false;

	for (var i = 0; i < _old.length; i++) {
		var _o = parseInt (_old[i]),
			_n = parseInt (_new[i]);

		if (_o === _n) {
			continue;
		} else if (_o < _n) {
			is_new = true;
			break;
		}
		break;
	}

	if (is_new) {
		$('#admin-bar>a').append ('Update Available: ' + res.latest + '');
	}
}

$(function () {
	// is the tools menu sliding up right now?
	var sliding_up = false;

	// fetch data for admin toolbar
	$('body').append ('

');
	$.get ('/admin/head/links', function (res) {
		$('#admin-logo').attr ('src', res.logo).attr ('alt', res.name);
		$('#admin-links').append (res.links);

		// show/hide tools menu
		if (!res.is_apps) {
			// custom tools menu
			var admin_tools = $('#admin-bar'),
				admin_tools_list = $('#admin-tools-list');

			$('#admin-bar>a').after ('');

			function toggle_custom_tools_open () {
				admin_tools_list.stop ().css ('height', 'auto').slideDown ('fast', function(){admin_tools_list.css ('overflow-y', 'auto');});
			}

			function toggle_custom_tools_close () {
				admin_tools_list.stop ().css ('overflow-y', 'hidden').slideUp ('fast');
			}

			function toggle_custom_tools (e) {
				if (e != null) e.preventDefault ();

				// fix for clicks on tools menu links
				if (e != null && $(e.target).attr ('id') !== 'admin-bar' && $(e.target).attr ('id') !== 'admin-tools-arrow') {
					window.location.href = $(e.target).attr ('href');
					return false;
				}

				if (admin_tools_list.is (':visible')) {
					admin_tools_list.stop ().css ('overflow-y', 'hidden').slideUp ('fast');
				} else {
					admin_tools_list.stop ().css ('height', 'auto').slideDown ('fast', function(){admin_tools_list.css ('overflow-y', 'auto');});
					$('#admin-tools-list a').first ().focus ();
				}

				return false;
			}

			function hide_custom_tools (e) {
				var $admin_bar = $('#admin-bar');

				if ($admin_bar.is (':visible') && ! $admin_bar[0].contains (e.target)) {
					toggle_custom_tools_close ();
				}
			}

			if (navigator.pointerEnabled) {
				$('#admin-tools-arrow').on ('pointerdown', toggle_custom_tools);
				$(window).on ('pointerdown', hide_custom_tools);
			} else if (navigator.msPointerEnabled) {
				$('#admin-tools-arrow').on ('MSPointerDown', toggle_custom_tools);
				$(window).on ('MSPointerDown', hide_custom_tools);
			} else {
				$('#admin-tools-arrow').on ('touchdown click', toggle_custom_tools);
				$(window).on ('touchdown click', hide_custom_tools);
			}

			document.onkeydown = function (z) {
				if (z.code === 'KeyE' && z.altKey && z.ctrlKey == false && z.shiftKey == false && z.metaKey == false) {
					z.preventDefault ();
					toggle_custom_tools (null);
				}
			};

		} else {
			// default tools menu
			var admin_tools = $('#admin-tools'),
				admin_tools_list = $('#admin-tools-list');

			function toggle_tools_open () {
				admin_tools_list.stop ().css ('height', 'auto').slideDown ('fast', function(){admin_tools_list.css ('overflow-y', 'auto');});
			}

			function toggle_tools_close () {
				admin_tools_list.stop ().css ('overflow-y', 'hidden').slideUp ('slow');
			}

			function toggle_tools (e) {
				e.preventDefault ();

				// fix for clicks on tools menu links
				if ($(e.target).attr ('id') !== 'admin-tools') {
					window.location.href = $(e.target).attr ('href');
					return false;
				}

				if (admin_tools_list.is (':visible')) {
					admin_tools_list.stop ().css ('overflow-y', 'hidden').slideUp ('fast');
				} else {
					admin_tools_list.stop ().css ('height', 'auto').slideDown ('fast', function(){admin_tools_list.css ('overflow-y', 'auto');});
					$('#admin-tools-list a')[0].focus ();
				}

				return false;
			}

			if (navigator.pointerEnabled) {
				admin_tools.on ('pointerdown', toggle_tools);
			} else if (navigator.msPointerEnabled) {
				admin_tools.on ('MSPointerDown', toggle_tools);
			} else {
				admin_tools.hover (
					toggle_tools_open,
					toggle_tools_close
				);

				admin_tools.on ('touchdown click', toggle_tools);
			}

			// hide the tools menu on hover of non-tools menu toolbar links
			$('#admin-links a').not('#admin-tools-list a').bind("mouseover", toggle_tools_close);
		}

		// website link should open to the last non-admin page visited
		var last_page = $('body').data ('admin-last-page');
		if (last_page) {
			$('#admin-tools-website').attr ('href', last_page);
		} else {
			$.cookie ('elefant_last_page', window.location.pathname, { path: '/' });
			$('#admin-tools-website').attr ('href', window.location.pathname);
		}

		// toggle preview mode, shows/hides edit buttons and admin toolbar
		var toggle_preview = function () {
			var b = $('body');

			if (b.hasClass ('is-preview')) {
				b.removeClass ('is-preview');
			} else {
				b.addClass ('is-preview');
			}
			return false;
		};

		// attach preview toggle events
		$('a.admin-tools-show-preview', '#admin-bar' ).click (toggle_preview);
		$('a.admin-tools-hide-preview', '#preview-bar').click (toggle_preview);

		// add keyboard shortcuts
		$.triggers ();
	});

    $('.admin-options a').hover (
		function () {
			this.tip = this.title;
			$(this).append (
				'

' +
				'
' + this.tip + '

'
			);
			this.title = '';
			$('.admin-tooltip').fadeIn (100);
		},
		function () {
			$('.admin-tooltip').fadeOut (100);
			$('.admin-tooltip').remove ();
			this.title = this.tip;
		}
	);

	// check for and display elefant updates if available
	if ($.elefant_updates && ! $.cookie ('elefant_update_checked')) {
		var major_minor = $.elefant_version.replace (/\.[0-9]+$/, '');

		$.ajax ({
			url: '/admin/head/updates/' + major_minor + '?callback=elefant_update_response',
			type: 'GET',
			dataType: 'jsonp',
			callback: elefant_update_response
		});

		$.cookie ('elefant_update_checked', 1, { expires: 1, path: '/' });
	}

	var jgrowl_interval = function () {
		var notice = $.cookie ('elefant_notification'),
			msglist = [],
			i = 0;

		$.cookie ('elefant_notification', null, {path: '/'});

		if (notice !== null) {
			msglist = notice.split ('|');
			for (i = 0; i < msglist.length; i++) {
				if (msglist[i].length > 0) {
					$.jGrowl (msglist[i].replace (/\+/g, ' '));
				}
			}
		}
		// clear notices
		setTimeout (jgrowl_interval, 1000);
	}

	jgrowl_interval ();

	// Set left column headers for responsive tables
	if ($(window).width () <= 480) {
		var th = [];

		$('th').each (function () {
			th.push ($(this).text ());
		});

		var n = 0;
		$('td').each (function () {
			var orig = $(this).html ();
			$(this).html (
				'
' + th[n] + '
' +
				'
' + orig + '
' +
				'

'
			);
			n++;
			if (n >= th.length) {
				n = 0;
			}
		});
	}

	// focus on the first form input on load
	if (typeof elefant_focus_input !== 'undefined') {
		try {
			$('input, textarea').eq (0).focus ();
		} catch (e) {}
	}
});
<|endoftext|>


<commit_before>const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require('path');

module.exports = {
    entry: {
        'admin': './assets/js/admin.js',
    },
    output: {
        filename: '[name].min.js',
        path: path.resolve(__dirname, 'assets/js/')
    },
    module: {
        rules: [
            {
                test: /\.(css|scss|sass)$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    {
                        loader: 'css-loader',
                        options: {
                            url: false
                        }
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: () => [require('autoprefixer')]
                        }
                    },
                    'sass-loader'
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: '../css/[name].min.css',
            allChunks: true
        })
    ],
    mode: 'production'
};
<commit_msg>Removes deprecated webpack option<commit_after>const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require('path');

module.exports = {
    entry: {
        'admin': './assets/js/admin.js',
    },
    output: {
        filename: '[name].min.js',
        path: path.resolve(__dirname, 'assets/js/')
    },
    module: {
        rules: [
            {
                test: /\.(css|scss|sass)$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    {
                        loader: 'css-loader',
                        options: {
                            url: false
                        }
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: () => [require('autoprefixer')]
                        }
                    },
                    'sass-loader'
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: '../css/[name].min.css'
        })
    ],
    mode: 'production'
};
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

function jsonp(obj) {
  T(jsonp_flag == 0);
  T(obj.results.length == 1 && obj.last_seq==1, "jsonp")
  jsonp_flag = 1;
}

couchTests.changes = function(debug) {
  var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"true"});
  db.deleteDb();
  db.createDb();
  if (debug) debugger;

  var req = CouchDB.request("GET", "/test_suite_db/_changes");
  var resp = JSON.parse(req.responseText);

  T(resp.results.length == 0 && resp.last_seq==0, "empty db")
  var docFoo = {_id:"foo", bar:1};
  T(db.save(docFoo).ok);
  T(db.ensureFullCommit().ok);
  T(db.open(docFoo._id)._id == docFoo._id);

  req = CouchDB.request("GET", "/test_suite_db/_changes");
  var resp = JSON.parse(req.responseText);

  T(resp.last_seq == 1);
  T(resp.results.length == 1, "one doc db")
  T(resp.results[0].changes[0].rev == docFoo._rev)

  // test with callback

  run_on_modified_server(
    [{section: "httpd",
      key: "allow_jsonp",
      value: "true"}],
  function() {
    var xhr = CouchDB.request("GET", "/test_suite_db/_changes?callback=jsonp");
    T(xhr.status == 200);
    jsonp_flag = 0;
    eval(xhr.responseText);
    T(jsonp_flag == 1);
  });

  req = CouchDB.request("GET", "/test_suite_db/_changes?feed=continuous&timeout=10");
  var lines = req.responseText.split("\n");
  T(JSON.parse(lines[0]).changes[0].rev == docFoo._rev);
  T(JSON.parse(lines[1]).last_seq == 1);

  var xhr;

  try {
    xhr = CouchDB.newXhr();
  } catch (err) {
  }

  // poor man's browser detection
  var is_safari = false;
  if(typeof(navigator) == "undefined") {
    is_safari = true; // For CouchHTTP based runners
  } else if(navigator.userAgent.match(/AppleWebKit/)) {
    is_safari = true;
  };
  if (!is_safari && xhr) {
    // Only test the continuous stuff if we have a real XHR object
    // with real async support.

    // WebKit (last checked on nightly #47686) does fail on processing
    // the async-request properly while javascript is executed.

    xhr.open("GET", "/test_suite_db/_changes?feed=continuous&timeout=500", true);
    xhr.send("");

    var docBar = {_id:"bar", bar:1};
    db.save(docBar);

    var lines, change1, change2;
    waitForSuccess(function() {
      lines = xhr.responseText.split("\n");
      change1 = JSON.parse(lines[0]);
      change2 = JSON.parse(lines[1]);
    }, "bar-only");

    T(change1.seq == 1)
    T(change1.id == "foo")

    T(change2.seq == 2)
    T(change2.id == "bar")
    T(change2.changes[0].rev == docBar._rev)

    var docBaz = {_id:"baz", baz:1};
    db.save(docBaz);

    var change3;
    waitForSuccess(function() {
      lines = xhr.responseText.split("\n");
      change3 = JSON.parse(lines[2]);
    });

    T(change3.seq == 3);
    T(change3.id == "baz");
    T(change3.changes[0].rev == docBaz._rev);

    xhr = CouchDB.newXhr();

    //verify the hearbeat newlines are sent
    xhr.open("GET", "/test_suite_db/_changes?feed=continuous&heartbeat=10&timeout=500", true);
    xhr.send("");

    var str;
    waitForSuccess(function() {
      str = xhr.responseText;
      if (str.charAt(str.length - 1) != "\n" || str.charAt(str.length - 2) != "\n") {
        throw("keep waiting");
      }
    }, "heartbeat");

    T(str.charAt(str.length - 1) == "\n")
    T(str.charAt(str.length - 2) == "\n")

    // otherwise we'll continue to receive heartbeats forever
    xhr.abort();

    // test longpolling
    xhr = CouchDB.newXhr();

    xhr.open("GET", "/test_suite_db/_changes?feed=longpoll", true);
    xhr.send("");

    waitForSuccess(function() {
      lines = xhr.responseText.split("\n");
      if (lines[5] != '"last_seq":3}') {
        throw("still waiting");
      }
    }, "last_seq");

    xhr = CouchDB.newXhr();

    xhr.open("GET", "/test_suite_db/_changes?feed=longpoll&since=3", true);
    xhr.send("");

    var docBarz = {_id:"barz", bar:1};
    db.save(docBarz);

    var parse_changes_line = function(line) {
      if (line.charAt(line.length-1) == ",") {
        var linetrimmed = line.substring(0, line.length-1);
      } else {
        var linetrimmed = line
      }
      return JSON.parse(linetrimmed);
    }

    waitForSuccess(function() {
      lines = xhr.responseText.split("\n");
      if (lines[3] != '"last_seq":4}') {
        throw("still waiting");
      }
    }, "change_lines");

    var change = parse_changes_line(lines[1]);
    T(change.seq == 4);
    T(change.id == "barz");
    T(change.changes[0].rev == docBarz._rev);
    T(lines[3]=='"last_seq":4}');
  }

  // test the filtered changes
  var ddoc = {
    _id : "_design/changes_filter",
    "filters" : {
      "bop" : "function(doc, req) { return (doc.bop);}",
      "dynamic" : stringFun(function(doc, req) {
        var field = req.query.field;
        return doc[field];
      }),
      "userCtx" : stringFun(function(doc, req) {
        return doc.user && (doc.user == req.userCtx.name);
      }),
      "conflicted" : "function(doc, req) { return (doc._conflicts);}",
    },
    options : {
      local_seq : true
    },
    views : {
      local_seq : {
        map : "function(doc) {emit(doc._local_seq, null)}"
      }
    }
  }

  db.save(ddoc);

  var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/bop");
  var resp = JSON.parse(req.responseText);
  T(resp.results.length == 0);

  db.save({"bop" : "foom"});
  db.save({"bop" : false});

  var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/bop");
  var resp = JSON.parse(req.responseText);
  T(resp.results.length == 1, "filtered/bop");

  req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/dynamic&field=woox");
  resp = JSON.parse(req.responseText);
  T(resp.results.length == 0);

  req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/dynamic&field=bop");
  resp = JSON.parse(req.responseText);
  T(resp.results.length == 1, "changes_filter/dynamic&field=bop");

  if (!is_safari && xhr) { // full test requires parallel connections
    // filter with longpoll
    // longpoll filters full history when run without a since seq
    xhr = CouchDB.newXhr();
    xhr.open("GET", "/test_suite_db/_changes?feed=longpoll&filter=changes_filter/bop", false);
    xhr.send("");
    var resp = JSON.parse(xhr.responseText);
    T(resp.last_seq == 7);
    // longpoll waits until a matching change before returning
    xhr = CouchDB.newXhr();
    xhr.open("GET", "/test_suite_db/_changes?feed=longpoll&since=7&filter=changes_filter/bop", true);
    xhr.send("");
    db.save({"_id":"falsy", "bop" : ""}); // empty string is falsy
    db.save({"_id":"bingo","bop" : "bingo"});

    waitForSuccess(function() {
      resp = JSON.parse(xhr.responseText);
    }, "longpoll-since");

    T(resp.last_seq == 9);
    T(resp.results && resp.results.length > 0 && resp.results[0]["id"] == "bingo", "filter the correct update");
    xhr.abort();

    timeout = 500;
    last_seq = 10
    while (true) {

      // filter with continuous
      xhr = CouchDB.newXhr();
      xhr.open("GET", "/test_suite_db/_changes?feed=continuous&filter=changes_filter/bop&timeout="+timeout, true);
      xhr.send("");

      db.save({"_id":"rusty", "bop" : "plankton"});
      T(xhr.readyState != 4, "test client too slow");
      var rusty = db.open("rusty", {cache_bust : new Date()});
      T(rusty._id == "rusty");

      waitForSuccess(function() { // throws an error after 5 seconds
        if (xhr.readyState != 4) {
          throw("still waiting")
        }
      }, "continuous-rusty");
      lines = xhr.responseText.split("\n");
      try {
        JSON.parse(lines[3])
        good = true;
      } catch(e) {
        good = false;
      }
      if (good) {
        T(JSON.parse(lines[1]).id == "bingo", lines[1]);
        T(JSON.parse(lines[2]).id == "rusty", lines[2]);
        T(JSON.parse(lines[3]).last_seq == last_seq, lines[3]);
        break;
      } else {
        xhr.abort();
        db.deleteDoc(rusty);
        timeout = timeout * 2;
        last_seq = last_seq + 2;
      }
    }
  }
  // error conditions

  // non-existing design doc
  var req = CouchDB.request("GET",
    "/test_suite_db/_changes?filter=nothingtosee/bop");
  TEquals(404, req.status, "should return 404 for non existant design doc");

  // non-existing filter
  var req = CouchDB.request("GET",
    "/test_suite_db/_changes?filter=changes_filter/movealong");
  TEquals(404, req.status, "should return 404 for non existant filter fun");

  // both
  var req = CouchDB.request("GET",
    "/test_suite_db/_changes?filter=nothingtosee/movealong");
  TEquals(404, req.status,
    "should return 404 for non existant design doc and filter fun");

  // changes get all_docs style with deleted docs
  var doc = {a:1};
  db.save(doc);
  db.deleteDoc(doc);
  var req = CouchDB.request("GET",
    "/test_suite_db/_changes?filter=changes_filter/bop&style=all_docs");
  var resp = JSON.parse(req.responseText);
  var expect = (!is_safari && xhr) ? 3: 1;
  TEquals(expect, resp.results.length, "should return matching rows");

  // test for userCtx
  run_on_modified_server(
    [{section: "httpd",
      key: "authentication_handlers",
      value: "{couch_httpd_auth, special_test_authentication_handler}"},
     {section:"httpd",
      key: "WWW-Authenticate",
      value:  "X-Couch-Test-Auth"}],

    function() {
      var authOpts = {"headers":{"WWW-Authenticate": "X-Couch-Test-Auth Chris Anderson:mp3"}};

      var req = CouchDB.request("GET", "/_session", authOpts);
      var resp = JSON.parse(req.responseText);

      T(db.save({"user" : "Noah Slater"}).ok);
      var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/userCtx", authOpts);
      var resp = JSON.parse(req.responseText);
      T(resp.results.length == 0);

      var docResp = db.save({"user" : "Chris Anderson"});
      T(docResp.ok);
      T(db.ensureFullCommit().ok);
      req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/userCtx", authOpts);
      resp = JSON.parse(req.responseText);
      T(resp.results.length == 1, "userCtx");
      T(resp.results[0].id == docResp.id);
    }
  );

  req = CouchDB.request("GET", "/test_suite_db/_changes?limit=1");
  resp = JSON.parse(req.responseText);
  TEquals(1, resp.results.length)

  //filter includes _conflicts
  var id = db.save({'food' : 'pizza'}).id;
  db.bulkSave([{_id: id, 'food' : 'pasta'}], {all_or_nothing:true});

  req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/conflicted");
  resp = JSON.parse(req.responseText);
  T(resp.results.length == 1, "filter=changes_filter/conflicted");

  // test with erlang filter function
  run_on_modified_server([{
    section: "native_query_servers",
    key: "erlang",
    value: "{couch_native_process, start_link, []}"
  }], function() {
    var erl_ddoc = {
      _id: "_design/erlang",
      language: "erlang",
      filters: {
        foo:
          'fun({Doc}, Req) -> ' +
          '  Value = couch_util:get_value(<<"value">>, Doc),' +
          '  (Value rem 2) =:= 0' +
          'end.'
      }
    };

    db.deleteDb();
    db.createDb();
    T(db.save(erl_ddoc).ok);

    var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=erlang/foo");
    var resp = JSON.parse(req.responseText);
    T(resp.results.length === 0);

    T(db.save({_id: "doc1", value : 1}).ok);
    T(db.save({_id: "doc2", value : 2}).ok);
    T(db.save({_id: "doc3", value : 3}).ok);
    T(db.save({_id: "doc4", value : 4}).ok);

    var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=erlang/foo");
    var resp = JSON.parse(req.responseText);
    T(resp.results.length === 2);
    T(resp.results[0].id === "doc2");
    T(resp.results[1].id === "doc4");
  });

};

<commit_msg>Fix for windows fsync, race conditions in attachments.js and the default shell used when launching windows CouchDB.<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

function jsonp(obj) {
  T(jsonp_flag == 0);
  T(obj.results.length == 1 && obj.last_seq==1, "jsonp")
  jsonp_flag = 1;
}

couchTests.changes = function(debug) {
  var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"true"});
  db.deleteDb();
  db.createDb();
  if (debug) debugger;

  var req = CouchDB.request("GET", "/test_suite_db/_changes");
  var resp = JSON.parse(req.responseText);

  T(resp.results.length == 0 && resp.last_seq==0, "empty db")
  var docFoo = {_id:"foo", bar:1};
  T(db.save(docFoo).ok);
  T(db.ensureFullCommit().ok);
  T(db.open(docFoo._id)._id == docFoo._id);

  req = CouchDB.request("GET", "/test_suite_db/_changes");
  var resp = JSON.parse(req.responseText);

  T(resp.last_seq == 1);
  T(resp.results.length == 1, "one doc db")
  T(resp.results[0].changes[0].rev == docFoo._rev)

  // test with callback

  run_on_modified_server(
    [{section: "httpd",
      key: "allow_jsonp",
      value: "true"}],
  function() {
    var xhr = CouchDB.request("GET", "/test_suite_db/_changes?callback=jsonp");
    T(xhr.status == 200);
    jsonp_flag = 0;
    eval(xhr.responseText);
    T(jsonp_flag == 1);
  });

  req = CouchDB.request("GET", "/test_suite_db/_changes?feed=continuous&timeout=10");
  var lines = req.responseText.split("\n");
  T(JSON.parse(lines[0]).changes[0].rev == docFoo._rev);
  T(JSON.parse(lines[1]).last_seq == 1);

  var xhr;

  try {
    xhr = CouchDB.newXhr();
  } catch (err) {
  }

  // poor man's browser detection
  var is_safari = false;
  if(typeof(navigator) == "undefined") {
    is_safari = true; // For CouchHTTP based runners
  } else if(navigator.userAgent.match(/AppleWebKit/)) {
    is_safari = true;
  };
  if (!is_safari && xhr) {
    // Only test the continuous stuff if we have a real XHR object
    // with real async support.

    // WebKit (last checked on nightly #47686) does fail on processing
    // the async-request properly while javascript is executed.

    xhr.open("GET", "/test_suite_db/_changes?feed=continuous&timeout=500", true);
    xhr.send("");

    var docBar = {_id:"bar", bar:1};
    db.save(docBar);

    var lines, change1, change2;
    waitForSuccess(function() {
      lines = xhr.responseText.split("\n");
      change1 = JSON.parse(lines[0]);
      change2 = JSON.parse(lines[1]);
      if (change2.seq != 2) {
          throw "bad seq, try again"
      }
    }, "bar-only");

    T(change1.seq == 1)
    T(change1.id == "foo")

    T(change2.seq == 2)
    T(change2.id == "bar")
    T(change2.changes[0].rev == docBar._rev)

    var docBaz = {_id:"baz", baz:1};
    db.save(docBaz);

    var change3;
    waitForSuccess(function() {
      lines = xhr.responseText.split("\n");
      change3 = JSON.parse(lines[2]);
      if (change3.seq != 3) {
        throw "bad seq, try again"
      }
    });

    T(change3.seq == 3);
    T(change3.id == "baz");
    T(change3.changes[0].rev == docBaz._rev);

    xhr = CouchDB.newXhr();

    //verify the hearbeat newlines are sent
    xhr.open("GET", "/test_suite_db/_changes?feed=continuous&heartbeat=10&timeout=500", true);
    xhr.send("");

    var str;
    waitForSuccess(function() {
      str = xhr.responseText;
      if (str.charAt(str.length - 1) != "\n" || str.charAt(str.length - 2) != "\n") {
        throw("keep waiting");
      }
    }, "heartbeat");

    T(str.charAt(str.length - 1) == "\n")
    T(str.charAt(str.length - 2) == "\n")

    // otherwise we'll continue to receive heartbeats forever
    xhr.abort();

    // test longpolling
    xhr = CouchDB.newXhr();

    xhr.open("GET", "/test_suite_db/_changes?feed=longpoll", true);
    xhr.send("");

    waitForSuccess(function() {
      lines = xhr.responseText.split("\n");
      if (lines[5] != '"last_seq":3}') {
        throw("still waiting");
      }
    }, "last_seq");

    xhr = CouchDB.newXhr();

    xhr.open("GET", "/test_suite_db/_changes?feed=longpoll&since=3", true);
    xhr.send("");

    var docBarz = {_id:"barz", bar:1};
    db.save(docBarz);

    var parse_changes_line = function(line) {
      if (line.charAt(line.length-1) == ",") {
        var linetrimmed = line.substring(0, line.length-1);
      } else {
        var linetrimmed = line
      }
      return JSON.parse(linetrimmed);
    }

    waitForSuccess(function() {
      lines = xhr.responseText.split("\n");
      if (lines[3] != '"last_seq":4}') {
        throw("still waiting");
      }
    }, "change_lines");

    var change = parse_changes_line(lines[1]);
    T(change.seq == 4);
    T(change.id == "barz");
    T(change.changes[0].rev == docBarz._rev);
    T(lines[3]=='"last_seq":4}');
  }

  // test the filtered changes
  var ddoc = {
    _id : "_design/changes_filter",
    "filters" : {
      "bop" : "function(doc, req) { return (doc.bop);}",
      "dynamic" : stringFun(function(doc, req) {
        var field = req.query.field;
        return doc[field];
      }),
      "userCtx" : stringFun(function(doc, req) {
        return doc.user && (doc.user == req.userCtx.name);
      }),
      "conflicted" : "function(doc, req) { return (doc._conflicts);}",
    },
    options : {
      local_seq : true
    },
    views : {
      local_seq : {
        map : "function(doc) {emit(doc._local_seq, null)}"
      }
    }
  }

  db.save(ddoc);

  var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/bop");
  var resp = JSON.parse(req.responseText);
  T(resp.results.length == 0);

  db.save({"bop" : "foom"});
  db.save({"bop" : false});

  var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/bop");
  var resp = JSON.parse(req.responseText);
  T(resp.results.length == 1, "filtered/bop");

  req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/dynamic&field=woox");
  resp = JSON.parse(req.responseText);
  T(resp.results.length == 0);

  req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/dynamic&field=bop");
  resp = JSON.parse(req.responseText);
  T(resp.results.length == 1, "changes_filter/dynamic&field=bop");

  if (!is_safari && xhr) { // full test requires parallel connections
    // filter with longpoll
    // longpoll filters full history when run without a since seq
    xhr = CouchDB.newXhr();
    xhr.open("GET", "/test_suite_db/_changes?feed=longpoll&filter=changes_filter/bop", false);
    xhr.send("");
    var resp = JSON.parse(xhr.responseText);
    T(resp.last_seq == 7);
    // longpoll waits until a matching change before returning
    xhr = CouchDB.newXhr();
    xhr.open("GET", "/test_suite_db/_changes?feed=longpoll&since=7&filter=changes_filter/bop", true);
    xhr.send("");
    db.save({"_id":"falsy", "bop" : ""}); // empty string is falsy
    db.save({"_id":"bingo","bop" : "bingo"});

    waitForSuccess(function() {
      resp = JSON.parse(xhr.responseText);
    }, "longpoll-since");

    T(resp.last_seq == 9);
    T(resp.results && resp.results.length > 0 && resp.results[0]["id"] == "bingo", "filter the correct update");
    xhr.abort();

    timeout = 500;
    last_seq = 10
    while (true) {

      // filter with continuous
      xhr = CouchDB.newXhr();
      xhr.open("GET", "/test_suite_db/_changes?feed=continuous&filter=changes_filter/bop&timeout="+timeout, true);
      xhr.send("");

      db.save({"_id":"rusty", "bop" : "plankton"});
      T(xhr.readyState != 4, "test client too slow");
      var rusty = db.open("rusty", {cache_bust : new Date()});
      T(rusty._id == "rusty");

      waitForSuccess(function() { // throws an error after 5 seconds
        if (xhr.readyState != 4) {
          throw("still waiting")
        }
      }, "continuous-rusty");
      lines = xhr.responseText.split("\n");
      try {
        JSON.parse(lines[3])
        good = true;
      } catch(e) {
        good = false;
      }
      if (good) {
        T(JSON.parse(lines[1]).id == "bingo", lines[1]);
        T(JSON.parse(lines[2]).id == "rusty", lines[2]);
        T(JSON.parse(lines[3]).last_seq == last_seq, lines[3]);
        break;
      } else {
        xhr.abort();
        db.deleteDoc(rusty);
        timeout = timeout * 2;
        last_seq = last_seq + 2;
      }
    }
  }
  // error conditions

  // non-existing design doc
  var req = CouchDB.request("GET",
    "/test_suite_db/_changes?filter=nothingtosee/bop");
  TEquals(404, req.status, "should return 404 for non existant design doc");

  // non-existing filter
  var req = CouchDB.request("GET",
    "/test_suite_db/_changes?filter=changes_filter/movealong");
  TEquals(404, req.status, "should return 404 for non existant filter fun");

  // both
  var req = CouchDB.request("GET",
    "/test_suite_db/_changes?filter=nothingtosee/movealong");
  TEquals(404, req.status,
    "should return 404 for non existant design doc and filter fun");

  // changes get all_docs style with deleted docs
  var doc = {a:1};
  db.save(doc);
  db.deleteDoc(doc);
  var req = CouchDB.request("GET",
    "/test_suite_db/_changes?filter=changes_filter/bop&style=all_docs");
  var resp = JSON.parse(req.responseText);
  var expect = (!is_safari && xhr) ? 3: 1;
  TEquals(expect, resp.results.length, "should return matching rows");

  // test for userCtx
  run_on_modified_server(
    [{section: "httpd",
      key: "authentication_handlers",
      value: "{couch_httpd_auth, special_test_authentication_handler}"},
     {section:"httpd",
      key: "WWW-Authenticate",
      value:  "X-Couch-Test-Auth"}],

    function() {
      var authOpts = {"headers":{"WWW-Authenticate": "X-Couch-Test-Auth Chris Anderson:mp3"}};

      var req = CouchDB.request("GET", "/_session", authOpts);
      var resp = JSON.parse(req.responseText);

      T(db.save({"user" : "Noah Slater"}).ok);
      var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/userCtx", authOpts);
      var resp = JSON.parse(req.responseText);
      T(resp.results.length == 0);

      var docResp = db.save({"user" : "Chris Anderson"});
      T(docResp.ok);
      T(db.ensureFullCommit().ok);
      req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/userCtx", authOpts);
      resp = JSON.parse(req.responseText);
      T(resp.results.length == 1, "userCtx");
      T(resp.results[0].id == docResp.id);
    }
  );

  req = CouchDB.request("GET", "/test_suite_db/_changes?limit=1");
  resp = JSON.parse(req.responseText);
  TEquals(1, resp.results.length)

  //filter includes _conflicts
  var id = db.save({'food' : 'pizza'}).id;
  db.bulkSave([{_id: id, 'food' : 'pasta'}], {all_or_nothing:true});

  req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/conflicted");
  resp = JSON.parse(req.responseText);
  T(resp.results.length == 1, "filter=changes_filter/conflicted");

  // test with erlang filter function
  run_on_modified_server([{
    section: "native_query_servers",
    key: "erlang",
    value: "{couch_native_process, start_link, []}"
  }], function() {
    var erl_ddoc = {
      _id: "_design/erlang",
      language: "erlang",
      filters: {
        foo:
          'fun({Doc}, Req) -> ' +
          '  Value = couch_util:get_value(<<"value">>, Doc),' +
          '  (Value rem 2) =:= 0' +
          'end.'
      }
    };

    db.deleteDb();
    db.createDb();
    T(db.save(erl_ddoc).ok);

    var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=erlang/foo");
    var resp = JSON.parse(req.responseText);
    T(resp.results.length === 0);

    T(db.save({_id: "doc1", value : 1}).ok);
    T(db.save({_id: "doc2", value : 2}).ok);
    T(db.save({_id: "doc3", value : 3}).ok);
    T(db.save({_id: "doc4", value : 4}).ok);

    var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=erlang/foo");
    var resp = JSON.parse(req.responseText);
    T(resp.results.length === 2);
    T(resp.results[0].id === "doc2");
    T(resp.results[1].id === "doc4");
  });

};

<|endoftext|>


<commit_before>var pull     = require('pull-stream')
var pushable = require('../')
var test     = require('tape')

test('pushable', function (t) {

  var buf = pushable()

  t.equal('function', typeof buf)
  t.equal(2, buf.length)

  buf.end(function (err) {
    console.error('end')
    t.notOk(err)
    t.end()
  })

  buf(null, function (end) {
    t.ok(end)

  })

})

<commit_msg>remove the api i never used<commit_after><|endoftext|>


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

// __dirname returns the current directory this file resides in

var dir = path.join(__dirname, 'a-chaining-calls')

// __filename returns the absolute path for the current file

var file = __filename
var target = path.join(dir, 'write-target')

var handleError = function (err) {
    console.error(err)
}

fs.mkdir(dir, function (err) {

    if (err) {
        handleError(err)
    } else {
        fs.readFile(file, function (err, content) {
            if (err) {
                handleError(err)
            } else {
                fs.writeFile(target, content, function (err) {
                    if (err) {
                        handleError(err)
                    } else {
                        console.log('Write completed successfully')
                    }
                })
            }
        })
    }
})

<commit_msg>1st - Chaining without callback hell and generalizing errors<commit_after>var fs = require('fs')
var path = require('path')

var dir = path.join(__dirname, 'a-chaining-calls')
var target = path.join(dir, 'write-target')
var file = __filename

var logError = function (err) {
    console.error(err)
}

var handleError = function (callback) {
    return function (err, result) {
        if (err) {
            logError(err)
        } else {
            callback(result)
        }
    }
}

var haveFile = function (content) {
    fs.writeFile(target, content, handleError(verifyWrite))
}

var verifyWrite = function () {
    console.log('Write completed successfully')
}

var writeContentToFile = function () {
    fs.readFile(file, handleError(haveFile))
}

fs.mkdir(dir, handleError(writeContentToFile))

<|endoftext|>


<commit_before>/* eslint-disable no-console */
const logger = {
  info: (...args) => {
    if (process.env.NODE_ENV === "test") {
      return;
    }

    console.info(...args);
  },
  error: (...args) => {
    if (process.env.NODE_ENV === "test") {
      throw new Error(args);
    }

    console.error(...args);
  },
  success: (...args) => {
    if (process.env.NODE_ENV === "test") {
      return;
    }

    console.log(...args);
  },
};

export default logger;
<commit_msg>feat: logger throws prod errors<commit_after>/* eslint-disable no-console */
import * as Sentry from "@sentry/node";

const logger = {
  info: (...args) => {
    if (process.env.NODE_ENV === "test") {
      return;
    }

    console.info(...args);
  },
  error: (...args) => {
    if (process.env.NODE_ENV === "test") {
      throw new Error(args);
    }

    if (args[0] instanceof Error) {
      Sentry.captureException(args[0]);
    } else if (typeof args[0] === "string") {
      Sentry.captureMessage(args[0]);
    }
    console.error(...args);
  },
  success: (...args) => {
    if (process.env.NODE_ENV === "test") {
      return;
    }

    console.log(...args);
  },
};

export default logger;
<|endoftext|>


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

    var igcFile = null;
    var barogramPlot = null;
    var altitudeConversionFactor = 1.0; // Conversion from metres to required units

    function plotBarogram() {
        var nPoints = igcFile.recordTime.length;
        var pressureBarogramData = [];
        var gpsBarogramData = [];
        var j;
        var timestamp;

        for (j = 0; j < nPoints; j++) {
            timestamp = igcFile.recordTime[j].getTime();
            pressureBarogramData.push([timestamp, igcFile.pressureAltitude[j] * altitudeConversionFactor]);
            gpsBarogramData.push([timestamp, igcFile.gpsAltitude[j] * altitudeConversionFactor]);
        }

        var baro = $.plot($('#barogram'), [{
            label: 'Pressure altitude',
            data: pressureBarogramData
        }, {
            label: 'GPS altitude',
            data: gpsBarogramData
        }], {
            axisLabels: {
                show: true
            },
            xaxis: {
                mode: 'time',
                timeformat: '%H:%M',
                axisLabel: 'Time (UTC)'
            },
            yaxis: {
                axisLabel: 'Altitude / ' + $('#altitudeUnits').val()
            },

            crosshair: {
                mode: 'xy'
            },

            grid: {
                clickable: true,
                autoHighlight: false
            }
        });

        return baro;
    }

    function updateTimeline (timeIndex, mapControl) {
        var currentPosition = igcFile.latLong[timeIndex];
        var positionText=positionDisplay(currentPosition);
        var unitName = $('#altitudeUnits').val();
        $('#timePositionDisplay').text(
           // igcFile.recordTime[timeIndex].toUTCString() + ': ' +
             igcFile.recordTime[timeIndex].getUTCHours() + ':' +pad( igcFile.recordTime[timeIndex].getUTCMinutes()) + ':' + pad(igcFile.recordTime[timeIndex].getSeconds()) + ' UTC; ' +
            (igcFile.pressureAltitude[timeIndex] * altitudeConversionFactor).toFixed(0) + ' ' +
            unitName + ' (barometric) / ' +
            (igcFile.gpsAltitude[timeIndex] * altitudeConversionFactor).toFixed(0) + ' ' +
            unitName + ' (GPS); ' +
            positionText
        );

        mapControl.setTimeMarker(timeIndex);

        barogramPlot.lockCrosshair({
           x: igcFile.recordTime[timeIndex].getTime(),
           y: igcFile.pressureAltitude[timeIndex] * altitudeConversionFactor
        });
    }

    function displayIgc(mapControl) {
        // Display the headers.
        var headerTable = $('#headerInfo tbody');
        headerTable.html('');
        var headerName;
        var headerIndex;
        for (headerIndex = 0; headerIndex < igcFile.headers.length; headerIndex++) {
            headerTable.append(
                $('

').append($('	').text(igcFile.headers[headerIndex].name))
                              .append($('	').text(igcFile.headers[headerIndex].value))
            );
        }

        // Show the task declaration if it is present.

        if (igcFile.task.coordinates.length > 0) {
            //eliminate anything with empty start line coordinates
            if(igcFile.task.coordinates[0][0] !==0) {
                    $('#task').show();
                    var taskList = $('#task ul').first().html('');
                    var j;
                    //Now add TP numbers.  Change to unordered list
                    if(igcFile.task.takeoff.length > 0) {
                               taskList.append($('

').text("Takeoff: " + igcFile.task.takeoff));
                    }
                    for (j =0; j <igcFile.task.names.length; j++) {
                            switch(j)  {
                            case 0:
                                    taskList.append($('

').text("Start: " + igcFile.task.names[j]));
                                    break;
                            case ( igcFile.task.names.length-1):
                                    taskList.append($('

').text("Finish: " + igcFile.task.names[j]));
                                    break;
                            default:
                                    taskList.append($('

').text("TP" + (j).toString() + ": " + igcFile.task.names[j]));
                        }
                    }
                 if(igcFile.task.landing.length > 0) {
                        taskList.append($('

').text("Landing: : " + igcFile.task.landing));
                 }
                mapControl.addTask(igcFile.task.coordinates, igcFile.task.names);
                }
        }
        else {
            $('#task').hide();
        }

        // Reveal the map and graph. We have to do this before
        // setting the zoom level of the map or plotting the graph.
        $('#igcFileDisplay').show();

        mapControl.addTrack(igcFile.latLong);
        barogramPlot = plotBarogram(igcFile);

        $('#timeSlider').prop('max', igcFile.recordTime.length - 1);
        updateTimeline(0, mapControl);
    }

    function toDegMins(degreevalue) {
        var wholedegrees= Math.floor(degreevalue);
        var minutevalue = (60*(degreevalue-wholedegrees)).toFixed(3);
        return wholedegrees +"\xB0 "  + minutevalue  + "\xB4";
    }

    function positionDisplay(position)  {
       // var positionLatitude=(Math.abs(position[0])).toFixed(3) + "\xB0";
        var positionLatitude= toDegMins(Math.abs(position[0]));
        var positionLongitude=toDegMins(Math.abs(position[1]));
        if(position[0]  >  0)  {
            positionLatitude += "N";
        }
        else  {
            positionLatitude += "S";
        }
        if(position[1]  >  0)  {
            positionLongitude += "E";
        }
        else  {
            positionLongitude += "W";
        }
        return positionLatitude + ",   " + positionLongitude;
    }

    function pad(n) {
    return (n < 10) ? ("0" + n) : n;
}

    $(document).ready(function () {
        var mapControl = createMapControl('map');

        $('#fileControl').change(function () {
            if (this.files.length > 0) {
                var reader = new FileReader();
                reader.onload = function(e)  {
                  try {
                      $('#errorMessage').text('');
                      mapControl.reset();
                      $('#timeSlider').val(0);

                      igcFile = parseIGC(this.result);
                      displayIgc(mapControl);
                  } catch (ex) {
                      if (ex instanceof IGCException) {
                          $('#errorMessage').text(ex.message);
                      }
                      else {
                          throw ex;
                      }
                  }
                };
                reader.readAsText(this.files[0]);
            }
        });

        $('#altitudeUnits').change(function () {
            var altitudeUnit = $(this).val();
            if (altitudeUnit === 'feet') {
                altitudeConversionFactor = 3.2808399;
            }
            else {
                altitudeConversionFactor = 1.0;
            }

            if (igcFile !== null) {
                barogramPlot = plotBarogram();
                updateTimeline($('#timeSlider').val(), mapControl);
            }
        });

        // We need to handle the 'change' event for IE, but
        // 'input' for Chrome and Firefox in order to update smoothly
        // as the range input is dragged.
        $('#timeSlider').on('input', function() {
          updateTimeline($(this).val(), mapControl);
        });
        $('#timeSlider').on('change', function() {
           updateTimeline($(this).val(), mapControl);
        });

        $('#timeBack').click(function() {
           var curTime = parseInt($('#timeSlider').val(), 10);
           curTime -=2;
           if(curTime < 0) {
                 curTime = 0;
           }
           $('#timeSlider').val(curTime);
            updateTimeline(curTime, mapControl);
        });

         $('#timeForward').click(function() {
           var curTime = parseInt($('#timeSlider').val(), 10);
           var maxval= $('#timeSlider').attr("max");
           curTime +=2;
           if(curTime >  maxval) {
                 curTime = maxval;
           }
           $('#timeSlider').val(curTime);
          updateTimeline(curTime, mapControl);
        });

         $('#barogram').on('plotclick', function (event, pos, item) {
             console.log('plot click');
             if (item) {
                 updateTimeline(item.dataIndex, mapControl);
                 $('#timeSlider').val(item.dataIndex);
             }
         });
    });
}(jQuery));
<commit_msg>Always convert slider value from string to number.<commit_after>(function ($) {
   'use strict';

    var igcFile = null;
    var barogramPlot = null;
    var altitudeConversionFactor = 1.0; // Conversion from metres to required units

    function plotBarogram() {
        var nPoints = igcFile.recordTime.length;
        var pressureBarogramData = [];
        var gpsBarogramData = [];
        var j;
        var timestamp;

        for (j = 0; j < nPoints; j++) {
            timestamp = igcFile.recordTime[j].getTime();
            pressureBarogramData.push([timestamp, igcFile.pressureAltitude[j] * altitudeConversionFactor]);
            gpsBarogramData.push([timestamp, igcFile.gpsAltitude[j] * altitudeConversionFactor]);
        }

        var baro = $.plot($('#barogram'), [{
            label: 'Pressure altitude',
            data: pressureBarogramData
        }, {
            label: 'GPS altitude',
            data: gpsBarogramData
        }], {
            axisLabels: {
                show: true
            },
            xaxis: {
                mode: 'time',
                timeformat: '%H:%M',
                axisLabel: 'Time (UTC)'
            },
            yaxis: {
                axisLabel: 'Altitude / ' + $('#altitudeUnits').val()
            },

            crosshair: {
                mode: 'xy'
            },

            grid: {
                clickable: true,
                autoHighlight: false
            }
        });

        return baro;
    }

    function updateTimeline (timeIndex, mapControl) {
        var currentPosition = igcFile.latLong[timeIndex];
        var positionText=positionDisplay(currentPosition);
        var unitName = $('#altitudeUnits').val();
        $('#timePositionDisplay').text(
           // igcFile.recordTime[timeIndex].toUTCString() + ': ' +
             igcFile.recordTime[timeIndex].getUTCHours() + ':' +pad( igcFile.recordTime[timeIndex].getUTCMinutes()) + ':' + pad(igcFile.recordTime[timeIndex].getSeconds()) + ' UTC; ' +
            (igcFile.pressureAltitude[timeIndex] * altitudeConversionFactor).toFixed(0) + ' ' +
            unitName + ' (barometric) / ' +
            (igcFile.gpsAltitude[timeIndex] * altitudeConversionFactor).toFixed(0) + ' ' +
            unitName + ' (GPS); ' +
            positionText
        );

        mapControl.setTimeMarker(timeIndex);

        barogramPlot.lockCrosshair({
           x: igcFile.recordTime[timeIndex].getTime(),
           y: igcFile.pressureAltitude[timeIndex] * altitudeConversionFactor
        });
    }

    function displayIgc(mapControl) {
        // Display the headers.
        var headerTable = $('#headerInfo tbody');
        headerTable.html('');
        var headerName;
        var headerIndex;
        for (headerIndex = 0; headerIndex < igcFile.headers.length; headerIndex++) {
            headerTable.append(
                $('

').append($('	').text(igcFile.headers[headerIndex].name))
                              .append($('	').text(igcFile.headers[headerIndex].value))
            );
        }

        // Show the task declaration if it is present.

        if (igcFile.task.coordinates.length > 0) {
            //eliminate anything with empty start line coordinates
            if(igcFile.task.coordinates[0][0] !==0) {
                    $('#task').show();
                    var taskList = $('#task ul').first().html('');
                    var j;
                    //Now add TP numbers.  Change to unordered list
                    if(igcFile.task.takeoff.length > 0) {
                               taskList.append($('

').text("Takeoff: " + igcFile.task.takeoff));
                    }
                    for (j =0; j <igcFile.task.names.length; j++) {
                            switch(j)  {
                            case 0:
                                    taskList.append($('

').text("Start: " + igcFile.task.names[j]));
                                    break;
                            case ( igcFile.task.names.length-1):
                                    taskList.append($('

').text("Finish: " + igcFile.task.names[j]));
                                    break;
                            default:
                                    taskList.append($('

').text("TP" + (j).toString() + ": " + igcFile.task.names[j]));
                        }
                    }
                 if(igcFile.task.landing.length > 0) {
                        taskList.append($('

').text("Landing: : " + igcFile.task.landing));
                 }
                mapControl.addTask(igcFile.task.coordinates, igcFile.task.names);
                }
        }
        else {
            $('#task').hide();
        }

        // Reveal the map and graph. We have to do this before
        // setting the zoom level of the map or plotting the graph.
        $('#igcFileDisplay').show();

        mapControl.addTrack(igcFile.latLong);
        barogramPlot = plotBarogram(igcFile);

        $('#timeSlider').prop('max', igcFile.recordTime.length - 1);
        updateTimeline(0, mapControl);
    }

    function toDegMins(degreevalue) {
        var wholedegrees= Math.floor(degreevalue);
        var minutevalue = (60*(degreevalue-wholedegrees)).toFixed(3);
        return wholedegrees +"\xB0 "  + minutevalue  + "\xB4";
    }

    function positionDisplay(position)  {
       // var positionLatitude=(Math.abs(position[0])).toFixed(3) + "\xB0";
        var positionLatitude= toDegMins(Math.abs(position[0]));
        var positionLongitude=toDegMins(Math.abs(position[1]));
        if(position[0]  >  0)  {
            positionLatitude += "N";
        }
        else  {
            positionLatitude += "S";
        }
        if(position[1]  >  0)  {
            positionLongitude += "E";
        }
        else  {
            positionLongitude += "W";
        }
        return positionLatitude + ",   " + positionLongitude;
    }

    function pad(n) {
    return (n < 10) ? ("0" + n) : n;
}

    $(document).ready(function () {
        var mapControl = createMapControl('map');

        $('#fileControl').change(function () {
            if (this.files.length > 0) {
                var reader = new FileReader();
                reader.onload = function(e)  {
                  try {
                      $('#errorMessage').text('');
                      mapControl.reset();
                      $('#timeSlider').val(0);

                      igcFile = parseIGC(this.result);
                      displayIgc(mapControl);
                  } catch (ex) {
                      if (ex instanceof IGCException) {
                          $('#errorMessage').text(ex.message);
                      }
                      else {
                          throw ex;
                      }
                  }
                };
                reader.readAsText(this.files[0]);
            }
        });

        $('#altitudeUnits').change(function () {
            var altitudeUnit = $(this).val();
            if (altitudeUnit === 'feet') {
                altitudeConversionFactor = 3.2808399;
            }
            else {
                altitudeConversionFactor = 1.0;
            }

            if (igcFile !== null) {
                barogramPlot = plotBarogram();
                updateTimeline($('#timeSlider').val(), mapControl);
            }
        });

        // We need to handle the 'change' event for IE, but
        // 'input' for Chrome and Firefox in order to update smoothly
        // as the range input is dragged.
        $('#timeSlider').on('input', function() {
          var t = parseInt($(this).val(), 10);
          updateTimeline(t, mapControl);
        });
        $('#timeSlider').on('change', function() {
           var t = parseInt($(this).val(), 10);
           updateTimeline(t, mapControl);
        });

        $('#timeBack').click(function() {
           var curTime = parseInt($('#timeSlider').val(), 10);
           curTime -=2;
           if(curTime < 0) {
                 curTime = 0;
           }
           $('#timeSlider').val(curTime);
            updateTimeline(curTime, mapControl);
        });

         $('#timeForward').click(function() {
           var curTime = parseInt($('#timeSlider').val(), 10);
           var maxval= $('#timeSlider').attr("max");
           curTime +=2;
           if(curTime >  maxval) {
                 curTime = maxval;
           }
           $('#timeSlider').val(curTime);
          updateTimeline(curTime, mapControl);
        });

         $('#barogram').on('plotclick', function (event, pos, item) {
             console.log('plot click');
             if (item) {
                 updateTimeline(item.dataIndex, mapControl);
                 $('#timeSlider').val(item.dataIndex);
             }
         });
    });
}(jQuery));
<|endoftext|>


<commit_before>/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 */

const path = require('path');

const fbjs = require('eslint-config-fbjs');

const rulesDirPlugin = require('eslint-plugin-rulesdir');
rulesDirPlugin.RULES_DIR = path.join(__dirname, 'eslint-rules');

// enforces copy-right header and @format directive to be present in every file
const pattern = /^\*\r?\n[\S\s]*Meta Platforms, Inc\.[\S\s]* \* @format\r?\n/;

// This list should match the replacements defined in `replace-flipper-requires.ts` and `dispatcher/plugins.tsx`
const builtInModules = [
  'flipper',
  'flipper-plugin',
  'flipper-plugin-lib',
  'react',
  'react-dom',
  'electron',
  'antd',
  'immer',
  '@emotion/styled',
  '@ant-design/icons',
  'jest',
  'ts-jest',
];

const prettierConfig = require('./.prettierrc.json');

// We should forbid using "flipper" import. However, we have hundreds of plugins using it.
// So we forbid it everywhere but in "plugins" directory.
// To do that we need to keep "error" level of linting for most imports, but downlevel warning for "flipper" import to "warn".
// It is not possible OOTB by eslint.
// Instead, we create a clone of the "no-restricted-imports" rule and use it to split out restricted imports in two groups: warn and error.
// https://github.com/eslint/eslint/issues/14061#issuecomment-772490154
const restrictedImportsUniversalErrorConfig = {
  paths: [
    {
      name: 'electron',
      message:
        "Direct imports from 'electron' are deprecated. Most functions can be found in getFlipperLib() from flipper-plugin package instead.",
    },
  ],
  patterns: [
    {
      group: ['flipper-plugin/*'],
      message:
        "Imports from nested flipper-plugin directories are not allowed. Import from 'flipper-plugin' module directly. If it is missing an export, add it there with corresponding documentation (https://fbflipper.com/docs/extending/flipper-plugin/).",
    },
    {
      group: ['flipper-common/*'],
      message:
        "Imports from nested flipper-common directories are not allowed. Import from 'flipper-common' module directly. If it is missing an export, add it there.",
    },
    {
      group: ['flipper-ui-core/*'],
      message:
        "Imports from nested flipper-ui-core directories are not allowed. Import from 'flipper-ui-core' module directly. If it is missing an export, add it there.",
    },
  ],
};

module.exports = {
  parser: 'babel-eslint',
  root: true,
  extends: ['fbjs', 'prettier'],
  plugins: [
    ...fbjs.plugins,
    'header',
    'prettier',
    '@typescript-eslint',
    'import',
    'node',
    'react-hooks',
    'flipper',
    'promise',
    'communist-spelling',
    'rulesdir',
  ],
  rules: {
    // disable rules from eslint-config-fbjs
    'flowtype/define-flow-type': 0,
    'flowtype/use-flow-type': 0,
    'react/react-in-jsx-scope': 0, // not needed with our metro implementation
    // Disallow boolean JSX properties set to true, e.g. `grow={true}`.
    'react/jsx-boolean-value': ['warn', 'never'],
    'react-hooks/rules-of-hooks': 'error',
    'react-hooks/exhaustive-deps': 'warn',
    'react/jsx-key': 'error',
    'no-new': 0, // new keyword needed e.g. new Notification
    'no-catch-shadow': 0, // only relevant for IE8 and below
    'no-bitwise': 0, // bitwise operations needed in some places
    'consistent-return': 0,
    'no-var': 2,
    'prefer-const': [2, {destructuring: 'all'}],
    'prefer-spread': 1,
    'prefer-rest-params': 1,
    'no-console': 0, // we're setting window.console in App.js
    'no-multi-spaces': 2,
    'prefer-promise-reject-errors': 1,
    'no-throw-literal': 'error',
    'no-extra-boolean-cast': 2,
    'no-extra-semi': 2,
    'no-unsafe-negation': 2,
    'no-useless-computed-key': 2,
    'no-useless-rename': 2,
    'no-restricted-properties': [
      1,
      {
        object: 'electron',
        property: 'remote',
      },
    ],
    'no-restricted-imports': [
      'error',
      {
        ...restrictedImportsUniversalErrorConfig,
        paths: [
          ...restrictedImportsUniversalErrorConfig.paths,
          {
            name: 'flipper',
            message:
              "Direct imports from 'flipper' are deprecated. Import from 'flipper-plugin' instead, which can be tested and distributed stand-alone. See https://fbflipper.com/docs/extending/sandy-migration for more details.",
          },
        ],
      },
    ],

    // additional rules for this project
    'header/header': [2, 'block', {pattern}],
    'prettier/prettier': [2, prettierConfig],
    'import/no-unresolved': [2, {commonjs: true, amd: true}],
    'node/no-extraneous-import': [2, {allowModules: builtInModules}],
    'node/no-extraneous-require': [2, {allowModules: builtInModules}],
    'node/no-sync': [1],
    'flipper/no-relative-imports-across-packages': [2],
    'flipper/no-electron-remote-imports': [1],
    'flipper/no-console-error-without-context': [2],
    'flipper/no-ts-file-extension': 2,
    'flipper/no-i-prefix-interfaces': 2,
    'flipper/no-interface-props-or-state': 2,
    'communist-spelling/communist-spelling': [1, {allow: ['cancelled']}],

    // promise rules, see https://github.com/xjamundx/eslint-plugin-promise for details on each of them
    'promise/catch-or-return': 'error',
    'promise/no-nesting': 'warn',
    'promise/no-promise-in-callback': 'warn',
    'promise/no-callback-in-promise': 'warn',
    'promise/no-return-in-finally': 'warn',
    'promise/valid-params': 'error',
  },
  settings: {
    'import/resolver': {
      typescript: {
        alwaysTryTypes: true,
        extensions: ['.js', '.jsx', '.ts', '.tsx'],
        project: '.',
      },
    },
  },
  overrides: [
    {
      files: ['*.tsx', '*.ts'],
      parser: '@typescript-eslint/parser',
      rules: {
        'prettier/prettier': [2, {...prettierConfig, parser: 'typescript'}],
        // following rules are disabled because TS already handles it
        'no-undef': 0,
        'import/no-unresolved': 0,
        // following rules are disabled because they don't handle TS correctly,
        // while their @typescript-eslint counterpart does
        // for reference: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/README.md#extension-rules
        'no-unused-vars': 0,
        'no-redeclare': 0,
        'no-dupe-class-members': 0,
        '@typescript-eslint/no-redeclare': 1,
        '@typescript-eslint/no-unused-vars': [
          1,
          {
            ignoreRestSiblings: true,
            varsIgnorePattern: '^_',
            argsIgnorePattern: '^_',
            caughtErrorsIgnorePattern: '^_',
          },
        ],
        '@typescript-eslint/naming-convention': [
          2,
          {
            selector: 'typeLike',
            format: ['PascalCase', 'UPPER_CASE'],
            leadingUnderscore: 'allow',
          },
        ],
      },
    },
    {
      files: ['plugins/**/*.ts', 'plugins/**/*.tsx'],
      excludedFiles: [
        'plugins/**/serverAddOn.ts',
        'plugins/**/serverAddOn.tsx',
      ],
      rules: {
        'no-restricted-imports': [
          'error',
          {
            ...restrictedImportsUniversalErrorConfig,
            paths: [
              ...restrictedImportsUniversalErrorConfig.paths,
              // Ban Node.js API
              'async_hooks',
              {
                name: 'child_process',
                message:
                  "Node APIs are not allowed. Use 'getFlipperLib().remoteServerContext.child_process' from 'flipper-plugin' instead. See https://fbflipper.com/docs/extending/flipper-plugin/.",
              },
              'cluster',
              'crypto',
              'dgram',
              'dns',
              {
                name: 'fs',
                message:
                  "Node APIs are not allowed. Use 'getFlipperLib().remoteServerContext.fs' from 'flipper-plugin' instead. See https://fbflipper.com/docs/extending/flipper-plugin/.",
              },
              {
                name: 'fs-extra',
                message:
                  "Node APIs are not allowed. Use 'getFlipperLib().remoteServerContext.fs' from 'flipper-plugin' instead. See https://fbflipper.com/docs/extending/flipper-plugin/.",
              },
              'http',
              'https',
              'net',
              {
                name: 'os',
                message:
                  "Node APIs are not allowed. Use 'getFlipperLib().paths' and 'getFlipperLib().environmentInfo' from 'flipper-plugin' instead. See https://fbflipper.com/docs/extending/flipper-plugin/.",
              },
              {
                name: 'path',
                message:
                  "Node APIs are not allowed. Use 'path' from 'flipper-plugin' instead. See https://fbflipper.com/docs/extending/flipper-plugin/.",
              },
              'stream',
            ],
          },
        ],
        'rulesdir/no-restricted-imports-clone': [
          'warn',
          {
            paths: [
              {
                name: 'flipper',
                message:
                  "Direct imports from 'flipper' are deprecated. Import from 'flipper-plugin' instead, which can be tested and distributed stand-alone. See https://fbflipper.com/docs/extending/sandy-migration for more details.",
              },
            ],
          },
        ],
      },
    },
    // Overide rules for tests and service scripts (postinstall). Allow Node APIs usage there.
    {
      files: [
        'plugins/**/__tests__/*.tsx',
        'plugins/**/__tests__/*.ts',
        'plugins/postinstall.tsx',
        // TODO: Remove specific plugin overrides down below
        'plugins/fb/kaios-portal/kaios-debugger-client/client.tsx',
        'plugins/public/reactdevtools/index.tsx',
      ],
      rules: {
        'no-restricted-imports': [
          'error',
          restrictedImportsUniversalErrorConfig,
        ],
        'rulesdir/no-restricted-imports-clone': [
          'warn',
          {
            paths: [
              {
                name: 'flipper',
                message:
                  "Direct imports from 'flipper' are deprecated. Import from 'flipper-plugin' instead, which can be tested and distributed stand-alone. See https://fbflipper.com/docs/extending/sandy-migration for more details.",
              },
            ],
          },
        ],
      },
    },
  ],
};
<commit_msg>Remove linting exception for react devtools<commit_after>/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 */

const path = require('path');

const fbjs = require('eslint-config-fbjs');

const rulesDirPlugin = require('eslint-plugin-rulesdir');
rulesDirPlugin.RULES_DIR = path.join(__dirname, 'eslint-rules');

// enforces copy-right header and @format directive to be present in every file
const pattern = /^\*\r?\n[\S\s]*Meta Platforms, Inc\.[\S\s]* \* @format\r?\n/;

// This list should match the replacements defined in `replace-flipper-requires.ts` and `dispatcher/plugins.tsx`
const builtInModules = [
  'flipper',
  'flipper-plugin',
  'flipper-plugin-lib',
  'react',
  'react-dom',
  'electron',
  'antd',
  'immer',
  '@emotion/styled',
  '@ant-design/icons',
  'jest',
  'ts-jest',
];

const prettierConfig = require('./.prettierrc.json');

// We should forbid using "flipper" import. However, we have hundreds of plugins using it.
// So we forbid it everywhere but in "plugins" directory.
// To do that we need to keep "error" level of linting for most imports, but downlevel warning for "flipper" import to "warn".
// It is not possible OOTB by eslint.
// Instead, we create a clone of the "no-restricted-imports" rule and use it to split out restricted imports in two groups: warn and error.
// https://github.com/eslint/eslint/issues/14061#issuecomment-772490154
const restrictedImportsUniversalErrorConfig = {
  paths: [
    {
      name: 'electron',
      message:
        "Direct imports from 'electron' are deprecated. Most functions can be found in getFlipperLib() from flipper-plugin package instead.",
    },
  ],
  patterns: [
    {
      group: ['flipper-plugin/*'],
      message:
        "Imports from nested flipper-plugin directories are not allowed. Import from 'flipper-plugin' module directly. If it is missing an export, add it there with corresponding documentation (https://fbflipper.com/docs/extending/flipper-plugin/).",
    },
    {
      group: ['flipper-common/*'],
      message:
        "Imports from nested flipper-common directories are not allowed. Import from 'flipper-common' module directly. If it is missing an export, add it there.",
    },
    {
      group: ['flipper-ui-core/*'],
      message:
        "Imports from nested flipper-ui-core directories are not allowed. Import from 'flipper-ui-core' module directly. If it is missing an export, add it there.",
    },
  ],
};

module.exports = {
  parser: 'babel-eslint',
  root: true,
  extends: ['fbjs', 'prettier'],
  plugins: [
    ...fbjs.plugins,
    'header',
    'prettier',
    '@typescript-eslint',
    'import',
    'node',
    'react-hooks',
    'flipper',
    'promise',
    'communist-spelling',
    'rulesdir',
  ],
  rules: {
    // disable rules from eslint-config-fbjs
    'flowtype/define-flow-type': 0,
    'flowtype/use-flow-type': 0,
    'react/react-in-jsx-scope': 0, // not needed with our metro implementation
    // Disallow boolean JSX properties set to true, e.g. `grow={true}`.
    'react/jsx-boolean-value': ['warn', 'never'],
    'react-hooks/rules-of-hooks': 'error',
    'react-hooks/exhaustive-deps': 'warn',
    'react/jsx-key': 'error',
    'no-new': 0, // new keyword needed e.g. new Notification
    'no-catch-shadow': 0, // only relevant for IE8 and below
    'no-bitwise': 0, // bitwise operations needed in some places
    'consistent-return': 0,
    'no-var': 2,
    'prefer-const': [2, {destructuring: 'all'}],
    'prefer-spread': 1,
    'prefer-rest-params': 1,
    'no-console': 0, // we're setting window.console in App.js
    'no-multi-spaces': 2,
    'prefer-promise-reject-errors': 1,
    'no-throw-literal': 'error',
    'no-extra-boolean-cast': 2,
    'no-extra-semi': 2,
    'no-unsafe-negation': 2,
    'no-useless-computed-key': 2,
    'no-useless-rename': 2,
    'no-restricted-properties': [
      1,
      {
        object: 'electron',
        property: 'remote',
      },
    ],
    'no-restricted-imports': [
      'error',
      {
        ...restrictedImportsUniversalErrorConfig,
        paths: [
          ...restrictedImportsUniversalErrorConfig.paths,
          {
            name: 'flipper',
            message:
              "Direct imports from 'flipper' are deprecated. Import from 'flipper-plugin' instead, which can be tested and distributed stand-alone. See https://fbflipper.com/docs/extending/sandy-migration for more details.",
          },
        ],
      },
    ],

    // additional rules for this project
    'header/header': [2, 'block', {pattern}],
    'prettier/prettier': [2, prettierConfig],
    'import/no-unresolved': [2, {commonjs: true, amd: true}],
    'node/no-extraneous-import': [2, {allowModules: builtInModules}],
    'node/no-extraneous-require': [2, {allowModules: builtInModules}],
    'node/no-sync': [1],
    'flipper/no-relative-imports-across-packages': [2],
    'flipper/no-electron-remote-imports': [1],
    'flipper/no-console-error-without-context': [2],
    'flipper/no-ts-file-extension': 2,
    'flipper/no-i-prefix-interfaces': 2,
    'flipper/no-interface-props-or-state': 2,
    'communist-spelling/communist-spelling': [1, {allow: ['cancelled']}],

    // promise rules, see https://github.com/xjamundx/eslint-plugin-promise for details on each of them
    'promise/catch-or-return': 'error',
    'promise/no-nesting': 'warn',
    'promise/no-promise-in-callback': 'warn',
    'promise/no-callback-in-promise': 'warn',
    'promise/no-return-in-finally': 'warn',
    'promise/valid-params': 'error',
  },
  settings: {
    'import/resolver': {
      typescript: {
        alwaysTryTypes: true,
        extensions: ['.js', '.jsx', '.ts', '.tsx'],
        project: '.',
      },
    },
  },
  overrides: [
    {
      files: ['*.tsx', '*.ts'],
      parser: '@typescript-eslint/parser',
      rules: {
        'prettier/prettier': [2, {...prettierConfig, parser: 'typescript'}],
        // following rules are disabled because TS already handles it
        'no-undef': 0,
        'import/no-unresolved': 0,
        // following rules are disabled because they don't handle TS correctly,
        // while their @typescript-eslint counterpart does
        // for reference: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/README.md#extension-rules
        'no-unused-vars': 0,
        'no-redeclare': 0,
        'no-dupe-class-members': 0,
        '@typescript-eslint/no-redeclare': 1,
        '@typescript-eslint/no-unused-vars': [
          1,
          {
            ignoreRestSiblings: true,
            varsIgnorePattern: '^_',
            argsIgnorePattern: '^_',
            caughtErrorsIgnorePattern: '^_',
          },
        ],
        '@typescript-eslint/naming-convention': [
          2,
          {
            selector: 'typeLike',
            format: ['PascalCase', 'UPPER_CASE'],
            leadingUnderscore: 'allow',
          },
        ],
      },
    },
    {
      files: ['plugins/**/*.ts', 'plugins/**/*.tsx'],
      excludedFiles: [
        'plugins/**/serverAddOn.ts',
        'plugins/**/serverAddOn.tsx',
      ],
      rules: {
        'no-restricted-imports': [
          'error',
          {
            ...restrictedImportsUniversalErrorConfig,
            paths: [
              ...restrictedImportsUniversalErrorConfig.paths,
              // Ban Node.js API
              'async_hooks',
              {
                name: 'child_process',
                message:
                  "Node APIs are not allowed. Use 'getFlipperLib().remoteServerContext.child_process' from 'flipper-plugin' instead. See https://fbflipper.com/docs/extending/flipper-plugin/.",
              },
              'cluster',
              'crypto',
              'dgram',
              'dns',
              {
                name: 'fs',
                message:
                  "Node APIs are not allowed. Use 'getFlipperLib().remoteServerContext.fs' from 'flipper-plugin' instead. See https://fbflipper.com/docs/extending/flipper-plugin/.",
              },
              {
                name: 'fs-extra',
                message:
                  "Node APIs are not allowed. Use 'getFlipperLib().remoteServerContext.fs' from 'flipper-plugin' instead. See https://fbflipper.com/docs/extending/flipper-plugin/.",
              },
              'http',
              'https',
              'net',
              {
                name: 'os',
                message:
                  "Node APIs are not allowed. Use 'getFlipperLib().paths' and 'getFlipperLib().environmentInfo' from 'flipper-plugin' instead. See https://fbflipper.com/docs/extending/flipper-plugin/.",
              },
              {
                name: 'path',
                message:
                  "Node APIs are not allowed. Use 'path' from 'flipper-plugin' instead. See https://fbflipper.com/docs/extending/flipper-plugin/.",
              },
              'stream',
            ],
          },
        ],
        'rulesdir/no-restricted-imports-clone': [
          'warn',
          {
            paths: [
              {
                name: 'flipper',
                message:
                  "Direct imports from 'flipper' are deprecated. Import from 'flipper-plugin' instead, which can be tested and distributed stand-alone. See https://fbflipper.com/docs/extending/sandy-migration for more details.",
              },
            ],
          },
        ],
      },
    },
    // Overide rules for tests and service scripts (postinstall). Allow Node APIs usage there.
    {
      files: [
        'plugins/**/__tests__/*.tsx',
        'plugins/**/__tests__/*.ts',
        'plugins/postinstall.tsx',
        // TODO: Remove specific plugin overrides down below
        'plugins/fb/kaios-portal/kaios-debugger-client/client.tsx',
      ],
      rules: {
        'no-restricted-imports': [
          'error',
          restrictedImportsUniversalErrorConfig,
        ],
        'rulesdir/no-restricted-imports-clone': [
          'warn',
          {
            paths: [
              {
                name: 'flipper',
                message:
                  "Direct imports from 'flipper' are deprecated. Import from 'flipper-plugin' instead, which can be tested and distributed stand-alone. See https://fbflipper.com/docs/extending/sandy-migration for more details.",
              },
            ],
          },
        ],
      },
    },
  ],
};
<|endoftext|>


<commit_before>'use strict'

const webpack = require('webpack')
const path = require('path')
const buildPath = path.resolve(__dirname, 'dist')
const args = require('yargs').argv

const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const postcssPresetEnv = require('postcss-preset-env')
const cssnano = require('cssnano')

const isProd = args.prod
const isDev = args.dev
const env = args.envFile
if (env) {
  // Load env file
  require('dotenv').config({ path: env })
}

const main = ['./src/site.js']
const common = ['./src/common.js']
let devtool

if (isDev) {
  main.push('webpack-dev-server/client?http://0.0.0.0:8080')
  devtool = 'source-map'
}

const plugins = [
  new MiniCssExtractPlugin({ filename: '[name].[contenthash].css' }),
  new HtmlWebpackPlugin({
    template: './src/index.html',
    chunks: ['main'],
    inject: 'body',
  }),
  new HtmlWebpackPlugin({
    template: './src/error.html',
    chunks: ['common'],
    inject: 'body',
    filename: 'error.html',
  }),
  new webpack.DefinePlugin({
    'process.env.CLIENT_ID': JSON.stringify(process.env.CLIENT_ID),
    'process.env.API_KEY': JSON.stringify(process.env.API_KEY),
    'process.env.ENABLE_GOOGLE_AUTH': JSON.stringify(process.env.ENABLE_GOOGLE_AUTH),
    'process.env.GTM_ID': JSON.stringify(process.env.GTM_ID),
  }),
]

if (isProd) {
  plugins.push(new webpack.NoEmitOnErrorsPlugin())
}

module.exports = {
  entry: {
    main: main,
    common: common,
  },

  output: {
    path: buildPath,
    publicPath: '/',
    filename: '[name].[contenthash].js',
    assetModuleFilename: 'images/[name].[ext]',
  },
  resolve: {
    fallback: {
      fs: false,
    },
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env'],
            },
          },
        ],
      },
      {
        test: /\.scss$/,
        exclude: /node_modules/,
        use: [
          'style-loader',
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: { importLoaders: 1, modules: true, url: false },
          },
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  postcssPresetEnv({ browsers: 'last 2 versions' }),
                  cssnano({
                    preset: ['default', { discardComments: { removeAll: true } }],
                  }),
                ],
              },
            },
          },
          'sass-loader',
        ],
      },
      {
        test: /\.(eot|otf|ttf|woff|woff2)$/,
        type: 'asset/resource',
      },
      {
        test: /\.(png|jpg|jpeg|gif|ico|svg)$/,
        exclude: /node_modules/,
        type: 'asset/resource',
      },
      {
        test: require.resolve('jquery'),
        loader: 'expose-loader',
        options: { exposes: ['$', 'jQuery'] },
      },
    ],
  },

  plugins: plugins,

  devtool: devtool,

  devServer: {
    static: { directory: buildPath },
    host: '0.0.0.0',
    port: 8080,
  },
}
<commit_msg>FIX emit correct asset names and CSS classes scope<commit_after>'use strict'

const webpack = require('webpack')
const path = require('path')
const buildPath = path.resolve(__dirname, 'dist')
const args = require('yargs').argv

const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const postcssPresetEnv = require('postcss-preset-env')
const cssnano = require('cssnano')

const isProd = args.prod
const isDev = args.dev
const env = args.envFile
if (env) {
  // Load env file
  require('dotenv').config({ path: env })
}

const main = ['./src/site.js']
const common = ['./src/common.js']
let devtool

if (isDev) {
  main.push('webpack-dev-server/client?http://0.0.0.0:8080')
  devtool = 'source-map'
}

const plugins = [
  new MiniCssExtractPlugin({ filename: '[name].[contenthash].css' }),
  new HtmlWebpackPlugin({
    template: './src/index.html',
    chunks: ['main'],
    inject: 'body',
  }),
  new HtmlWebpackPlugin({
    template: './src/error.html',
    chunks: ['common'],
    inject: 'body',
    filename: 'error.html',
  }),
  new webpack.DefinePlugin({
    'process.env.CLIENT_ID': JSON.stringify(process.env.CLIENT_ID),
    'process.env.API_KEY': JSON.stringify(process.env.API_KEY),
    'process.env.ENABLE_GOOGLE_AUTH': JSON.stringify(process.env.ENABLE_GOOGLE_AUTH),
    'process.env.GTM_ID': JSON.stringify(process.env.GTM_ID),
  }),
]

if (isProd) {
  plugins.push(new webpack.NoEmitOnErrorsPlugin())
}

module.exports = {
  entry: {
    main: main,
    common: common,
  },

  output: {
    path: buildPath,
    publicPath: '/',
    filename: '[name].[contenthash].js',
    assetModuleFilename: 'images/[name][ext]',
  },
  resolve: {
    fallback: {
      fs: false,
    },
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env'],
            },
          },
        ],
      },
      {
        test: /\.scss$/,
        exclude: /node_modules/,
        use: [
          'style-loader',
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: { importLoaders: 1, modules: 'global', url: false },
          },
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  postcssPresetEnv({ browsers: 'last 2 versions' }),
                  cssnano({
                    preset: ['default', { discardComments: { removeAll: true } }],
                  }),
                ],
              },
            },
          },
          'sass-loader',
        ],
      },
      {
        test: /\.(eot|otf|ttf|woff|woff2)$/,
        type: 'asset/resource',
      },
      {
        test: /\.(png|jpg|jpeg|gif|ico|svg)$/,
        exclude: /node_modules/,
        type: 'asset/resource',
      },
      {
        test: require.resolve('jquery'),
        loader: 'expose-loader',
        options: { exposes: ['$', 'jQuery'] },
      },
    ],
  },

  plugins: plugins,

  devtool: devtool,

  devServer: {
    static: { directory: buildPath },
    host: '0.0.0.0',
    port: 8080,
  },
}
<|endoftext|>


<commit_before>$(document).ready(function() {
   $('#fileControl').change(function() {
      if (this.files.length > 0) {
	      var reader = new FileReader();
		  reader.onload = function(e) {
		      try {
			     $('#errorMessage').text('');
		         var model = parseIGC(this.result);
				 var nPoints = model.recordTime.length;
				 var pressureBarogramData = [];
				 var gpsBarogramData = [];
				 var j;
				 var timestamp;
				 for (j = 0; j < nPoints; j++) {
				     timestamp = model.recordTime[j].getTime();
				     pressureBarogramData.push([timestamp, model.pressureAltitude[j]]);
                     gpsBarogramData.push([timestamp, model.gpsAltitude[j]]);
				 }

				 var map = L.map('map').setView([51.505, -0.09], 13);
				 L.tileLayer('http://otile1.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.jpg', {
                              attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA,
Tiles Courtesy of MapQuest
',
                              maxZoom: 18
                            }).addTo(map);

				 var gliderTrack = L.polyline(model.latLong, {color: 'red'}).addTo(map);
                 map.fitBounds(gliderTrack.getBounds());

				 $('#barograph').plot([{
					label: 'Pressure altitude',
					data: pressureBarogramData}, {
					label: 'GPS altitude',
				    data: gpsBarogramData}], {
					 axisLabels: {
					    show: true
					 },
				     xaxis: {
						mode: 'time',
                        timeformat: '%H:%M:%S',
						axisLabel: 'Time'
                     },
					 yaxis: {
					    axisLabel: 'Altitude / metres'
					 }
				 });
			  } catch (e) {
			    if (e instanceof IGCException) {
				    $('#errorMessage').text(e.message);
				}
				else {
				    throw e;
				}
			  }
		  };
		  reader.readAsText(this.files[0]);
	  }
   });
});<commit_msg>Removed extraneous paragraph break from map attribution.<commit_after>$(document).ready(function() {
   $('#fileControl').change(function() {
      if (this.files.length > 0) {
	      var reader = new FileReader();
		  reader.onload = function(e) {
		      try {
			     $('#errorMessage').text('');
		         var model = parseIGC(this.result);
				 var nPoints = model.recordTime.length;
				 var pressureBarogramData = [];
				 var gpsBarogramData = [];
				 var j;
				 var timestamp;
				 for (j = 0; j < nPoints; j++) {
				     timestamp = model.recordTime[j].getTime();
				     pressureBarogramData.push([timestamp, model.pressureAltitude[j]]);
                     gpsBarogramData.push([timestamp, model.gpsAltitude[j]]);
				 }

				 var map = L.map('map');
				 L.tileLayer('http://otile1.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.jpg', {
                              attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Tiles Courtesy of MapQuest ',
                              maxZoom: 18
                            }).addTo(map);

				 var gliderTrack = L.polyline(model.latLong, {color: 'red'}).addTo(map);
                 map.fitBounds(gliderTrack.getBounds());

				 $('#barograph').plot([{
					label: 'Pressure altitude',
					data: pressureBarogramData}, {
					label: 'GPS altitude',
				    data: gpsBarogramData}], {
					 axisLabels: {
					    show: true
					 },
				     xaxis: {
						mode: 'time',
                        timeformat: '%H:%M:%S',
						axisLabel: 'Time'
                     },
					 yaxis: {
					    axisLabel: 'Altitude / metres'
					 }
				 });
			  } catch (e) {
			    if (e instanceof IGCException) {
				    $('#errorMessage').text(e.message);
				}
				else {
				    throw e;
				}
			  }
		  };
		  reader.readAsText(this.files[0]);
	  }
   });
});<|endoftext|>