<commit_before>/* global $, brackets, define */

define(function (require, exports, module) {
  'use strict';

  // imports
  var CodeInspection = brackets.getModule('language/CodeInspection');
  var ProjectManager = brackets.getModule('project/ProjectManager');
  var ExtensionUtils = brackets.getModule('utils/ExtensionUtils');
  var NodeDomain = brackets.getModule('utils/NodeDomain');
  var CommandManager = brackets.getModule('command/CommandManager');
  var Menus = brackets.getModule('command/Menus');
  var DocumentManager = brackets.getModule('document/DocumentManager');
  var EditorManager = brackets.getModule('editor/EditorManager');
  var PreferencesManager = brackets.getModule('preferences/PreferencesManager');
  var PackageJson = JSON.parse(require('text!./package.json'));
  var EXTENSION_NAME = PackageJson.name;
  var EXTENSION_UNIQUE_NAME = 'zaggino.' + EXTENSION_NAME;
  var AUTOFIX_COMMAND_ID = EXTENSION_UNIQUE_NAME + '.autofix';
  var AUTOFIX_COMMAND_NAME = 'Auto-fix with ESLint';

  // Load extension modules that are not included by core
  var gutterManager = require('src/GutterManager')();
  var preferences = PreferencesManager.getExtensionPrefs(EXTENSION_NAME);

  // Setup preferences used by the extension
  preferences.definePreference('gutterMarks', 'boolean', true);
  preferences.set('gutterMarks', preferences.get('gutterMarks'));

  // Constants
  var LINTER_NAME = 'ESLint';
  var nodeDomain = new NodeDomain(EXTENSION_UNIQUE_NAME, ExtensionUtils.getModulePath(module, 'domain'));

  // Load CSS
  ExtensionUtils.loadStyleSheet(module, 'styles/brackets-eslint.less');

  // this will map ESLint output to match format expected by Brackets
  function remapResults(results, version) {
    var SEVERITY_ERROR = 2;
    var SEVERITY_WARNING = 1;

    function mapResult(result) {
      var offset = version < 1 ? 0 : 1;
      var message = result.message;
      if (result.ruleId) {
        message += ' [' + result.ruleId + ']';
      }
      var severity;
      switch (result.severity) {
        case SEVERITY_ERROR:
          severity = 'ERROR: ';
          break;
        case SEVERITY_WARNING:
          severity = 'WARNING: ';
          break;
        default:
          severity = 'UNKNOWN: ';
      }
      return {
        message: severity + message,
        pos: {
          line: result.line - 1,
          ch: result.column - offset
        },
        type: result.ruleId
      };
    }

    return {
      errors: results.map(mapResult)
    };
  }

  function handleLintSync(text, fullPath) {
    throw new Error('ESLint sync is not available, use async for ' + fullPath);
  }

  function handleLintAsync(text, fullPath) {
    var deferred = new $.Deferred();
    var projectRoot = ProjectManager.getProjectRoot().fullPath;
    nodeDomain.exec('lintFile', fullPath, projectRoot)
      .then(function (report) {
        if (report === 'typescript-no-config') {
          deferred.resolve({ errors: [] });
        }
        if (report.results.length > 1) {
          // console.warn('ESLint returned multiple results, where only one set was expected');
        }
        var results = report.results[0];
        // if version is missing, assume 1
        var version = report.eslintVersion ? report.eslintVersion.split('.')[0] : 1;
        var remapped = remapResults(results.messages, version);
        var gutterMarksPref = preferences.get('gutterMarks', projectRoot);
        if (gutterMarksPref) {
          gutterManager.setGutterMarkers(results.messages, gutterMarksPref);
          gutterManager.refresh(fullPath);
        }
        deferred.resolve(remapped);
      }, function (err) {
        deferred.reject(err);
      });

    return deferred.promise();
  }

  function handleAutoFix() {
    var doc = DocumentManager.getCurrentDocument();
    var language = doc.getLanguage();
    var fileType = language._id;
    var fullPath = doc.file.fullPath;
    var editor = EditorManager.getCurrentFullEditor();
    var cursor = editor.getCursorPos();
    var scroll = editor.getScrollPos();

    // Do nothing unless it's a Javascript file
    if (fileType !== 'javascript') {
      return;
    }

    nodeDomain.exec('fixFile', doc.getText(), fullPath)
      .then(function (response) {
        var text = response && response.results[0] ? response.results[0].output : '';
        if (text) {
          doc.setText(text);
        }

        // Reset editor back to previous cursor position
        editor.setCursorPos(cursor);
        editor.setScrollPos(scroll.x, scroll.y);
      }/* TODO: Error handling?*/);
  }

  // =================================================================================

  // Register the auto-fix command
  CommandManager.register(AUTOFIX_COMMAND_NAME, AUTOFIX_COMMAND_ID, handleAutoFix);

  // Add to Edit menu
  var editMenu = Menus.getMenu(Menus.AppMenuBar.EDIT_MENU);
  editMenu.addMenuDivider();
  editMenu.addMenuItem(AUTOFIX_COMMAND_ID);

  // Add context-menu option (only for Javascript files)
  var contextMenu = Menus.getContextMenu(Menus.ContextMenuIds.EDITOR_MENU);
  contextMenu.addMenuItem(AUTOFIX_COMMAND_ID);

  // register a linter with CodeInspection
  ['javascript', 'jsx', 'typescript', 'tsx'].forEach(function (langId) {
    CodeInspection.register(langId, {
      name: LINTER_NAME,
      scanFile: handleLintSync,
      scanFileAsync: handleLintAsync
    });
  });

});
<commit_msg>Version 2.8.1<commit_after>/* global $, brackets, define */

define(function (require, exports, module) {
  'use strict';

  // imports
  var CodeInspection = brackets.getModule('language/CodeInspection');
  var ProjectManager = brackets.getModule('project/ProjectManager');
  var ExtensionUtils = brackets.getModule('utils/ExtensionUtils');
  var NodeDomain = brackets.getModule('utils/NodeDomain');
  var CommandManager = brackets.getModule('command/CommandManager');
  var Menus = brackets.getModule('command/Menus');
  var DocumentManager = brackets.getModule('document/DocumentManager');
  var EditorManager = brackets.getModule('editor/EditorManager');
  var PreferencesManager = brackets.getModule('preferences/PreferencesManager');
  var PackageJson = JSON.parse(require('text!./package.json'));
  var EXTENSION_NAME = PackageJson.name;
  var EXTENSION_UNIQUE_NAME = 'zaggino.' + EXTENSION_NAME;
  var AUTOFIX_COMMAND_ID = EXTENSION_UNIQUE_NAME + '.autofix';
  var AUTOFIX_COMMAND_NAME = 'Auto-fix with ESLint';

  // Load extension modules that are not included by core
  var gutterManager = require('src/GutterManager')();
  var preferences = PreferencesManager.getExtensionPrefs(EXTENSION_NAME);

  // Setup preferences used by the extension
  preferences.definePreference('gutterMarks', 'boolean', true);
  preferences.set('gutterMarks', preferences.get('gutterMarks'));

  // Constants
  var LINTER_NAME = 'ESLint';
  var nodeDomain = new NodeDomain(EXTENSION_UNIQUE_NAME, ExtensionUtils.getModulePath(module, 'domain'));

  // Load CSS
  ExtensionUtils.loadStyleSheet(module, 'styles/brackets-eslint.less');

  // this will map ESLint output to match format expected by Brackets
  function remapResults(results, version) {
    var SEVERITY_ERROR = 2;
    var SEVERITY_WARNING = 1;

    function mapResult(result) {
      var offset = version < 1 ? 0 : 1;
      var message = result.message;
      if (result.ruleId) {
        message += ' [' + result.ruleId + ']';
      }
      var severity;
      switch (result.severity) {
        case SEVERITY_ERROR:
          severity = 'ERROR: ';
          break;
        case SEVERITY_WARNING:
          severity = 'WARNING: ';
          break;
        default:
          severity = 'UNKNOWN: ';
      }
      return {
        message: severity + message,
        pos: {
          line: result.line - 1,
          ch: result.column - offset
        },
        type: result.ruleId
      };
    }

    return {
      errors: results.map(mapResult)
    };
  }

  function handleLintSync(text, fullPath) {
    throw new Error('ESLint sync is not available, use async for ' + fullPath);
  }

  function handleLintAsync(text, fullPath) {
    var deferred = new $.Deferred();
    var projectRoot = ProjectManager.getProjectRoot().fullPath;
    nodeDomain.exec('lintFile', fullPath, projectRoot)
      .then(function (report) {
        if (report === 'typescript-no-config') {
          return deferred.resolve({ errors: [] });
        }
        if (report.results.length > 1) {
          // console.warn('ESLint returned multiple results, where only one set was expected');
        }
        var results = report.results[0];
        // if version is missing, assume 1
        var version = report.eslintVersion ? report.eslintVersion.split('.')[0] : 1;
        var remapped = remapResults(results.messages, version);
        var gutterMarksPref = preferences.get('gutterMarks', projectRoot);
        if (gutterMarksPref) {
          gutterManager.setGutterMarkers(results.messages, gutterMarksPref);
          gutterManager.refresh(fullPath);
        }
        deferred.resolve(remapped);
      }, function (err) {
        deferred.reject(err);
      });

    return deferred.promise();
  }

  function handleAutoFix() {
    var doc = DocumentManager.getCurrentDocument();
    var language = doc.getLanguage();
    var fileType = language._id;
    var fullPath = doc.file.fullPath;
    var editor = EditorManager.getCurrentFullEditor();
    var cursor = editor.getCursorPos();
    var scroll = editor.getScrollPos();

    // Do nothing unless it's a Javascript file
    if (fileType !== 'javascript') {
      return;
    }

    nodeDomain.exec('fixFile', doc.getText(), fullPath)
      .then(function (response) {
        var text = response && response.results[0] ? response.results[0].output : '';
        if (text) {
          doc.setText(text);
        }

        // Reset editor back to previous cursor position
        editor.setCursorPos(cursor);
        editor.setScrollPos(scroll.x, scroll.y);
      }/* TODO: Error handling?*/);
  }

  // =================================================================================

  // Register the auto-fix command
  CommandManager.register(AUTOFIX_COMMAND_NAME, AUTOFIX_COMMAND_ID, handleAutoFix);

  // Add to Edit menu
  var editMenu = Menus.getMenu(Menus.AppMenuBar.EDIT_MENU);
  editMenu.addMenuDivider();
  editMenu.addMenuItem(AUTOFIX_COMMAND_ID);

  // Add context-menu option (only for Javascript files)
  var contextMenu = Menus.getContextMenu(Menus.ContextMenuIds.EDITOR_MENU);
  contextMenu.addMenuItem(AUTOFIX_COMMAND_ID);

  // register a linter with CodeInspection
  ['javascript', 'jsx', 'typescript', 'tsx'].forEach(function (langId) {
    CodeInspection.register(langId, {
      name: LINTER_NAME,
      scanFile: handleLintSync,
      scanFileAsync: handleLintAsync
    });
  });

});
<|endoftext|>


<commit_before>/* global __dirname, process */

const {
    BrowserWindow,
    Menu,
    app,
    ipcMain
} = require('electron');
const contextMenu = require('electron-context-menu');
const debug = require('electron-debug');
const isDev = require('electron-is-dev');
const { autoUpdater } = require('electron-updater');
const windowStateKeeper = require('electron-window-state');
const {
    initPopupsConfigurationMain,
    getPopupTarget,
    setupAlwaysOnTopMain,
    setupPowerMonitorMain,
    setupScreenSharingMain
} = require('jitsi-meet-electron-utils');
const path = require('path');
const URL = require('url');
const config = require('./app/features/config');
const { openExternalLink } = require('./app/features/utils/openExternalLink');

const showDevTools = Boolean(process.env.SHOW_DEV_TOOLS) || (process.argv.indexOf('--show-dev-tools') > -1);

