<commit_before>'use strict';

describe('sandstone.filebrowser.fbFileDetails', function() {
  var baseElement = '

';

  var volumeDetails = {
    available: '11G',
    filepath: '/volume1/',
    size: '18G',
    type: 'volume',
    used: '6.0G',
    used_pct: 36
  };
  var fsDetails = {
    groups: ['testgrp'],
    type: 'filesystem',
    volumes: [volumeDetails]
  };
  var fileDetails = {
    type: 'file',
    filepath: '/volume1/file1',
    dirpath: '/volume1',
    name: 'file1',
    owner: 'testuser',
    group: 'testgrp',
    permissions: 'rwxrw-r--',
    size: '8.8K'
  };
  var dirDetails = {
    type: 'directory',
    filepath: '/volume1',
    dirpath: '/volume1/',
    name: 'volume1',
    owner: 'testuser',
    group: 'testgrp',
    permissions: 'rwxrw-r--',
    size: '4.0K',
    contents: [fileDetails]
  };

  var FilesystemService;
  var FilebrowserService;
  var AlertService;
  var mockResolve, mockReject;
  var $rootScope, digest, $q;

  beforeEach(module('sandstone'));
  beforeEach(module('sandstone.templates'));
  beforeEach(module('sandstone.broadcastservice'));
  beforeEach(module('sandstone.filesystemservice'));
  beforeEach(module('sandstone.filebrowser'));

  beforeEach(inject(function(_FilesystemService_,_$q_) {
    $q = _$q_;

    FilesystemService = _FilesystemService_;
    // FilebrowserService automatically calls FS service methods
    var deferredGetFsDetails = $q.defer();
    deferredGetFsDetails.resolve(fsDetails);
    spyOn(FilesystemService,'getFilesystemDetails').and.returnValue(deferredGetFsDetails.promise);
  }));

  beforeEach(inject(function(_FilebrowserService_,_AlertService_,_$rootScope_) {
    FilebrowserService = _FilebrowserService_;
    AlertService = _AlertService_;
    $rootScope = _$rootScope_;

    digest = function() {
      $rootScope.$digest();
    };
  }));

  describe('controller', function() {
    var $compile, $scope, isolateScope, element;

    beforeEach(inject(function(_$compile_) {
      $compile = _$compile_;
      $scope = $rootScope.$new();

      element = $compile(baseElement)($scope);
      $scope.$digest();
      isolateScope = element.isolateScope();
    }));

    it('gets filesystem details on load',function() {
      spyOn(FilebrowserService,'getFilesystem').and.returnValue(fsDetails);
      element = $compile(baseElement)($scope);
      $scope.$digest();
      expect(FilebrowserService.getFilesystem).toHaveBeenCalled();
    });

    it('watches for selection changes and deep copies file',function() {
      // File is selected
      var selection = {selectedFile: fileDetails};
      spyOn(FilebrowserService,'getSelection').and.returnValue(selection);
      $scope.$digest();
      expect(isolateScope.selection).toBe(selection);
      expect(isolateScope.editFile).not.toBe(fileDetails);
      expect(isolateScope.editFile.filepath).toEqual(fileDetails.filepath);
      // Selected file is undefined
      selection = {selectedFile: undefined};
      FilebrowserService.getSelection = jasmine.createSpy().and.returnValue(selection);
      $scope.$digest();
      expect(isolateScope.selection).toBe(selection);
      expect(isolateScope.editFile).toEqual({});
    });

    it('edit file contains a model for permissions edits',function() {
      var selection = {selectedFile: fileDetails};
      var permModel = {
        0: true,
        1: true,
        2: true,
        3: true,
        4: true,
        5: false,
        6: true,
        7: false,
        8: false
      }
      spyOn(FilebrowserService,'getSelection').and.returnValue(selection);
      $scope.$digest();
      expect(isolateScope.editFile.permModel).toEqual(permModel);
    });

    it('editing filename renames the file',function() {
      var filepath = '/file/path';
      var filename = 'filename';
      var newpath = '/volume1/file1';

      var deferredRename = $q.defer();
      deferredRename.resolve(newpath);
      spyOn(FilesystemService,'rename').and.returnValue(deferredRename.promise);
      var deferredGetFileDetails = $q.defer();
      deferredGetFileDetails.resolve(fileDetails);
      spyOn(FilesystemService,'getFileDetails').and.returnValue(deferredGetFileDetails.promise);
      spyOn(FilebrowserService,'setSelectedFile').and.callThrough();

      isolateScope.editFile = {name: filename};
      isolateScope.selection = {selectedFile: {filepath: filepath}};
      isolateScope.renameFile();
      $scope.$digest();

      expect(FilesystemService.rename.calls.argsFor(0)).toEqual([filepath,filename]);
      expect(FilebrowserService.setSelectedFile.calls.argsFor(0)).toEqual([fileDetails]);
    });

    it('rename error shows alert and resets filename',function() {
      var filepath = '/file/path';
      var filename = 'filename';
      var originalFilename = 'orig-filename';
      var newpath = '/volume1/file1';

      var deferredRename = $q.defer();
      deferredRename.reject({},500);
      spyOn(FilesystemService,'rename').and.returnValue(deferredRename.promise);
      spyOn(AlertService,'addAlert').and.returnValue('uuid-4444');

      isolateScope.editFile = {name: filename};
      isolateScope.selection = {
        selectedFile: {
          filepath: filepath,
          name: originalFilename
        }
      };
      isolateScope.renameFile();
      $scope.$digest();

      expect(AlertService.addAlert.calls.count()).toEqual(1);
      expect(isolateScope.editFile.name).toEqual(originalFilename);
    });

    it('selecting a new group changes the group',function() {});

    it('editing permissions model changes permissions',function() {});

    it('opening in editor sends signal and changes location',function() {});

    it('duplicates created with proper suffix',function() {});

    it('file moved to location specified by move modal',function() {});

    it('file is deleted and selection is cleared',function() {});

  });

  describe('directive', function() {
    var $compile, $scope, isolateScope, element;

    var getMatchesFromTpl = function(pattern,tpl) {
      var matches = tpl.match(pattern);
      if (!matches) {
        return [];
      }
      return matches;
    };

    var renderTpl = function(scope,el) {
      var tpl;
      scope.$digest();
      tpl = el.html();
      return tpl;
    };

    beforeEach(inject(function(_$compile_) {
      $compile = _$compile_;
      $scope = $rootScope.$new();

      element = $compile(baseElement)($scope);
      $scope.$digest();
      isolateScope = element.isolateScope();
    }));

    it('changes to edit propagate to template',function() {});

    it('group select is populated',function() {});

    it('permissions matrix renders properly',function() {});

  });

});
<commit_msg>Added more tests for fbFileDetails.<commit_after>'use strict';

