<commit_before>'use strict';

const electron = require('electron');
const app = electron.app;  // Module to control application life.
const BrowserWindow = electron.BrowserWindow;  // Module to create native browser window.
const ipcMain = require('electron').ipcMain;
const Menu = require('electron').Menu;
const Tray = require('electron').Tray;
const globalShortcut = electron.globalShortcut;
const dialog = electron.dialog;

var debugMode;
var startupFilePath;
var trayIcon = null;

//handling start parameter
//console.log(JSON.stringify(process.argv));
process.argv.forEach(function(arg, count) {
  if (arg.toLowerCase() === '-d' || arg.toLowerCase() === '--debug') {
    debugMode = true;
  } else if (arg.toLowerCase() === '-p' || arg.toLowerCase() === '--portable') {
    app.setPath('userData', process.cwd() + '/tsprofile'); // making the app portable
  } else if (arg === '.' || count === 0) { // ignoring the first argument
    //Ignore these argument
  } else if (arg.length > 2) {
    console.log("Opening file: " + arg);
    startupFilePath = arg;
  }
});

ipcMain.on('quit-application', function(event, arg) {
  app.quit();
});

var path = require('path');
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
var mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  //if (process.platform != 'darwin') {
  app.quit();
  //}
});

app.on('will-quit', function() {
  // Unregister all shortcuts.
  globalShortcut.unregisterAll();
});

app.on('ready', function(event) {
  //console.log(app.getLocale());
  //console.log(app.getAppPath());
  mainWindow = new BrowserWindow({width: 1280, height: 768});

  //var indexPath = 'file://' + __dirname + '/index.html';
  var startupParameter = "";
  if (startupFilePath) {
    startupParameter = "?open=" + encodeURIComponent(startupFilePath);
  }
  var indexPath = 'file://' + path.dirname(__dirname) + '/index.html' + startupParameter;

  mainWindow.setMenu(null);
  mainWindow.loadURL(indexPath);

  if (debugMode) {
    mainWindow.webContents.openDevTools();
  }

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });

  mainWindow.webContents.on('crashed', function() {
    const options = {
      type: 'info',
      title: 'Renderer Process Crashed',
      message: 'This process has crashed.',
      buttons: ['Reload', 'Close']
    };
    dialog.showMessageBox(mainWindow, options, function(index) {
      mainWindow.hide();
      if (index === 0) {
        mainWindow.reload();
      } else {
        mainWindow.close();
      }
    });
  });

  if (process.platform === 'darwin') {
    trayIcon = new Tray('Contents/Resources/app/assets/trayicon.png');
  } else if (process.platform === 'win') {
    trayIcon = new Tray('resources/app/assets/trayicon.png');
  } else {
    trayIcon = new Tray('resources/app/assets/trayicon.png');
  }
  var trayMenuTemplate = [
    {
      label: 'Show TagSpaces',
      click: showTagSpaces
    },
    {
      type: 'separator'
    },
    {
      label: 'New Text File',
      click: newTextFile
    },
    {
      label: 'New HTML File',
      click: newHTMLFile
    },
    {
      label: 'New Markdown File',
      click: newMDFile
    },
    {
      label: 'New Audio File',
      click: newAudioFile
    },
    {
      type: 'separator'
    },
    {
      label: 'Open Next File',
      click: getNextFile
    },
    {
      label: 'Open Previous File',
      click: getPreviousFile
    },
    {
      type: 'separator'
    },
    {
      label: 'Pause/Resume Playback',
      sublabel: 'Ctrl+Alt+P',
      click: resumePlayback
    },
    {
      type: 'separator'
    },
    {
      label: 'Quit TagSpaces',
      click: function() {
        app.quit();
      }
    }
  ];

  trayIcon.on('click', function() {
    mainWindow.show();
    //mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
  });

  var title = 'TagSpaces App';
  var trayMenu = Menu.buildFromTemplate(trayMenuTemplate);
  trayIcon.setToolTip(title);
  trayIcon.setTitle(title);
  trayIcon.setContextMenu(trayMenu);

  globalShortcut.register('CommandOrControl+Alt+P', resumePlayback);

  globalShortcut.register('CommandOrControl+Alt+N', newTextFile);

  globalShortcut.register('CommandOrControl+Alt+I', getNextFile);

  globalShortcut.register('CommandOrControl+Alt+O', getPreviousFile);

  globalShortcut.register('CommandOrControl+Alt+S', showTagSpaces);

  function showTagSpaces() {
    mainWindow.show();
    //mainWindow.webContents.send("showing-tagspaces", "tagspaces");
  }

  function newTextFile() {
    mainWindow.show();
    mainWindow.webContents.send("new-file", "text");
  }

  function newHTMLFile() {
    mainWindow.show();
    mainWindow.webContents.send("new-file", "html");
  }

  function newMDFile() {
    mainWindow.show();
    mainWindow.webContents.send("new-file", "markdown");
  }

  function newAudioFile() {
    mainWindow.show();
    mainWindow.webContents.send("new-file", "audio");
  }

  function getNextFile() {
    mainWindow.show();
    mainWindow.webContents.send("next-file", "next");
  }

  function getPreviousFile() {
    mainWindow.show();
    mainWindow.webContents.send("previous-file", "previous");
  }

  function resumePlayback() {
    //mainWindow.show();
    mainWindow.webContents.send('play-pause', true);
  }

});

process.on('uncaughtException', function(error) {
  if (error.stack) {
    console.error('error:', error.stack);
  }
  mainWindow.reload();
  // Handle the error
  /*if (error) {
   const options = {
   type: 'info',
   title: 'Renderer Process Crashed',
   message: 'This process has crashed.',
   buttons: ['Reload', 'Close']
   };
   dialog.showMessageBox(mainWindow, options, function(index) {
   if (index === 0) {
   mainWindow.reload();
   } else {
   mainWindow.close();
   }
   });
   }*/
});<commit_msg>fixing tray icon path<commit_after>'use strict';

const electron = require('electron');
const app = electron.app;  // Module to control application life.
const BrowserWindow = electron.BrowserWindow;  // Module to create native browser window.
const ipcMain = require('electron').ipcMain;
const Menu = require('electron').Menu;
const Tray = require('electron').Tray;
const globalShortcut = electron.globalShortcut;
const dialog = electron.dialog;

var debugMode;
var startupFilePath;
var trayIcon = null;

//handling start parameter
//console.log(JSON.stringify(process.argv));
process.argv.forEach(function(arg, count) {
  if (arg.toLowerCase() === '-d' || arg.toLowerCase() === '--debug') {
    debugMode = true;
  } else if (arg.toLowerCase() === '-p' || arg.toLowerCase() === '--portable') {
    app.setPath('userData', process.cwd() + '/tsprofile'); // making the app portable
  } else if (arg === '.' || count === 0) { // ignoring the first argument
    //Ignore these argument
  } else if (arg.length > 2) {
    console.log("Opening file: " + arg);
    startupFilePath = arg;
  }
});

ipcMain.on('quit-application', function(event, arg) {
  app.quit();
});

var path = require('path');
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
var mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  //if (process.platform != 'darwin') {
  app.quit();
  //}
});

app.on('will-quit', function() {
  // Unregister all shortcuts.
  globalShortcut.unregisterAll();
});

app.on('ready', function(event) {
  //console.log(app.getLocale());
  //console.log(app.getAppPath());
  mainWindow = new BrowserWindow({width: 1280, height: 768});

  //var indexPath = 'file://' + __dirname + '/index.html';
  var startupParameter = "";
  if (startupFilePath) {
    startupParameter = "?open=" + encodeURIComponent(startupFilePath);
  }
  var indexPath = 'file://' + path.dirname(__dirname) + '/index.html' + startupParameter;

  mainWindow.setMenu(null);
  mainWindow.loadURL(indexPath);

  if (debugMode) {
    mainWindow.webContents.openDevTools();
  }

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });

  mainWindow.webContents.on('crashed', function() {
    const options = {
      type: 'info',
      title: 'Renderer Process Crashed',
      message: 'This process has crashed.',
      buttons: ['Reload', 'Close']
    };
    dialog.showMessageBox(mainWindow, options, function(index) {
      mainWindow.hide();
      if (index === 0) {
        mainWindow.reload();
      } else {
        mainWindow.close();
      }
    });
  });

  if (process.platform === 'darwin') {
    trayIcon = new Tray('Contents/Resources/app/assets/trayicon.png');
  } else if (process.platform === 'win') {
    trayIcon = new Tray('resources/app/assets/trayicon.png');
  } else {
    trayIcon = new Tray('resources/app/assets/trayicon.png');
  }
  //trayIcon = new Tray('assets/trayicon.png'); // 4 dev

  var trayMenuTemplate = [
    {
      label: 'Show TagSpaces',
      click: showTagSpaces
    },
    {
      type: 'separator'
    },
    {
      label: 'New Text File',
      click: newTextFile
    },
    {
      label: 'New HTML File',
      click: newHTMLFile
    },
    {
      label: 'New Markdown File',
      click: newMDFile
    },
    {
      label: 'New Audio File',
      click: newAudioFile
    },
    {
      type: 'separator'
    },
    {
      label: 'Open Next File',
      click: getNextFile
    },
    {
      label: 'Open Previous File',
      click: getPreviousFile
    },
    {
      type: 'separator'
    },
    {
      label: 'Pause/Resume Playback',
      sublabel: 'Ctrl+Alt+P',
      click: resumePlayback
    },
    {
      type: 'separator'
    },
    {
      label: 'Quit TagSpaces',
      click: function() {
        app.quit();
      }
    }
  ];

  trayIcon.on('click', function() {
    mainWindow.show();
    //mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
  });

  var title = 'TagSpaces App';
  var trayMenu = Menu.buildFromTemplate(trayMenuTemplate);
  trayIcon.setToolTip(title);
  trayIcon.setTitle(title);
  trayIcon.setContextMenu(trayMenu);

  globalShortcut.register('CommandOrControl+Alt+P', resumePlayback);

  globalShortcut.register('CommandOrControl+Alt+N', newTextFile);

  globalShortcut.register('CommandOrControl+Alt+I', getNextFile);

  globalShortcut.register('CommandOrControl+Alt+O', getPreviousFile);

  globalShortcut.register('CommandOrControl+Alt+S', showTagSpaces);

  function showTagSpaces() {
    mainWindow.show();
    //mainWindow.webContents.send("showing-tagspaces", "tagspaces");
  }

  function newTextFile() {
    mainWindow.show();
    mainWindow.webContents.send("new-file", "text");
  }

  function newHTMLFile() {
    mainWindow.show();
    mainWindow.webContents.send("new-file", "html");
  }

  function newMDFile() {
    mainWindow.show();
    mainWindow.webContents.send("new-file", "markdown");
  }

  function newAudioFile() {
    mainWindow.show();
    mainWindow.webContents.send("new-file", "audio");
  }

  function getNextFile() {
    mainWindow.show();
    mainWindow.webContents.send("next-file", "next");
  }

  function getPreviousFile() {
    mainWindow.show();
    mainWindow.webContents.send("previous-file", "previous");
  }

  function resumePlayback() {
    //mainWindow.show();
    mainWindow.webContents.send('play-pause', true);
  }

});