// We need this because of https://github.com/electron/electron/issues/18214
app.commandLine.appendSwitch('disable-site-isolation-trials');

// Needed until robot.js is fixed: https://github.com/octalmage/robotjs/issues/580
app.allowRendererProcessReuse = false;

autoUpdater.logger = require('electron-log');
autoUpdater.logger.transports.file.level = 'info';

// Enable context menu so things like copy and paste work in input fields.
contextMenu({
    showLookUpSelection: false,
    showSearchWithGoogle: false,
    showCopyImage: false,
    showCopyImageAddress: false,
    showSaveImage: false,
    showSaveImageAs: false,
    showInspectElement: true,
    showServices: false
});

// Enable DevTools also on release builds to help troubleshoot issues. Don't
// show them automatically though.
debug({
    isEnabled: true,
    showDevTools
});

/**
 * When in development mode:
 * - Enable automatic reloads
 */
if (isDev) {
    require('electron-reload')(path.join(__dirname, 'build'));
}

/**
 * The window object that will load the iframe with Jitsi Meet.
 * IMPORTANT: Must be defined as global in order to not be garbage collected
 * acidentally.
 */
let mainWindow = null;

/**
 * Add protocol data
 */
const appProtocolSurplus = `${config.default.appProtocolPrefix}://`;
let rendererReady = false;
let protocolDataForFrontApp = null;

/**
 * Sets the application menu. It is hidden on all platforms except macOS because
 * otherwise copy and paste functionality is not available.
 */
function setApplicationMenu() {
    if (process.platform === 'darwin') {
        const template = [ {
            label: app.name,
            submenu: [
                {
                    role: 'services',
                    submenu: []
                },
                { type: 'separator' },
                { role: 'hide' },
                { role: 'hideothers' },
                { role: 'unhide' },
                { type: 'separator' },
                { role: 'quit' }
            ]
        }, {
            label: 'Edit',
            submenu: [ {
                label: 'Undo',
                accelerator: 'CmdOrCtrl+Z',
                selector: 'undo:'
            },
            {
                label: 'Redo',
                accelerator: 'Shift+CmdOrCtrl+Z',
                selector: 'redo:'
            },
            {
                type: 'separator'
            },
            {
                label: 'Cut',
                accelerator: 'CmdOrCtrl+X',
                selector: 'cut:'
            },
            {
                label: 'Copy',
                accelerator: 'CmdOrCtrl+C',
                selector: 'copy:'
            },
            {
                label: 'Paste',
                accelerator: 'CmdOrCtrl+V',
                selector: 'paste:'
            },
            {
                label: 'Select All',
                accelerator: 'CmdOrCtrl+A',
                selector: 'selectAll:'
            } ]
        }, {
            label: '&Window',
            role: 'window',
            submenu: [
                { role: 'minimize' },
                { role: 'close' }
            ]
        } ];

        Menu.setApplicationMenu(Menu.buildFromTemplate(template));
    } else {
        Menu.setApplicationMenu(null);
    }
}

/**
 * Opens new window with index.html(Jitsi Meet is loaded in iframe there).
 */
function createJitsiMeetWindow() {
    // Application menu.
    setApplicationMenu();

    // Check for Updates.
    autoUpdater.checkForUpdatesAndNotify();

    // Load the previous window state with fallback to defaults.
    const windowState = windowStateKeeper({
        defaultWidth: 800,
        defaultHeight: 600
    });

    // Path to root directory.
    const basePath = isDev ? __dirname : app.getAppPath();

    // URL for index.html which will be our entry point.
    const indexURL = URL.format({
        pathname: path.resolve(basePath, './build/index.html'),
        protocol: 'file:',
        slashes: true
    });

    // Options used when creating the main Jitsi Meet window.
    // Use a preload script in order to provide node specific functionality
    // to a isolated BrowserWindow in accordance with electron security
    // guideline.
    const options = {
        x: windowState.x,
        y: windowState.y,
        width: windowState.width,
        height: windowState.height,
        icon: path.resolve(basePath, './resources/icons/icon_512x512.png'),
        minWidth: 800,
        minHeight: 600,
        show: false,
        webPreferences: {
            enableRemoteModule: true,
            experimentalFeatures: true, // Insertable streams, for E2EE.
            nativeWindowOpen: true,
            nodeIntegration: false,
            preload: path.resolve(basePath, './build/preload.js')
        }
    };

    mainWindow = new BrowserWindow(options);
    windowState.manage(mainWindow);
    mainWindow.loadURL(indexURL);

    initPopupsConfigurationMain(mainWindow);
    setupAlwaysOnTopMain(mainWindow);
    setupPowerMonitorMain(mainWindow);
    setupScreenSharingMain(mainWindow, config.default.appName);

    mainWindow.webContents.on('new-window', (event, url, frameName) => {
        const target = getPopupTarget(url, frameName);

        if (!target || target === 'browser') {
            event.preventDefault();
            openExternalLink(url);
        }
    });
    mainWindow.on('closed', () => {
        mainWindow = null;
    });
    mainWindow.once('ready-to-show', () => {
        mainWindow.show();
    });

    /**
     * When someone tries to enter something like jitsi-meet://test
     *  while app is closed
     * it will trigger this event below
     */
    handleProtocolCall(process.argv.pop());
}

/**
 * Handler for application protocol links to initiate a conference.
 */
function handleProtocolCall(fullProtocolCall) {
    // don't touch when something is bad
    if (
        !fullProtocolCall
        || fullProtocolCall.trim() === ''
        || fullProtocolCall.indexOf(appProtocolSurplus) !== 0
    ) {
        return;
    }

    const inputURL = fullProtocolCall.replace(appProtocolSurplus, '');

    if (app.isReady() && mainWindow === null) {
        createJitsiMeetWindow();
    }

    protocolDataForFrontApp = inputURL;

    if (rendererReady) {
        mainWindow
            .webContents
            .send('protocol-data-msg', inputURL);
    }
}

/**
 * Force Single Instance Application.
 */
const gotInstanceLock = app.requestSingleInstanceLock();

if (!gotInstanceLock) {
    app.quit();
    process.exit(0);
}

/**
 * Run the application.
 */

app.on('activate', () => {
    if (mainWindow === null) {
        createJitsiMeetWindow();
    }
});

app.on('certificate-error',
    // eslint-disable-next-line max-params
    (event, webContents, url, error, certificate, callback) => {
        if (isDev) {
            event.preventDefault();
            callback(true);
        } else {
            callback(false);
        }
    }
);

app.on('ready', createJitsiMeetWindow);

app.on('second-instance', (event, commandLine) => {
    /**
     * If someone creates second instance of the application, set focus on
     * existing window.
     */
    if (mainWindow) {
        mainWindow.isMinimized() && mainWindow.restore();
        mainWindow.focus();

        /**
         * This is for windows [win32]
         * so when someone tries to enter something like jitsi-meet://test
         * while app is opened it will trigger protocol handler.
         */
        handleProtocolCall(commandLine.pop());
    }
});