describe('sandstone.filebrowser.fbFileDetails', function() {
  var baseElement = '

';

  var volumeDetails, fsDetails, fileDetails, dirDetails;

  var FilesystemService;
  var FilebrowserService;
  var AlertService;
  var mockResolve, mockReject;
  var $rootScope, digest, $q;

  beforeEach(module('sandstone'));
  beforeEach(module('sandstone.templates'));
  beforeEach(module('sandstone.broadcastservice'));
  beforeEach(module('sandstone.filesystemservice'));
  beforeEach(module('sandstone.filebrowser'));

  beforeEach(function() {
    volumeDetails = {
      available: '11G',
      filepath: '/volume1/',
      size: '18G',
      type: 'volume',
      used: '6.0G',
      used_pct: 36
    };
    fsDetails = {
      groups: ['testgrp'],
      type: 'filesystem',
      volumes: [volumeDetails]
    };
    fileDetails = {
      type: 'file',
      filepath: '/volume1/file1',
      dirpath: '/volume1',
      name: 'file1',
      owner: 'testuser',
      group: 'testgrp',
      permissions: 'rwxrw-r--',
      size: '8.8K'
    };
    dirDetails = {
      type: 'directory',
      filepath: '/volume1',
      dirpath: '/volume1/',
      name: 'volume1',
      owner: 'testuser',
      group: 'testgrp',
      permissions: 'rwxrw-r--',
      size: '4.0K',
      contents: [fileDetails]
    };
  });

  beforeEach(inject(function(_FilesystemService_,_$q_) {
    $q = _$q_;

    FilesystemService = _FilesystemService_;
    // FilebrowserService automatically calls FS service methods
    var deferredGetFsDetails = $q.defer();
    deferredGetFsDetails.resolve(fsDetails);
    spyOn(FilesystemService,'getFilesystemDetails').and.returnValue(deferredGetFsDetails.promise);
  }));

  beforeEach(inject(function(_FilebrowserService_,_AlertService_,_$rootScope_) {
    FilebrowserService = _FilebrowserService_;
    AlertService = _AlertService_;
    $rootScope = _$rootScope_;

    digest = function() {
      $rootScope.$digest();
    };
  }));

  describe('controller', function() {
    var $compile, $scope, isolateScope, element;

    beforeEach(inject(function(_$compile_) {
      $compile = _$compile_;
      $scope = $rootScope.$new();

      element = $compile(baseElement)($scope);
      $scope.$digest();
      isolateScope = element.isolateScope();
    }));

    it('gets filesystem details on load',function() {
      spyOn(FilebrowserService,'getFilesystem').and.returnValue(fsDetails);
      element = $compile(baseElement)($scope);
      $scope.$digest();
      expect(FilebrowserService.getFilesystem).toHaveBeenCalled();
    });

    it('watches for selection changes and deep copies file',function() {
      // File is selected
      var selection = {selectedFile: fileDetails};
      spyOn(FilebrowserService,'getSelection').and.returnValue(selection);
      $scope.$digest();
      expect(isolateScope.selection).toBe(selection);
      expect(isolateScope.editFile).not.toBe(fileDetails);
      expect(isolateScope.editFile.filepath).toEqual(fileDetails.filepath);
      // Selected file is undefined
      selection = {selectedFile: undefined};
      FilebrowserService.getSelection = jasmine.createSpy().and.returnValue(selection);
      $scope.$digest();
      expect(isolateScope.selection).toBe(selection);
      expect(isolateScope.editFile).toEqual({});
    });

    it('edit file contains a model for permissions edits',function() {
      var selection = {selectedFile: fileDetails};
      var permModel = {
        0: true,
        1: true,
        2: true,
        3: true,
        4: true,
        5: false,
        6: true,
        7: false,
        8: false
      }
      spyOn(FilebrowserService,'getSelection').and.returnValue(selection);
      $scope.$digest();
      expect(isolateScope.editFile.permModel).toEqual(permModel);
    });

    it('editing filename renames the file',function() {
      var filepath = '/file/path';
      var filename = 'filename';
      var newpath = '/volume1/file1';

      var deferredRename = $q.defer();
      deferredRename.resolve(newpath);
      spyOn(FilesystemService,'rename').and.returnValue(deferredRename.promise);
      var deferredGetFileDetails = $q.defer();
      deferredGetFileDetails.resolve(fileDetails);
      spyOn(FilesystemService,'getFileDetails').and.returnValue(deferredGetFileDetails.promise);
      spyOn(FilebrowserService,'setSelectedFile').and.callThrough();

      isolateScope.editFile = {name: filename};
      isolateScope.selection = {selectedFile: {filepath: filepath}};
      isolateScope.renameFile();
      $scope.$digest();

      expect(FilesystemService.rename.calls.argsFor(0)).toEqual([filepath,filename]);
      expect(FilebrowserService.setSelectedFile.calls.argsFor(0)).toEqual([fileDetails]);
    });

    it('rename error shows alert and resets filename',function() {
      var filepath = '/file/path';
      var filename = 'filename';
      var originalFilename = 'orig-filename';
      var newpath = '/volume1/file1';

      var deferredRename = $q.defer();
      deferredRename.reject({},500);
      spyOn(FilesystemService,'rename').and.returnValue(deferredRename.promise);
      spyOn(AlertService,'addAlert').and.returnValue('uuid-4444');

      isolateScope.editFile = {name: filename};
      isolateScope.selection = {
        selectedFile: {
          filepath: filepath,
          name: originalFilename
        }
      };
      isolateScope.renameFile();
      $scope.$digest();

      expect(AlertService.addAlert.calls.count()).toEqual(1);
      expect(isolateScope.editFile.name).toEqual(originalFilename);
    });

    it('selecting a new group changes the group',function() {
      var filepath = '/volume1/file1';
      var group = 'testgrp2';
      FilebrowserService.setSelectedFile(fileDetails);
      $scope.$digest();

      var deferredChangeGroup = $q.defer();
      deferredChangeGroup.resolve();
      spyOn(FilesystemService,'changeGroup').and.returnValue(deferredChangeGroup.promise);

      isolateScope.editFile = {group: group};
      isolateScope.changeGroup();
      $scope.$digest();

      expect(FilesystemService.changeGroup.calls.argsFor(0)).toEqual([filepath,group]);
      expect(isolateScope.selection.selectedFile.group).toEqual(group);
    });

    it('group change error shows alert and resets group',function() {
      var filepath = '/volume1/file1';
      var originalGroup = fileDetails.group;
      var group = 'testgrp2';
      FilebrowserService.setSelectedFile(fileDetails);
      $scope.$digest();

      var deferredChangeGroup = $q.defer();
      deferredChangeGroup.reject({},500);
      spyOn(FilesystemService,'changeGroup').and.returnValue(deferredChangeGroup.promise);
      spyOn(AlertService,'addAlert').and.returnValue('uuid-4444');

      isolateScope.editFile = {group: group};
      isolateScope.changeGroup();
      $scope.$digest();

      expect(AlertService.addAlert.calls.count()).toEqual(1);
      expect(isolateScope.editFile.group).toEqual(originalGroup);
    });

    it('editing permissions model changes permissions',function() {});

    it('opening in editor sends signal and changes location',function() {});

    it('duplicates created with proper suffix',function() {});

    it('file moved to location specified by move modal',function() {});

    it('file is deleted and selection is cleared',function() {});

  });

  describe('directive', function() {
    var $compile, $scope, isolateScope, element;

    var getMatchesFromTpl = function(pattern,tpl) {
      var matches = tpl.match(pattern);
      if (!matches) {
        return [];
      }
      return matches;
    };

    var renderTpl = function(scope,el) {
      var tpl;
      scope.$digest();
      tpl = el.html();
      return tpl;
    };

    beforeEach(inject(function(_$compile_) {
      $compile = _$compile_;
      $scope = $rootScope.$new();

      element = $compile(baseElement)($scope);
      $scope.$digest();
      isolateScope = element.isolateScope();
    }));

    it('changes to edit propagate to template',function() {});

    it('group select is populated',function() {});

    it('permissions matrix renders properly',function() {});

  });

});
<|endoftext|>


<commit_before>import { createStore } from "redux";
<commit_msg>first stage reducer<commit_after>import { createStore } from "redux";

const stage = (state, action) => {
	if (action.type === "RESIZE_STAGE") {
		return {
			width: action.width,
			height: action.height
		};
	}
	return state;
};<|endoftext|>


<commit_before>import { app, BrowserWindow, shell } from 'electron';
import fs from 'fs-extra';
import path from 'path';

import windowStateKeeper from 'electron-window-state';

import { isDevMode, isMac, isWindows, isLinux } from './environment';
import ipcApi from './electron/ipc-api';
import Tray from './lib/Tray';
import Settings from './electron/Settings';
import handleDeepLink from './electron/deepLinking';
import { appId } from './package.json'; // eslint-disable-line import/no-unresolved
import './electron/exception';

const debug = require('debug')('App');

// 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.
let mainWindow;
let willQuitApp = false;

// DEV MODE: Save user data into FranzDev
if (isDevMode) {
  app.setPath('userData', path.join(app.getPath('appData'), 'FranzDev'));
}

// Ensure that the recipe directory exists
fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp'));
fs.ensureFileSync(path.join(app.getPath('userData'), 'window-state.json'));

// Set App ID for Windows
if (isWindows) {
  app.setAppUserModelId(appId);
}

// Force single window
const isSecondInstance = app.makeSingleInstance((argv) => {
  if (mainWindow) {
    if (mainWindow.isMinimized()) mainWindow.restore();
    mainWindow.focus();

    if (process.platform === 'win32') {
      // Keep only command line / deep linked arguments
      const url = argv.slice(1);

      if (url) {
        handleDeepLink(mainWindow, url.toString());
      }
    }
  }
});

if (isSecondInstance) {
  console.log('An instance of Franz is already running. Exiting...');
  app.exit();
}

// Fix Unity indicator issue
// https://github.com/electron/electron/issues/9046
if (isLinux && ['Pantheon', 'Unity:Unity7'].indexOf(process.env.XDG_CURRENT_DESKTOP) !== -1) {
  process.env.XDG_CURRENT_DESKTOP = 'Unity';
}

// Initialize Settings
const settings = new Settings();

// Disable GPU acceleration
if (!settings.get('enableGPUAcceleration')) {
  debug('Disable GPU Acceleration');
  app.disableHardwareAcceleration();
}