process.on('uncaughtException', function(error) {
  if (error.stack) {
    console.error('error:', error.stack);
  }
  mainWindow.reload();
  // Handle the error
  /*if (error) {
   const options = {
   type: 'info',
   title: 'Renderer Process Crashed',
   message: 'This process has crashed.',
   buttons: ['Reload', 'Close']
   };
   dialog.showMessageBox(mainWindow, options, function(index) {
   if (index === 0) {
   mainWindow.reload();
   } else {
   mainWindow.close();
   }
   });
   }*/
});<|endoftext|>


<commit_before>import React, { useRef, useState } from 'react';
import PropTypes from 'prop-types';

import { generateUID, classnames } from '../../helpers/component';
import Icon from '../icon/Icon';
import { usePopper, Popper, usePopperAnchor } from '../popper';
import useRightToLeft from '../../containers/rightToLeft/useRightToLeft';

const Info = ({ url, title, originalPlacement = 'top', scrollContainerClass = 'main', ...rest }) => {
    const [uid] = useState(generateUID('tooltip'));

    const { isRTL } = useRightToLeft();
    const rtlAdjustedPlacement = originalPlacement.includes('right')
        ? originalPlacement.replace('right', 'left')
        : originalPlacement.replace('left', 'right');

    const popperRef = useRef();
    const { anchorRef, open, close, isOpen } = usePopperAnchor();
    const { position, placement } = usePopper(popperRef, anchorRef, isOpen, {
        originalPlacement: isRTL ? rtlAdjustedPlacement : originalPlacement,
        scrollContainerClass
    });

    const handleClick = () => {
        url && window.open(url);
    };

    return (
        <>
            <button
                tabIndex="-1"
                className="inline-flex"
                onClick={handleClick}
                ref={anchorRef}
                onMouseEnter={open}
                onMouseLeave={close}
                onFocus={open}
                onBlur={close}
                aria-describedby={uid}
                type="button"
            >
                <Icon className="icon-16p fill-primary" name="info" {...rest} />
            </button>
            <Popper
                ref={popperRef}
                id={uid}
                isOpen={isOpen}
                position={position}
                className={classnames(['tooltip', `tooltip--${placement}`])}
            >
                {title}
            </Popper>
        </>
    );
};

Info.propTypes = {
    originalPlacement: PropTypes.oneOf(['top', 'bottom', 'left', 'right']),
    url: PropTypes.string,
    title: PropTypes.node,
    scrollContainerClass: PropTypes.string
};

export default Info;
<commit_msg>Hotfix - Don't define Popper is title is not defined<commit_after>import React, { useRef, useState } from 'react';
import PropTypes from 'prop-types';

import { generateUID, classnames } from '../../helpers/component';
import Icon from '../icon/Icon';
import { usePopper, Popper, usePopperAnchor } from '../popper';
import useRightToLeft from '../../containers/rightToLeft/useRightToLeft';

const Info = ({ url, title, originalPlacement = 'top', scrollContainerClass = 'main', ...rest }) => {
    const [uid] = useState(generateUID('tooltip'));

    const { isRTL } = useRightToLeft();
    const rtlAdjustedPlacement = originalPlacement.includes('right')
        ? originalPlacement.replace('right', 'left')
        : originalPlacement.replace('left', 'right');

    const popperRef = useRef();
    const { anchorRef, open, close, isOpen } = usePopperAnchor();
    const { position, placement } = usePopper(popperRef, anchorRef, isOpen, {
        originalPlacement: isRTL ? rtlAdjustedPlacement : originalPlacement,
        scrollContainerClass
    });

    const handleClick = () => {
        url && window.open(url);
    };

    return (
        <>
            <button
                tabIndex="-1"
                className="inline-flex"
                onClick={handleClick}
                ref={anchorRef}
                onMouseEnter={open}
                onMouseLeave={close}
                onFocus={open}
                onBlur={close}
                aria-describedby={uid}
                type="button"
            >
                <Icon className="icon-16p fill-primary" name="info" {...rest} />
            </button>
            {title ? (
                <Popper
                    ref={popperRef}
                    id={uid}
                    isOpen={isOpen}
                    position={position}
                    className={classnames(['tooltip', `tooltip--${placement}`])}
                >
                    {title}
                </Popper>
            ) : null}
        </>
    );
};

Info.propTypes = {
    originalPlacement: PropTypes.oneOf(['top', 'bottom', 'left', 'right']),
    url: PropTypes.string,
    title: PropTypes.node,
    scrollContainerClass: PropTypes.string
};

export default Info;
<|endoftext|>