app.on('window-all-closed', () => {
    // Don't quit the application on macOS.
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

// remove so we can register each time as we run the app.
app.removeAsDefaultProtocolClient(config.default.appProtocolPrefix);

// If we are running a non-packaged version of the app && on windows
if (isDev && process.platform === 'win32') {
    // Set the path of electron.exe and your app.
    // These two additional parameters are only available on windows.
    app.setAsDefaultProtocolClient(
        config.default.appProtocolPrefix,
        process.execPath,
        [ path.resolve(process.argv[1]) ]
    );
} else {
    app.setAsDefaultProtocolClient(config.default.appProtocolPrefix);
}

/**
 * This is for mac [darwin]
 * so when someone tries to enter something like jitsi-meet://test
 * it will trigger this event below
 */
app.on('open-url', (event, data) => {
    event.preventDefault();
    handleProtocolCall(data);
});

/**
 * This is to notify main.js [this] that front app is ready to receive messages.
 */
ipcMain.on('renderer-ready', () => {
    rendererReady = true;
    if (protocolDataForFrontApp) {
        mainWindow
            .webContents
            .send('protocol-data-msg', protocolDataForFrontApp);
    }
});
<commit_msg>Enable just insertable streams instead of all experimental features<commit_after>/* global __dirname, process */

const {
    BrowserWindow,
    Menu,
    app,
    ipcMain
} = require('electron');
const contextMenu = require('electron-context-menu');
const debug = require('electron-debug');
const isDev = require('electron-is-dev');
const { autoUpdater } = require('electron-updater');
const windowStateKeeper = require('electron-window-state');
const {
    initPopupsConfigurationMain,
    getPopupTarget,
    setupAlwaysOnTopMain,
    setupPowerMonitorMain,
    setupScreenSharingMain
} = require('jitsi-meet-electron-utils');
const path = require('path');
const URL = require('url');
const config = require('./app/features/config');
const { openExternalLink } = require('./app/features/utils/openExternalLink');

const showDevTools = Boolean(process.env.SHOW_DEV_TOOLS) || (process.argv.indexOf('--show-dev-tools') > -1);

// We need this because of https://github.com/electron/electron/issues/18214
app.commandLine.appendSwitch('disable-site-isolation-trials');

// Needed until robot.js is fixed: https://github.com/octalmage/robotjs/issues/580
app.allowRendererProcessReuse = false;

autoUpdater.logger = require('electron-log');
autoUpdater.logger.transports.file.level = 'info';

// Enable context menu so things like copy and paste work in input fields.
contextMenu({
    showLookUpSelection: false,
    showSearchWithGoogle: false,
    showCopyImage: false,
    showCopyImageAddress: false,
    showSaveImage: false,
    showSaveImageAs: false,
    showInspectElement: true,
    showServices: false
});

// Enable DevTools also on release builds to help troubleshoot issues. Don't
// show them automatically though.
debug({
    isEnabled: true,
    showDevTools
});

/**
 * When in development mode:
 * - Enable automatic reloads
 */
if (isDev) {
    require('electron-reload')(path.join(__dirname, 'build'));
}

/**
 * The window object that will load the iframe with Jitsi Meet.
 * IMPORTANT: Must be defined as global in order to not be garbage collected
 * acidentally.
 */
let mainWindow = null;

/**
 * Add protocol data
 */
const appProtocolSurplus = `${config.default.appProtocolPrefix}://`;
let rendererReady = false;
let protocolDataForFrontApp = null;

/**
 * Sets the application menu. It is hidden on all platforms except macOS because
 * otherwise copy and paste functionality is not available.
 */
function setApplicationMenu() {
    if (process.platform === 'darwin') {
        const template = [ {
            label: app.name,
            submenu: [
                {
                    role: 'services',
                    submenu: []
                },
                { type: 'separator' },
                { role: 'hide' },
                { role: 'hideothers' },
                { role: 'unhide' },
                { type: 'separator' },
                { role: 'quit' }
            ]
        }, {
            label: 'Edit',
            submenu: [ {
                label: 'Undo',
                accelerator: 'CmdOrCtrl+Z',
                selector: 'undo:'
            },
            {
                label: 'Redo',
                accelerator: 'Shift+CmdOrCtrl+Z',
                selector: 'redo:'
            },
            {
                type: 'separator'
            },
            {
                label: 'Cut',
                accelerator: 'CmdOrCtrl+X',
                selector: 'cut:'
            },
            {
                label: 'Copy',
                accelerator: 'CmdOrCtrl+C',
                selector: 'copy:'
            },
            {
                label: 'Paste',
                accelerator: 'CmdOrCtrl+V',
                selector: 'paste:'
            },
            {
                label: 'Select All',
                accelerator: 'CmdOrCtrl+A',
                selector: 'selectAll:'
            } ]
        }, {
            label: '&Window',
            role: 'window',
            submenu: [
                { role: 'minimize' },
                { role: 'close' }
            ]
        } ];

        Menu.setApplicationMenu(Menu.buildFromTemplate(template));
    } else {
        Menu.setApplicationMenu(null);
    }
}

/**
 * Opens new window with index.html(Jitsi Meet is loaded in iframe there).
 */
function createJitsiMeetWindow() {
    // Application menu.
    setApplicationMenu();

    // Check for Updates.
    autoUpdater.checkForUpdatesAndNotify();

    // Load the previous window state with fallback to defaults.
    const windowState = windowStateKeeper({
        defaultWidth: 800,
        defaultHeight: 600
    });

    // Path to root directory.
    const basePath = isDev ? __dirname : app.getAppPath();

    // URL for index.html which will be our entry point.
    const indexURL = URL.format({
        pathname: path.resolve(basePath, './build/index.html'),
        protocol: 'file:',
        slashes: true
    });

    // Options used when creating the main Jitsi Meet window.
    // Use a preload script in order to provide node specific functionality
    // to a isolated BrowserWindow in accordance with electron security
    // guideline.
    const options = {
        x: windowState.x,
        y: windowState.y,
        width: windowState.width,
        height: windowState.height,
        icon: path.resolve(basePath, './resources/icons/icon_512x512.png'),
        minWidth: 800,
        minHeight: 600,
        show: false,
        webPreferences: {
            enableBlinkFeatures: 'RTCInsertableStreams',
            enableRemoteModule: true,
            nativeWindowOpen: true,
            nodeIntegration: false,
            preload: path.resolve(basePath, './build/preload.js')
        }
    };

    mainWindow = new BrowserWindow(options);
    windowState.manage(mainWindow);
    mainWindow.loadURL(indexURL);

    initPopupsConfigurationMain(mainWindow);
    setupAlwaysOnTopMain(mainWindow);
    setupPowerMonitorMain(mainWindow);
    setupScreenSharingMain(mainWindow, config.default.appName);

    mainWindow.webContents.on('new-window', (event, url, frameName) => {
        const target = getPopupTarget(url, frameName);

        if (!target || target === 'browser') {
            event.preventDefault();
            openExternalLink(url);
        }
    });
    mainWindow.on('closed', () => {
        mainWindow = null;
    });
    mainWindow.once('ready-to-show', () => {
        mainWindow.show();
    });

    /**
     * When someone tries to enter something like jitsi-meet://test
     *  while app is closed
     * it will trigger this event below
     */
    handleProtocolCall(process.argv.pop());
}

/**
 * Handler for application protocol links to initiate a conference.
 */
function handleProtocolCall(fullProtocolCall) {
    // don't touch when something is bad
    if (
        !fullProtocolCall
        || fullProtocolCall.trim() === ''
        || fullProtocolCall.indexOf(appProtocolSurplus) !== 0
    ) {
        return;
    }

    const inputURL = fullProtocolCall.replace(appProtocolSurplus, '');

    if (app.isReady() && mainWindow === null) {
        createJitsiMeetWindow();
    }

    protocolDataForFrontApp = inputURL;

    if (rendererReady) {
        mainWindow
            .webContents
            .send('protocol-data-msg', inputURL);
    }
}

/**
 * Force Single Instance Application.
 */
const gotInstanceLock = app.requestSingleInstanceLock();

if (!gotInstanceLock) {
    app.quit();
    process.exit(0);
}

/**
 * Run the application.
 */

app.on('activate', () => {
    if (mainWindow === null) {
        createJitsiMeetWindow();
    }
});

app.on('certificate-error',
    // eslint-disable-next-line max-params
    (event, webContents, url, error, certificate, callback) => {
        if (isDev) {
            event.preventDefault();
            callback(true);
        } else {
            callback(false);
        }
    }
);

app.on('ready', createJitsiMeetWindow);

app.on('second-instance', (event, commandLine) => {
    /**
     * If someone creates second instance of the application, set focus on
     * existing window.
     */
    if (mainWindow) {
        mainWindow.isMinimized() && mainWindow.restore();
        mainWindow.focus();

        /**
         * This is for windows [win32]
         * so when someone tries to enter something like jitsi-meet://test
         * while app is opened it will trigger protocol handler.
         */
        handleProtocolCall(commandLine.pop());
    }
});

app.on('window-all-closed', () => {
    // Don't quit the application on macOS.
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

// remove so we can register each time as we run the app.
app.removeAsDefaultProtocolClient(config.default.appProtocolPrefix);

// If we are running a non-packaged version of the app && on windows
if (isDev && process.platform === 'win32') {
    // Set the path of electron.exe and your app.
    // These two additional parameters are only available on windows.
    app.setAsDefaultProtocolClient(
        config.default.appProtocolPrefix,
        process.execPath,
        [ path.resolve(process.argv[1]) ]
    );
} else {
    app.setAsDefaultProtocolClient(config.default.appProtocolPrefix);
}

/**
 * This is for mac [darwin]
 * so when someone tries to enter something like jitsi-meet://test
 * it will trigger this event below
 */
app.on('open-url', (event, data) => {
    event.preventDefault();
    handleProtocolCall(data);
});

/**
 * This is to notify main.js [this] that front app is ready to receive messages.
 */
ipcMain.on('renderer-ready', () => {
    rendererReady = true;
    if (protocolDataForFrontApp) {
        mainWindow
            .webContents
            .send('protocol-data-msg', protocolDataForFrontApp);
    }
});
<|endoftext|>


<commit_before>var $ = document.querySelectorAll.bind(document);

var GAME = {
	board: new Board()
}

'tile tile-0-0 tile-phase-1'

var $grid = $('.grid')[0]
Events.on('move', function(move) {
	if (move.fromRow === move.toRow && move.fromCol === move.toCol) return;
	var $tiles = $('.tile-'+move.fromRow+'-'+move.fromCol)
	var $old = $('.tile-'+move.toRow+'-'+move.toCol)[0]
	_.map($tiles, function($tile) {
		$tile.className = $tile.className.replace(/tile-\d-\d/, 'tile-'+move.toRow+'-'+move.toCol)
	})

	if ($old) {
		setTimeout(function() {
			_.map($tiles, function($tile) {
				try {
					$tile.parentElement.removeChild($tile)
				} catch(e) {
				}
			})
		}, 1000)
	}
})

Events.on('spawn', function(spawn) {
	var $div = document.createElement('div')
	var $tile = document.createElement('div')
	$tile.setAttribute('class', 'tile '+'tile-'+spawn.row+'-'+spawn.col+' tile-phase-'+(spawn.color-1))
	$tile.appendChild($div)
	$grid.appendChild($tile)
})

var maxColor = 1
Events.on('setColor', function(elem) {
	var $tiles = $('.tile-'+elem.row+'-'+elem.col)
	try {
		_.map($tiles, function($tile) {
			$tile.className = $tile.className.replace(/tile-phase-\d/, 'tile-phase-'+(elem.color-1))
		})

		if (elem.color > maxColor) {
			maxColor = elem.color
			$progress = $('#progress-cover')[0]
			$progress.className = $progress.className.replace(/progress-\d/, 'progress-'+(maxColor-1))
		}
	} catch (e) {}
})

Events.on('gameOver', function() {
	var infoScreen = document.getElementById('info-screen')
	infoScreen.className = 'show'
	var gameOverBox = document.getElementById('game-over-box')
	var challengeButton = document.createElement('button')
	challengeButton.innerText = 'Challenge a Friend'
	// Should add some sort of fastclick here... (touch first)
	challengeButton.addEventListener('click', function() {
		Events.emit('challengeFriend')
	})
	gameOverBox.appendChild(challengeButton)
})

Events.on('challengeFriend', function() {
	var score = 0;
	Clay.Social.smartShare({
		message: 'Think you can beat my score?'
		title: 'I just scored ' + score + ' in Prism!',
		//image: screenshotURL,
		data: {},
		//respond: // the username of our opponent // cards.kik.returnToConversation
	})
})

// keybindings
Hammer(window).on("swipeleft", function(e) {
	e.preventDefault()
	GAME.board.move('left')
}).on("swiperight", function(e) {
	e.preventDefault()
	GAME.board.move('right')
}).on("swipeup", function(e) {
	e.preventDefault()
	GAME.board.move('up')
}).on("swipedown", function(e) {
	e.preventDefault()
	GAME.board.move('down')
});

Mousetrap.bind(['up', 'down', 'left', 'right'], function(e) {
	GAME.board.move(e.keyIdentifier.toLowerCase())
});

// init
GAME.board.spawn()
GAME.board.spawn()

function sizing() {
	var gridWidth = $grid.offsetWidth
	var gridHeight = $grid.offsetHeight
	var boxSize = Math.min(gridWidth, gridHeight) + 'px'
	$grid.style.width = boxSize
	$grid.style.height = boxSize
	$('.grid-background')[0].style.width = boxSize
	$('.grid-background')[0].style.height = boxSize
}
sizing()
$grid.style.visibility = 'visible'
$('.grid-background')[0].style.visibility = 'visible'
window.onresize = sizing
<commit_msg>forgot comma<commit_after>var $ = document.querySelectorAll.bind(document);

var GAME = {
	board: new Board()
}

'tile tile-0-0 tile-phase-1'

var $grid = $('.grid')[0]
Events.on('move', function(move) {
	if (move.fromRow === move.toRow && move.fromCol === move.toCol) return;
	var $tiles = $('.tile-'+move.fromRow+'-'+move.fromCol)
	var $old = $('.tile-'+move.toRow+'-'+move.toCol)[0]
	_.map($tiles, function($tile) {
		$tile.className = $tile.className.replace(/tile-\d-\d/, 'tile-'+move.toRow+'-'+move.toCol)
	})

	if ($old) {
		setTimeout(function() {
			_.map($tiles, function($tile) {
				try {
					$tile.parentElement.removeChild($tile)
				} catch(e) {
				}
			})
		}, 1000)
	}
})

Events.on('spawn', function(spawn) {
	var $div = document.createElement('div')
	var $tile = document.createElement('div')
	$tile.setAttribute('class', 'tile '+'tile-'+spawn.row+'-'+spawn.col+' tile-phase-'+(spawn.color-1))
	$tile.appendChild($div)
	$grid.appendChild($tile)
})

var maxColor = 1
Events.on('setColor', function(elem) {
	var $tiles = $('.tile-'+elem.row+'-'+elem.col)
	try {
		_.map($tiles, function($tile) {
			$tile.className = $tile.className.replace(/tile-phase-\d/, 'tile-phase-'+(elem.color-1))
		})

		if (elem.color > maxColor) {
			maxColor = elem.color
			$progress = $('#progress-cover')[0]
			$progress.className = $progress.className.replace(/progress-\d/, 'progress-'+(maxColor-1))
		}
	} catch (e) {}
})

Events.on('gameOver', function() {
	var infoScreen = document.getElementById('info-screen')
	infoScreen.className = 'show'
	var gameOverBox = document.getElementById('game-over-box')
	var challengeButton = document.createElement('button')
	challengeButton.innerText = 'Challenge a Friend'
	// Should add some sort of fastclick here... (touch first)
	challengeButton.addEventListener('click', function() {
		Events.emit('challengeFriend')
	})
	gameOverBox.appendChild(challengeButton)
})

Events.on('challengeFriend', function() {
	var score = 0;
	Clay.Social.smartShare({
		message: 'Think you can beat my score?',
		title: 'I just scored ' + score + ' in Prism!',
		//image: screenshotURL,
		data: {},
		//respond: // the username of our opponent // cards.kik.returnToConversation
	})
})

// keybindings
Hammer(window).on("swipeleft", function(e) {
	e.preventDefault()
	GAME.board.move('left')
}).on("swiperight", function(e) {
	e.preventDefault()
	GAME.board.move('right')
}).on("swipeup", function(e) {
	e.preventDefault()
	GAME.board.move('up')
}).on("swipedown", function(e) {
	e.preventDefault()
	GAME.board.move('down')
});

Mousetrap.bind(['up', 'down', 'left', 'right'], function(e) {
	GAME.board.move(e.keyIdentifier.toLowerCase())
});

// init
GAME.board.spawn()
GAME.board.spawn()

function sizing() {
	var gridWidth = $grid.offsetWidth
	var gridHeight = $grid.offsetHeight
	var boxSize = Math.min(gridWidth, gridHeight) + 'px'
	$grid.style.width = boxSize
	$grid.style.height = boxSize
	$('.grid-background')[0].style.width = boxSize
	$('.grid-background')[0].style.height = boxSize
}
sizing()
$grid.style.visibility = 'visible'
$('.grid-background')[0].style.visibility = 'visible'
window.onresize = sizing
<|endoftext|>


<commit_before>var sidebar = new ol.control.Sidebar({ element: 'sidebar', position: 'right' });

var projection = ol.proj.get('EPSG:3857');
var projectionExtent = projection.getExtent();
var size = ol.extent.getWidth(projectionExtent) / 256;
var resolutions = new Array(20);
var matrixIds = new Array(20);
for (var z = 0; z < 20; ++z) {
    // generate resolutions and matrixIds arrays for this WMTS
    resolutions[z] = size / Math.pow(2, z);
    matrixIds[z] = z;
}
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var closer = document.getElementById('popup-closer');
var rivers = ['1580', '1590', '1600', '1630', '1650', '1660'];

closer.onclick = function() {
  popup.setPosition(undefined);
  closer.blur();
  return false;
};

var popup = new ol.Overlay({
  element: container,
  autoPan: true,
  autoPanAnimation: {
    duration: 250
  }
});

var nlscMatrixIds = new Array(21);
for (var i=0; i<21; ++i) {
  nlscMatrixIds[i] = i;
}

var styleLines = new ol.style.Style({
  stroke: new ol.style.Stroke({
      color: 'rgba(86,113,228,0.7)',
      width: 3
  })
});

var styleAreas = new ol.style.Style({
  stroke: new ol.style.Stroke({
      color: 'rgba(86,113,228,0.7)',
      width: 3
  }),
  fill: new ol.style.Fill({
      color: 'rgba(86,113,228,0.3)',
  })
});

var styleWalk = new ol.style.Style({
  stroke: new ol.style.Stroke({
      color: 'rgba(82,184,48,0.7)',
      width: 8
  }),
  image: new ol.style.Circle({
    radius: 10,
    fill: new ol.style.Fill({
      color: 'rgba(82,184,48,0.7)',
    })
  }),
});

var vectorLines = new ol.layer.Vector({
  source: new ol.source.Vector({
    url: 'lines.json',
    format: new ol.format.GeoJSON()
  }),
  style: styleLines
});

var vectorAreas = new ol.layer.Vector({
  source: new ol.source.Vector({
    url: 'areas.json',
    format: new ol.format.GeoJSON()
  }),
  style:styleAreas
});

var vectorWalk = new ol.layer.Vector({
  source: new ol.source.Vector({
    url: 'walk.json',
    format: new ol.format.GeoJSON()
  }),
  style:styleWalk
});

var baseLayer = new ol.layer.Tile({
    source: new ol.source.WMTS({
        matrixSet: 'EPSG:3857',
        format: 'image/png',
        url: 'https://wmts.nlsc.gov.tw/wmts',
        layer: 'EMAP',
        tileGrid: new ol.tilegrid.WMTS({
            origin: ol.extent.getTopLeft(projectionExtent),
            resolutions: resolutions,
            matrixIds: matrixIds
        }),
        style: 'default',
        wrapX: true,
        attributions: '國土測繪圖資服務雲'
    }),
    opacity: 0.5
});

var targetLayer;
var pointStyle = new ol.style.Style({
  image: new ol.style.Circle({
    radius: 10,
    fill: new ol.style.Fill({
      color: [249, 157, 34, 0.7]
    })
  }),
  text: new ol.style.Text({
    font: 'bold 16px "Open Sans", "Arial Unicode MS", "sans-serif"',
    fill: new ol.style.Fill({
      color: [215, 48, 39, 0.7]
    })
  })
});
var pointRedStyle = new ol.style.Style({
  image: new ol.style.Circle({
    radius: 10,
    fill: new ol.style.Fill({
      color: [243, 0, 80, 0.7]
    })
  })
});
var pointGreenStyle = new ol.style.Style({
  image: new ol.style.Circle({
    radius: 10,
    fill: new ol.style.Fill({
      color: [0, 243, 80, 0.7]
    })
  })
});

var points;
$.get('points.json', function(jPoints) {
  points = jPoints;
  var fc = [];
  for(k in points) {
    if (k.substr(0, 1) !== 'V') {
      continue;
    }
    var p = points[k];
    p.fType = 'img';
    p.geometry = new ol.geom.Point(ol.proj.fromLonLat([p.longitude, p.latitude]));
    var f = new ol.Feature(p);
    fc.push(f);
  }
  targetLayer = new ol.layer.Vector({
    source: new ol.source.Vector({
      features: fc
    }),
    style: function(f) {
      var fStyle = pointStyle.clone();
      fStyle.getText().setText(f.get('name'));
      return fStyle;
    },
    map: map
  });
})

var appView = new ol.View({
  center: ol.proj.fromLonLat([120.20345985889435, 22.994906062625773]),
  zoom: 14
});

var map = new ol.Map({
  layers: [baseLayer, vectorLines, vectorAreas],
  overlays: [popup],
  target: 'map',
  view: appView
});

map.addControl(sidebar);

var geolocation = new ol.Geolocation({
  projection: appView.getProjection()
});

geolocation.setTracking(true);

geolocation.on('error', function(error) {
        console.log(error.message);
      });

var positionFeature = new ol.Feature();

positionFeature.setStyle(new ol.style.Style({
  image: new ol.style.Circle({
    radius: 6,
    fill: new ol.style.Fill({
      color: '#3399CC'
    }),
    stroke: new ol.style.Stroke({
      color: '#fff',
      width: 2
    })
  })
}));

var geolocationCentered = false;
geolocation.on('change:position', function() {
  var coordinates = geolocation.getPosition();
  if(coordinates) {
    positionFeature.setGeometry(new ol.geom.Point(coordinates));
    if(false === geolocationCentered) {
      map.getView().setCenter(coordinates);
      geolocationCentered = true;
    }
  }
});

new ol.layer.Vector({
  map: map,
  source: new ol.source.Vector({
    features: [positionFeature]
  })
});

map.on('singleclick', function(evt) {
  map.getView().setZoom(17);
  var sideBarOpened = false;
  $('#sidebar-main-block').html('');
  map.forEachFeatureAtPixel(evt.pixel, function (feature, layer) {
    var p = feature.getProperties();
    var message = '';
    if(p.RIV_NA) {
      message += '
' + p.RIV_NA + '
';
      message += '
河川: ' + p.RV_NAME;
      message += '
河川排水: ' + p.RIV_NA;
      $('#sidebar-main-block').append(message);
      if(false === sideBarOpened) {
        sideBarOpened = true;
        sidebar.open('home');
        map.getView().fit(feature.getGeometry());
      }
    } else if(p.DR_NAME) {
      message += '
' + p.DR_NAME + '
';
      message += '
河川: ' + p.RV_NAME;
      message += '
行政區: ' + p.TOWN_NAME;
      $('#sidebar-main-block').append(message);
      if(false === sideBarOpened) {
        sideBarOpened = true;
        sidebar.open('home');
        map.getView().fit(feature.getGeometry());
      }
    } else if(p.code) {
      message += '
' + p.name + '
';
      message += '
站碼: ' + p.code;
      message += '
河川分區: ' + p.type;
      message += '
行政區: ' + p.area;
      message += '
轄管單位: ' + p.admin;
      message += '
河川排水: ' + p.river;
      if(p.image && p.image !== '') {
        message += '
';
      } else {
        message += '
警戒狀態: ' + p.alert_level;
        message += '
說明: ' + p.warn_info;
        message += '
時間: ' + p.date;
      }
      $('#sidebar-main-block').append(message);
      if(false === sideBarOpened) {
        var fCenter = feature.getGeometry().getCoordinates();
        sideBarOpened = true;
        sidebar.open('home');
        map.getView().setCenter(fCenter);
      }
    }
  });
});

var riverLayers = [];
for (k in rivers) {
  $.getJSON('http://210.61.23.112/tainanwatermobile/TainanLocalWst/GetLocalWstWarnInfo3.aspx?basin=' + rivers[k], {}, function (i) {
    var riverFc = [];
    for (g in i.local_wst_warn_info) {
        var key = i.local_wst_warn_info[g].st_no;
        if (key.substr(0, 1) === 'V') {
          continue;
        }
        if (!points[key]) {
            console.log(key);
            continue;
        }
        points[key].alert_level = i.local_wst_warn_info[g].alert_level;
        points[key].change = i.local_wst_warn_info[g].change;
        points[key].date = i.local_wst_warn_info[g].date;
        points[key].info = i.local_wst_warn_info[g].info;
        points[key].warn_info = i.local_wst_warn_info[g].warn_info;
        var p = points[key];
        if(p.alert_level === '未達警戒') {
          p.fType = 'green';
        } else {
          p.fType = 'red';
        }
        p.geometry = new ol.geom.Point(ol.proj.fromLonLat([points[key].longitude, points[key].latitude]));
        var f = new ol.Feature(p);
        riverFc.push(f);
    }
    var riverLayer = new ol.layer.Vector({
      source: new ol.source.Vector({
        features: riverFc
      }),
      style: function(f) {
        var fStyle;
        if(f.get('alert_level') === '未達警戒') {
          fStyle = pointGreenStyle.clone();
        } else {
          fStyle = pointRedStyle.clone();
        }
        return fStyle;
      },
      map: map
    });
    riverLayers.push(riverLayer);
  });
}

$('a.btnShowAll').click(function() {
  sidebar.close();
  var baseExtent = ol.extent.createEmpty();
  map.getLayers().forEach(function(layer) {
    if(layer instanceof ol.layer.Vector) {
      ol.extent.extend(baseExtent, layer.getSource().getExtent());
    }
  });
  map.getView().fit(baseExtent);

  for(k in riverLayers) {
    riverLayers[k].getSource().forEachFeature(function(f) {
      if(f.get('fType') === 'green') {
        f.setStyle(pointGreenStyle);
      } else {
        f.setStyle(pointRedStyle);
      }
    })
  }
  targetLayer.getSource().forEachFeature(function(f) {
    var fStyle = pointStyle.clone();
    fStyle.getText().setText(f.get('name'));
    f.setStyle(fStyle);
  });

  return false;
});

var emptyStyle = new ol.style.Style({ image: '' });

$('a.btnShowImg').click(function() {
  sidebar.close();
  var baseExtent = ol.extent.createEmpty();
  for(k in riverLayers) {
    riverLayers[k].getSource().forEachFeature(function(f) {
      f.setStyle(emptyStyle);
    })
  }
  targetLayer.getSource().forEachFeature(function(f) {
    var fStyle = pointStyle.clone();
    fStyle.getText().setText(f.get('name'));
    f.setStyle(fStyle);
    ol.extent.extend(baseExtent, f.getGeometry().getExtent());
  });
  map.getView().fit(baseExtent);
  return false;
});

$('a.btnShowRed').click(function() {
  sidebar.close();
  var baseExtent = ol.extent.createEmpty();
  for(k in riverLayers) {
    riverLayers[k].getSource().forEachFeature(function(f) {
      if(f.get('fType') === 'green') {
        f.setStyle(emptyStyle);
      } else {
        ol.extent.extend(baseExtent, f.getGeometry().getExtent());
        f.setStyle(pointRedStyle);
      }
    })
  }
  targetLayer.getSource().forEachFeature(function(f) {
    f.setStyle(emptyStyle);
  });
  map.getView().fit(baseExtent);
  return false;
});
<commit_msg>a dirty way to use real time data<commit_after>var sidebar = new ol.control.Sidebar({ element: 'sidebar', position: 'right' });

var projection = ol.proj.get('EPSG:3857');
var projectionExtent = projection.getExtent();
var size = ol.extent.getWidth(projectionExtent) / 256;
var resolutions = new Array(20);
var matrixIds = new Array(20);
for (var z = 0; z < 20; ++z) {
    // generate resolutions and matrixIds arrays for this WMTS
    resolutions[z] = size / Math.pow(2, z);
    matrixIds[z] = z;
}
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var closer = document.getElementById('popup-closer');
var rivers = ['1580', '1590', '1600', '1630', '1650', '1660'];

closer.onclick = function() {
  popup.setPosition(undefined);
  closer.blur();
  return false;
};

var popup = new ol.Overlay({
  element: container,
  autoPan: true,
  autoPanAnimation: {
    duration: 250
  }
});

var nlscMatrixIds = new Array(21);
for (var i=0; i<21; ++i) {
  nlscMatrixIds[i] = i;
}

var styleLines = new ol.style.Style({
  stroke: new ol.style.Stroke({
      color: 'rgba(86,113,228,0.7)',
      width: 3
  })
});

var styleAreas = new ol.style.Style({
  stroke: new ol.style.Stroke({
      color: 'rgba(86,113,228,0.7)',
      width: 3
  }),
  fill: new ol.style.Fill({
      color: 'rgba(86,113,228,0.3)',
  })
});

var styleWalk = new ol.style.Style({
  stroke: new ol.style.Stroke({
      color: 'rgba(82,184,48,0.7)',
      width: 8
  }),
  image: new ol.style.Circle({
    radius: 10,
    fill: new ol.style.Fill({
      color: 'rgba(82,184,48,0.7)',
    })
  }),
});

var vectorLines = new ol.layer.Vector({
  source: new ol.source.Vector({
    url: 'lines.json',
    format: new ol.format.GeoJSON()
  }),
  style: styleLines
});

var vectorAreas = new ol.layer.Vector({
  source: new ol.source.Vector({
    url: 'areas.json',
    format: new ol.format.GeoJSON()
  }),
  style:styleAreas
});

var vectorWalk = new ol.layer.Vector({
  source: new ol.source.Vector({
    url: 'walk.json',
    format: new ol.format.GeoJSON()
  }),
  style:styleWalk
});

var baseLayer = new ol.layer.Tile({
    source: new ol.source.WMTS({
        matrixSet: 'EPSG:3857',
        format: 'image/png',
        url: 'https://wmts.nlsc.gov.tw/wmts',
        layer: 'EMAP',
        tileGrid: new ol.tilegrid.WMTS({
            origin: ol.extent.getTopLeft(projectionExtent),
            resolutions: resolutions,
            matrixIds: matrixIds
        }),
        style: 'default',
        wrapX: true,
        attributions: '國土測繪圖資服務雲'
    }),
    opacity: 0.5
});

var targetLayer;
var pointStyle = new ol.style.Style({
  image: new ol.style.Circle({
    radius: 10,
    fill: new ol.style.Fill({
      color: [249, 157, 34, 0.7]
    })
  }),
  text: new ol.style.Text({
    font: 'bold 16px "Open Sans", "Arial Unicode MS", "sans-serif"',
    fill: new ol.style.Fill({
      color: [215, 48, 39, 0.7]
    })
  })
});
var pointRedStyle = new ol.style.Style({
  image: new ol.style.Circle({
    radius: 10,
    fill: new ol.style.Fill({
      color: [243, 0, 80, 0.7]
    })
  })
});
var pointGreenStyle = new ol.style.Style({
  image: new ol.style.Circle({
    radius: 10,
    fill: new ol.style.Fill({
      color: [0, 243, 80, 0.7]
    })
  })
});

var points;
$.get('points.json', function(jPoints) {
  points = jPoints;
  var fc = [];
  for(k in points) {
    if (k.substr(0, 1) !== 'V') {
      continue;
    }
    var p = points[k];
    p.fType = 'img';
    p.geometry = new ol.geom.Point(ol.proj.fromLonLat([p.longitude, p.latitude]));
    var f = new ol.Feature(p);
    fc.push(f);
  }
  targetLayer = new ol.layer.Vector({
    source: new ol.source.Vector({
      features: fc
    }),
    style: function(f) {
      var fStyle = pointStyle.clone();
      fStyle.getText().setText(f.get('name'));
      return fStyle;
    },
    map: map
  });
})

var appView = new ol.View({
  center: ol.proj.fromLonLat([120.20345985889435, 22.994906062625773]),
  zoom: 14
});

var map = new ol.Map({
  layers: [baseLayer, vectorLines, vectorAreas],
  overlays: [popup],
  target: 'map',
  view: appView
});

map.addControl(sidebar);

var geolocation = new ol.Geolocation({
  projection: appView.getProjection()
});

geolocation.setTracking(true);

geolocation.on('error', function(error) {
        console.log(error.message);
      });

var positionFeature = new ol.Feature();

positionFeature.setStyle(new ol.style.Style({
  image: new ol.style.Circle({
    radius: 6,
    fill: new ol.style.Fill({
      color: '#3399CC'
    }),
    stroke: new ol.style.Stroke({
      color: '#fff',
      width: 2
    })
  })
}));

var geolocationCentered = false;
geolocation.on('change:position', function() {
  var coordinates = geolocation.getPosition();
  if(coordinates) {
    positionFeature.setGeometry(new ol.geom.Point(coordinates));
    if(false === geolocationCentered) {
      map.getView().setCenter(coordinates);
      geolocationCentered = true;
    }
  }
});

new ol.layer.Vector({
  map: map,
  source: new ol.source.Vector({
    features: [positionFeature]
  })
});

map.on('singleclick', function(evt) {
  map.getView().setZoom(17);
  var sideBarOpened = false;
  $('#sidebar-main-block').html('');
  map.forEachFeatureAtPixel(evt.pixel, function (feature, layer) {
    var p = feature.getProperties();
    var message = '';
    if(p.RIV_NA) {
      message += '
' + p.RIV_NA + '
';
      message += '
河川: ' + p.RV_NAME;
      message += '
河川排水: ' + p.RIV_NA;
      $('#sidebar-main-block').append(message);
      if(false === sideBarOpened) {
        sideBarOpened = true;
        sidebar.open('home');
        map.getView().fit(feature.getGeometry());
      }
    } else if(p.DR_NAME) {
      message += '
' + p.DR_NAME + '
';
      message += '
河川: ' + p.RV_NAME;
      message += '
行政區: ' + p.TOWN_NAME;
      $('#sidebar-main-block').append(message);
      if(false === sideBarOpened) {
        sideBarOpened = true;
        sidebar.open('home');
        map.getView().fit(feature.getGeometry());
      }
    } else if(p.code) {
      message += '
' + p.name + '
';
      message += '
站碼: ' + p.code;
      message += '
河川分區: ' + p.type;
      message += '
行政區: ' + p.area;
      message += '
轄管單位: ' + p.admin;
      message += '
河川排水: ' + p.river;
      if(p.image && p.image !== '') {
        message += '
';
      } else {
        message += '
警戒狀態: ' + p.alert_level;
        message += '
說明: ' + p.warn_info;
        message += '
時間: ' + p.date;
      }
      $('#sidebar-main-block').append(message);
      if(false === sideBarOpened) {
        var fCenter = feature.getGeometry().getCoordinates();
        sideBarOpened = true;
        sidebar.open('home');
        map.getView().setCenter(fCenter);
      }
    }
  });
});

var riverLayers = [];
for (k in rivers) {
  $.getJSON('https://h.olc.tw/TainanWaterMap.php?river=' + rivers[k], {}, function (i) {
    var riverFc = [];
    for (g in i.local_wst_warn_info) {
        var key = i.local_wst_warn_info[g].st_no;
        if (key.substr(0, 1) === 'V') {
          continue;
        }
        if (!points[key]) {
            console.log(key);
            continue;
        }
        points[key].alert_level = i.local_wst_warn_info[g].alert_level;
        points[key].change = i.local_wst_warn_info[g].change;
        points[key].date = i.local_wst_warn_info[g].date;
        points[key].info = i.local_wst_warn_info[g].info;
        points[key].warn_info = i.local_wst_warn_info[g].warn_info;
        var p = points[key];
        if(p.alert_level === '未達警戒') {
          p.fType = 'green';
        } else {
          p.fType = 'red';
        }
        p.geometry = new ol.geom.Point(ol.proj.fromLonLat([points[key].longitude, points[key].latitude]));
        var f = new ol.Feature(p);
        riverFc.push(f);
    }
    var riverLayer = new ol.layer.Vector({
      source: new ol.source.Vector({
        features: riverFc
      }),
      style: function(f) {
        var fStyle;
        if(f.get('alert_level') === '未達警戒') {
          fStyle = pointGreenStyle.clone();
        } else {
          fStyle = pointRedStyle.clone();
        }
        return fStyle;
      },
      map: map
    });
    riverLayers.push(riverLayer);
  });
}

$('a.btnShowAll').click(function() {
  sidebar.close();
  var baseExtent = ol.extent.createEmpty();
  map.getLayers().forEach(function(layer) {
    if(layer instanceof ol.layer.Vector) {
      ol.extent.extend(baseExtent, layer.getSource().getExtent());
    }
  });
  map.getView().fit(baseExtent);

  for(k in riverLayers) {
    riverLayers[k].getSource().forEachFeature(function(f) {
      if(f.get('fType') === 'green') {
        f.setStyle(pointGreenStyle);
      } else {
        f.setStyle(pointRedStyle);
      }
    })
  }
  targetLayer.getSource().forEachFeature(function(f) {
    var fStyle = pointStyle.clone();
    fStyle.getText().setText(f.get('name'));
    f.setStyle(fStyle);
  });

  return false;
});

var emptyStyle = new ol.style.Style({ image: '' });

$('a.btnShowImg').click(function() {
  sidebar.close();
  var baseExtent = ol.extent.createEmpty();
  for(k in riverLayers) {
    riverLayers[k].getSource().forEachFeature(function(f) {
      f.setStyle(emptyStyle);
    })
  }
  targetLayer.getSource().forEachFeature(function(f) {
    var fStyle = pointStyle.clone();
    fStyle.getText().setText(f.get('name'));
    f.setStyle(fStyle);
    ol.extent.extend(baseExtent, f.getGeometry().getExtent());
  });
  map.getView().fit(baseExtent);
  return false;
});

$('a.btnShowRed').click(function() {
  sidebar.close();
  var baseExtent = ol.extent.createEmpty();
  for(k in riverLayers) {
    riverLayers[k].getSource().forEachFeature(function(f) {
      if(f.get('fType') === 'green') {
        f.setStyle(emptyStyle);
      } else {
        ol.extent.extend(baseExtent, f.getGeometry().getExtent());
        f.setStyle(pointRedStyle);
      }
    })
  }
  targetLayer.getSource().forEachFeature(function(f) {
    f.setStyle(emptyStyle);
  });
  map.getView().fit(baseExtent);
  return false;
});
<|endoftext|>


<commit_before>const ROMVID = 0x0451;
const ROMPID = 0x6141;
const BOOTPS = 67;
const BOOTPC = 68;
const IPUDP = 17;
const SPLVID = 0x0525;
const SPLPID = 0xA4A2;
const ETHIPP = 0x0800;
const ETHARPP = 0x0806;
const MAXBUF = 450;
const server_hwaddr = [0x9a, 0x1f, 0x85, 0x1c, 0x3d, 0x0e];
const server_ip = [0xc0, 0xa8, 0x01, 0x09];     // 192.168.1.9
const BB_ip = [0xc0, 0xa8, 0x01, 0x03];         // 192.168.1.3
const servername = [66, 69, 65, 71, 76, 69, 66, 79, 79, 84];       // ASCII ['B','E','A','G','L','E','B','O','O','T']
const file_spl = [83, 80, 76, 0, 0];                             // ASCII ['S','P','L']
const file_uboot = [85, 66, 79, 79, 84];                           // ASCII ['U','B','O','O','T']
const UMSVID = 0x0451;
const UMSPID = 0xd022;

// Size of all packets
var rndisSize = 44;
var etherSize = 14;
var arp_Size = 28;
var ipSize = 20;
var udpSize = 8;
var bootpSize = 300;
var tftpSize = 4;
var fullSize = 386;

// Include modules
var usb = require('usb');
var protocols = require('./src/protocols');
var EventEmitter = require('events').EventEmitter;
var emitter = new EventEmitter();
var fs = require('fs');
var path = require('path');
var os = require('os');
var platform = os.platform();
var rndis_win = require('./src/rndis_win');
var inEndpoint, outEndpoint, Data, ether, rndis, eth2, ip, udp, bootreply, romDevice, splDevice, umsDevice;
var emitterMod = new EventEmitter();    // Emitter for module status
var percent;    // Percentage for progress
var description;    // Description for current status

// Set usb debug log
//usb.setDebugLevel(4);

exports.usbMassStorage = function(){

    // Connect to BeagleBone
    usb.on('attach', function(device){

        if(device === usb.findByIds(ROMVID, ROMPID)){
            transfer('spl', device, 0x02);
            romDevice = device;
        }

        if(device === usb.findByIds(SPLVID, SPLPID)){
            setTimeout(()=>{ transfer('uboot', device, 0x01); }, 1000);
            splDevice = device;
        }

        if(device === usb.findByIds(UMSVID, UMSPID)){
            emitterMod.emit('progress', {description: 'Ready for Flashing!', complete: 100});
            umsDevice = device;
        }
    });

    usb.on('detach', function(device){

        if(device === romDevice && percent < 40)
            emitterMod.emit('disconnect', 'ROM');

        if(device === splDevice && percent < 85)
            emitterMod.emit('disconnect', 'SPL');

        if(device === umsDevice)
            emitterMod.emit('disconnect', 'UMS');
    });

    return emitterMod;
};

// Function for device initialization
function transfer(file, device, outEnd){
    if(file === 'spl') percent = 0;

    description = file+" =>";
    emitterMod.emit('progress', {description: description, complete: percent});
    percent += 5;

    if(file == 'uboot' && platform != 'linux'){
        device.open(false);
        device.setConfiguration(2, function(err){console.log(err);});
        device.__open();
        device.__claimInterface(0);
    }

    device.open();
    var interface = device.interface(1);    // Select interface 1 for BULK transfers

    windows = 0;
    if(platform == 'win32') windows = 1;

    if(!windows){                // Not supported in Windows
        // Detach Kernel Driver
        if(interface.isKernelDriverActive()){
            interface.detachKernelDriver();
        }
    }

    try{
        interface.claim();
    }

    catch(err){
        emitterMod.emit('error', "Can't claim interface " +err);
    }

    description = "Interface claimed";
    emitterMod.emit('progress', {description: description, complete: percent});
    percent += 5;

    // Code to initialize RNDIS device on Windows and OSX
    if(platform != 'linux' && file == 'spl'){
        var intf0 = device.interface(0);    // Select interface 0 for CONTROL transfer
        intf0.claim();

        var CONTROL_BUFFER_SIZE = 1025;
        var rndis_init_size = 24;
        var rndis_set_size = 28;

        var rndis_buf = Buffer.alloc(CONTROL_BUFFER_SIZE);
        var init_msg = rndis_win.make_rndis_init();
        init_msg.copy(rndis_buf, 0, 0, rndis_init_size);

        // Windows Control Transfer
        // https://msdn.microsoft.com/en-us/library/aa447434.aspx
        // http://www.beyondlogic.org/usbnutshell/usb6.shtml

        var bmRequestType_send = 0x21; // USB_TYPE=CLASS | USB_RECIPIENT=INTERFACE
        var bmRequestType_receive = 0xA1; // USB_DATA=DeviceToHost | USB_TYPE=CLASS | USB_RECIPIENT=INTERFACE

        // Sending rndis_init_msg (SEND_ENCAPSULATED_COMMAND)
        device.controlTransfer(bmRequestType_send, 0, 0, 0, rndis_buf, function(error, data){
            console.log(error);
        });

        // Receive rndis_init_cmplt (GET_ENCAPSULATED_RESPONSE)
        device.controlTransfer(bmRequestType_receive, 0x01, 0, 0, CONTROL_BUFFER_SIZE, function(error, data){
            console.log(data);
        });

        var set_msg = rndis_win.make_rndis_set();
        set_msg.copy(rndis_buf, 0, 0, rndis_set_size+4);

        // Send rndis_set_msg (SEND_ENCAPSULATED_COMMAND)
        device.controlTransfer(bmRequestType_send, 0, 0, 0, rndis_buf, function(error, data){
            console.log(error);
        });

        // Receive rndis_init_cmplt (GET_ENCAPSULATED_RESPONSE)
        device.controlTransfer(bmRequestType_receive, 0x01, 0, 0, CONTROL_BUFFER_SIZE, function(error, data){
            console.log(data);
        });

    }

    // Set endpoints for usb transfer
    inEndpoint = interface.endpoint(0x81);
    outEndpoint = interface.endpoint(outEnd);

    // Set endpoint transfer type
    inEndpoint.transferType = usb.LIBUSB_TRANSFER_TYPE_BULK;
    outEndpoint.transferType = usb.LIBUSB_TRANSFER_TYPE_BULK;

    emitter.emit('inTransfer', file);
}

// Event for inEnd transfer
emitter.on('inTransfer', function(file){

    inEndpoint.transfer(MAXBUF, function(error, data){

        if(!error){
            var request = identifyRequest(data);

            if(request === 'notIdentified') emitter.emit('inTransfer', file);

            else {

                emitterMod.emit('progress', {description: request + " request received", complete: percent});
                percent += 5;

                if(request == 'BOOTP') Data = processBOOTP(file, data);

                if(request == 'ARP') Data = processARP(data);

                if(request == 'TFTP') {
                    Data = processTFTP(data);
                    emitter.emit('sendFile', file);
                }

                else emitter.emit('outTransfer', file, Data, request);
            }
        }

        else {
            emitterMod.emit('error', "ERROR in inTransfer");
            console.log(error);
        }
    });
});

// Event for outEnd Transfer
emitter.on('outTransfer', function(file, data, request){

    outEndpoint.transfer(data, function(error){

        if(!error){
            emitterMod.emit('progress', {description: request + " reply done", complete: percent});
            percent += 5;

            emitter.emit('inTransfer', file);
        }
        else {
            emitterMod.emit('error', "ERROR sending " + request);
            console.log(error);
        }
    });

});

////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////// File Transfer ////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
emitter.on('sendFile', function(file){
    description = file+" transfer starts";
    emitterMod.emit('progress', {description: description, complete: percent});
    percent += 5;

    fs.readFile(path.join(__dirname, "bin", file), function(error, data){

        if(!error){

            var blocks = Math.ceil(data.length/512);         // Total number of blocks of file

            eth2 = protocols.make_ether2(ether.h_source, server_hwaddr, ETHIPP);

            var start = 0;                                  // Source start for copy

            for(var i=1; i<=blocks; i++){                   // i is block number

                var blk_size = (i==blocks)? data.length - (blocks-1)*512 : 512;  // Different block size for last block

                var blk_data = Buffer.alloc(blk_size);
                data.copy(blk_data, 0, start, start + blk_size);                 // Copying data to block
                start += blk_size;

                rndis = protocols.make_rndis(etherSize + ipSize + udpSize + tftpSize + blk_size);
                ip = protocols.make_ipv4(server_ip, BB_ip, IPUDP, 0, ipSize + udpSize + tftpSize + blk_size, 0);
                udp = protocols.make_udp(tftpSize + blk_size, udpSPL.udpDest, udpSPL.udpSrc);
                tftp = protocols.make_tftp(3, i);

                var file_data = Buffer.concat([rndis, eth2, ip, udp, tftp, blk_data], rndisSize + etherSize + ipSize + udpSize + tftpSize + blk_size);

                // Send SPL file data
                outEndpoint.transfer(file_data, function(error){});

                // Receive buffer back
                inEndpoint.transfer(MAXBUF, function(error, data){});

            }

            description = file+" transfer complete";
            emitterMod.emit('progress', {description: description, complete: percent});
            percent += 5;
        }
        else emitterMod.emit('error', "Error reading "+file+" : "+error);
    });
});

// Function to identify request packet
function identifyRequest(buff){
    var val = buff[4];

    if(val == 0xc2 || val == 0x6c) return 'BOOTP';

    if(val == 0x56) return 'ARP';

    if(val == 0x62 || val == 0x7b) return 'TFTP';

    return 'notIdentified';

}

// Function to process BOOTP request
function processBOOTP(file, data){

    var bootp_buf = Buffer.alloc(MAXBUF-rndisSize);

    if(file == 'spl'){

        data.copy(bootp_buf, 0, rndisSize, MAXBUF);

        ether = protocols.decode_ether(bootp_buf);      // Gets decoded ether packet data

        rndis = protocols.make_rndis(fullSize-rndisSize);   // Make RNDIS

        eth2 = protocols.make_ether2(ether.h_source, server_hwaddr, ETHIPP);    // Make ether2

        ip = protocols.make_ipv4(server_ip, BB_ip, IPUDP, 0, ipSize + udpSize + bootpSize, 0); // Make ipv4

        udp = protocols.make_udp(bootpSize, BOOTPS, BOOTPC);    // Make udp

        bootreply = protocols.make_bootp(servername, file_spl, 1, ether.h_source, BB_ip, server_ip);    // Make BOOTP for reply

        buff = Buffer.concat([rndis, eth2, ip, udp, bootreply], fullSize);      // BOOT Reply

    }

    else{

        var udpUboot_buf = Buffer.alloc(udpSize);

        var spl_bootp_buf = Buffer.alloc(bootpSize);

        data.copy(udpUboot_buf, 0, rndisSize + etherSize + ipSize, MAXBUF);

        data.copy(spl_bootp_buf, 0, rndisSize + etherSize + ipSize + udpSize, MAXBUF);

        var udpUboot = protocols.parse_udp(udpUboot_buf);       // parsed udp header

        var spl_bootp = protocols.parse_bootp(spl_bootp_buf);   // parsed bootp header

        rndis = protocols.make_rndis(fullSize - rndisSize);

        eth2 = protocols.make_ether2(ether.h_source, server_hwaddr, ETHIPP);

        ip = protocols.make_ipv4(server_ip, BB_ip, IPUDP, 0, ipSize + udpSize + bootpSize, 0);

        udp = protocols.make_udp(bootpSize, udpUboot.udpDest, udpUboot.udpSrc);

        bootreply = protocols.make_bootp(servername, file_uboot, spl_bootp.xid, ether.h_source, BB_ip, server_ip);

        buff = Buffer.concat([rndis, eth2, ip, udp, bootreply], fullSize);
    }

    return buff;
}

// Function to process ARP request
function processARP(data){

    var arp_buf = Buffer.alloc(arp_Size);

    data.copy(arp_buf, 0, rndisSize + etherSize, rndisSize + etherSize + arp_Size);

    receivedARP = protocols.parse_arp(arp_buf);         // Parsed received ARP request

    // ARP response
    var arpResponse = protocols.make_arp(2, server_hwaddr, receivedARP.ip_dest, receivedARP.hw_source, receivedARP.ip_source );

    rndis = protocols.make_rndis(etherSize + arp_Size);

    eth2 = protocols.make_ether2(ether.h_source, server_hwaddr, ETHARPP);

    buff = Buffer.concat([rndis, eth2, arpResponse], rndisSize + etherSize + arp_Size);

    return buff;
}

// Function to process TFTP request
function processTFTP(data){

    var udpSPL_buf = Buffer.alloc(udpSize);

    data.copy(udpSPL_buf, 0, rndisSize + etherSize + ipSize, rndisSize + etherSize + ipSize + udpSize);

    udpSPL = protocols.parse_udp(udpSPL_buf);           // Received UDP packet for SPL tftp

}<commit_msg>do not log setconfig error when there's no error<commit_after>const ROMVID = 0x0451;
const ROMPID = 0x6141;
const BOOTPS = 67;
const BOOTPC = 68;
const IPUDP = 17;
const SPLVID = 0x0525;
const SPLPID = 0xA4A2;
const ETHIPP = 0x0800;
const ETHARPP = 0x0806;
const MAXBUF = 450;
const server_hwaddr = [0x9a, 0x1f, 0x85, 0x1c, 0x3d, 0x0e];
const server_ip = [0xc0, 0xa8, 0x01, 0x09];     // 192.168.1.9
const BB_ip = [0xc0, 0xa8, 0x01, 0x03];         // 192.168.1.3
const servername = [66, 69, 65, 71, 76, 69, 66, 79, 79, 84];       // ASCII ['B','E','A','G','L','E','B','O','O','T']
const file_spl = [83, 80, 76, 0, 0];                             // ASCII ['S','P','L']
const file_uboot = [85, 66, 79, 79, 84];                           // ASCII ['U','B','O','O','T']
const UMSVID = 0x0451;
const UMSPID = 0xd022;

// Size of all packets
var rndisSize = 44;
var etherSize = 14;
var arp_Size = 28;
var ipSize = 20;
var udpSize = 8;
var bootpSize = 300;
var tftpSize = 4;
var fullSize = 386;

// Include modules
var usb = require('usb');
var protocols = require('./src/protocols');
var EventEmitter = require('events').EventEmitter;
var emitter = new EventEmitter();
var fs = require('fs');
var path = require('path');
var os = require('os');
var platform = os.platform();
var rndis_win = require('./src/rndis_win');
var inEndpoint, outEndpoint, Data, ether, rndis, eth2, ip, udp, bootreply, romDevice, splDevice, umsDevice;
var emitterMod = new EventEmitter();    // Emitter for module status
var percent;    // Percentage for progress
var description;    // Description for current status

// Set usb debug log
//usb.setDebugLevel(4);

exports.usbMassStorage = function(){

    // Connect to BeagleBone
    usb.on('attach', function(device){

        if(device === usb.findByIds(ROMVID, ROMPID)){
            transfer('spl', device, 0x02);
            romDevice = device;
        }

        if(device === usb.findByIds(SPLVID, SPLPID)){
            setTimeout(()=>{ transfer('uboot', device, 0x01); }, 1000);
            splDevice = device;
        }

        if(device === usb.findByIds(UMSVID, UMSPID)){
            emitterMod.emit('progress', {description: 'Ready for Flashing!', complete: 100});
            umsDevice = device;
        }
    });

    usb.on('detach', function(device){

        if(device === romDevice && percent < 40)
            emitterMod.emit('disconnect', 'ROM');

        if(device === splDevice && percent < 85)
            emitterMod.emit('disconnect', 'SPL');

        if(device === umsDevice)
            emitterMod.emit('disconnect', 'UMS');
    });

    return emitterMod;
};

// Function for device initialization
function transfer(file, device, outEnd){
    if(file === 'spl') percent = 0;

    description = file+" =>";
    emitterMod.emit('progress', {description: description, complete: percent});
    percent += 5;

    if(file == 'uboot' && platform != 'linux'){
        device.open(false);
        device.setConfiguration(2, function(err){if(err) console.log(err);});
        device.__open();
        device.__claimInterface(0);
    }

    device.open();
    var interface = device.interface(1);    // Select interface 1 for BULK transfers

    windows = 0;
    if(platform == 'win32') windows = 1;

    if(!windows){                // Not supported in Windows
        // Detach Kernel Driver
        if(interface.isKernelDriverActive()){
            interface.detachKernelDriver();
        }
    }

    try{
        interface.claim();
    }

    catch(err){
        emitterMod.emit('error', "Can't claim interface " +err);
    }

    description = "Interface claimed";
    emitterMod.emit('progress', {description: description, complete: percent});
    percent += 5;

    // Code to initialize RNDIS device on Windows and OSX
    if(platform != 'linux' && file == 'spl'){
        var intf0 = device.interface(0);    // Select interface 0 for CONTROL transfer
        intf0.claim();

        var CONTROL_BUFFER_SIZE = 1025;
        var rndis_init_size = 24;
        var rndis_set_size = 28;

        var rndis_buf = Buffer.alloc(CONTROL_BUFFER_SIZE);
        var init_msg = rndis_win.make_rndis_init();
        init_msg.copy(rndis_buf, 0, 0, rndis_init_size);

        // Windows Control Transfer
        // https://msdn.microsoft.com/en-us/library/aa447434.aspx
        // http://www.beyondlogic.org/usbnutshell/usb6.shtml

        var bmRequestType_send = 0x21; // USB_TYPE=CLASS | USB_RECIPIENT=INTERFACE
        var bmRequestType_receive = 0xA1; // USB_DATA=DeviceToHost | USB_TYPE=CLASS | USB_RECIPIENT=INTERFACE

        // Sending rndis_init_msg (SEND_ENCAPSULATED_COMMAND)
        device.controlTransfer(bmRequestType_send, 0, 0, 0, rndis_buf, function(error, data){
            console.log(error);
        });

        // Receive rndis_init_cmplt (GET_ENCAPSULATED_RESPONSE)
        device.controlTransfer(bmRequestType_receive, 0x01, 0, 0, CONTROL_BUFFER_SIZE, function(error, data){
            console.log(data);
        });

        var set_msg = rndis_win.make_rndis_set();
        set_msg.copy(rndis_buf, 0, 0, rndis_set_size+4);

        // Send rndis_set_msg (SEND_ENCAPSULATED_COMMAND)
        device.controlTransfer(bmRequestType_send, 0, 0, 0, rndis_buf, function(error, data){
            console.log(error);
        });

        // Receive rndis_init_cmplt (GET_ENCAPSULATED_RESPONSE)
        device.controlTransfer(bmRequestType_receive, 0x01, 0, 0, CONTROL_BUFFER_SIZE, function(error, data){
            console.log(data);
        });

    }

    // Set endpoints for usb transfer
    inEndpoint = interface.endpoint(0x81);
    outEndpoint = interface.endpoint(outEnd);

    // Set endpoint transfer type
    inEndpoint.transferType = usb.LIBUSB_TRANSFER_TYPE_BULK;
    outEndpoint.transferType = usb.LIBUSB_TRANSFER_TYPE_BULK;

    emitter.emit('inTransfer', file);
}

// Event for inEnd transfer
emitter.on('inTransfer', function(file){

    inEndpoint.transfer(MAXBUF, function(error, data){

        if(!error){
            var request = identifyRequest(data);

            if(request === 'notIdentified') emitter.emit('inTransfer', file);

            else {

                emitterMod.emit('progress', {description: request + " request received", complete: percent});
                percent += 5;

                if(request == 'BOOTP') Data = processBOOTP(file, data);

                if(request == 'ARP') Data = processARP(data);

                if(request == 'TFTP') {
                    Data = processTFTP(data);
                    emitter.emit('sendFile', file);
                }

                else emitter.emit('outTransfer', file, Data, request);
            }
        }

        else {
            emitterMod.emit('error', "ERROR in inTransfer");
            console.log(error);
        }
    });
});

// Event for outEnd Transfer
emitter.on('outTransfer', function(file, data, request){

    outEndpoint.transfer(data, function(error){

        if(!error){
            emitterMod.emit('progress', {description: request + " reply done", complete: percent});
            percent += 5;

            emitter.emit('inTransfer', file);
        }
        else {
            emitterMod.emit('error', "ERROR sending " + request);
            console.log(error);
        }
    });

});

////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////// File Transfer ////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
emitter.on('sendFile', function(file){
    description = file+" transfer starts";
    emitterMod.emit('progress', {description: description, complete: percent});
    percent += 5;

    fs.readFile(path.join(__dirname, "bin", file), function(error, data){

        if(!error){

            var blocks = Math.ceil(data.length/512);         // Total number of blocks of file

            eth2 = protocols.make_ether2(ether.h_source, server_hwaddr, ETHIPP);

            var start = 0;                                  // Source start for copy

            for(var i=1; i<=blocks; i++){                   // i is block number

                var blk_size = (i==blocks)? data.length - (blocks-1)*512 : 512;  // Different block size for last block

                var blk_data = Buffer.alloc(blk_size);
                data.copy(blk_data, 0, start, start + blk_size);                 // Copying data to block
                start += blk_size;

                rndis = protocols.make_rndis(etherSize + ipSize + udpSize + tftpSize + blk_size);
                ip = protocols.make_ipv4(server_ip, BB_ip, IPUDP, 0, ipSize + udpSize + tftpSize + blk_size, 0);
                udp = protocols.make_udp(tftpSize + blk_size, udpSPL.udpDest, udpSPL.udpSrc);
                tftp = protocols.make_tftp(3, i);

                var file_data = Buffer.concat([rndis, eth2, ip, udp, tftp, blk_data], rndisSize + etherSize + ipSize + udpSize + tftpSize + blk_size);

                // Send SPL file data
                outEndpoint.transfer(file_data, function(error){});

                // Receive buffer back
                inEndpoint.transfer(MAXBUF, function(error, data){});

            }

            description = file+" transfer complete";
            emitterMod.emit('progress', {description: description, complete: percent});
            percent += 5;
        }
        else emitterMod.emit('error', "Error reading "+file+" : "+error);
    });
});

// Function to identify request packet
function identifyRequest(buff){
    var val = buff[4];

    if(val == 0xc2 || val == 0x6c) return 'BOOTP';

    if(val == 0x56) return 'ARP';

    if(val == 0x62 || val == 0x7b) return 'TFTP';

    return 'notIdentified';

}

// Function to process BOOTP request
function processBOOTP(file, data){

    var bootp_buf = Buffer.alloc(MAXBUF-rndisSize);

    if(file == 'spl'){

        data.copy(bootp_buf, 0, rndisSize, MAXBUF);

        ether = protocols.decode_ether(bootp_buf);      // Gets decoded ether packet data

        rndis = protocols.make_rndis(fullSize-rndisSize);   // Make RNDIS

        eth2 = protocols.make_ether2(ether.h_source, server_hwaddr, ETHIPP);    // Make ether2

        ip = protocols.make_ipv4(server_ip, BB_ip, IPUDP, 0, ipSize + udpSize + bootpSize, 0); // Make ipv4

        udp = protocols.make_udp(bootpSize, BOOTPS, BOOTPC);    // Make udp

        bootreply = protocols.make_bootp(servername, file_spl, 1, ether.h_source, BB_ip, server_ip);    // Make BOOTP for reply

        buff = Buffer.concat([rndis, eth2, ip, udp, bootreply], fullSize);      // BOOT Reply

    }

    else{

        var udpUboot_buf = Buffer.alloc(udpSize);

        var spl_bootp_buf = Buffer.alloc(bootpSize);

        data.copy(udpUboot_buf, 0, rndisSize + etherSize + ipSize, MAXBUF);

        data.copy(spl_bootp_buf, 0, rndisSize + etherSize + ipSize + udpSize, MAXBUF);

        var udpUboot = protocols.parse_udp(udpUboot_buf);       // parsed udp header

        var spl_bootp = protocols.parse_bootp(spl_bootp_buf);   // parsed bootp header

        rndis = protocols.make_rndis(fullSize - rndisSize);

        eth2 = protocols.make_ether2(ether.h_source, server_hwaddr, ETHIPP);

        ip = protocols.make_ipv4(server_ip, BB_ip, IPUDP, 0, ipSize + udpSize + bootpSize, 0);

        udp = protocols.make_udp(bootpSize, udpUboot.udpDest, udpUboot.udpSrc);

        bootreply = protocols.make_bootp(servername, file_uboot, spl_bootp.xid, ether.h_source, BB_ip, server_ip);

        buff = Buffer.concat([rndis, eth2, ip, udp, bootreply], fullSize);
    }

    return buff;
}

// Function to process ARP request
function processARP(data){

    var arp_buf = Buffer.alloc(arp_Size);

    data.copy(arp_buf, 0, rndisSize + etherSize, rndisSize + etherSize + arp_Size);

    receivedARP = protocols.parse_arp(arp_buf);         // Parsed received ARP request

    // ARP response
    var arpResponse = protocols.make_arp(2, server_hwaddr, receivedARP.ip_dest, receivedARP.hw_source, receivedARP.ip_source );

    rndis = protocols.make_rndis(etherSize + arp_Size);

    eth2 = protocols.make_ether2(ether.h_source, server_hwaddr, ETHARPP);

    buff = Buffer.concat([rndis, eth2, arpResponse], rndisSize + etherSize + arp_Size);

    return buff;
}

// Function to process TFTP request
function processTFTP(data){

    var udpSPL_buf = Buffer.alloc(udpSize);

    data.copy(udpSPL_buf, 0, rndisSize + etherSize + ipSize, rndisSize + etherSize + ipSize + udpSize);

    udpSPL = protocols.parse_udp(udpSPL_buf);           // Received UDP packet for SPL tftp

}<|endoftext|>


<commit_before>const electron = require('electron')
const {app, Menu} = require('electron')
var path = require('path')
// Module to control application life.
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

var window_size_width = 250;
var window_size_height = 350;

// 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

function createWindow () {
  // Create the browser window.
  console.log(process.versions.electron);

  mainWindow = new BrowserWindow({
    width: 250,
    height: 350,
    minWidth: 250,
    maxWidth: 500,
    minHeight: 100,
    maxHeight: 400,
    title: 'Unit',
    icon: path.join(__dirname, 'assets/icons/png/64x64.png'),
    frame: false,
    titleBarStyle: 'hidden',
    acceptFirstMouse: true,
    maximizable: false,
    resizable: false,
  })

  app.on('window-all-closed', () => {
    app.quit()
  })

  mainWindow.on('unmaximize', function (event) {
  console.log('unmax');
    event.preventDefault();
    window_size_width = mainWindow.getSize().width;
    window_size_height = mainWindow.getSize().height;
    console.log(window_size_width);
    console.log(window_size_height);
    mainWindow.setSize(
      300,
      200
    )
  })

  mainWindow.on('maximize', function (event) {
  console.log('max');
    event.preventDefault();
    mainWindow.setSize(
      600,
      800
    )
  })

  mainWindow.setFullScreenable(false);

  mainWindow.setMaximizable(false);

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

  // 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
  })

const template = [
  {
    label: 'Edit',
    submenu: [
      {role: 'cut'},
      {role: 'copy'},
      {role: 'paste'},
      {role: 'selectall'}
    ]
  },
  {
    label: 'View',
    submenu: [
      {label: 'Full', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(500,400);
        mainWindow.setSize(500,400);
        mainWindow.setResizable(false);
        mainWindow.webContents.executeJavaScript("addExpressionsButtons();");
        console.log("Full window was toggled");
      }, type: 'radio'},
      {label: 'Expressions', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(250,500);
        mainWindow.setSize(250,400);
        mainWindow.setResizable(false);
        mainWindow.webContents.executeJavaScript("addExpressionsButtons();");
        console.log("Expressions window was toggled");
      }, type: 'radio'},
      {label: 'Basic', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(250,500);
        mainWindow.setSize(250,350);
        mainWindow.setResizable(false);
        mainWindow.webContents.executeJavaScript("removeExpressionsButtons();");
        console.log("Basic window was toggled");
      }, type: 'radio',
         checked: true},
      {label: 'Minimal', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(500,100);
        mainWindow.setSize(250,100);
        mainWindow.setResizable(true);
        mainWindow.webContents.executeJavaScript("removeExpressionsButtons();");
        console.log("Minimal window was toggled");
      }, type: 'radio'},
      {type: 'separator'},
      {role: 'reload'},
      {role: 'toggledevtools'},
    ]
  },
  {
    role: 'window',
    submenu: [
      {role: 'minimize'},
      {role: 'close'}
    ]
  },
  {
    role: 'help',
    submenu: [
      {
        label: 'Learn More',
        click () { require('electron').shell.openExternal('https://electron.atom.io') }
      }
    ]
  }
]