const createWindow = () => {
  // Remember window size
  const mainWindowState = windowStateKeeper({
    defaultWidth: 800,
    defaultHeight: 600,
  });

  // Create the browser window.
  mainWindow = new BrowserWindow({
    x: mainWindowState.x,
    y: mainWindowState.y,
    width: mainWindowState.width,
    height: mainWindowState.height,
    minWidth: 600,
    minHeight: 500,
    titleBarStyle: isMac ? 'hidden' : '',
    frame: isLinux,
    backgroundColor: '#3498db',
  });

  // Initialize System Tray
  const trayIcon = new Tray();

  // Initialize ipcApi
  ipcApi({ mainWindow, settings, trayIcon });

  // Manage Window State
  mainWindowState.manage(mainWindow);

  // and load the index.html of the app.
  mainWindow.loadURL(`file://${__dirname}/index.html`);

  // Open the DevTools.
  if (isDevMode) {
    mainWindow.webContents.openDevTools();
  }

  // Emitted when the window is closed.
  mainWindow.on('close', (e) => {
    // 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.
    if (!willQuitApp && (settings.get('runInBackground') === undefined || settings.get('runInBackground'))) {
      e.preventDefault();
      if (isWindows) {
        mainWindow.minimize();
      } else {
        mainWindow.hide();
      }

      if (isWindows && settings.get('minimizeToSystemTray')) {
        mainWindow.setSkipTaskbar(true);
      }
    } else {
      app.quit();
    }
  });

  // For Windows we need to store a flag to properly restore the window
  // if the window was maximized before minimizing it so system tray
  mainWindow.on('minimize', () => {
    app.wasMaximized = app.isMaximized;

    if (settings.get('minimizeToSystemTray')) {
      mainWindow.setSkipTaskbar(true);
      trayIcon.show();
    }
  });

  mainWindow.on('maximize', () => {
    app.isMaximized = true;
  });

  mainWindow.on('unmaximize', () => {
    app.isMaximized = false;
  });

  mainWindow.on('restore', () => {
    mainWindow.setSkipTaskbar(false);

    if (app.wasMaximized) {
      mainWindow.maximize();
    }

    if (!settings.get('enableSystemTray')) {
      trayIcon.hide();
    }
  });

  mainWindow.on('show', () => {
    mainWindow.setSkipTaskbar(false);
  });

  app.mainWindow = mainWindow;
  app.isMaximized = mainWindow.isMaximized();

  mainWindow.webContents.on('new-window', (e, url) => {
    e.preventDefault();
    shell.openExternal(url);
  });
};

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);

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

app.on('before-quit', () => {
  willQuitApp = true;
});

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow();
  } else {
    mainWindow.show();
  }
});

app.on('will-finish-launching', () => {
  // Protocol handler for osx
  app.on('open-url', (event, url) => {
    event.preventDefault();
    console.log(`open-url event: ${url}`);
    handleDeepLink(mainWindow, url);
  });
});

// Register App URL
app.setAsDefaultProtocolClient('franz');
<commit_msg>fix(Windows): Remove minimize setting check on close event (#1038) @imaginarny<commit_after>import { app, BrowserWindow, shell } from 'electron';
import fs from 'fs-extra';
import path from 'path';

import windowStateKeeper from 'electron-window-state';

import { isDevMode, isMac, isWindows, isLinux } from './environment';
import ipcApi from './electron/ipc-api';
import Tray from './lib/Tray';
import Settings from './electron/Settings';
import handleDeepLink from './electron/deepLinking';
import { appId } from './package.json'; // eslint-disable-line import/no-unresolved
import './electron/exception';

const debug = require('debug')('App');

// 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.
let mainWindow;
let willQuitApp = false;

// DEV MODE: Save user data into FranzDev
if (isDevMode) {
  app.setPath('userData', path.join(app.getPath('appData'), 'FranzDev'));
}

// Ensure that the recipe directory exists
fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp'));
fs.ensureFileSync(path.join(app.getPath('userData'), 'window-state.json'));

// Set App ID for Windows
if (isWindows) {
  app.setAppUserModelId(appId);
}

// Force single window
const isSecondInstance = app.makeSingleInstance((argv) => {
  if (mainWindow) {
    if (mainWindow.isMinimized()) mainWindow.restore();
    mainWindow.focus();

    if (process.platform === 'win32') {
      // Keep only command line / deep linked arguments
      const url = argv.slice(1);

      if (url) {
        handleDeepLink(mainWindow, url.toString());
      }
    }
  }
});

if (isSecondInstance) {
  console.log('An instance of Franz is already running. Exiting...');
  app.exit();
}

// Fix Unity indicator issue
// https://github.com/electron/electron/issues/9046
if (isLinux && ['Pantheon', 'Unity:Unity7'].indexOf(process.env.XDG_CURRENT_DESKTOP) !== -1) {
  process.env.XDG_CURRENT_DESKTOP = 'Unity';
}

// Initialize Settings
const settings = new Settings();

// Disable GPU acceleration
if (!settings.get('enableGPUAcceleration')) {
  debug('Disable GPU Acceleration');
  app.disableHardwareAcceleration();
}

const createWindow = () => {
  // Remember window size
  const mainWindowState = windowStateKeeper({
    defaultWidth: 800,
    defaultHeight: 600,
  });

  // Create the browser window.
  mainWindow = new BrowserWindow({
    x: mainWindowState.x,
    y: mainWindowState.y,
    width: mainWindowState.width,
    height: mainWindowState.height,
    minWidth: 600,
    minHeight: 500,
    titleBarStyle: isMac ? 'hidden' : '',
    frame: isLinux,
    backgroundColor: '#3498db',
  });

  // Initialize System Tray
  const trayIcon = new Tray();

  // Initialize ipcApi
  ipcApi({ mainWindow, settings, trayIcon });

  // Manage Window State
  mainWindowState.manage(mainWindow);

  // and load the index.html of the app.
  mainWindow.loadURL(`file://${__dirname}/index.html`);

  // Open the DevTools.
  if (isDevMode) {
    mainWindow.webContents.openDevTools();
  }

  // Emitted when the window is closed.
  mainWindow.on('close', (e) => {
    // 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.
    if (!willQuitApp && (settings.get('runInBackground') === undefined || settings.get('runInBackground'))) {
      e.preventDefault();
      if (isWindows) {
        mainWindow.minimize();
      } else {
        mainWindow.hide();
      }

      if (isWindows) {
        mainWindow.setSkipTaskbar(true);
      }
    } else {
      app.quit();
    }
  });

  // For Windows we need to store a flag to properly restore the window
  // if the window was maximized before minimizing it so system tray
  mainWindow.on('minimize', () => {
    app.wasMaximized = app.isMaximized;

    if (settings.get('minimizeToSystemTray')) {
      mainWindow.setSkipTaskbar(true);
      trayIcon.show();
    }
  });

  mainWindow.on('maximize', () => {
    app.isMaximized = true;
  });

  mainWindow.on('unmaximize', () => {
    app.isMaximized = false;
  });

  mainWindow.on('restore', () => {
    mainWindow.setSkipTaskbar(false);

    if (app.wasMaximized) {
      mainWindow.maximize();
    }

    if (!settings.get('enableSystemTray')) {
      trayIcon.hide();
    }
  });

  mainWindow.on('show', () => {
    mainWindow.setSkipTaskbar(false);
  });

  app.mainWindow = mainWindow;
  app.isMaximized = mainWindow.isMaximized();

  mainWindow.webContents.on('new-window', (e, url) => {
    e.preventDefault();
    shell.openExternal(url);
  });
};

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);

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

app.on('before-quit', () => {
  willQuitApp = true;
});

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow();
  } else {
    mainWindow.show();
  }
});

app.on('will-finish-launching', () => {
  // Protocol handler for osx
  app.on('open-url', (event, url) => {
    event.preventDefault();
    console.log(`open-url event: ${url}`);
    handleDeepLink(mainWindow, url);
  });
});

// Register App URL
app.setAsDefaultProtocolClient('franz');
<|endoftext|>


<commit_before>import React, {Component, PropTypes as PT} from 'react'
import * as u from './utils'

export default class BreakpointMonitor extends Component {
  static style = {
    query: {},
    wrapper: {}
  }
  static defaultBp = {
    xs: 320,
    sm: 480,
    md: 768,
    lg: 960
  }
  static defaultStyles = {
    backgroundColor: 'rgba(0,0,0,.5)',
    color: '#fff',
    position: 'fixed',
    top: '25px',
    right: 0,
    zIndex: 9999,
    padding: '20px',
    fontSize: '16px',
    fontFamily: 'Sans Serif',
    textTransform: 'uppercase'
  }
  static propTypes = {
    bp: PT.object.isRequired,
    overwriteDefaultBp: PT.bool,
    throttleBy: PT.number,
    style: PT.object
  }
  static defaultProps = {
    bp: {},
    overwriteDefaultBp: false,
    throttleBy: 5,
    style: {},
  }
  state = {
    currentBpLabel: '-',
    finalBp: {...BreakpointMonitor.defaultBp}
  }
  componentDidMount () {
    Promise
      .resolve(this.composeFinalBp(this.props))
      .then(this.findCurrentBpLabel)
      .then(() => {
        u.safeWindow(
          'addEventListener',
          'resize',
          u.throttle(this.findCurrentBpLabel, this.props.throttleBy)
        )
      })
  }
  componentWillUnmount () {
    u.safeWindow('removeEventListener', 'resize', this.findCurrentBpLabel)
  }
  componentWillReceiveProps (nextProps) {
    this.composeFinalBp(nextProps)
  }
  composeFinalBp({bp, overwriteDefaultBp}) {
    const finalBp = overwriteDefaultBp
      ? bp
      : Object.assign({}, BreakpointMonitor.defaultBp, bp)
    this.setState({ finalBp });
  }
  findCurrentBpLabel = () => {
    const width = this.props.__windowWidth || u.safeWindow('innerWidth')
    const currentBpLabel = u.findKey(this.state.finalBp, this.isWWW(width))
    this.setState({currentBpLabel});
  }
  // Within Window Width
  isWWW = (width) => (prevBp = 0, currentBp, nextBp = Infinity) => {
    return prevBp <= width && width < nextBp
  }
  render() {
    const {bp, overwriteDefaultBp, throttleBy, style, ...attrs} = this.props
    const style = Object.assign({}, BreakpointMonitor.defaultStyles, this.props.style)
    return (
      <div {...attrs} style={style}>
        {this.state.currentBpLabel}
      </div>
    )
  }
}