<commit_before>/*! overthrow.js. An overflow:auto polyfill for responsive design. (c) 2012: Scott Jehl, Filament Group, Inc. Dual MIT/GPLv2 license */
(function( w, undefined ){

	var doc = w.document,
		docElem = doc.documentElement,
		classtext = "overthrow",

		// Touch events are used in the polyfill, and thus are a prerequisite
		canBeFilledWithPoly = "ontouchmove" in doc,

		// The following attempts to determine whether the browser has native overflow support
		// so we can enable it but not polyfill
		overflowProbablyAlreadyWorks =
			// Features-first. iOS5 overflow scrolling property check - no UA needed here. thanks Apple :)
			"WebkitOverflowScrolling" in docElem.style
			// Touch events aren't supported and screen width is greater than X
			// ...basically, this is a loose "desktop browser" check.
			// It may wrongly opt-in very large tablets with no touch support.
			|| ( !canBeFilledWithPoly && w.screen.width > 1200 )
			// Hang on to your hats.
			// Whitelist some popular, overflow-supporting mobile browsers for now and the future
			// These browsers are known to get overlow support right, but give us no way of detecting it.
			|| (function(){
				var ua = w.navigator.userAgent,
					// Webkit crosses platforms, and the browsers on our list run at least version 534
					webkit = ua.match( /AppleWebKit\/([0-9]+)/ ),
					wkversion = webkit && webkit[1],
					wkLte534 = webkit && wkversion >= 534;

				return (
					/* Android 3+ with webkit gte 534
					   Sample: Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13 */
					ua.match( /Android ([0-9]+)/ ) && RegExp.$1 >= 3 && wkLte534
					/* Blackberry 7+ with webkit gte 534
					   ~: Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0 Mobile Safari/534.11+ */
					|| ua.match( / Version\/([0-9]+)/ ) && RegExp.$1 >= 0 && w.blackberry && wkLte534
					/* Blackberry Playbook with webkit gte 534
					   ~: Mozilla/5.0 (PlayBook; U; RIM Tablet OS 1.0.0; en-US) AppleWebKit/534.8+ (KHTML, like Gecko) Version/0.0.1 Safari/534.8+ */
					|| ua.indexOf( /PlayBook/ ) > -1 && RegExp.$1 >= 0 && wkLte534
					/* Firefox Mobile (Fennec) 4 and up
					   ~: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:2.1.1) Gecko/ Firefox/4.0.2pre Fennec/4.0. */
					|| ua.match( /Fennec\/([0-9]+)/ ) && RegExp.$1 >= 4
					/* WebOS 3 and up (TouchPad too)
					   ~: Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.48 Safari/534.6 TouchPad/1.0 */
					|| ua.match( /wOSBrowser\/([0-9]+)/ ) && RegExp.$1 >= 233 && wkLte534
					/* Nokia Browser N8
					   ~: Mozilla/5.0 (Symbian/3; Series60/5.2 NokiaN8-00/012.002; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.0 Mobile Safari/533.4 3gpp-gba
					   ~: Note: the N9 doesn't have native overflow with one-finger touch. wtf */
					|| ua.match( /NokiaBrowser\/([0-9\.]+)/ ) && parseFloat(RegExp.$1) === 7.3 && webkit && wkversion >= 533
				);
			})(),

		// Easing uses any of Robert Penner's equations. By default, overthrow uses ease-out-cubic
		// arguments: t = current iteration, b = initial value, c = end value, d = total iterations
		// use w.overthrow.easing to provide a custom function externally, or pass an easing function as a callback to the toss method
		defaultEasing = function (t, b, c, d) {
			return c*((t=t/d-1)*t*t + 1) + b;
		},

		enabled = false,

		// Keeper of intervals
		timeKeeper,

		/* toss scrolls and element with easing

		// elem is the element to scroll
		// options hash:
			* left is the desired horizontal scroll. Default is "+0". For relative distances, pass a string with "+" or "-" in front.
			* top is the desired vertical scroll. Default is "+0". For relative distances, pass a string with "+" or "-" in front.
			* duration is the number of milliseconds the throw will take. Default is 100.
			* easing is an optional custom easing function. Default is w.overthrow.easing. Must follow the easing function signature
		*/
		toss = function( elem, options ){
			var i = 0,
				o = options || {},
				top = o.top || "+0",
				left = o.left || "+0",
				duration = o.duration || 100,
				easing = o.easing || w.overthrow.easing,
				sLeft = elem.scrollLeft,
				sTop = elem.scrollTop;

			// top and left relative or positive distance
			left = typeof left === "string" ? parseFloat( left ) : left - sLeft,
			top = typeof top === "string" ? parseFloat( top ) : top - sTop;

			timeKeeper = setInterval(function(){
				if( i++ <= duration ){
					elem.scrollLeft = easing( i, sLeft, left, duration );
					elem.scrollTop = easing( i, sTop, top, duration );
				}
				else{
					intercept();
				}
			}, 1 );
		},

		// find closest overthrow (elem or a parent)
		closest = function( target, ascend ){
			return !ascend && target.className && target.className.indexOf( "overthrow" ) > -1 && target || closest( target.parentNode );
		},

		// Intercept any throw in progress
		intercept = function(){
			clearInterval( timeKeeper );
		},

		// Enable and potentially polyfill overflow
		polyfill = function(){

			// If it's on,
			if( enabled ){
				return;
			}
			// It's on.
			enabled = true;

			// If overflowProbablyAlreadyWorks or at least the element canBeFilledWithPoly, add a class to cue CSS that assumes overflow scrolling will work (setting height on elements and such)
			if( overflowProbablyAlreadyWorks || canBeFilledWithPoly ){
				docElem.className += " " + classtext;
			}

			// Destroy everything later. If you want to.
			w.overthrow.forget = function(){
				// Strip the class name from docElem
				docElem.className = docElem.className.replace( classtext, "" );
				// Remove touch binding (check for method support since this part isn't qualified by touch support like the rest)
				if( doc.removeEventListener ){
					doc.removeEventListener( "touchstart", start, false );
				}
				// reset easing to default
				w.overthrow.easing = defaultEasing;

				// Let 'em know
				enabled = false;
			};

			// If overflowProbablyAlreadyWorks or it doesn't look like the browser canBeFilledWithPoly, our job is done here. Exit viewport left.
			if( overflowProbablyAlreadyWorks || !canBeFilledWithPoly ){
				return;
			}

			// Fill 'er up!
			// From here down, all logic is associated with touch scroll handling
				// elem references the overthrow element in use
			var elem,

				// The last several Y values are kept here
				lastTops = [],

				// The last several X values are kept here
				lastLefts = [],

				// lastDown will be true if the last scroll direction was down, false if it was up
				lastDown,

				// lastRight will be true if the last scroll direction was right, false if it was left
				lastRight,

				// For a new gesture, or change in direction, reset the values from last scroll
				resetVertTracking = function(){
					lastTops = [];
					lastDown = null;
				},

				resetHorTracking = function(){
					lastLefts = [];
					lastRight = null;
				},

				// After releasing touchend, throw the overthrow element, depending on momentum
				finishScroll = function(){
					// Come up with a distance and duration based on how
					// Multipliers are tweaked to a comfortable balance across platforms
					var top = ( lastTops[ 0 ] - lastTops[ lastTops.length -1 ] ) * 8,
						left = ( lastLefts[ 0 ] - lastLefts[ lastLefts.length -1 ] ) * 8,
						duration = Math.max( Math.abs( left ), Math.abs( top ) ) / 14;

					// Make top and left relative-style strings (positive vals need "+" prefix)
					top = ( top > 0 ? "+" : "" ) + top;
					left = ( left > 0 ? "+" : "" ) + left;

					// Make sure there's a significant amount of throw involved, otherwise, just stay still
					if( !isNaN( duration ) && duration > 0 && ( Math.abs( left ) > 80 || Math.abs( top ) > 80 ) ){
						toss( elem, { left: left, top: top, duration: duration } );
					}
				},

				// On webkit, touch events hardly trickle through textareas and inputs
				// Disabling CSS pointer events makes sure they do, but it also makes the controls innaccessible
				// Toggling pointer events at the right moments seems to do the trick
				// Thanks Thomas Bachem http://stackoverflow.com/a/5798681 for the following
				inputs,
				setPointers = function( val ){
					inputs = elem.querySelectorAll( "textarea, input" );
				    for( var i = 0, il = inputs.length; i < il; i++) {
				        inputs[ i ].style.pointerEvents = val;
				    }
				},

				// For nested overthrows, changeScrollTarget restarts a touch event cycle on a parent or child overthrow
				changeScrollTarget = function( startEvent, ascend ){
					if( doc.createEvent ){
						var newTarget = ( !ascend || ascend === undefined ) && elem.parentNode || elem.touchchild || elem,
							tEnd;

						if( newTarget !== elem ){
							tEnd = doc.createEvent( "HTMLEvents" );
							tEnd.initEvent( "touchend", true, true );
							elem.dispatchEvent( tEnd );
							newTarget.touchchild = elem;
							elem = newTarget;
							newTarget.dispatchEvent( startEvent );
						}
					}
				},

				// Touchstart handler
				// On touchstart, touchmove and touchend are freshly bound, and all three share a bunch of vars set by touchstart
				// Touchend unbinds them again, until next time
				start = function( e ){

					// Stop any throw in progress
					intercept();

					// Reset the distance and direction tracking
					resetVertTracking();
					resetHorTracking();

					elem = closest( e.target );

					if( !elem || elem === docElem || e.touches.length > 1 ){
						return;
					}

					setPointers( "none" );
					var touchStartE = e,
						scrollT = elem.scrollTop,
						scrollL = elem.scrollLeft,
						height = elem.offsetHeight,
						width = elem.offsetWidth,
						startY = e.touches[ 0 ].pageY,
						startX = e.touches[ 0 ].pageX,
						scrollHeight = elem.scrollHeight,
						scrollWidth = elem.scrollWidth,

						// Touchmove handler
						move = function( e ){

							var ty = scrollT + startY - e.touches[ 0 ].pageY,
								tx = scrollL + startX - e.touches[ 0 ].pageX,
								down = ty >= ( lastTops.length ? lastTops[ 0 ] : 0 ),
								right = tx >= ( lastLefts.length ? lastLefts[ 0 ] : 0 );

							// If there's room to scroll the current container, prevent the default window scroll
							if( ( ty > 0 && ty < scrollHeight - height ) || ( roomToScrollX = tx > 0 && tx < scrollWidth - width ) ){
								e.preventDefault();
							}
							// This bubbling is dumb. Needs a rethink.
							else {
								changeScrollTarget( touchStartE );
							}

							// If down and lastDown are inequal, the y scroll has changed direction. Reset tracking.
							if( lastDown && down !== lastDown ){
								resetVertTracking();
							}

							// If right and lastRight are inequal, the x scroll has changed direction. Reset tracking.
							if( lastRight && right !== lastRight ){
								resetHorTracking();
							}

							// remember the last direction in which we were headed
							lastDown = down;
							lastRight = right;

							// set the container's scroll
							elem.scrollTop = ty;
							elem.scrollLeft = tx;

							lastTops.unshift( ty );
							lastLefts.unshift( tx );

							if( lastTops.length > 3 ){
								lastTops.pop();
							}
							if( lastLefts.length > 3 ){
								lastLefts.pop();
							}
						},

						// Touchend handler
						end = function( e ){
							// Apply momentum based easing for a graceful finish
							finishScroll();
							// Bring the pointers back
							setPointers( "auto" );
							setTimeout( function(){
								setPointers( "none" );
							}, 450 );
							elem.removeEventListener( "touchmove", move, false );
							elem.removeEventListener( "touchend", end, false );
						};

					elem.addEventListener( "touchmove", move, false );
					elem.addEventListener( "touchend", end, false );
				};

			// Bind to touch, handle move and end within
			doc.addEventListener( "touchstart", start, false );
		};

	// Expose overthrow API
	w.overthrow = {
		set: polyfill,
		forget: function(){},
		easing: defaultEasing,
		toss: toss,
		intercept: intercept,
		closest: closest,
		support: overflowProbablyAlreadyWorks ? "native" : canBeFilledWithPoly && "polyfilled" || "none"
	};

	polyfill();

})( this );<commit_msg>renamed internal polyfill function to enable<commit_after>/*! overthrow.js. An overflow:auto polyfill for responsive design. (c) 2012: Scott Jehl, Filament Group, Inc. Dual MIT/GPLv2 license */
(function( w, undefined ){

	var doc = w.document,
		docElem = doc.documentElement,
		classtext = "overthrow",

		// Touch events are used in the polyfill, and thus are a prerequisite
		canBeFilledWithPoly = "ontouchmove" in doc,

		// The following attempts to determine whether the browser has native overflow support
		// so we can enable it but not polyfill
		overflowProbablyAlreadyWorks =
			// Features-first. iOS5 overflow scrolling property check - no UA needed here. thanks Apple :)
			"WebkitOverflowScrolling" in docElem.style
			// Touch events aren't supported and screen width is greater than X
			// ...basically, this is a loose "desktop browser" check.
			// It may wrongly opt-in very large tablets with no touch support.
			|| ( !canBeFilledWithPoly && w.screen.width > 1200 )
			// Hang on to your hats.
			// Whitelist some popular, overflow-supporting mobile browsers for now and the future
			// These browsers are known to get overlow support right, but give us no way of detecting it.
			|| (function(){
				var ua = w.navigator.userAgent,
					// Webkit crosses platforms, and the browsers on our list run at least version 534
					webkit = ua.match( /AppleWebKit\/([0-9]+)/ ),
					wkversion = webkit && webkit[1],
					wkLte534 = webkit && wkversion >= 534;

				return (
					/* Android 3+ with webkit gte 534
					   Sample: Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13 */
					ua.match( /Android ([0-9]+)/ ) && RegExp.$1 >= 3 && wkLte534
					/* Blackberry 7+ with webkit gte 534
					   ~: Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0 Mobile Safari/534.11+ */
					|| ua.match( / Version\/([0-9]+)/ ) && RegExp.$1 >= 0 && w.blackberry && wkLte534
					/* Blackberry Playbook with webkit gte 534
					   ~: Mozilla/5.0 (PlayBook; U; RIM Tablet OS 1.0.0; en-US) AppleWebKit/534.8+ (KHTML, like Gecko) Version/0.0.1 Safari/534.8+ */
					|| ua.indexOf( /PlayBook/ ) > -1 && RegExp.$1 >= 0 && wkLte534
					/* Firefox Mobile (Fennec) 4 and up
					   ~: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:2.1.1) Gecko/ Firefox/4.0.2pre Fennec/4.0. */
					|| ua.match( /Fennec\/([0-9]+)/ ) && RegExp.$1 >= 4
					/* WebOS 3 and up (TouchPad too)
					   ~: Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.48 Safari/534.6 TouchPad/1.0 */
					|| ua.match( /wOSBrowser\/([0-9]+)/ ) && RegExp.$1 >= 233 && wkLte534
					/* Nokia Browser N8
					   ~: Mozilla/5.0 (Symbian/3; Series60/5.2 NokiaN8-00/012.002; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.0 Mobile Safari/533.4 3gpp-gba
					   ~: Note: the N9 doesn't have native overflow with one-finger touch. wtf */
					|| ua.match( /NokiaBrowser\/([0-9\.]+)/ ) && parseFloat(RegExp.$1) === 7.3 && webkit && wkversion >= 533
				);
			})(),

		// Easing uses any of Robert Penner's equations. By default, overthrow uses ease-out-cubic
		// arguments: t = current iteration, b = initial value, c = end value, d = total iterations
		// use w.overthrow.easing to provide a custom function externally, or pass an easing function as a callback to the toss method
		defaultEasing = function (t, b, c, d) {
			return c*((t=t/d-1)*t*t + 1) + b;
		},

		enabled = false,

		// Keeper of intervals
		timeKeeper,

		/* toss scrolls and element with easing

		// elem is the element to scroll
		// options hash:
			* left is the desired horizontal scroll. Default is "+0". For relative distances, pass a string with "+" or "-" in front.
			* top is the desired vertical scroll. Default is "+0". For relative distances, pass a string with "+" or "-" in front.
			* duration is the number of milliseconds the throw will take. Default is 100.
			* easing is an optional custom easing function. Default is w.overthrow.easing. Must follow the easing function signature
		*/
		toss = function( elem, options ){
			var i = 0,
				o = options || {},
				top = o.top || "+0",
				left = o.left || "+0",
				duration = o.duration || 100,
				easing = o.easing || w.overthrow.easing,
				sLeft = elem.scrollLeft,
				sTop = elem.scrollTop;

			// top and left relative or positive distance
			left = typeof left === "string" ? parseFloat( left ) : left - sLeft,
			top = typeof top === "string" ? parseFloat( top ) : top - sTop;

			timeKeeper = setInterval(function(){
				if( i++ <= duration ){
					elem.scrollLeft = easing( i, sLeft, left, duration );
					elem.scrollTop = easing( i, sTop, top, duration );
				}
				else{
					intercept();
				}
			}, 1 );
		},

		// find closest overthrow (elem or a parent)
		closest = function( target, ascend ){
			return !ascend && target.className && target.className.indexOf( "overthrow" ) > -1 && target || closest( target.parentNode );
		},

		// Intercept any throw in progress
		intercept = function(){
			clearInterval( timeKeeper );
		},

		// Enable and potentially polyfill overflow
		enable = function(){

			// If it's on,
			if( enabled ){
				return;
			}
			// It's on.
			enabled = true;

			// If overflowProbablyAlreadyWorks or at least the element canBeFilledWithPoly, add a class to cue CSS that assumes overflow scrolling will work (setting height on elements and such)
			if( overflowProbablyAlreadyWorks || canBeFilledWithPoly ){
				docElem.className += " " + classtext;
			}

			// Destroy everything later. If you want to.
			w.overthrow.forget = function(){
				// Strip the class name from docElem
				docElem.className = docElem.className.replace( classtext, "" );
				// Remove touch binding (check for method support since this part isn't qualified by touch support like the rest)
				if( doc.removeEventListener ){
					doc.removeEventListener( "touchstart", start, false );
				}
				// reset easing to default
				w.overthrow.easing = defaultEasing;

				// Let 'em know
				enabled = false;
			};

			// If overflowProbablyAlreadyWorks or it doesn't look like the browser canBeFilledWithPoly, our job is done here. Exit viewport left.
			if( overflowProbablyAlreadyWorks || !canBeFilledWithPoly ){
				return;
			}

			// Fill 'er up!
			// From here down, all logic is associated with touch scroll handling
				// elem references the overthrow element in use
			var elem,

				// The last several Y values are kept here
				lastTops = [],

				// The last several X values are kept here
				lastLefts = [],

				// lastDown will be true if the last scroll direction was down, false if it was up
				lastDown,

				// lastRight will be true if the last scroll direction was right, false if it was left
				lastRight,

				// For a new gesture, or change in direction, reset the values from last scroll
				resetVertTracking = function(){
					lastTops = [];
					lastDown = null;
				},

				resetHorTracking = function(){
					lastLefts = [];
					lastRight = null;
				},

				// After releasing touchend, throw the overthrow element, depending on momentum
				finishScroll = function(){
					// Come up with a distance and duration based on how
					// Multipliers are tweaked to a comfortable balance across platforms
					var top = ( lastTops[ 0 ] - lastTops[ lastTops.length -1 ] ) * 8,
						left = ( lastLefts[ 0 ] - lastLefts[ lastLefts.length -1 ] ) * 8,
						duration = Math.max( Math.abs( left ), Math.abs( top ) ) / 8;

					// Make top and left relative-style strings (positive vals need "+" prefix)
					top = ( top > 0 ? "+" : "" ) + top;
					left = ( left > 0 ? "+" : "" ) + left;

					// Make sure there's a significant amount of throw involved, otherwise, just stay still
					if( !isNaN( duration ) && duration > 0 && ( Math.abs( left ) > 80 || Math.abs( top ) > 80 ) ){
						toss( elem, { left: left, top: top, duration: duration } );
					}
				},

				// On webkit, touch events hardly trickle through textareas and inputs
				// Disabling CSS pointer events makes sure they do, but it also makes the controls innaccessible
				// Toggling pointer events at the right moments seems to do the trick
				// Thanks Thomas Bachem http://stackoverflow.com/a/5798681 for the following
				inputs,
				setPointers = function( val ){
					inputs = elem.querySelectorAll( "textarea, input" );
				    for( var i = 0, il = inputs.length; i < il; i++) {
				        inputs[ i ].style.pointerEvents = val;
				    }
				},

				// For nested overthrows, changeScrollTarget restarts a touch event cycle on a parent or child overthrow
				changeScrollTarget = function( startEvent, ascend ){
					if( doc.createEvent ){
						var newTarget = ( !ascend || ascend === undefined ) && elem.parentNode || elem.touchchild || elem,
							tEnd;

						if( newTarget !== elem ){
							tEnd = doc.createEvent( "HTMLEvents" );
							tEnd.initEvent( "touchend", true, true );
							elem.dispatchEvent( tEnd );
							newTarget.touchchild = elem;
							elem = newTarget;
							newTarget.dispatchEvent( startEvent );
						}
					}
				},

				// Touchstart handler
				// On touchstart, touchmove and touchend are freshly bound, and all three share a bunch of vars set by touchstart
				// Touchend unbinds them again, until next time
				start = function( e ){

					// Stop any throw in progress
					intercept();

					// Reset the distance and direction tracking
					resetVertTracking();
					resetHorTracking();

					elem = closest( e.target );

					if( !elem || elem === docElem || e.touches.length > 1 ){
						return;
					}

					setPointers( "none" );
					var touchStartE = e,
						scrollT = elem.scrollTop,
						scrollL = elem.scrollLeft,
						height = elem.offsetHeight,
						width = elem.offsetWidth,
						startY = e.touches[ 0 ].pageY,
						startX = e.touches[ 0 ].pageX,
						scrollHeight = elem.scrollHeight,
						scrollWidth = elem.scrollWidth,

						// Touchmove handler
						move = function( e ){

							var ty = scrollT + startY - e.touches[ 0 ].pageY,
								tx = scrollL + startX - e.touches[ 0 ].pageX,
								down = ty >= ( lastTops.length ? lastTops[ 0 ] : 0 ),
								right = tx >= ( lastLefts.length ? lastLefts[ 0 ] : 0 );

							// If there's room to scroll the current container, prevent the default window scroll
							if( ( ty > 0 && ty < scrollHeight - height ) || ( roomToScrollX = tx > 0 && tx < scrollWidth - width ) ){
								e.preventDefault();
							}
							// This bubbling is dumb. Needs a rethink.
							else {
								changeScrollTarget( touchStartE );
							}

							// If down and lastDown are inequal, the y scroll has changed direction. Reset tracking.
							if( lastDown && down !== lastDown ){
								resetVertTracking();
							}

							// If right and lastRight are inequal, the x scroll has changed direction. Reset tracking.
							if( lastRight && right !== lastRight ){
								resetHorTracking();
							}

							// remember the last direction in which we were headed
							lastDown = down;
							lastRight = right;

							// set the container's scroll
							elem.scrollTop = ty;
							elem.scrollLeft = tx;

							lastTops.unshift( ty );
							lastLefts.unshift( tx );

							if( lastTops.length > 3 ){
								lastTops.pop();
							}
							if( lastLefts.length > 3 ){
								lastLefts.pop();
							}
						},

						// Touchend handler
						end = function( e ){
							// Apply momentum based easing for a graceful finish
							finishScroll();
							// Bring the pointers back
							setPointers( "auto" );
							setTimeout( function(){
								setPointers( "none" );
							}, 450 );
							elem.removeEventListener( "touchmove", move, false );
							elem.removeEventListener( "touchend", end, false );
						};

					elem.addEventListener( "touchmove", move, false );
					elem.addEventListener( "touchend", end, false );
				};

			// Bind to touch, handle move and end within
			doc.addEventListener( "touchstart", start, false );
		};

	// Expose overthrow API
	w.overthrow = {
		set: enable,
		forget: function(){},
		easing: defaultEasing,
		toss: toss,
		intercept: intercept,
		closest: closest,
		support: overflowProbablyAlreadyWorks ? "native" : canBeFilledWithPoly && "polyfilled" || "none"
	};

	// Auto-init
	enable();

})( this );<|endoftext|>