if (process.platform === 'darwin') {
  template.unshift({
    label: app.getName(),
    submenu: [
      {role: 'about'},
      {type: 'separator'},
      {role: 'services', submenu: []},
      {type: 'separator'},
      {role: 'hide'},
      {role: 'hideothers'},
      {role: 'unhide'},
      {type: 'separator'},
      {role: 'quit'}
    ]
  })

if (process.platform === 'win32') {
  template.unshift({
    label: app.getName(),
    submenu: [
      {label: 'Full', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(500,400);
        mainWindow.setSize(500,400);
        mainWindow.setResizable(false);
        mainWindow.webContents.executeJavaScript("addExpressionsButtons();");
        console.log("Full window was toggled");
      }, type: 'radio'},
      {label: 'Expressions', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(250,500);
        mainWindow.setSize(250,400);
        mainWindow.setResizable(false);
        mainWindow.webContents.executeJavaScript("addExpressionsButtons();");
        console.log("Expressions window was toggled");
      }, type: 'radio'},
      {label: 'Basic', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(250,500);
        mainWindow.setSize(250,350);
        mainWindow.setResizable(false);
        mainWindow.webContents.executeJavaScript("removeExpressionsButtons();");
        console.log("Basic window was toggled");
      }, type: 'radio',
         checked: true},
      {label: 'Minimal', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(500,100);
        mainWindow.setSize(250,100);
        mainWindow.setResizable(true);
        mainWindow.webContents.executeJavaScript("removeExpressionsButtons();");
        console.log("Minimal window was toggled");
      }, type: 'radio'},
      {type: 'separator'},
      {role: 'reload'},
      {role: 'toggledevtools'},
      {type: 'separator'},
      {role: 'services', submenu: []},
      {type: 'separator'},
      {role: 'hide'},
      {role: 'hideothers'},
      {role: 'unhide'},
      {type: 'separator'},
      {role: 'quit'}
    ]
  })
}

  // Window menu
  template[3].submenu = [
    {role: 'close'},
    {role: 'minimize'},
    {type: 'separator'},
    {role: 'front'}
  ]
}