<commit_msg>fix(): fix error preventing compilation<commit_after>import React, {Component, PropTypes as PT} from 'react'
import * as u from './utils'

export default class BreakpointMonitor extends Component {
  static style = {
    query: {},
    wrapper: {}
  }
  static defaultBp = {
    xs: 320,
    sm: 480,
    md: 768,
    lg: 960
  }
  static defaultStyles = {
    backgroundColor: 'rgba(0,0,0,.5)',
    color: '#fff',
    position: 'fixed',
    top: '25px',
    right: 0,
    zIndex: 9999,
    padding: '20px',
    fontSize: '16px',
    fontFamily: 'Sans Serif',
    textTransform: 'uppercase'
  }
  static propTypes = {
    bp: PT.object.isRequired,
    overwriteDefaultBp: PT.bool,
    throttleBy: PT.number,
    style: PT.object
  }
  static defaultProps = {
    bp: {},
    overwriteDefaultBp: false,
    throttleBy: 5,
    style: {},
  }
  state = {
    currentBpLabel: '-',
    finalBp: {...BreakpointMonitor.defaultBp}
  }
  componentDidMount () {
    Promise
      .resolve(this.composeFinalBp(this.props))
      .then(this.findCurrentBpLabel)
      .then(() => {
        u.safeWindow(
          'addEventListener',
          'resize',
          u.throttle(this.findCurrentBpLabel, this.props.throttleBy)
        )
      })
  }
  componentWillUnmount () {
    u.safeWindow('removeEventListener', 'resize', this.findCurrentBpLabel)
  }
  componentWillReceiveProps (nextProps) {
    this.composeFinalBp(nextProps)
  }
  composeFinalBp({bp, overwriteDefaultBp}) {
    const finalBp = overwriteDefaultBp
      ? bp
      : Object.assign({}, BreakpointMonitor.defaultBp, bp)
    this.setState({ finalBp });
  }
  findCurrentBpLabel = () => {
    const width = this.props.__windowWidth || u.safeWindow('innerWidth')
    const currentBpLabel = u.findKey(this.state.finalBp, this.isWWW(width))
    this.setState({currentBpLabel});
  }
  // Within Window Width
  isWWW = (width) => (prevBp = 0, currentBp, nextBp = Infinity) => {
    return prevBp <= width && width < nextBp
  }
  render() {
    const {bp, overwriteDefaultBp, throttleBy, style, ...attrs} = this.props
    const fullStyle = Object.assign({}, BreakpointMonitor.defaultStyles, style)
    return (
      <div {...attrs} style={fullStyle}>
        {this.state.currentBpLabel}
      </div>
    )
  }
}

<|endoftext|>


<commit_before>'use strict';

(function () {

  var _ = require('underscore');
  var request = require('superagent');
  var cheerio = require('cheerio');
  var parseDomain = require('parse-domain');
  var utils = require('./utils');

  var error = utils.error;

  var MATCHES_NO_PROTOCOL = /^\/\//;
  var MATCHES_RELATIVE_URL = /\.?\//;

  function crawl(options, callback) {
    if (!options.url) {
      error('No url specified');
    }

    var baseDomain = parseDomain(options.url);

    if (!baseDomain) {
      error('Invalid domain');
    }

    var urls = [options.url];
    var json = {};
    var depth = options.depth;
    var format = options.format;

    function continueCrawl (url) {
      request
      .get(url)
      .accept('text/html')
      .send()
      .end(function (err, res) {
        if (err) {
          error(err);
        } else {
          var html = res.text;
          var $ = cheerio.load(html);

          var links = _.chain($('a[href]').toArray().map(function (el) {
            var element = $(el);

            return element.attr('href');
          }))
          .groupBy(_.identity)
          .map(function (values, key) {
            return {
              url: key,
              references: values.length
            };
          })
          .sortBy('url')
          .groupBy(function (link) {
            var linkDomain = parseDomain(link.url.replace(MATCHES_NO_PROTOCOL, ''));

            if (!linkDomain) {
              var relativeUrl = MATCHES_RELATIVE_URL.exec(link.url);
              return relativeUrl && relativeUrl.index === 0 ? 'internal' : 'unknown';
            }

            return linkDomain.domain === baseDomain.domain &&
              linkDomain.tld === baseDomain.tld ? 'internal' : 'external';
          })
          .value();

          json[url] = {
            title: $('title').text() || null,
            charset: $('meta[charset]').attr('charset') || null,
            meta: _.object($('meta[name]').toArray().map(function (el) {
              var element = $(el);

              return [element.attr('name'), element.attr('content')];
            })),
            links: {
              internal: links.internal || [],
              external: links.external || [],
              unknown: links.unknown || []
            }
          };

          if (urls.length) {

          } else if (typeof process === 'object') {
            process.stdout.write(JSON.stringify(json, null, 2) + '\n')
          } if (typeof callback === 'function') {
            callback(JSON.stringify(json, null, 2) + '\n');
          }
        }
      });
    }

    continueCrawl(urls.shift());

  }

  module.exports = {
    crawl: crawl
  };

})();
<commit_msg>Split out same page links<commit_after>'use strict';

(function () {

  var _ = require('underscore');
  var request = require('superagent');
  var cheerio = require('cheerio');
  var parseDomain = require('parse-domain');
  var utils = require('./utils');

  var error = utils.error;

  var MATCHES_NO_PROTOCOL = /^\/\//;
  var MATCHES_RELATIVE_URL = /\.?\//;

  function crawl(options, callback) {
    if (!options.url) {
      error('No url specified');
    }

    var baseDomain = parseDomain(options.url);

    if (!baseDomain) {
      error('Invalid domain');
    }

    var urls = [options.url];
    var json = {};
    var depth = options.depth;
    var format = options.format;

    function continueCrawl (url) {
      request
      .get(url)
      .accept('text/html')
      .send()
      .end(function (err, res) {
        if (err) {
          error(err);
        } else {
          var html = res.text;
          var $ = cheerio.load(html);

          var links = _.chain($('a[href]').toArray().map(function (el) {
            var element = $(el);

            return element.attr('href');
          }))
          .groupBy(_.identity)
          .map(function (values, key) {
            return {
              url: key,
              references: values.length
            };
          })
          .sortBy('url')
          .groupBy(function (link) {
            if (link.url.indexOf('#') === 0) {
              return 'same-page';
            }

            var linkDomain = parseDomain(link.url.replace(MATCHES_NO_PROTOCOL, ''));

            if (!linkDomain) {
              var relativeUrl = MATCHES_RELATIVE_URL.exec(link.url);
              return relativeUrl && relativeUrl.index === 0 ? 'internal' : 'unknown';
            }

            return linkDomain.domain === baseDomain.domain &&
              linkDomain.tld === baseDomain.tld ? 'internal' : 'external';
          })
          .value();

          json[url] = {
            title: $('title').text() || null,
            charset: $('meta[charset]').attr('charset') || null,
            meta: _.object($('meta[name]').toArray().map(function (el) {
              var element = $(el);

              return [element.attr('name'), element.attr('content')];
            })),
            links: {
              internal: links.internal || [],
              external: links.external || [],
              'same-page': links['same-page'] || [],
              unknown: links.unknown || []
            }
          };

          if (urls.length) {

          } else if (typeof process === 'object') {
            process.stdout.write(JSON.stringify(json, null, 2) + '\n')
          } if (typeof callback === 'function') {
            callback(JSON.stringify(json, null, 2) + '\n');
          }
        }
      });
    }

    continueCrawl(urls.shift());

  }

  module.exports = {
    crawl: crawl
  };

})();
<|endoftext|>


<commit_before>/* eslint-disable no-underscore-dangle */

import off from 'dom-helpers/events/off';
import on from 'dom-helpers/events/on';
import scrollLeft from 'dom-helpers/query/scrollLeft';
import scrollTop from 'dom-helpers/query/scrollTop';
import requestAnimationFrame from 'dom-helpers/util/requestAnimationFrame';
import invariant from 'invariant';

// Try at most this many times to scroll, to avoid getting stuck.
const MAX_SCROLL_ATTEMPTS = 2;