<commit_before>var fs = require('fs');
var proxy = require('proxy-middleware');
var url = require('url');

module.exports = function(grunt) {

  var conf = {};

  try {
    conf = grunt.file.readJSON('./.firebase.conf');
  } catch (err) {
    conf = {};
  }

  var oldConfig = grunt.config.data;

  var proxyOptions = url.parse('http://' + conf.siteName + '.webhook.org/webhook-uploads');
  proxyOptions.route = '/webhook-uploads';

  var mergeConfig = {
    webhook: conf,

    open : {
      'wh-open': {
        path: 'http://localhost:2002/'
      }
    },

    connect: {
      'wh-server': {
        options: {
          port: 2002,
          base: '.build',
          livereload: 35730,
          middleware: function(connect, options) {
            // Return array of whatever middlewares you want
            return [
              connect.static(options.base),
              proxy(proxyOptions),
              function(req, res, next) {
                if ('GET' != req.method && 'HEAD' != req.method) return next();

                var contents = fs.readFileSync('./libs/debug404.html');
                res.end(contents);
              },
            ];
          }
        }
      }
    },

    watch: {
      'wh-watch': {
        files: ['pages/**/*', 'templates/**/*', 'static/**/*'],
        tasks: ['build']
      }
    },

    concurrent: {
      options: {
        logConcurrentOutput: true
      },
      "wh-concurrent": {
        tasks: ["watch", "webListener-open"]
      }
    },

    // Compile static assets into dist/static
    // Copy pages/html files into dist/pages and dist/html
    // Run rev on dist/static and then run usemin on dist/pages and dist/html
    // Copy unmodified static folder into dist/static

    useminPrepare: {
      src: ['dist/pages/**/*.html', 'dist/templates/**/*.html'],
      options: {
        root: '.',
        dest: 'dist'
      }
    },

    rev: {
      assets: {
        files: [{
          src: [
            'dist/static/**/*.{jpg,jpeg,gif,png,js,css,eot,svg,ttf,woff}',
          ]
        }]
      }
    },

    usemin: {
      html: ['dist/pages/**/*.html', 'dist/templates/**/*.html'],
      options: {
        assetsDirs: ['dist']
      }
    }
  };

  for(var key in mergeConfig) {
    if(oldConfig[key]) {
      var oldData = oldConfig[key];
      grunt.util._.extend(oldData, mergeConfig[key]);
      oldConfig[key] = oldData;
    } else {
      oldConfig[key] = mergeConfig[key];
    }
  }

  grunt.initConfig(oldConfig);
};
<commit_msg>from anywhere<commit_after>var fs = require('fs');
var proxy = require('proxy-middleware');
var url = require('url');