const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)

}

// 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', 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('activate', function () {
  // 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()
  }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<commit_msg>clean up<commit_after>const electron = require('electron')
const {app, Menu} = require('electron')
var path = require('path')
// Module to control application life.
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

var window_size_width = 250;
var window_size_height = 350;

// 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

function createWindow () {
  // Create the browser window.
  console.log(process.versions.electron);

  mainWindow = new BrowserWindow({
    width: 250,
    height: 350,
    minWidth: 250,
    maxWidth: 500,
    minHeight: 100,
    maxHeight: 400,
    title: 'Unit',
    icon: path.join(__dirname, 'assets/icons/png/64x64.png'),
    frame: false,
    titleBarStyle: 'hidden',
    acceptFirstMouse: true,
    maximizable: false,
    resizable: false,
  })

  app.on('window-all-closed', () => {
    app.quit()
  })

  mainWindow.on('unmaximize', function (event) {
  console.log('unmax');
    event.preventDefault();
    window_size_width = mainWindow.getSize().width;
    window_size_height = mainWindow.getSize().height;
    console.log(window_size_width);
    console.log(window_size_height);
    mainWindow.setSize(
      300,
      200
    )
  })

  mainWindow.on('maximize', function (event) {
  console.log('max');
    event.preventDefault();
    mainWindow.setSize(
      600,
      800
    )
  })

  mainWindow.setFullScreenable(false);

  mainWindow.setMaximizable(false);

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

  // 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
  })