export default class ScrollBehavior {
  constructor({
    addTransitionHook,
    stateStorage,
    getCurrentLocation,
    shouldUpdateScroll,
  }) {
    this._stateStorage = stateStorage;
    this._getCurrentLocation = getCurrentLocation;
    this._shouldUpdateScroll = shouldUpdateScroll;

    // This helps avoid some jankiness in fighting against the browser's
    // default scroll behavior on `POP` transitions.
    /* istanbul ignore if: not supported by any browsers on Travis */
    if ('scrollRestoration' in window.history) {
      this._oldScrollRestoration = window.history.scrollRestoration;
      window.history.scrollRestoration = 'manual';
    } else {
      this._oldScrollRestoration = null;
    }

    this._saveWindowPositionHandle = null;
    this._checkWindowScrollHandle = null;
    this._windowScrollTarget = null;
    this._numWindowScrollAttempts = 0;

    this._scrollElements = {};

    // We have to listen to each window scroll update rather than to just
    // location updates, because some browsers will update scroll position
    // before emitting the location change.
    on(window, 'scroll', this._onWindowScroll);

    this._removeTransitionHook = addTransitionHook(() => {
      if (this._saveWindowPositionHandle !== null) {
        requestAnimationFrame.cancel(this._saveWindowPositionHandle);
        this._saveWindowPositionHandle = null;
      }

      // It's fine to save element scroll positions here, though; the browser
      // won't modify them.
      Object.keys(this._scrollElements).forEach((key) => {
        this._saveElementPosition(key);
      });
    });
  }

  registerElement(key, element, shouldUpdateScroll, context) {
    invariant(
      !this._scrollElements[key],
      'ScrollBehavior: There is already an element registered for `%s`.',
      key
    );

    this._scrollElements[key] = { element, shouldUpdateScroll };
    this._updateElementScroll(key, null, context);
  }

  unregisterElement(key) {
    invariant(
      this._scrollElements[key],
      'ScrollBehavior: There is no element registered for `%s`.',
      key
    );

    delete this._scrollElements[key];
  }

  updateScroll(prevContext, context) {
    this._updateWindowScroll(prevContext, context);

    Object.keys(this._scrollElements).forEach((key) => {
      this._updateElementScroll(key, prevContext, context);
    });
  }

  stop() {
    /* istanbul ignore if: not supported by any browsers on Travis */
    if (this._oldScrollRestoration) {
      window.history.scrollRestoration = this._oldScrollRestoration;
    }

    off(window, 'scroll', this._onWindowScroll);
    this._cancelCheckWindowScroll();

    this._removeTransitionHook();
  }

  _onWindowScroll = () => {
    // It's possible that this scroll operation was triggered by what will be a
    // `POP` transition. Instead of updating the saved location immediately, we
    // have to enqueue the update, then potentially cancel it if we observe a
    // location update.
    if (this._saveWindowPositionHandle === null) {
      this._saveWindowPositionHandle =
        requestAnimationFrame(this._saveWindowPosition);
    }

    if (this._windowScrollTarget) {
      const [xTarget, yTarget] = this._windowScrollTarget;
      const x = scrollLeft(window);
      const y = scrollTop(window);

      if (x === xTarget && y === yTarget) {
        this._windowScrollTarget = null;
        this._cancelCheckWindowScroll();
      }
    }
  };

  _saveWindowPosition = () => {
    this._saveWindowPositionHandle = null;

    this._savePosition(null, window);
  };

  _cancelCheckWindowScroll() {
    if (this._checkWindowScrollHandle !== null) {
      requestAnimationFrame.cancel(this._checkWindowScrollHandle);
      this._checkWindowScrollHandle = null;
    }
  }

  _saveElementPosition(key) {
    const { element } = this._scrollElements[key];

    this._savePosition(key, element);
  }

  _savePosition(key, element) {
    this._stateStorage.save(
      this._getCurrentLocation(),
      key,
      [scrollLeft(element), scrollTop(element)],
    );
  }

  _updateWindowScroll(prevContext, context) {
    // Whatever we were doing before isn't relevant any more.
    this._cancelCheckWindowScroll();

    this._windowScrollTarget = this._getScrollTarget(
      null, this._shouldUpdateScroll, prevContext, context,
    );

    // Check the scroll position to see if we even need to scroll. This call
    // will unset _windowScrollTarget if the current scroll position matches
    // the target.
    this._onWindowScroll();

    if (!this._windowScrollTarget) {
      return;
    }

    // Updating the window scroll position is really flaky. Just trying to
    // scroll it isn't enough. Instead, try to scroll a few times until it
    // works.
    this._numWindowScrollAttempts = 0;
    this._checkWindowScrollPosition();
  }

  _updateElementScroll(key, prevContext, context) {
    const { element, shouldUpdateScroll } = this._scrollElements[key];

    const scrollTarget = this._getScrollTarget(
      key, shouldUpdateScroll, prevContext, context,
    );
    if (!scrollTarget) {
      return;
    }

    // Unlike with the window, there shouldn't be any flakiness to deal with
    // here.
    const [x, y] = scrollTarget;
    scrollLeft(element, x);
    scrollTop(element, y);
  }

  _getScrollTarget(key, shouldUpdateScroll, prevContext, context) {
    const scrollTarget = shouldUpdateScroll ?
      shouldUpdateScroll.call(this, prevContext, context) : true;

    if (!scrollTarget || Array.isArray(scrollTarget)) {
      return scrollTarget;
    }

    const location = this._getCurrentLocation();
    if (location.action === 'PUSH') {
      return [0, 0];
    }

    return this._stateStorage.read(location, key) || [0, 0];
  }

  _checkWindowScrollPosition = () => {
    this._checkWindowScrollHandle = null;

    // We can only get here if scrollTarget is set. Every code path that unsets
    // scroll target also cancels the handle to avoid calling this handler.
    // Still, check anyway just in case.
    /* istanbul ignore if: paranoid guard */
    if (!this._windowScrollTarget) {
      return;
    }

    const [x, y] = this._windowScrollTarget;
    window.scrollTo(x, y);

    ++this._numWindowScrollAttempts;

    /* istanbul ignore if: paranoid guard */
    if (this._numWindowScrollAttempts >= MAX_SCROLL_ATTEMPTS) {
      this._windowScrollTarget = null;
      return;
    }

    this._checkWindowScrollHandle =
      requestAnimationFrame(this._checkWindowScrollPosition);
  };
}
<commit_msg>Don't check initial scroll due to browser quirks<commit_after>/* eslint-disable no-underscore-dangle */

import off from 'dom-helpers/events/off';
import on from 'dom-helpers/events/on';
import scrollLeft from 'dom-helpers/query/scrollLeft';
import scrollTop from 'dom-helpers/query/scrollTop';
import requestAnimationFrame from 'dom-helpers/util/requestAnimationFrame';
import invariant from 'invariant';

// Try at most this many times to scroll, to avoid getting stuck.
const MAX_SCROLL_ATTEMPTS = 2;

export default class ScrollBehavior {
  constructor({
    addTransitionHook,
    stateStorage,
    getCurrentLocation,
    shouldUpdateScroll,
  }) {
    this._stateStorage = stateStorage;
    this._getCurrentLocation = getCurrentLocation;
    this._shouldUpdateScroll = shouldUpdateScroll;

    // This helps avoid some jankiness in fighting against the browser's
    // default scroll behavior on `POP` transitions.
    /* istanbul ignore if: not supported by any browsers on Travis */
    if ('scrollRestoration' in window.history) {
      this._oldScrollRestoration = window.history.scrollRestoration;
      window.history.scrollRestoration = 'manual';
    } else {
      this._oldScrollRestoration = null;
    }

    this._saveWindowPositionHandle = null;
    this._checkWindowScrollHandle = null;
    this._windowScrollTarget = null;
    this._numWindowScrollAttempts = 0;

    this._scrollElements = {};

    // We have to listen to each window scroll update rather than to just
    // location updates, because some browsers will update scroll position
    // before emitting the location change.
    on(window, 'scroll', this._onWindowScroll);

    this._removeTransitionHook = addTransitionHook(() => {
      if (this._saveWindowPositionHandle !== null) {
        requestAnimationFrame.cancel(this._saveWindowPositionHandle);
        this._saveWindowPositionHandle = null;
      }

      // It's fine to save element scroll positions here, though; the browser
      // won't modify them.
      Object.keys(this._scrollElements).forEach((key) => {
        this._saveElementPosition(key);
      });
    });
  }

  registerElement(key, element, shouldUpdateScroll, context) {
    invariant(
      !this._scrollElements[key],
      'ScrollBehavior: There is already an element registered for `%s`.',
      key
    );

    this._scrollElements[key] = { element, shouldUpdateScroll };
    this._updateElementScroll(key, null, context);
  }

  unregisterElement(key) {
    invariant(
      this._scrollElements[key],
      'ScrollBehavior: There is no element registered for `%s`.',
      key
    );

    delete this._scrollElements[key];
  }

  updateScroll(prevContext, context) {
    this._updateWindowScroll(prevContext, context);

    Object.keys(this._scrollElements).forEach((key) => {
      this._updateElementScroll(key, prevContext, context);
    });
  }

  stop() {
    /* istanbul ignore if: not supported by any browsers on Travis */
    if (this._oldScrollRestoration) {
      window.history.scrollRestoration = this._oldScrollRestoration;
    }

    off(window, 'scroll', this._onWindowScroll);
    this._cancelCheckWindowScroll();

    this._removeTransitionHook();
  }