module.exports = function(grunt) {

  var conf = {};

  try {
    conf = grunt.file.readJSON('./.firebase.conf');
  } catch (err) {
    conf = {};
  }

  var oldConfig = grunt.config.data;

  var proxyOptions = url.parse('http://' + conf.siteName + '.webhook.org/webhook-uploads');
  proxyOptions.route = '/webhook-uploads';

  var mergeConfig = {
    webhook: conf,

    open : {
      'wh-open': {
        path: 'http://localhost:2002/'
      }
    },

    connect: {
      'wh-server': {
        options: {
          port: 2002,
          hostname: '*',
          base: '.build',
          livereload: 35730,
          middleware: function(connect, options) {
            // Return array of whatever middlewares you want
            return [
              connect.static(options.base),
              proxy(proxyOptions),
              function(req, res, next) {
                if ('GET' != req.method && 'HEAD' != req.method) return next();

                var contents = fs.readFileSync('./libs/debug404.html');
                res.end(contents);
              },
            ];
          }
        }
      }
    },

    watch: {
      'wh-watch': {
        files: ['pages/**/*', 'templates/**/*', 'static/**/*'],
        tasks: ['build']
      }
    },

    concurrent: {
      options: {
        logConcurrentOutput: true
      },
      "wh-concurrent": {
        tasks: ["watch", "webListener-open"]
      }
    },

    // Compile static assets into dist/static
    // Copy pages/html files into dist/pages and dist/html
    // Run rev on dist/static and then run usemin on dist/pages and dist/html
    // Copy unmodified static folder into dist/static

    useminPrepare: {
      src: ['dist/pages/**/*.html', 'dist/templates/**/*.html'],
      options: {
        root: '.',
        dest: 'dist'
      }
    },

    rev: {
      assets: {
        files: [{
          src: [
            'dist/static/**/*.{jpg,jpeg,gif,png,js,css,eot,svg,ttf,woff}',
          ]
        }]
      }
    },

    usemin: {
      html: ['dist/pages/**/*.html', 'dist/templates/**/*.html'],
      options: {
        assetsDirs: ['dist']
      }
    }
  };

  for(var key in mergeConfig) {
    if(oldConfig[key]) {
      var oldData = oldConfig[key];
      grunt.util._.extend(oldData, mergeConfig[key]);
      oldConfig[key] = oldData;
    } else {
      oldConfig[key] = mergeConfig[key];
    }
  }

  grunt.initConfig(oldConfig);
};
<|endoftext|>


<commit_before>// Your init script
//
// Atom will evaluate this file each time a new window is opened. It is run
// after packages are loaded/activated and after the previous editor state
// has been restored.
'use strict';

const {exec} = require('child_process');

// Set preferred size of current Atom window while preserving window position;
// assumes Tree View is open
function setPreferredWindowDimensions() {
  const originalWindowDimensions = atom.getWindowDimensions();
  atom.setWindowDimensions({
    width: 1080,
    height: 710,
    x: originalWindowDimensions.x,
    y: originalWindowDimensions.y
  });
}
setPreferredWindowDimensions();

// Sync Atom packages via package-sync package
function syncPackages() {
  const workspaceView = atom.views.getView(atom.workspace);
  return atom.commands.dispatch(workspaceView, 'package-sync:sync');
}
syncPackages();

// Extend the JavaScript tree-sitter grammar with additional highlighting
function extendJavaScriptTSGrammar() {
  // All Atom grammars are loaded asynchronously, so use setImmediate() to
  // ensure that the JS grammar is only modified when it has fully loaded
  setImmediate(() => {
    const jsGrammar = atom.grammars.treeSitterGrammarsById['source.js'];
    if (jsGrammar && jsGrammar.scopeMap) {
      // Colorize `this` and `arguments` in red like other language keywords
      jsGrammar.scopeMap.namedScopeTable.this = {result: 'variable.language.js'};
      jsGrammar.scopeMap.namedScopeTable.identifier.result.unshift({
        match: /^arguments$/,
        scopes: 'variable.language.js'
      });
      // Colorize JSON built-in object
      jsGrammar.scopeMap.namedScopeTable.identifier.result.unshift({
        match: /^JSON$/,
        scopes: 'meta.class'
      });
    }
  });
}
extendJavaScriptTSGrammar();

// Extend the Python tree-sitter grammar with additional highlighting
function extendPythonTSGrammar() {
  setImmediate(() => {
    // Force tree-sitter grammar to override first-mate grammar
    const pyGrammar = atom.grammars.treeSitterGrammarsById['source.python'];
    if (pyGrammar && pyGrammar.firstLineRegex) {
      pyGrammar.firstLineRegex = atom.grammars.textmateRegistry.grammarsByScopeName['source.python'].firstLineRegex;
    }
    if (pyGrammar && pyGrammar.scopeMap) {
      // Colorize function parameter names
      pyGrammar.scopeMap.namedScopeTable.identifier.parents.parameters = {result: 'variable.parameter.function'};
      pyGrammar.scopeMap.namedScopeTable.identifier.indices[0].parents.default_parameter = {result: 'variable.parameter.function'};
      // Colorize variable and class names within class argument lists
      pyGrammar.scopeMap.namedScopeTable.identifier.parents.argument_list = {parents: {class_definition: {result: 'entity.other.inherited-class.python'}}};
      pyGrammar.scopeMap.namedScopeTable.attribute = {parents: {argument_list: {parents: {class_definition: {result: 'entity.other.inherited-class.python'}}}}};
      // Colorize variable and class names as values of keyword arguments within
      // class argument lists
      pyGrammar.scopeMap.namedScopeTable.identifier.indices[2].parents.keyword_argument = {parents: {argument_list: {parents: {class_definition: {result: 'entity.other.inherited-class.python'}}}}};
      pyGrammar.scopeMap.namedScopeTable.attribute.parents.keyword_argument = {parents: {argument_list: {parents: {class_definition: {result: 'entity.other.inherited-class.python'}}}}};
    }
    // Re-apply Python tree-sitter grammar to all open Python files
    atom.grammars.grammarScoresByBuffer.forEach((score, buffer) => {
      if (buffer.getLanguageMode().grammar.scopeName === 'source.python' && !atom.grammars.languageOverridesByBufferId.has(buffer.id)) {
        atom.grammars.autoAssignLanguageMode(buffer);
      }
    });
  });
}
extendPythonTSGrammar();

// Override getGrammars to work around bug with tree-sitter grammars never
// applying; see
// <https://github.com/atom/atom/issues/17029#issuecomment-457084440>
atom.grammars.getGrammars = () => {
  const allGrammars = atom.grammars.textmateRegistry.getGrammars();
  const tsGrammars = Object.values(atom.grammars.treeSitterGrammarsById);
  const combinedGrammars = tsGrammars.concat(allGrammars);
  const combinedGrammarNames = combinedGrammars.map((grammar) => grammar.name);
  return combinedGrammars.filter((grammar, g) => {
    return (
      // Prefer tree-sitter grammars whenever possible
      grammar.constructor.name === 'TreeSitterGrammar'
      // OR, if this is a first-mate grammar without a corresponding tree-sitter
      // grammar, add it to the list
      || combinedGrammarNames.indexOf(grammar.name) === g
    );
  });
};