const template = [
  {
    label: 'Edit',
    submenu: [
      {role: 'cut'},
      {role: 'copy'},
      {role: 'paste'},
      {role: 'selectall'}
    ]
  },
  {
    label: 'View',
    submenu: [
      {label: 'Full', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(500,400);
        mainWindow.setSize(500,400);
        mainWindow.setResizable(false);
        mainWindow.webContents.executeJavaScript("addExpressionsButtons();");
        console.log("Full window was toggled");
      }, type: 'radio'},
      {label: 'Expressions', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(250,500);
        mainWindow.setSize(250,400);
        mainWindow.setResizable(false);
        mainWindow.webContents.executeJavaScript("addExpressionsButtons();");
        console.log("Expressions window was toggled");
      }, type: 'radio'},
      {label: 'Basic', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(250,500);
        mainWindow.setSize(250,350);
        mainWindow.setResizable(false);
        mainWindow.webContents.executeJavaScript("removeExpressionsButtons();");
        console.log("Basic window was toggled");
      }, type: 'radio',
         checked: true},
      {label: 'Minimal', click: function(item, BrowserWindow){
        mainWindow.setMaximumSize(500,100);
        mainWindow.setSize(250,100);
        mainWindow.setResizable(true);
        mainWindow.webContents.executeJavaScript("removeExpressionsButtons();");
        console.log("Minimal window was toggled");
      }, type: 'radio'},
      {type: 'separator'},
      {role: 'reload'},
      {role: 'toggledevtools'},
    ]
  },
  {
    role: 'window',
    submenu: [
      {role: 'minimize'},
      {role: 'close'}
    ]
  },
  {
    role: 'help',
    submenu: [
      {
        label: 'Learn More',
        click () { require('electron').shell.openExternal('https://electron.atom.io') }
      }
    ]
  }
]