  _onWindowScroll = () => {
    // It's possible that this scroll operation was triggered by what will be a
    // `POP` transition. Instead of updating the saved location immediately, we
    // have to enqueue the update, then potentially cancel it if we observe a
    // location update.
    if (this._saveWindowPositionHandle === null) {
      this._saveWindowPositionHandle =
        requestAnimationFrame(this._saveWindowPosition);
    }

    if (this._windowScrollTarget) {
      const [xTarget, yTarget] = this._windowScrollTarget;
      const x = scrollLeft(window);
      const y = scrollTop(window);

      if (x === xTarget && y === yTarget) {
        this._windowScrollTarget = null;
        this._cancelCheckWindowScroll();
      }
    }
  };

  _saveWindowPosition = () => {
    this._saveWindowPositionHandle = null;

    this._savePosition(null, window);
  };

  _cancelCheckWindowScroll() {
    if (this._checkWindowScrollHandle !== null) {
      requestAnimationFrame.cancel(this._checkWindowScrollHandle);
      this._checkWindowScrollHandle = null;
    }
  }

  _saveElementPosition(key) {
    const { element } = this._scrollElements[key];

    this._savePosition(key, element);
  }

  _savePosition(key, element) {
    this._stateStorage.save(
      this._getCurrentLocation(),
      key,
      [scrollLeft(element), scrollTop(element)],
    );
  }

  _updateWindowScroll(prevContext, context) {
    // Whatever we were doing before isn't relevant any more.
    this._cancelCheckWindowScroll();

    this._windowScrollTarget = this._getScrollTarget(
      null, this._shouldUpdateScroll, prevContext, context,
    );

    // Updating the window scroll position is really flaky. Just trying to
    // scroll it isn't enough. Instead, try to scroll a few times until it
    // works.
    this._numWindowScrollAttempts = 0;
    this._checkWindowScrollPosition();
  }

  _updateElementScroll(key, prevContext, context) {
    const { element, shouldUpdateScroll } = this._scrollElements[key];

    const scrollTarget = this._getScrollTarget(
      key, shouldUpdateScroll, prevContext, context,
    );
    if (!scrollTarget) {
      return;
    }

    // Unlike with the window, there shouldn't be any flakiness to deal with
    // here.
    const [x, y] = scrollTarget;
    scrollLeft(element, x);
    scrollTop(element, y);
  }

  _getScrollTarget(key, shouldUpdateScroll, prevContext, context) {
    const scrollTarget = shouldUpdateScroll ?
      shouldUpdateScroll.call(this, prevContext, context) : true;

    if (!scrollTarget || Array.isArray(scrollTarget)) {
      return scrollTarget;
    }

    const location = this._getCurrentLocation();
    if (location.action === 'PUSH') {
      return [0, 0];
    }

    return this._stateStorage.read(location, key) || [0, 0];
  }

  _checkWindowScrollPosition = () => {
    this._checkWindowScrollHandle = null;

    // We can only get here if scrollTarget is set. Every code path that unsets
    // scroll target also cancels the handle to avoid calling this handler.
    // Still, check anyway just in case.
    /* istanbul ignore if: paranoid guard */
    if (!this._windowScrollTarget) {
      return;
    }

    const [x, y] = this._windowScrollTarget;
    window.scrollTo(x, y);

    ++this._numWindowScrollAttempts;

    /* istanbul ignore if: paranoid guard */
    if (this._numWindowScrollAttempts >= MAX_SCROLL_ATTEMPTS) {
      this._windowScrollTarget = null;
      return;
    }

    this._checkWindowScrollHandle =
      requestAnimationFrame(this._checkWindowScrollPosition);
  };
}
<|endoftext|>


<commit_before>'use strict';

import { camelCase, paramCase, pascalCase, titleCase } from 'change-case';
import configuration from './configuration';
import inquirer from 'inquirer';
import { showErrorMessageAndQuit, showMessage, showStartScreen } from './messages';
import path from 'path';
import replace from 'replace';
import { cd, exec, mkdir, mv, rm } from 'shelljs';

const EDORAS_ONE_WIDGET_NAME = 'addon';
const EDORAS_ONE_WIDGET_NAME_PREFIX = 'edoras';
const WIDGET_PATH = 'widget';

const questionAddonName = {
  type: 'input',
  name: 'name',
  message: `What's the name of your widget?`,
  default: predictWidgetName()
};

const questionLogLevel = {
  type: 'list',
  name: 'logLevel',
  message: `Which log level do you prefer?`,
  choices: [
    'info',
    'verbose'
  ]
};

let isExecutionSilent;
let widgetName;
let widgetNameFull;

showStartScreen();

inquirer.prompt([questionAddonName]).then((answers) => {
  initialize(answers.name);
  return asPromise({code: 0}, () => {});
}).then(() => {
  return setLogLevel();
}).then(() => {
  showMessage(`Creating widget...`);
  return cleanup();
}).then(() => {
  showMessage(`Cloning template repository...`);
  return cloneRepo(configuration.TEMPLATE_REPO_URL, WIDGET_PATH);
}).then(() => {
  showMessage(`Renaming files in cloned template...`);
  return renameFiles();
}).then(() => {
  showMessage(`Replacing names in cloned template...`);
  return replaceNames();
}).then(() => {
  showMessage(`Moving files...`);
  return moveFiles();
}).then(() => {
  showMessage(`Creating build files...`);
  return createBuild();
}).then(() => {
  showMessage([
    ``,
    `New project with name '${titleCase(widgetName)}' has been created from frontend template.`,
    `Please have a look at the README file for instructions.`,
    ``
  ]);
})
.catch((error) => {
  showErrorMessageAndQuit(error);
});

/**
 * Resolve or reject based on result code
 * asPromise :: (object, function, function) -> Promise
 */
function asPromise(result, resolve, reject) {
  return result.code === 0 ? resolve() : reject(result.stderr);
}

/**
 * Remove widget and palette files
 * cleanup :: undefined -> Promise
 */
function cleanup() {
  return new Promise((resolve, reject) => {
    rm('-rf',
      path.join(__dirname, '..', '..', '..', WIDGET_PATH));
    const result = rm('-rf',
      path.join(__dirname, '..', '..', '..', '..', widgetNameFull, 'src', 'main', 'resources', 'com', 'edorasware', 'one', 'widgets'));
    return asPromise(result, resolve, reject);
  });
}

/**
 * Clone a git repo to a specified path
 * cloneRepo :: (string, string) -> Promise
 */
function cloneRepo(repoUrl, repoPath) {
  return new Promise((resolve, reject) => {
    let result = exec(`git clone ${repoUrl} ${repoPath}`,
      {silent: isExecutionSilent});

    // remove meta data in .git folder
    result = rm('-rf',
      path.join(__dirname, '..', '..', '..', repoPath, '.git'));

    return asPromise(result, resolve, reject);
  });
}

/**
 * Create build files with webpack
 * createBuild :: undefined -> Promise
 */
function createBuild() {
  return new Promise((resolve, reject) => {
    cd(path.join(__dirname, '..', '..', '..', WIDGET_PATH));
    exec(`npm install`,
      {silent: isExecutionSilent});
    const result = exec(`npm run dist`,
      {silent: isExecutionSilent});
    return asPromise(result, resolve, reject);
  });
}

/**
 * Execute a command in a specific path
 * executeInPath :: (string, path) -> Promise
 */
function executeInPath(command, path) {
  return new Promise((resolve, reject) => {
    cd(path);
    const result = exec(command, {silent: isExecutionSilent});

    return asPromise(result, resolve, reject);
  });
}

/**
 * Initialize cli by setting name variables
 * initialize :: string -> undefined
 */
function initialize(aName) {
  showMessage(`Your widget name is ${aName}.`);
  widgetName = aName.replace(/-/g, ' ').toLowerCase();
  widgetNameFull =
    `${EDORAS_ONE_WIDGET_NAME_PREFIX}-${EDORAS_ONE_WIDGET_NAME}-${paramCase(widgetName)}`;
}

/**
 * Move palette files to addon folder
 * moveFiles :: undefined -> Promise
 */
function moveFiles() {
  return new Promise((resolve, reject) => {
    const source =
      path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'palette');
    const dest =
      path.join(__dirname, '..', '..', '..', '..', widgetNameFull, 'src', 'main', 'resources', 'com', 'edorasware', 'one', 'widgets');
    mkdir('-p', dest);

    const result = mv('-f', source, dest);
    return asPromise(result, resolve, reject);
  });
}

/**
 * Predict the widget name in param case from the parent directory
 * predictWidgetName :: undefined -> string
 */
function predictWidgetName() {
  try {
    let rootName;
    let currentPathParts = path.dirname(__dirname).split(path.sep);

    // go three levels up in path
    for (let i = 0; i < 3; i++) {
      rootName = currentPathParts.pop();
    }

    // extract widget name
    const regExp = new RegExp('edoras-addon-(.*)-frontend');
    const widgetName = rootName.match(regExp)[1];
    if (widgetName) {
      return paramCase(widgetName);
    } else {
      throw 'Invalid name';
    }
  } catch (err) {
    // return default value
    return 'star-rating';
  }
}

/**
 * Rename file in path
 * renameFile :: (path, string, target) -> string
 */