// Add command to copy to clipboard an array of the editor's current cursor
// scopes
atom.commands.add('atom-text-editor:not([mini])', 'editor:copy-cursor-scope', () => {
  const editor = atom.workspace.getActiveTextEditor();
  const scopes = editor.getCursorScope().scopes;
  if (scopes) {
    const scopeString = JSON.stringify(scopes)
      .replace(/,/g, ', ')
      .replace(/"/g, '\'');
    atom.clipboard.write(scopeString);
    const list = scopes.map((item) => `* ${item}`);
    const content = `Copied Scopes at Cursor\n${list.join('\n')}`;
    atom.notifications.addInfo(content, {
      dismissable: true
    });
  } else {
    atom.notifications.addError('Scopes at Cursor', {
      detail: 'Could not write scopes to clipboard'
    });
  }
});

// Add command for revealing the project folder at the workspace level
atom.commands.add('atom-workspace', 'application:show-project-folder-in-file-manager', () => {
  const projectPaths = atom.project.getPaths();
  if (projectPaths.length > 0) {
    exec(`open ${projectPaths[0]}`);
  }
});
<commit_msg>Use addSelector method to safely modify grammars<commit_after>// Your init script
//
// Atom will evaluate this file each time a new window is opened. It is run
// after packages are loaded/activated and after the previous editor state
// has been restored.
'use strict';

const {exec} = require('child_process');

// Set preferred size of current Atom window while preserving window position;
// assumes Tree View is open
function setPreferredWindowDimensions() {
  const originalWindowDimensions = atom.getWindowDimensions();
  atom.setWindowDimensions({
    width: 1080,
    height: 710,
    x: originalWindowDimensions.x,
    y: originalWindowDimensions.y
  });
}
setPreferredWindowDimensions();

// Sync Atom packages via package-sync package
function syncPackages() {
  const workspaceView = atom.views.getView(atom.workspace);
  return atom.commands.dispatch(workspaceView, 'package-sync:sync');
}
syncPackages();

// Extend the JavaScript tree-sitter grammar with additional highlighting
function extendJavaScriptTSGrammar() {
  // All Atom grammars are loaded asynchronously, so use setImmediate() to
  // ensure that the JS grammar is only modified when it has fully loaded
  setImmediate(() => {
    const jsGrammar = atom.grammars.treeSitterGrammarsById['source.js'];
    if (jsGrammar && jsGrammar.scopeMap) {
      // Colorize `this` and `arguments` in red like other language keywords
      jsGrammar.scopeMap.addSelector('this', 'variable.language.js');
      jsGrammar.scopeMap.addSelector('identifier', {
        match: /^arguments$/,
        scopes: 'variable.language.js'
      });
      // Colorize JSON built-in object
      jsGrammar.scopeMap.addSelector('identifier', {
        match: /^JSON$/,
        scopes: 'meta.class'
      });
    }
  });
}
extendJavaScriptTSGrammar();

// Extend the Python tree-sitter grammar with additional highlighting
function extendPythonTSGrammar() {
  setImmediate(() => {
    // Force tree-sitter grammar to override first-mate grammar
    const pyGrammar = atom.grammars.treeSitterGrammarsById['source.python'];
    if (pyGrammar && pyGrammar.firstLineRegex) {
      pyGrammar.firstLineRegex = atom.grammars.textmateRegistry.grammarsByScopeName['source.python'].firstLineRegex;
    }
    if (pyGrammar && pyGrammar.scopeMap) {
      // Colorize function parameter names
      pyGrammar.scopeMap.addSelector('parameters > identifier', 'variable.parameter.function');
      pyGrammar.scopeMap.addSelector('default_parameter > identifier:nth-child(0)', 'variable.parameter.function');
      // Colorize variable and class names within class argument lists
      pyGrammar.scopeMap.addSelector('class_definition > argument_list > attribute', 'entity.other.inherited-class.python');
      pyGrammar.scopeMap.addSelector('class_definition > argument_list > identifier', 'entity.other.inherited-class.python');
      // Colorize variable and class names as values of keyword arguments within
      // class argument lists
      pyGrammar.scopeMap.addSelector('class_definition > argument_list > keyword_argument > attribute', 'entity.other.inherited-class.python');
      pyGrammar.scopeMap.addSelector('class_definition > argument_list > keyword_argument > identifier:nth-child(2)', 'entity.other.inherited-class.python');
    }
    // Re-apply Python tree-sitter grammar to all open Python files
    atom.grammars.grammarScoresByBuffer.forEach((score, buffer) => {
      if (buffer.getLanguageMode().grammar.scopeName === 'source.python' && !atom.grammars.languageOverridesByBufferId.has(buffer.id)) {
        atom.grammars.autoAssignLanguageMode(buffer);
      }
    });
  });
}
extendPythonTSGrammar();

// Override getGrammars to work around bug with tree-sitter grammars never
// applying; see
// <https://github.com/atom/atom/issues/17029#issuecomment-457084440>
atom.grammars.getGrammars = () => {
  const allGrammars = atom.grammars.textmateRegistry.getGrammars();
  const tsGrammars = Object.values(atom.grammars.treeSitterGrammarsById);
  const combinedGrammars = tsGrammars.concat(allGrammars);
  const combinedGrammarNames = combinedGrammars.map((grammar) => grammar.name);
  return combinedGrammars.filter((grammar, g) => {
    return (
      // Prefer tree-sitter grammars whenever possible
      grammar.constructor.name === 'TreeSitterGrammar'
      // OR, if this is a first-mate grammar without a corresponding tree-sitter
      // grammar, add it to the list
      || combinedGrammarNames.indexOf(grammar.name) === g
    );
  });
};

// Add command to copy to clipboard an array of the editor's current cursor
// scopes
atom.commands.add('atom-text-editor:not([mini])', 'editor:copy-cursor-scope', () => {
  const editor = atom.workspace.getActiveTextEditor();
  const scopes = editor.getCursorScope().scopes;
  if (scopes) {
    const scopeString = JSON.stringify(scopes)
      .replace(/,/g, ', ')
      .replace(/"/g, '\'');
    atom.clipboard.write(scopeString);
    const list = scopes.map((item) => `* ${item}`);
    const content = `Copied Scopes at Cursor\n${list.join('\n')}`;
    atom.notifications.addInfo(content, {
      dismissable: true
    });
  } else {
    atom.notifications.addError('Scopes at Cursor', {
      detail: 'Could not write scopes to clipboard'
    });
  }
});

// Add command for revealing the project folder at the workspace level
atom.commands.add('atom-workspace', 'application:show-project-folder-in-file-manager', () => {
  const projectPaths = atom.project.getPaths();
  if (projectPaths.length > 0) {
    exec(`open ${projectPaths[0]}`);
  }
});
<|endoftext|>


<commit_before>import assert from "assert";
import {isString, has, keys, each, without} from "underscore";
import {sha1, readAndWatchFileWithHash} from "../fs/watch.js";
import {matches as archMatches} from "../utils/archinfo.js";
import {findImportedModuleIdentifiers} from "./js-analyze.js";
import buildmessage from "../utils/buildmessage.js";
import {
  pathJoin,
  pathRelative,
  pathNormalize,
  pathDirname,
  pathBasename,
  pathExtname,
  statOrNull,
  convertToPosixPath,
} from "../fs/files.js";

// Default handlers for well-known file extensions.
const extensions = {
  ".js"(data) {
    return data;
  },

  ".json"(data) {
    return "module.exports = " +
      JSON.stringify(JSON.parse(data), null, 2) +
      ";\n";
  }
};

export default class ImportScanner {
  constructor({
    name,
    bundleArch,
    sourceRoot,
    usedPackageNames = {},
    nodeModulesPath,
    watchSet,
  }) {
    assert.ok(isString(sourceRoot));

    this.name = name;
    this.bundleArch = bundleArch;
    this.sourceRoot = sourceRoot;
    this.usedPackageNames = usedPackageNames;
    this.nodeModulesPath = nodeModulesPath;
    this.watchSet = watchSet;
    this.absPathToOutputIndex = {};
    this.outputFiles = [];
  }

  addInputFiles(files) {
    files.forEach(file => {
      const absPath = pathJoin(this.sourceRoot, file.sourcePath);

      // Files that are not eagerly evaluated (lazy) will only be included
      // in the bundle if they are actually imported.
      file.lazy = this._isFileLazy(file);

      // Files that are eagerly evaluated are effectively "imported" as
      // entry points.
      file.imported = ! file.lazy;

      file.installPath = this._getInstallPath(absPath);

      if (has(this.absPathToOutputIndex, absPath)) {
        const index = this.absPathToOutputIndex[absPath];
        this.outputFiles[index] = file;
      } else {
        this.absPathToOutputIndex[absPath] =
          this.outputFiles.push(file) - 1;
      }
    });

    return this;
  }

  getOutputFiles() {
    this.outputFiles.forEach(file => {
      if (! file.lazy || file.imported) {
        const absPath = pathJoin(this.sourceRoot, file.sourcePath);
        file.deps = this._scanDeps(absPath, file.data);
      }
    });

    return this.outputFiles;
  }

  _isFileLazy(file) {
    if (typeof file.lazy === "boolean") {
      return file.lazy;
    }

    if (file.sourcePath.endsWith(".json")) {
      // JSON files have no side effects, so there is no reason for them
      // ever to be evaluated eagerly.
      return true;
    }

    // If file.lazy was not previously defined, mark the file lazy if it
    // is contained by an imports directory. Note that any files contained
    // by a node_modules directory will already have been marked lazy in
    // PackageSource#_inferFileOptions. The reason we can't do all our
    // lazy marking in the _inferFileOptions method is that we don't know
    // then whether the current app or package is using the modules
    // package. At this point, we know the modules package must be in use,
    // because the ImportScanner is only ever used when modules are used.
    return this._splitPath(
      pathDirname(file.sourcePath)
    ).indexOf("imports") >= 0;
  }

  _scanDeps(absPath, data) {
    const deps = keys(findImportedModuleIdentifiers(data.toString("utf8")));

    each(deps, id => {
      const absImportedPath = this._tryToResolveImportedPath(id, absPath);
      if (! absImportedPath) {
        return;
      }

      if (has(this.absPathToOutputIndex, absImportedPath)) {
        // Avoid scanning files that we've scanned before, but mark them
        // as imported so we know to include them in the bundle if they
        // are lazy.
        const index = this.absPathToOutputIndex[absImportedPath];
        const file = this.outputFiles[index];

        // Eager files and files that we have imported before do not need
        // to be scanned again. Lazy files that we have not imported
        // before still need to be scanned, however.
        const alreadyScanned = ! file.lazy || file.imported;

        // Whether the file is eager or lazy, mark it as imported. For
        // lazy files, this makes the difference between being included in
        // or omitted from the bundle. For eager files, this just ensures
        // we won't scan them again.
        file.imported = true;

        if (alreadyScanned) {
          return;
        }
      }

      if (! this._hasKnownExtension(absImportedPath)) {
        // The _readModule method provides hardcoded support for files
        // with known extensions, but any other type of file must be
        // ignored at this point, because it was not in the set of input
        // files and therefore must not have been processed by a compiler
        // plugin for the current architecture (this.bundleArch).
        return;
      }

      const installPath = this._getInstallPath(absImportedPath);
      if (! installPath) {
        // The given path cannot be installed on this architecture.
        return;
      }

      var relImportedPath = pathRelative(this.sourceRoot, absImportedPath);

      // The result of _readModule will have .data and .hash properties.
      const depFile = this._readModule(absImportedPath);
      depFile.type = "js"; // TODO Is this correct?
      depFile.sourcePath = relImportedPath;
      depFile.installPath = installPath;
      depFile.servePath = installPath;
      depFile.lazy = true;
      depFile.imported = true;

      // Append this file to the output array and record its index.
      this.absPathToOutputIndex[absImportedPath] =
        this.outputFiles.push(depFile) - 1;

      depFile.deps = this._scanDeps(absImportedPath, depFile.data);
    });

    return deps;
  }

  _readFile(absPath) {
    let { contents, hash } =
      readAndWatchFileWithHash(this.watchSet, absPath);

    return {
      data: contents.toString("utf8"),
      hash,
    };
  }

  _readModule(absPath) {
    const info = this._readFile(absPath);

    // Same logic/comment as stripBOM in node/lib/module.js:
    // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
    // because the buffer-to-string conversion in `fs.readFileSync()`
    // translates it to FEFF, the UTF-16 BOM.
    if (info.data.charCodeAt(0) === 0xfeff) {
      info.data = info.data.slice(1);
    }

    const ext = pathExtname(absPath).toLowerCase();
    info.data = extensions[ext](info.data);

    return info;
  }

  // Returns a relative path indicating where to install the given file
  // via meteorInstall. May return undefined if the file should not be
  // installed on the current architecture.
  _getInstallPath(absPath) {
    let path =
      this._getNodeModulesInstallPath(absPath) ||
      this._getSourceRootInstallPath(absPath);

    if (! path) {
      return;
    }

    if (this.name) {
      // If we're bundling a package, prefix path with
      // node_modules/<package name>/.
      path = pathJoin("node_modules", "meteor", this.name, path);
    }

    return path;
  }

  _getNodeModulesInstallPath(absPath) {
    if (this.nodeModulesPath) {
      const relPathWithinNodeModules =
        pathRelative(this.nodeModulesPath, absPath);

      if (relPathWithinNodeModules.startsWith("..")) {
        // absPath is not a subdirectory of this.nodeModulesPath.
        return;
      }

      if (! this._hasKnownExtension(relPathWithinNodeModules)) {
        // Only accept files within node_modules directories if they
        // have one of the known extensions.
        return;
      }

      // Install the module into the local node_modules directory within
      // this app or package.
      return pathJoin("node_modules", relPathWithinNodeModules);
    }
  }

  _getSourceRootInstallPath(absPath) {
    const installPath = pathRelative(this.sourceRoot, absPath);

    if (installPath.startsWith("..")) {
      // absPath is not a subdirectory of this.sourceRoot.
      return;
    }

    const dirs = this._splitPath(pathDirname(installPath));
    const bundlingClientApp =
      ! this.name && // Indicates we are bundling an app.
      archMatches(this.bundleArch, "web");

    for (let dir of dirs) {
      if (dir.charAt(0) === "." ||
          dir === "packages" ||
          dir === "programs" ||
          dir === "cordova-build-override") {
        // These directories are never loaded as part of an app.
        return;
      }

      if (bundlingClientApp && (dir === "server" ||
                                dir === "private")) {
        // If we're bundling an app for a client architecture, any files
        // contained by a server-only directory that is not contained by
        // a node_modules directory must be ignored.
        return;
      }

      if (dir === "node_modules") {
        if (! this._hasKnownExtension(installPath)) {
          // Reject any files within node_modules directories that do
          // not have one of the known extensions.
          return;
        }

        // Accept any file within a node_modules directory if it has a
        // known file extension.
        return installPath;
      }
    }

    return installPath;
  }

  _hasKnownExtension(path) {
    return has(extensions, pathExtname(path).toLowerCase());
  }

  _splitPath(path) {
    const partsInReverse = [];
    for (let dir; (dir = pathDirname(path)) !== path; path = dir) {
      partsInReverse.push(pathBasename(path));
    }
    return partsInReverse.reverse();
  }

  _tryToResolveImportedPath(id, path) {
    let resolved =
      this._resolveAbsolute(id) ||
      this._resolveRelative(id, path) ||
      this._resolveNodeModule(id, path);

    while (resolved && resolved.stat.isDirectory()) {
      resolved = this._resolvePkgJsonMain(resolved.path) ||
        this._joinAndStat(resolved.path, "index.js");
    }

    return resolved && resolved.path;
  }

  _joinAndStat(...joinArgs) {
    const path = pathNormalize(pathJoin(...joinArgs));
    const exactStat = statOrNull(path);
    const exactResult = exactStat && { path, stat: exactStat };
    if (exactResult && exactStat.isFile()) {
      return exactResult;
    }

    for (let ext in extensions) {
      if (has(extensions, ext)) {
        const pathWithExt = path + ext;
        const stat = statOrNull(pathWithExt);
        if (stat) {
          return { path: pathWithExt, stat };
        }
      }
    }

    if (exactResult && exactStat.isDirectory()) {
      // After trying all available file extensions, fall back to the
      // original result if it was a directory.
      return exactResult;
    }

    return null;
  }

  _resolveAbsolute(id) {
    return id.charAt(0) === "/" &&
      this._joinAndStat(this.sourceRoot, id.slice(1));
  }

  _resolveRelative(id, path) {
    return id.charAt(0) === "." &&
      this._joinAndStat(path, "..", id);
  }

  _resolveNodeModule(id, path) {
    let resolved = null;
    let dir = path;

    do {
      dir = pathDirname(dir);
      resolved = this._joinAndStat(dir, "node_modules", id);
    } while (! resolved && dir !== this.sourceRoot);

    if (! resolved && this.nodeModulesPath) {
      // After checking any local node_modules directories, fall back to
      // the package NPM directory, if one was specified.
      resolved = this._joinAndStat(this.nodeModulesPath, id);
    }

    // If the dependency is still not resolved, it might be handled by the
    // fallback function defined in meteor/packages/modules/modules.js, or
    // it might be imported in code that will never run on this platform,
    // so there is always the possibility that its absence is not actually
    // a problem. As much as we might like to issue warnings about missing
    // dependencies here, we just don't have enough information to make
    // that determination until the code actually runs.

    return resolved;
  }

  _resolvePkgJsonMain(dirPath) {
    const pkgJsonPath = pathJoin(dirPath, "package.json");

    let pkg;
    try {
      pkg = JSON.parse(this._readFile(pkgJsonPath).data);
    } catch (e) {
      return null;
    }

    if (pkg && isString(pkg.main)) {
      const resolved = this._joinAndStat(dirPath, pkg.main);
      if (resolved) {
        this._addPkgJsonToOutput(pkgJsonPath, pkg);
        return resolved;
      }
    }

    return null;
  }

  _addPkgJsonToOutput(pkgJsonPath, pkg) {
    if (! has(this.absPathToOutputIndex, pkgJsonPath)) {
      const data = new Buffer(
        // Output a JS module that exports just the "name" and "main"
        // properties defined in the package.json file.
        "exports.name = " + JSON.stringify(pkg.name) + ";\n" +
        "exports.main = " + JSON.stringify(pkg.main) + ";\n"
      );

      const relPkgJsonPath = pathRelative(this.sourceRoot, pkgJsonPath);

      const pkgFile = {
        type: "js", // We represent the JSON module with JS.
        data,
        deps: [], // Avoid accidentally re-scanning this file.
        sourcePath: relPkgJsonPath,
        installPath: this._getInstallPath(pkgJsonPath),
        servePath: relPkgJsonPath,
        hash: sha1(data),
        lazy: true,
        imported: true,
      };

      this.absPathToOutputIndex[pkgJsonPath] =
        this.outputFiles.push(pkgFile) - 1;
    }
  }
}
<commit_msg>Make sure to scan previously seen modules, but do not read them again.<commit_after>import assert from "assert";
import {isString, has, keys, each, without} from "underscore";
import {sha1, readAndWatchFileWithHash} from "../fs/watch.js";
import {matches as archMatches} from "../utils/archinfo.js";
import {findImportedModuleIdentifiers} from "./js-analyze.js";
import buildmessage from "../utils/buildmessage.js";
import {
  pathJoin,
  pathRelative,
  pathNormalize,
  pathDirname,
  pathBasename,
  pathExtname,
  statOrNull,
  convertToPosixPath,
} from "../fs/files.js";

// Default handlers for well-known file extensions.
const extensions = {
  ".js"(data) {
    return data;
  },

  ".json"(data) {
    return "module.exports = " +
      JSON.stringify(JSON.parse(data), null, 2) +
      ";\n";
  }
};

export default class ImportScanner {
  constructor({
    name,
    bundleArch,
    sourceRoot,
    usedPackageNames = {},
    nodeModulesPath,
    watchSet,
  }) {
    assert.ok(isString(sourceRoot));

    this.name = name;
    this.bundleArch = bundleArch;
    this.sourceRoot = sourceRoot;
    this.usedPackageNames = usedPackageNames;
    this.nodeModulesPath = nodeModulesPath;
    this.watchSet = watchSet;
    this.absPathToOutputIndex = {};
    this.outputFiles = [];
  }

  addInputFiles(files) {
    files.forEach(file => {
      const absPath = pathJoin(this.sourceRoot, file.sourcePath);

      // Files that are not eagerly evaluated (lazy) will only be included
      // in the bundle if they are actually imported.
      file.lazy = this._isFileLazy(file);

      // Files that are eagerly evaluated are effectively "imported" as
      // entry points.
      file.imported = ! file.lazy;

      file.installPath = this._getInstallPath(absPath);

      if (has(this.absPathToOutputIndex, absPath)) {
        const index = this.absPathToOutputIndex[absPath];
        this.outputFiles[index] = file;
      } else {
        this.absPathToOutputIndex[absPath] =
          this.outputFiles.push(file) - 1;
      }
    });

    return this;
  }

  getOutputFiles() {
    this.outputFiles.forEach(file => {
      if (! file.lazy || file.imported) {
        const absPath = pathJoin(this.sourceRoot, file.sourcePath);
        file.deps = this._scanDeps(absPath, file.data);
      }
    });

    return this.outputFiles;
  }

  _isFileLazy(file) {
    if (typeof file.lazy === "boolean") {
      return file.lazy;
    }

    if (file.sourcePath.endsWith(".json")) {
      // JSON files have no side effects, so there is no reason for them
      // ever to be evaluated eagerly.
      return true;
    }

    // If file.lazy was not previously defined, mark the file lazy if it
    // is contained by an imports directory. Note that any files contained
    // by a node_modules directory will already have been marked lazy in
    // PackageSource#_inferFileOptions. The reason we can't do all our
    // lazy marking in the _inferFileOptions method is that we don't know
    // then whether the current app or package is using the modules
    // package. At this point, we know the modules package must be in use,
    // because the ImportScanner is only ever used when modules are used.
    return this._splitPath(
      pathDirname(file.sourcePath)
    ).indexOf("imports") >= 0;
  }

  _scanDeps(absPath, data) {
    const deps = keys(findImportedModuleIdentifiers(data.toString("utf8")));

    each(deps, id => {
      const absImportedPath = this._tryToResolveImportedPath(id, absPath);
      if (! absImportedPath) {
        return;
      }

      if (has(this.absPathToOutputIndex, absImportedPath)) {
        // Avoid scanning files that we've scanned before, but mark them
        // as imported so we know to include them in the bundle if they
        // are lazy.
        const index = this.absPathToOutputIndex[absImportedPath];
        const file = this.outputFiles[index];

        // Eager files and files that we have imported before do not need
        // to be scanned again. Lazy files that we have not imported
        // before still need to be scanned, however.
        const alreadyScanned = ! file.lazy || file.imported;

        // Whether the file is eager or lazy, mark it as imported. For
        // lazy files, this makes the difference between being included in
        // or omitted from the bundle. For eager files, this just ensures
        // we won't scan them again.
        file.imported = true;

        if (! alreadyScanned) {
          this._scanDeps(absImportedPath, file.data);
        }

        return;
      }

      if (! this._hasKnownExtension(absImportedPath)) {
        // The _readModule method provides hardcoded support for files
        // with known extensions, but any other type of file must be
        // ignored at this point, because it was not in the set of input
        // files and therefore must not have been processed by a compiler
        // plugin for the current architecture (this.bundleArch).
        return;
      }

      const installPath = this._getInstallPath(absImportedPath);
      if (! installPath) {
        // The given path cannot be installed on this architecture.
        return;
      }

      var relImportedPath = pathRelative(this.sourceRoot, absImportedPath);

      // The result of _readModule will have .data and .hash properties.
      const depFile = this._readModule(absImportedPath);
      depFile.type = "js"; // TODO Is this correct?
      depFile.sourcePath = relImportedPath;
      depFile.installPath = installPath;
      depFile.servePath = installPath;
      depFile.lazy = true;
      depFile.imported = true;

      // Append this file to the output array and record its index.
      this.absPathToOutputIndex[absImportedPath] =
        this.outputFiles.push(depFile) - 1;

      depFile.deps = this._scanDeps(absImportedPath, depFile.data);
    });

    return deps;
  }

  _readFile(absPath) {
    let { contents, hash } =
      readAndWatchFileWithHash(this.watchSet, absPath);

    return {
      data: contents.toString("utf8"),
      hash,
    };
  }

  _readModule(absPath) {
    const info = this._readFile(absPath);

    // Same logic/comment as stripBOM in node/lib/module.js:
    // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
    // because the buffer-to-string conversion in `fs.readFileSync()`
    // translates it to FEFF, the UTF-16 BOM.
    if (info.data.charCodeAt(0) === 0xfeff) {
      info.data = info.data.slice(1);
    }

    const ext = pathExtname(absPath).toLowerCase();
    info.data = extensions[ext](info.data);

    return info;
  }

  // Returns a relative path indicating where to install the given file
  // via meteorInstall. May return undefined if the file should not be
  // installed on the current architecture.
  _getInstallPath(absPath) {
    let path =
      this._getNodeModulesInstallPath(absPath) ||
      this._getSourceRootInstallPath(absPath);

    if (! path) {
      return;
    }

    if (this.name) {
      // If we're bundling a package, prefix path with
      // node_modules/<package name>/.
      path = pathJoin("node_modules", "meteor", this.name, path);
    }

    return path;
  }

  _getNodeModulesInstallPath(absPath) {
    if (this.nodeModulesPath) {
      const relPathWithinNodeModules =
        pathRelative(this.nodeModulesPath, absPath);

      if (relPathWithinNodeModules.startsWith("..")) {
        // absPath is not a subdirectory of this.nodeModulesPath.
        return;
      }

      if (! this._hasKnownExtension(relPathWithinNodeModules)) {
        // Only accept files within node_modules directories if they
        // have one of the known extensions.
        return;
      }

      // Install the module into the local node_modules directory within
      // this app or package.
      return pathJoin("node_modules", relPathWithinNodeModules);
    }
  }

  _getSourceRootInstallPath(absPath) {
    const installPath = pathRelative(this.sourceRoot, absPath);

    if (installPath.startsWith("..")) {
      // absPath is not a subdirectory of this.sourceRoot.
      return;
    }

    const dirs = this._splitPath(pathDirname(installPath));
    const bundlingClientApp =
      ! this.name && // Indicates we are bundling an app.
      archMatches(this.bundleArch, "web");

    for (let dir of dirs) {
      if (dir.charAt(0) === "." ||
          dir === "packages" ||
          dir === "programs" ||
          dir === "cordova-build-override") {
        // These directories are never loaded as part of an app.
        return;
      }

      if (bundlingClientApp && (dir === "server" ||
                                dir === "private")) {
        // If we're bundling an app for a client architecture, any files
        // contained by a server-only directory that is not contained by
        // a node_modules directory must be ignored.
        return;
      }

      if (dir === "node_modules") {
        if (! this._hasKnownExtension(installPath)) {
          // Reject any files within node_modules directories that do
          // not have one of the known extensions.
          return;
        }

        // Accept any file within a node_modules directory if it has a
        // known file extension.
        return installPath;
      }
    }

    return installPath;
  }

  _hasKnownExtension(path) {
    return has(extensions, pathExtname(path).toLowerCase());
  }

  _splitPath(path) {
    const partsInReverse = [];
    for (let dir; (dir = pathDirname(path)) !== path; path = dir) {
      partsInReverse.push(pathBasename(path));
    }
    return partsInReverse.reverse();
  }

  _tryToResolveImportedPath(id, path) {
    let resolved =
      this._resolveAbsolute(id) ||
      this._resolveRelative(id, path) ||
      this._resolveNodeModule(id, path);

    while (resolved && resolved.stat.isDirectory()) {
      resolved = this._resolvePkgJsonMain(resolved.path) ||
        this._joinAndStat(resolved.path, "index.js");
    }

    return resolved && resolved.path;
  }

  _joinAndStat(...joinArgs) {
    const path = pathNormalize(pathJoin(...joinArgs));
    const exactStat = statOrNull(path);
    const exactResult = exactStat && { path, stat: exactStat };
    if (exactResult && exactStat.isFile()) {
      return exactResult;
    }

    for (let ext in extensions) {
      if (has(extensions, ext)) {
        const pathWithExt = path + ext;
        const stat = statOrNull(pathWithExt);
        if (stat) {
          return { path: pathWithExt, stat };
        }
      }
    }

    if (exactResult && exactStat.isDirectory()) {
      // After trying all available file extensions, fall back to the
      // original result if it was a directory.
      return exactResult;
    }

    return null;
  }

  _resolveAbsolute(id) {
    return id.charAt(0) === "/" &&
      this._joinAndStat(this.sourceRoot, id.slice(1));
  }

  _resolveRelative(id, path) {
    return id.charAt(0) === "." &&
      this._joinAndStat(path, "..", id);
  }

  _resolveNodeModule(id, path) {
    let resolved = null;
    let dir = path;

    do {
      dir = pathDirname(dir);
      resolved = this._joinAndStat(dir, "node_modules", id);
    } while (! resolved && dir !== this.sourceRoot);

    if (! resolved && this.nodeModulesPath) {
      // After checking any local node_modules directories, fall back to
      // the package NPM directory, if one was specified.
      resolved = this._joinAndStat(this.nodeModulesPath, id);
    }

    // If the dependency is still not resolved, it might be handled by the
    // fallback function defined in meteor/packages/modules/modules.js, or
    // it might be imported in code that will never run on this platform,
    // so there is always the possibility that its absence is not actually
    // a problem. As much as we might like to issue warnings about missing
    // dependencies here, we just don't have enough information to make
    // that determination until the code actually runs.

    return resolved;
  }

  _resolvePkgJsonMain(dirPath) {
    const pkgJsonPath = pathJoin(dirPath, "package.json");

    let pkg;
    try {
      pkg = JSON.parse(this._readFile(pkgJsonPath).data);
    } catch (e) {
      return null;
    }

    if (pkg && isString(pkg.main)) {
      const resolved = this._joinAndStat(dirPath, pkg.main);
      if (resolved) {
        this._addPkgJsonToOutput(pkgJsonPath, pkg);
        return resolved;
      }
    }

    return null;
  }

  _addPkgJsonToOutput(pkgJsonPath, pkg) {
    if (! has(this.absPathToOutputIndex, pkgJsonPath)) {
      const data = new Buffer(
        // Output a JS module that exports just the "name" and "main"
        // properties defined in the package.json file.
        "exports.name = " + JSON.stringify(pkg.name) + ";\n" +
        "exports.main = " + JSON.stringify(pkg.main) + ";\n"
      );

      const relPkgJsonPath = pathRelative(this.sourceRoot, pkgJsonPath);

      const pkgFile = {
        type: "js", // We represent the JSON module with JS.
        data,
        deps: [], // Avoid accidentally re-scanning this file.
        sourcePath: relPkgJsonPath,
        installPath: this._getInstallPath(pkgJsonPath),
        servePath: relPkgJsonPath,
        hash: sha1(data),
        lazy: true,
        imported: true,
      };

      this.absPathToOutputIndex[pkgJsonPath] =
        this.outputFiles.push(pkgFile) - 1;
    }
  }
}
<|endoftext|>


<commit_before>
window.onload = function() {

    // Page elements
    var input = document.getElementById('input');
    var openBtn = document.getElementById('open');
    var sendBtn = document.getElementById('send');
    var closeBtn = document.getElementById('close');
    var messages = document.getElementById('messages');

    // Our websocket
    var socket;

    function output(style, text){
        messages.innerHTML += "
" + text + "";
    }

    // Open
    openBtn.onclick = function(e) {
        e.preventDefault();
        if (socket !== undefined) {
            output("error", "Already connected");
            return;
        }

        var uri = "ws://" + location.host + location.pathname;
        uri = uri.substring(0, uri.lastIndexOf('/'));
        socket = new WebSocket(uri);

        socket.onerror = function(error) {
            output("error", error);
        };

        socket.onopen = function(event) {
            output("opened", "Connected to " + event.currentTarget.url);
        };

        socket.onmessage = function(event) {
            var message = event.data;
            output("received", "<<< " + message);
        };

        socket.onclose = function(event) {
            output("closed", "Disconnected: " + event.code + " " + event.reason);
        };
    };

    // Send
    sendBtn.onclick = function(e) {
        if (socket == undefined) {
            output("error", 'Not connected');
            return;
        }
        var text = document.getElementById("input").value;
        socket.send(text);
        output("sent", ">>> " + text);
    };

    // Close
    closeBtn.onclick = function(e) {
        if (socket == undefined) {
            output('error', 'Not connected');
            return;
        }
        socket.close(1000, "Close button clicked");
        socket = undefined;
    };

};
<commit_msg>The app is more robust resetting the socket in the close hdlr<commit_after>
window.onload = function() {

    // Page elements
    var input = document.getElementById('input');
    var openBtn = document.getElementById('open');
    var sendBtn = document.getElementById('send');
    var closeBtn = document.getElementById('close');
    var messages = document.getElementById('messages');

    // Our websocket
    var socket;

    function output(style, text){
        messages.innerHTML += "
" + text + "";
    }

    // Open
    openBtn.onclick = function(e) {
        e.preventDefault();
        if (socket !== undefined) {
            output("error", "Already connected");
            return;
        }

        var uri = "ws://" + location.host + location.pathname;
        uri = uri.substring(0, uri.lastIndexOf('/'));
        socket = new WebSocket(uri);

        socket.onerror = function(error) {
            output("error", error);
        };

        socket.onopen = function(event) {
            output("opened", "Connected to " + event.currentTarget.url);
        };

        socket.onmessage = function(event) {
            var message = event.data;
            output("received", "<<< " + message);
        };

        socket.onclose = function(event) {
            output("closed", "Disconnected: " + event.code + " " + event.reason);
            socket = undefined;
        };
    };

    // Send
    sendBtn.onclick = function(e) {
        if (socket == undefined) {
            output("error", 'Not connected');
            return;
        }
        var text = document.getElementById("input").value;
        socket.send(text);
        output("sent", ">>> " + text);
    };

    // Close
    closeBtn.onclick = function(e) {
        if (socket == undefined) {
            output('error', 'Not connected');
            return;
        }
        socket.close(1000, "Close button clicked");
    };

};
<|endoftext|>


<commit_before>/**
 * PHP服务端脚本模板
 * 开写：2016/04/12
 * 更新：-
 * 作者：蚁逅 <https://github.com/antoor>
 */
'use strict';

// import Base from '../base';
const Base = require('../base');

class PHP extends Base {
  constructor(opts) {
    super(opts);
    // 解析模板
    [
      'base', 'command', 'filemanager',
      'database/mysql',
      'database/mysqli',
      'database/mssql',
      'database/oracle',
      'database/informix'
    ].map((_) => {
      this.parseTemplate(`./php/template/${_}`);
    });
    // 解析编码器
    this.encoders.map((_) => {
      this.parseEncoder(`./php/encoder/${_}`);
    });
  }

  /**
   * 获取编码器列表
   * ? 可以在antSword.core.php.prototype.encoders中获取此变量
   * @return {array} 编码器列表
   */
  get encoders() {
    return ["base64", "chr", "chr16", "rot13"];
  }

  /**
   * HTTP请求数据组合函数
   * @param  {Object} data 通过模板解析后的代码对象
   * @return {Promise}     返回一个Promise操作对象
   */
  complete(data) {
    // 分隔符号
    let tag_s = "->|";
    let tag_e = "|<-";

    // 组合完整的代码
    let tmpCode = data['_'];
    data['_'] = `@ini_set("display_errors", "0");@set_time_limit(0);header('HTTP/1.1 200 OK');echo "${tag_s}";${tmpCode};echo "${tag_e}";die();`;

    // 使用编码器进行处理并返回
    return this.encodeComplete(tag_s, tag_e, data);
  }
}

module.exports = PHP;
<commit_msg>php: remove force response 200<commit_after>/**
 * PHP服务端脚本模板
 * 开写：2016/04/12
 * 更新：-
 * 作者：蚁逅 <https://github.com/antoor>
 */
'use strict';

// import Base from '../base';
const Base = require('../base');

class PHP extends Base {
  constructor(opts) {
    super(opts);
    // 解析模板
    [
      'base', 'command', 'filemanager',
      'database/mysql',
      'database/mysqli',
      'database/mssql',
      'database/oracle',
      'database/informix'
    ].map((_) => {
      this.parseTemplate(`./php/template/${_}`);
    });
    // 解析编码器
    this.encoders.map((_) => {
      this.parseEncoder(`./php/encoder/${_}`);
    });
  }

  /**
   * 获取编码器列表
   * ? 可以在antSword.core.php.prototype.encoders中获取此变量
   * @return {array} 编码器列表
   */
  get encoders() {
    return ["base64", "chr", "chr16", "rot13"];
  }

  /**
   * HTTP请求数据组合函数
   * @param  {Object} data 通过模板解析后的代码对象
   * @return {Promise}     返回一个Promise操作对象
   */
  complete(data) {
    // 分隔符号
    let tag_s = "->|";
    let tag_e = "|<-";

    // 组合完整的代码
    let tmpCode = data['_'];
    data['_'] = `@ini_set("display_errors", "0");@set_time_limit(0);echo "${tag_s}";${tmpCode};echo "${tag_e}";die();`;

    // 使用编码器进行处理并返回
    return this.encodeComplete(tag_s, tag_e, data);
  }
}

module.exports = PHP;
<|endoftext|>