if (process.platform === 'darwin') {
  template.unshift({
    label: app.getName(),
    submenu: [
      {role: 'about'},
      {type: 'separator'},
      {role: 'services', submenu: []},
      {type: 'separator'},
      {role: 'hide'},
      {role: 'hideothers'},
      {role: 'unhide'},
      {type: 'separator'},
      {role: 'quit'}
    ]
  })

  // Window menu
  template[3].submenu = [
    {role: 'close'},
    {role: 'minimize'},
    {type: 'separator'},
    {role: 'front'}
  ]
}

const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)

}

// 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', 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('activate', function () {
  // 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()
  }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<|endoftext|>


<commit_before>const Menubar = require('menubar')
const electron = require('electron')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

const path = require('path')
const url = require('url')
const menubar = Menubar({
  width:300,
  height:400,
  icon: './images/kitchen-fork-icon.png'
})

// 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
// Capture command line argument
let argsCmd = process.argv.slice(2);
let timerTime = parseInt(argsCmd[0]);

menubar.on('ready', () => {
  console.log('READY!');
})

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600})

  // and load the index.html of the app.
  mainWindow.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

  // Open the DevTools.
  mainWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {

    mainWindow = null
  })

  // // When UI has finish loading
  // mainWindow.webContents.on('did-finish-load', () => {
  //     // Send the timer value
  //     mainWindow.webContents.send('timer-change', timerTime);
  // });
}

// 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', 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('activate', function () {
  // 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()
  }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<commit_msg>Delete unecessary things from main<commit_after>const Menubar = require('menubar')
const electron = require('electron')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

const path = require('path')
const url = require('url')
const menubar = Menubar({
  width:300,
  height:400,
  icon: './images/kitchen-fork-icon.png'
})

// 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

menubar.on('ready', () => {
  console.log('READY!');
})

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600})

  // and load the index.html of the app.
  mainWindow.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

  // Open the DevTools.
  mainWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {

    mainWindow = null
  })
}

app.on('ready', createWindow)

// 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('activate', function () {
  // 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()
  }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<|endoftext|>