function renameFile(path, source, target) {
  return new Promise((resolve) => {
    const command = `mv ${source} ${target}`;
    executeInPath(command, path);
    resolve();
  });
}

/**
 * Rename multiple files
 * renameFile :: undefined -> Promise
 */
function renameFiles() {
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'palette'),
    'widget.form.palette.xml', `${widgetNameFull}.form.palette.xml`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'palette', 'i18n'),
    'widget.translation.properties', `${widgetNameFull}.translation.properties`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'palette', 'icon'),
    'widget.icon.png', `${widgetNameFull}.icon.png`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.component.js', `${paramCase(widgetName)}.component.js`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.configuration.js', `${paramCase(widgetName)}.configuration.js`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.controller.js', `${paramCase(widgetName)}.controller.js`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.module.js', `${paramCase(widgetName)}.module.js`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.service.js', `${paramCase(widgetName)}.service.js`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.tpl.html', `${paramCase(widgetName)}.tpl.html`);
  return renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src', 'adapters'),
    'widget.adapter.js', `${paramCase(widgetName)}.adapter.js`);
}

/**
 * Replace string with pattern in file
 * replaceInPath :: (path, string, string) -> Promise
 */
function replaceInPath(path, searchRegex, replacement) {
  return new Promise((resolve) => {
    replace({
      regex: `{{${searchRegex}}}`,
      replacement: replacement,
      paths: [path],
      recursive: true,
      silent: isExecutionSilent
    });

    resolve();
  });
}

/**
 * Replace template strings with widget name in multiple files
 * replaceNames :: undefined -> Promise
 */
function replaceNames() {
  const filePatterns = [
    '**/*.html',
    '**/*.js',
    '**/*.json',
    '**/*.md',
    '**/*.properties',
    '**/*.scss',
    '**/*.xml'
  ];

  replaceInPath(path.join(__dirname, '..', '..', '..', WIDGET_PATH),
    'widgetNameFullCamelCase', camelCase(widgetNameFull), filePatterns);
  replaceInPath(path.join(__dirname, '..', '..', '..', WIDGET_PATH),
    'widgetNameFullParamCase', widgetNameFull, filePatterns);
  replaceInPath(path.join(__dirname, '..', '..', '..', WIDGET_PATH),
    'widgetNameFullPascalCase', pascalCase(widgetNameFull), filePatterns);
  replaceInPath(path.join(__dirname, '..', '..', '..', WIDGET_PATH),
    'widgetNameParamCase', paramCase(widgetName), filePatterns);
  return replaceInPath(path.join(__dirname, '..', '..', '..', WIDGET_PATH),
    'widgetNameTitleCase', titleCase(widgetName), filePatterns);
}

/**
 * Ask for log level and store it
 * setLogLevel :: undefined -> Promise
 */
function setLogLevel() {
  return inquirer.prompt([questionLogLevel]).then((answers) => {
    showMessage(`Set log level to ${answers.logLevel}.`);
    isExecutionSilent = answers.logLevel === 'info' ? true : false;
    return asPromise({code: 0}, () => {});
  });
}
<commit_msg>Introduce original widget name<commit_after>'use strict';

import { camelCase, paramCase, pascalCase, titleCase } from 'change-case';
import configuration from './configuration';
import inquirer from 'inquirer';
import { showErrorMessageAndQuit, showMessage, showStartScreen } from './messages';
import path from 'path';
import replace from 'replace';
import { cd, exec, mkdir, mv, rm } from 'shelljs';

const EDORAS_ONE_WIDGET_NAME = 'addon';
const EDORAS_ONE_WIDGET_NAME_PREFIX = 'edoras';
const WIDGET_PATH = 'widget';

const questionAddonName = {
  type: 'input',
  name: 'name',
  message: `What's the name of your widget?`,
  default: predictWidgetName()
};

const questionLogLevel = {
  type: 'list',
  name: 'logLevel',
  message: `Which log level do you prefer?`,
  choices: [
    'info',
    'verbose'
  ]
};

let isExecutionSilent;
let widgetName;
let widgetNameFull;
let widgetNameOriginal;

showStartScreen();

inquirer.prompt([questionAddonName]).then((answers) => {
  initialize(answers.name);
  return asPromise({code: 0}, () => {});
}).then(() => {
  return setLogLevel();
}).then(() => {
  showMessage(`Creating widget...`);
  return cleanup();
}).then(() => {
  showMessage(`Cloning template repository...`);
  return cloneRepo(configuration.TEMPLATE_REPO_URL, WIDGET_PATH);
}).then(() => {
  showMessage(`Renaming files in cloned template...`);
  return renameFiles();
}).then(() => {
  showMessage(`Replacing names in cloned template...`);
  return replaceNames();
}).then(() => {
  showMessage(`Moving files...`);
  return moveFiles();
}).then(() => {
  showMessage(`Creating build files...`);
  return createBuild();
}).then(() => {
  showMessage([
    ``,
    `New project with name '${titleCase(widgetName)}' has been created from frontend template.`,
    `Please have a look at the README file for instructions.`,
    ``
  ]);
})
.catch((error) => {
  showErrorMessageAndQuit(error);
});

/**
 * Resolve or reject based on result code
 * asPromise :: (object, function, function) -> Promise
 */
function asPromise(result, resolve, reject) {
  return result.code === 0 ? resolve() : reject(result.stderr);
}

/**
 * Remove widget and palette files
 * cleanup :: undefined -> Promise
 */
function cleanup() {
  return new Promise((resolve, reject) => {
    rm('-rf',
      path.join(__dirname, '..', '..', '..', WIDGET_PATH));
    const result = rm('-rf',
      path.join(__dirname, '..', '..', '..', '..', widgetNameFull, 'src', 'main', 'resources', 'com', 'edorasware', 'one', 'widgets'));
    return asPromise(result, resolve, reject);
  });
}

/**
 * Clone a git repo to a specified path
 * cloneRepo :: (string, string) -> Promise
 */
function cloneRepo(repoUrl, repoPath) {
  return new Promise((resolve, reject) => {
    let result = exec(`git clone ${repoUrl} ${repoPath}`,
      {silent: isExecutionSilent});

    // remove meta data in .git folder
    result = rm('-rf',
      path.join(__dirname, '..', '..', '..', repoPath, '.git'));

    return asPromise(result, resolve, reject);
  });
}

/**
 * Create build files with webpack
 * createBuild :: undefined -> Promise
 */
function createBuild() {
  return new Promise((resolve, reject) => {
    cd(path.join(__dirname, '..', '..', '..', WIDGET_PATH));
    exec(`npm install`,
      {silent: isExecutionSilent});
    const result = exec(`npm run dist`,
      {silent: isExecutionSilent});
    return asPromise(result, resolve, reject);
  });
}

/**
 * Execute a command in a specific path
 * executeInPath :: (string, path) -> Promise
 */
function executeInPath(command, path) {
  return new Promise((resolve, reject) => {
    cd(path);
    const result = exec(command, {silent: isExecutionSilent});

    return asPromise(result, resolve, reject);
  });
}

/**
 * Initialize cli by setting name variables
 * initialize :: string -> undefined
 */
function initialize(aName) {
  showMessage(`Your widget name is ${aName}.`);
  widgetName = aName.replace(/-/g, ' ').toLowerCase();
  widgetNameFull =
    `${EDORAS_ONE_WIDGET_NAME_PREFIX}-${EDORAS_ONE_WIDGET_NAME}-${paramCase(widgetName)}`;
}

/**
 * Move palette files to addon folder
 * moveFiles :: undefined -> Promise
 */
function moveFiles() {
  return new Promise((resolve, reject) => {
    const source =
      path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'palette');
    const dest =
      path.join(__dirname, '..', '..', '..', '..', widgetNameOriginal, 'src', 'main', 'resources', 'com', 'edorasware', 'one', 'widgets');
    mkdir('-p', dest);

    const result = mv('-f', source, dest);
    return asPromise(result, resolve, reject);
  });
}

/**
 * Predict the widget name in param case from the parent directory
 * predictWidgetName :: undefined -> string
 */
function predictWidgetName() {
  try {
    let rootName;
    let currentPathParts = path.dirname(__dirname).split(path.sep);

    // go three levels up in path
    for (let i = 0; i < 3; i++) {
      rootName = currentPathParts.pop();
    }

    widgetNameOriginal = rootName.replace('-frontend', '');

    // extract widget name
    const regExp = new RegExp('edoras-addon-(.*)-frontend');
    const widgetName = rootName.match(regExp)[1];
    if (widgetName) {
      return paramCase(widgetName);
    } else {
      throw 'Invalid name';
    }
  } catch (err) {
    // return default value
    return 'star-rating';
  }
}

/**
 * Rename file in path
 * renameFile :: (path, string, target) -> string
 */
function renameFile(path, source, target) {
  return new Promise((resolve) => {
    const command = `mv ${source} ${target}`;
    executeInPath(command, path);
    resolve();
  });
}

/**
 * Rename multiple files
 * renameFile :: undefined -> Promise
 */
function renameFiles() {
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'palette'),
    'widget.form.palette.xml', `${widgetNameFull}.form.palette.xml`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'palette', 'i18n'),
    'widget.translation.properties', `${widgetNameFull}.translation.properties`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'palette', 'icon'),
    'widget.icon.png', `${widgetNameFull}.icon.png`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.component.js', `${paramCase(widgetName)}.component.js`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.configuration.js', `${paramCase(widgetName)}.configuration.js`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.controller.js', `${paramCase(widgetName)}.controller.js`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.module.js', `${paramCase(widgetName)}.module.js`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.service.js', `${paramCase(widgetName)}.service.js`);
  renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src'),
    'widget.tpl.html', `${paramCase(widgetName)}.tpl.html`);
  return renameFile(path.join(__dirname, '..', '..', '..', WIDGET_PATH, 'src', 'adapters'),
    'widget.adapter.js', `${paramCase(widgetName)}.adapter.js`);
}

/**
 * Replace string with pattern in file
 * replaceInPath :: (path, string, string) -> Promise
 */
function replaceInPath(path, searchRegex, replacement) {
  return new Promise((resolve) => {
    replace({
      regex: `{{${searchRegex}}}`,
      replacement: replacement,
      paths: [path],
      recursive: true,
      silent: isExecutionSilent
    });

    resolve();
  });
}

/**
 * Replace template strings with widget name in multiple files
 * replaceNames :: undefined -> Promise
 */
function replaceNames() {
  const filePatterns = [
    '**/*.html',
    '**/*.js',
    '**/*.json',
    '**/*.md',
    '**/*.properties',
    '**/*.scss',
    '**/*.xml'
  ];

  replaceInPath(path.join(__dirname, '..', '..', '..', WIDGET_PATH),
    'widgetNameFullCamelCase', camelCase(widgetNameFull), filePatterns);
  replaceInPath(path.join(__dirname, '..', '..', '..', WIDGET_PATH),
    'widgetNameFullParamCase', widgetNameFull, filePatterns);
  replaceInPath(path.join(__dirname, '..', '..', '..', WIDGET_PATH),
    'widgetNameFullPascalCase', pascalCase(widgetNameFull), filePatterns);
  replaceInPath(path.join(__dirname, '..', '..', '..', WIDGET_PATH),
    'widgetNameParamCase', paramCase(widgetName), filePatterns);
  return replaceInPath(path.join(__dirname, '..', '..', '..', WIDGET_PATH),
    'widgetNameTitleCase', titleCase(widgetName), filePatterns);
}

/**
 * Ask for log level and store it
 * setLogLevel :: undefined -> Promise
 */
function setLogLevel() {
  return inquirer.prompt([questionLogLevel]).then((answers) => {
    showMessage(`Set log level to ${answers.logLevel}.`);
    isExecutionSilent = answers.logLevel === 'info' ? true : false;
    return asPromise({code: 0}, () => {});
  });
}
<|endoftext|>


<commit_before>export { Badge, BadgeColors } from './components/badge';
export { Breadcrumbs, BreadcrumbItem } from './components/breadcrumbs';
export { Button, Link, ButtonSizes, ButtonColors } from './components/button';
export { ButtonGroup, ButtonGroupSizes, ButtonGroupColors } from './components/button-group';
export { Callout, CalloutColors, CalloutSizes } from './components/callout';
export { CloseButton } from './components/close-button';
export { FlexVideo } from './components/flex-video';
export { Row, Column } from './components/grid';
export { Div, Span } from './components/html';
export { Icon } from './components/icon';
export { Label, LabelColors } from './components/label';
export { MediaObject, MediaObjectSection, MediaObjectSectionAlignments } from './components/media-object';
export { Menu, MenuItem, MenuText, MenuAlignments } from './components/menu';
export { Pagination, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis } from './components/pagination';
export { Progress, ProgressMeter, ProgressMeterWithText, ProgressMeterText, NativeProgress, ProgressColors } from './components/progress-bar';
export { ResponsiveNavigation, TitleBar, MenuIcon, TitleBarTitle } from './components/responsive';
export { Switch, SwitchInput, SwitchPaddle, SwitchActive, SwitchInactive, SwitchTypes, SwitchSizes } from './components/switch';
export { Thumbnail, ThumbnailLink } from './components/thumbnail';
export { TopBar, TopBarTitle, TopBarLeft, TopBarRight } from './components/top-bar';

<commit_msg>Refactor entry script<commit_after>export { BadgeColors, Badge } from './components/badge';
export { Breadcrumbs, BreadcrumbItem } from './components/breadcrumbs';
export { ButtonSizes, ButtonColors, Button, Link } from './components/button';
export { ButtonGroupSizes, ButtonGroupColors, ButtonGroup } from './components/button-group';
export { CalloutColors, CalloutSizes, Callout } from './components/callout';
export { CloseButton } from './components/close-button';
export { FlexVideo } from './components/flex-video';
export { Row, Column } from './components/grid';
export { Div, Span } from './components/html';
export { Icon } from './components/icon';
export { LabelColors, Label } from './components/label';
export { MediaObject, MediaObjectSection } from './components/media-object';
export { MenuAlignments, Menu, MenuItem, MenuText } from './components/menu';
export { Pagination, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis } from './components/pagination';
export { Progress, ProgressMeter, ProgressMeterWithText, ProgressMeterText, NativeProgress, ProgressColors } from './components/progress-bar';
export { ResponsiveNavigation, TitleBar, MenuIcon, TitleBarTitle } from './components/responsive';
export { SwitchTypes, SwitchSizes, Switch, SwitchInput, SwitchPaddle, SwitchActive, SwitchInactive } from './components/switch';
export { Thumbnail, ThumbnailLink } from './components/thumbnail';
export { TopBar, TopBarTitle, TopBarLeft, TopBarRight } from './components/top-bar';

<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');

var proxyLoader = function(source)
{
	var extract = /(require\s*\()['"]?([^\)'"]*)['"]?(\))/g;

	var cache = {};

	var x;
	while (x = extract.exec(source))
	{
		cache[x[2]] = {
			prefix: x[1],
			name: x[2],
			postfix: x[3]
		};
	}

	var results = [
		'\'use strict\';',
		'var cache = {'
	];

	var cacheToReuire = _.map(cache, function(value, key)
	{
		return '\'' + key + '\': require(\'' + value.name + '\')';
	}).join(',\n');

	results.push(cacheToReuire);
	results.push('};');

	// The injector function
	function injector(inject)
	{
		// Override require
		var require = function(moduleName)
		{
			if (inject[moduleName])
			{
				return inject[moduleName];
			}

			if (!cache[moduleName])
			{
				throw 'Could not find module: ' + moduleName;
			}
			return cache[moduleName];
		};

		// Global module exporters
		var module = {exports: {}};
		var getResult = function()
		{
			return module.exports;
		};
		var define = function(moduleDef)
		{
			return getResult = function()
			{
				return moduleDef(require, module);
			};
		};

		return (function()
		{
			__INJECTION_POINT__

			return getResult();
		})();
	}

	var injectorBlock = injector.toString().replace('__INJECTION_POINT__', source);

	results.push(injectorBlock);

	var tail = [
		'module.exports = injector;'
	];

	results = results.concat(tail).join('\n');

	return results;
};

module.exports = proxyLoader;
<commit_msg>Better AMD loading<commit_after>'use strict';

var _ = require('lodash');

var proxyLoader = function(source)
{
	var extract = /(require\s*\()['"]?([^\)'"]*)['"]?(\))/g;

	var cache = {};

	var x;
	while (x = extract.exec(source))
	{
		cache[x[2]] = {
			prefix: x[1],
			name: x[2],
			postfix: x[3]
		};
	}

	var results = [
		'\'use strict\';',
		'var cache = {'
	];

	var cacheToReuire = _.map(cache, function(value, key)
	{
		return '\'' + key + '\': require(\'' + value.name + '\')';
	}).join(',\n');

	results.push(cacheToReuire);
	results.push('};');

	// The injector function
	function injector(inject)
	{
		// Override require
		var require = function(moduleName)
		{
			if (inject[moduleName])
			{
				return inject[moduleName];
			}

			if (!cache[moduleName])
			{
				throw 'Could not find module: ' + moduleName;
			}
			return cache[moduleName];
		};

		// Global module exporters
		var module = {exports: {}};

		// A getter that can switch between CommonJS or AMD
		var getResult = function()
		{
			return module.exports;
		};

		var define = function(moduleDef)
		{
			// Update getResult to support AMD
			getResult = function()
			{
				var result = moduleDef(require, module);

				// Support AMD modules which export through module.exports inside a define
				if (!result && module.exports)
				{
					return module.exports;
				}

				return result;
			};

			return getResult;
		};
		define.amd = true;

		// Finally, run the module with the overridden define and module objects.
		return (function()
		{
			__INJECTION_POINT__

			return getResult();
		})();
	}

	var injectorBlock = injector.toString().replace('__INJECTION_POINT__', source);

	results.push(injectorBlock);

	var tail = [
		'module.exports = injector;'
	];

	results = results.concat(tail).join('\n');

	return results;
};

module.exports = proxyLoader;
<|endoftext|>