<commit_before>// copied and modified from https://gist.github.com/dsully/1938283
$(function () {

    function loadPage(url) {
        window.location.href = url;
    }

    // Handle tabs, page reloads & browser forward/back history.
    var History = window.History;

    if (!History.enabled) {
        return false;
    }

    var statechange = function () {
        var State = History.getState();
        var hash  = History.getHash();

        // Our default tab.
        if (!State.data || !State.data.tab) {
            if (hash) {
                State.data.tab = hash;
                window.location.hash = '';
            } else {
                State.data.tab = '';
            }
        }

        var link;
        if (State.data.tab) {
            link = $('a[data-toggle="tab"][href$="#' + State.data.tab + '"]');
        } else {
            // if you can't find it by hash, try matching the url
            // this is for first loading a page,
            // where State.data.tab won't be available
            link = $('a[data-toggle="tab"][href^="' + window.location.pathname + '"]');
            if (link.length !== 0) {
                link = link.first();
                History.replaceState({
                    tab: link.attr('href').split('#')[1]
                }, null, State.url);
            }
        }
        link.tab('show');
    };
    $(window).bind('load', statechange);
    History.Adapter.bind(window, 'statechange', statechange);
    History.Adapter.bind(window, 'statechange', function () {
        var State = History.getState();
        if (!State.data || !State.data.tab) {
            // just go to the url specified with a reload
            loadPage(window.location.href);
        }
    });

    $('a[data-toggle="tab"]').on('show', function (event) {

        // Set the selected tab to be the current state. But don't update the URL.
        var url = event.target.href.split("#")[0];
        var tab = event.target.href.split("#")[1];

        var State = History.getState();

        if (url === window.location.href) {
            // for tabs that we don't want to change the url on
            return;
        }

        if ($('#' + tab).length === 0) {
            loadPage(url);
        }

        // Don't set the state if we haven't changed tabs.
        if (State.data.tab != tab) {
            var message = COMMCAREHQ.beforeUnloadCallback();
            var ask = message !== undefined && message !== undefined;
            if (!ask) {
                History.pushState({'tab': tab}, null, url);
            } else {
                // instead of using tabs, reload page
                // so as to trigger warning
                event.preventDefault();
                loadPage(url);
            }
        }
    });
});
<commit_msg>make bootstrap-tab-history-custom.js B3 compatible<commit_after>// copied and modified from https://gist.github.com/dsully/1938283
$(function () {

    function loadPage(url) {
        window.location.href = url;
    }

    // Handle tabs, page reloads & browser forward/back history.
    var History = window.History;

    if (!History.enabled) {
        return false;
    }

    var statechange = function () {
        var State = History.getState();
        var hash  = History.getHash();

        // Our default tab.
        if (!State.data || !State.data.tab) {
            if (hash) {
                State.data.tab = hash;
                window.location.hash = '';
            } else {
                State.data.tab = '';
            }
        }

        var link;
        if (State.data.tab) {
            link = $('a[data-toggle="tab"][href$="#' + State.data.tab + '"]');
        } else {
            // if you can't find it by hash, try matching the url
            // this is for first loading a page,
            // where State.data.tab won't be available
            link = $('a[data-toggle="tab"][href^="' + window.location.pathname + '"]');
            if (link.length !== 0) {
                link = link.first();
                History.replaceState({
                    tab: link.attr('href').split('#')[1]
                }, null, State.url);
            }
        }
        link.tab('show');
    };
    $(window).bind('load', statechange);
    History.Adapter.bind(window, 'statechange', statechange);
    History.Adapter.bind(window, 'statechange', function () {
        var State = History.getState();
        if (!State.data || !State.data.tab) {
            // just go to the url specified with a reload
            loadPage(window.location.href);
        }
    });

    $('a[data-toggle="tab"]').on('show show.bs.tab', function (event) {

        // Set the selected tab to be the current state. But don't update the URL.
        var url = event.target.href.split("#")[0];
        var tab = event.target.href.split("#")[1];

        var State = History.getState();

        if (url === window.location.href) {
            // for tabs that we don't want to change the url on
            return;
        }

        if ($('#' + tab).length === 0) {
            loadPage(url);
        }

        // Don't set the state if we haven't changed tabs.
        if (State.data.tab != tab) {
            var message = COMMCAREHQ.beforeUnloadCallback();
            var ask = message !== undefined && message !== undefined;
            if (!ask) {
                History.pushState({'tab': tab}, null, url);
            } else {
                // instead of using tabs, reload page
                // so as to trigger warning
                event.preventDefault();
                loadPage(url);
            }
        }
    });
});
<|endoftext|>


<commit_before>import ApiConfig from './_Classes/ApiConfig';
import Error from './_Classes/Error';
import Image from './_Classes/Image';
import Receiver from './_Classes/Receiver';
import ReceiverDisplayStatus from './_Classes/ReceiverDisplayStatus';
import SenderApplication from './_Classes/SenderApplication';
import Session from './_Classes/Session';
import SessionRequest from './_Classes/SessionRequest';
import Volume from './_Classes/Volume';

import Media from './media';

import mdns from 'mdns';

// DEV: workaround for RPi (and apparently Ubuntu)
// https://github.com/agnat/node_mdns/issues/130#issuecomment-120731155

const sequence = [
  mdns.rst.DNSServiceResolve(), // eslint-disable-line
  'DNSServiceGetAddrInfo' in mdns.dns_sd ? mdns.rst.DNSServiceGetAddrInfo() : mdns.rst.getaddrinfo({ families: [0] }), // eslint-disable-line
  mdns.rst.makeAddressesUnique(),
];
const browser = mdns.createBrowser(mdns.tcp('googlecast'), { resolverSequence: sequence });

// DEV: Global config variables
let globalApiConfig;
let receiverList = [];
const sessions = [];

browser.on('serviceUp', (service) => {
  const receiver = new chrome.cast.Receiver(service.fullname, service.name);
  receiver.ipAddress = service.addresses[0];
  receiverList.push(receiver);
  /**
  Service object
  {
    interfaceIndex: 4,
    name: 'somehost',
    networkInterface: 'en0',
    type: {name: 'http', protocol: 'tcp', subtypes: []},
    replyDomain: 'local.',
    fullname: 'somehost._http._tcp.local.',
    host: 'somehost.local.',
    port: 4321,
    addresses: [ '10.1.1.50', 'fe80::21f:5bff:fecd:ce64' ]
  }
  **/
  // DEV: Notify listeners that we found cast devices
  if (globalApiConfig) globalApiConfig.receiverListener(chrome.cast.ReceiverAvailability.AVAILABLE);
});

browser.on('serviceDown', (service) => {
  const downReceiver = new chrome.cast.Receiver(service.fullname, service.name);
  downReceiver.ipAddress = service.addresses[0];

  receiverList = receiverList.filter((receiver) =>
    receiver.ipAddress !== downReceiver.ipAddress &&
    receiver.name !== downReceiver.name &&
    receiver.friendlyName !== downReceiver.friendlyName
  );
  // DEV: If we have run out of receivers, notify listeners that there are none available
  if (receiverList.length === 0) globalApiConfig.receiverListener(chrome.cast.ReceiverAvailability.UNAVAILABLE);
});
browser.start();

export default class Cast {
  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.AutoJoinPolicy
  static AutoJoinPolicy = {
    TAB_AND_ORIGIN_SCOPED: 'TAB_AND_ORIGIN_SCOPED',
    ORIGIN_SCOPED: 'ORIGIN_SCOPED',
    PAGE_SCOPED: 'PAGE_SCOPED',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.Capability
  static Capability = {
    VIDEO_OUT: 'VIDEO_OUT',
    VIDEO_IN: 'VIDEO_IN',
    AUDIO_OUT: 'AUDIO_OUT',
    AUDIO_IN: 'AUDIO_IN',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.DefaultActionPolicy
  static DefaultActionPolicy = {
    CREATE_SESSION: 'CREATE_SESSION',
    CAST_THIS_TAB: 'CAST_THIS_TAB',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.ErrorCode
  static ErrorCode = {
    CANCEL: 'CANCEL',
    TIMEOUT: 'TIMEOUT',
    API_NOT_INITIALIZED: 'API_NOT_INITIALIZED',
    INVALID_PARAMETER: 'INVALID_PARAMETER',
    EXTENSION_NOT_COMPATIBLE: 'EXTENSION_NOT_COMPATIBLE',
    EXTENSION_MISSING: 'EXTENSION_MISSING',
    RECEIVER_UNAVAILABLE: 'RECEIVER_UNAVAILABLE',
    SESSION_ERROR: 'SESSION_ERROR',
    CHANNEL_ERROR: 'CHANNEL_ERROR',
    LOAD_MEDIA_FAILED: 'LOAD_MEDIA_FAILED',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.isAvailable
  static isAvailable = true;

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.ReceiverAction
  static ReceiverAction = {
    CAST: 'CAST',
    STOP: 'STOP',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast.html#.ReceiverActionListener
  static ReceiverActionListener = class {};

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.ReceiverAvailability
  static ReceiverAvailability = {
    AVAILABLE: 'AVAILABLE',
    UNAVAILABLE: 'UNAVAILABLE',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.ReceiverType
  static ReceiverType = {
    CAST: 'CAST',
    HANGOUT: 'HANGOUT',
    CUSTOM: 'CUSTOM',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.SenderPlatform
  static SenderPlatform = {
    CHROME: 'CHROME',
    IOS: 'IOS',
    ANDROID: 'ANDROID',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.SessionStatus
  static SessionStatus = {
    CONNECTED: 'CONNECTED',
    DISCONNECTED: 'DISCONNECTED',
    STOPPED: 'STOPPED',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.VERSION
  static VERSION = [1, 2];

  static addReceiverActionListener = (listener) => {
    // TODO: https://developers.google.com/cast/docs/reference/chrome/chrome.cast.html#.addReceiverActionListener
    castConsole.log(listener);
  }

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.initialize
  static initialize = (apiConfig, successCallback, errorCallback) => {
    if (globalApiConfig) {
      // DEV: The chromecast API has already been initialzed
      errorCallback(new chrome.cast.Error(chrome.cast.ErrorCode.INVALID_PARAMETER));
      return;
    }
    globalApiConfig = apiConfig;

    if (receiverList.length > 0) {
      globalApiConfig.receiverListener(chrome.cast.ReceiverAvailability.AVAILABLE);
    } else {
      globalApiConfig.receiverListener(chrome.cast.ReceiverAvailability.UNAVAILABLE);
    }
    successCallback();
  }

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.logMessage
  static logMessage = (message) => {
    castConsole.info('CAST MSG:', message); // eslint-disable-line
  }

  static removeReceiverActionListener = (listener) => {
    // TODO: https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.removeReceiverActionListener
    castConsole.log(listener);
  }

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.requestSession
  static requestSession = (successCallback, errorCallback, opt_sessionRequest) => { // eslint-disable-line
    // TODO: Utilize passed in opt_sessionRequest if present, remove disable line
    const id = sessions.length;

    if (receiverList.length === 0) {
      errorCallback(new chrome.cast.Error(chrome.cast.ErrorCode.RECEIVER_UNAVAILABLE));
    } else {
      global.requestHandler(receiverList)
        .then((chosenDevice) => {
          const session = new chrome.cast.Session(
            id,
            globalApiConfig.sessionRequest.appId,
            chosenDevice.friendlyName,
            [],
            chosenDevice,
            successCallback
          );
          sessions.push(session);
        })
        .catch(() => errorCallback(new chrome.cast.Error(chrome.cast.ErrorCode.CANCEL)));
    }
  }

  static requestSessionById = (sessionId) => {
    // TODO: https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.requestSessionById
    castConsole.log('Get Session', sessionId);
  }

  static setCustomReceivers = (receivers, successCallback, errorCallback) => {
    // TODO: https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.setCustomReceivers
    castConsole.log(receivers, successCallback, errorCallback);
  }

  static setReceiverDisplayStatus = (receiver, successCallback, errorCallback) => {
    // TODO: https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.setReceiverDisplayStatus
    castConsole.log(receiver, successCallback, errorCallback);
  }

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.unescape
  static unescape = (escaped) => unescape(escaped);
}

// Static Classes
Cast.ApiConfig = ApiConfig;
Cast.Error = Error;
Cast.Image = Image;
Cast.Receiver = Receiver;
Cast.ReceiverDisplayStatus = ReceiverDisplayStatus;
Cast.SenderApplication = SenderApplication;
Cast.Session = Session;
Cast.SessionRequest = SessionRequest;
Cast.Volume = Volume;

// Extensions
Cast.media = Media;
Cast.timeout = {};
<commit_msg>Handle the user not have bonjour installed<commit_after>import ApiConfig from './_Classes/ApiConfig';
import Error from './_Classes/Error';
import Image from './_Classes/Image';
import Receiver from './_Classes/Receiver';
import ReceiverDisplayStatus from './_Classes/ReceiverDisplayStatus';
import SenderApplication from './_Classes/SenderApplication';
import Session from './_Classes/Session';
import SessionRequest from './_Classes/SessionRequest';
import Volume from './_Classes/Volume';

import Media from './media';

let mdns;
try {
  mdns = require('mdns');
} catch (e) {
  console.error('Failed to start chromecast browser'); // eslint-disable-line
  mdns = null;
}

let browser;

if (mdns) {
// DEV: workaround for RPi (and apparently Ubuntu)
// https://github.com/agnat/node_mdns/issues/130#issuecomment-120731155

  const sequence = [
    mdns.rst.DNSServiceResolve(), // eslint-disable-line
    'DNSServiceGetAddrInfo' in mdns.dns_sd ? mdns.rst.DNSServiceGetAddrInfo() : mdns.rst.getaddrinfo({ families: [0] }), // eslint-disable-line
    mdns.rst.makeAddressesUnique(),
  ];
  browser = mdns.createBrowser(mdns.tcp('googlecast'), { resolverSequence: sequence });
  browser.on('error', () => {});
} else {
  browser = {
    on: () => {},
    start: () => {},
  };
}

// DEV: Global config variables
let globalApiConfig;
let receiverList = [];
const sessions = [];

browser.on('serviceUp', (service) => {
  const receiver = new chrome.cast.Receiver(service.fullname, service.name);
  receiver.ipAddress = service.addresses[0];
  receiverList.push(receiver);
  /**
  Service object
  {
    interfaceIndex: 4,
    name: 'somehost',
    networkInterface: 'en0',
    type: {name: 'http', protocol: 'tcp', subtypes: []},
    replyDomain: 'local.',
    fullname: 'somehost._http._tcp.local.',
    host: 'somehost.local.',
    port: 4321,
    addresses: [ '10.1.1.50', 'fe80::21f:5bff:fecd:ce64' ]
  }
  **/
  // DEV: Notify listeners that we found cast devices
  if (globalApiConfig) globalApiConfig.receiverListener(chrome.cast.ReceiverAvailability.AVAILABLE);
});

browser.on('serviceDown', (service) => {
  const downReceiver = new chrome.cast.Receiver(service.fullname, service.name);
  downReceiver.ipAddress = service.addresses[0];

  receiverList = receiverList.filter((receiver) =>
    receiver.ipAddress !== downReceiver.ipAddress &&
    receiver.name !== downReceiver.name &&
    receiver.friendlyName !== downReceiver.friendlyName
  );
  // DEV: If we have run out of receivers, notify listeners that there are none available
  if (receiverList.length === 0) globalApiConfig.receiverListener(chrome.cast.ReceiverAvailability.UNAVAILABLE);
});
browser.start();

export default class Cast {
  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.AutoJoinPolicy
  static AutoJoinPolicy = {
    TAB_AND_ORIGIN_SCOPED: 'TAB_AND_ORIGIN_SCOPED',
    ORIGIN_SCOPED: 'ORIGIN_SCOPED',
    PAGE_SCOPED: 'PAGE_SCOPED',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.Capability
  static Capability = {
    VIDEO_OUT: 'VIDEO_OUT',
    VIDEO_IN: 'VIDEO_IN',
    AUDIO_OUT: 'AUDIO_OUT',
    AUDIO_IN: 'AUDIO_IN',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.DefaultActionPolicy
  static DefaultActionPolicy = {
    CREATE_SESSION: 'CREATE_SESSION',
    CAST_THIS_TAB: 'CAST_THIS_TAB',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.ErrorCode
  static ErrorCode = {
    CANCEL: 'CANCEL',
    TIMEOUT: 'TIMEOUT',
    API_NOT_INITIALIZED: 'API_NOT_INITIALIZED',
    INVALID_PARAMETER: 'INVALID_PARAMETER',
    EXTENSION_NOT_COMPATIBLE: 'EXTENSION_NOT_COMPATIBLE',
    EXTENSION_MISSING: 'EXTENSION_MISSING',
    RECEIVER_UNAVAILABLE: 'RECEIVER_UNAVAILABLE',
    SESSION_ERROR: 'SESSION_ERROR',
    CHANNEL_ERROR: 'CHANNEL_ERROR',
    LOAD_MEDIA_FAILED: 'LOAD_MEDIA_FAILED',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.isAvailable
  static isAvailable = true;

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.ReceiverAction
  static ReceiverAction = {
    CAST: 'CAST',
    STOP: 'STOP',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast.html#.ReceiverActionListener
  static ReceiverActionListener = class {};

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.ReceiverAvailability
  static ReceiverAvailability = {
    AVAILABLE: 'AVAILABLE',
    UNAVAILABLE: 'UNAVAILABLE',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.ReceiverType
  static ReceiverType = {
    CAST: 'CAST',
    HANGOUT: 'HANGOUT',
    CUSTOM: 'CUSTOM',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.SenderPlatform
  static SenderPlatform = {
    CHROME: 'CHROME',
    IOS: 'IOS',
    ANDROID: 'ANDROID',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.SessionStatus
  static SessionStatus = {
    CONNECTED: 'CONNECTED',
    DISCONNECTED: 'DISCONNECTED',
    STOPPED: 'STOPPED',
  };

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.VERSION
  static VERSION = [1, 2];

  static addReceiverActionListener = (listener) => {
    // TODO: https://developers.google.com/cast/docs/reference/chrome/chrome.cast.html#.addReceiverActionListener
    castConsole.log(listener);
  }

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.initialize
  static initialize = (apiConfig, successCallback, errorCallback) => {
    if (globalApiConfig) {
      // DEV: The chromecast API has already been initialzed
      errorCallback(new chrome.cast.Error(chrome.cast.ErrorCode.INVALID_PARAMETER));
      return;
    }
    globalApiConfig = apiConfig;

    if (receiverList.length > 0) {
      globalApiConfig.receiverListener(chrome.cast.ReceiverAvailability.AVAILABLE);
    } else {
      globalApiConfig.receiverListener(chrome.cast.ReceiverAvailability.UNAVAILABLE);
    }
    successCallback();
  }

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.logMessage
  static logMessage = (message) => {
    castConsole.info('CAST MSG:', message); // eslint-disable-line
  }

  static removeReceiverActionListener = (listener) => {
    // TODO: https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.removeReceiverActionListener
    castConsole.log(listener);
  }

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.requestSession
  static requestSession = (successCallback, errorCallback, opt_sessionRequest) => { // eslint-disable-line
    // TODO: Utilize passed in opt_sessionRequest if present, remove disable line
    const id = sessions.length;

    if (receiverList.length === 0) {
      errorCallback(new chrome.cast.Error(chrome.cast.ErrorCode.RECEIVER_UNAVAILABLE));
    } else {
      global.requestHandler(receiverList)
        .then((chosenDevice) => {
          const session = new chrome.cast.Session(
            id,
            globalApiConfig.sessionRequest.appId,
            chosenDevice.friendlyName,
            [],
            chosenDevice,
            successCallback
          );
          sessions.push(session);
        })
        .catch(() => errorCallback(new chrome.cast.Error(chrome.cast.ErrorCode.CANCEL)));
    }
  }

  static requestSessionById = (sessionId) => {
    // TODO: https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.requestSessionById
    castConsole.log('Get Session', sessionId);
  }

  static setCustomReceivers = (receivers, successCallback, errorCallback) => {
    // TODO: https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.setCustomReceivers
    castConsole.log(receivers, successCallback, errorCallback);
  }

  static setReceiverDisplayStatus = (receiver, successCallback, errorCallback) => {
    // TODO: https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.setReceiverDisplayStatus
    castConsole.log(receiver, successCallback, errorCallback);
  }

  // https://developers.google.com/cast/docs/reference/chrome/chrome.cast#.unescape
  static unescape = (escaped) => unescape(escaped);
}

// Static Classes
Cast.ApiConfig = ApiConfig;
Cast.Error = Error;
Cast.Image = Image;
Cast.Receiver = Receiver;
Cast.ReceiverDisplayStatus = ReceiverDisplayStatus;
Cast.SenderApplication = SenderApplication;
Cast.Session = Session;
Cast.SessionRequest = SessionRequest;
Cast.Volume = Volume;

// Extensions
Cast.media = Media;
Cast.timeout = {};
<|endoftext|>


<commit_before>import logger from 'chayns-logger';
import loadTapp, { getTappById } from './tapp/custom-tapp';
import { loadLocation, loadTapps } from './chayns-info';
import { setDynamicStyle } from './ui/dynamic-style';
import Navigation from './ui/navigation';
import { validateTobitAccessToken, getUrlParameters, stringisEmptyOrWhitespace } from './utils/helper';
import { decodeTobitAccessToken } from './utils/convert';
import { setTobitAccessToken, getTobitAccessToken } from './json-native-calls/calls/index';
import { showLogin } from './login';
import ConsoleLogger from './utils/console-logger';

import { DEFAULT_LOCATIONID, DEFAULT_TAPPID } from './constants/defaults';
import LOGIN_TAPP from './constants/login-tapp';
import TAPPIDS from './constants/tapp-ids';
import Dialog from './ui/dialog/dialog';

const consoleLogger = new ConsoleLogger('(chayns-web.js)');

function startup() {
    let tappId = parseInt(getUrlParameters().tappid, 10);
    let locationId = parseInt(getUrlParameters().locationid, 10);

    if (tappId === -7) {
        tappId = -2;
    }

    logger.info({
        message: 'ChaynsWebLight requested',
        locationId,
        customNumber: tappId,
    });

    const parameterAccessToken = getUrlParameters().accesstoken;
    if (!stringisEmptyOrWhitespace(parameterAccessToken) && validateTobitAccessToken(parameterAccessToken)) {
        const decodedToken = decodeTobitAccessToken(parameterAccessToken);
        locationId = decodedToken.LocationID;
        tappId = DEFAULT_TAPPID;

        setTobitAccessToken(parameterAccessToken);
        logger.info({
            message: 'accessToken as URLParameter',
            personId: decodedToken.PersonID,
        });

        if (decodedToken.roles.indexOf('tobitBuha') !== -1) {
            Navigation.disableTappId(TAPPIDS.INTERCOM);
        }
    } else if (!locationId || !tappId) {
        let url = `${location.href}${location.href.indexOf('?') === -1 ? '?' : '&'}`;

        if (!locationId) {
            url += `${url.endsWith('&') || url.endsWith('?') ? '' : '&'}locationid=${DEFAULT_LOCATIONID}`;
        }

        if (!tappId) {
            url += `${url.endsWith('&') || url.endsWith('?') ? '' : '&'}tappId=${DEFAULT_TAPPID}`;
        }
        location.href = url;
        return;
    }

    Navigation.init();

    loadLocation(locationId)
        .then(() => {
            setDynamicStyle();
            init(tappId);
        });
}

export async function init(tappId) {
    try {
        await loadTapps();

        const getTobitAccessTokenRes = await getTobitAccessToken();
        const tobitAccessToken = getTobitAccessTokenRes.data.tobitAccessToken;

        const tapp = getTappById(tappId);

        if ((!tapp && !validateTobitAccessToken(tobitAccessToken)) || getUrlParameters().forcelogin === '1') {
            logger.info({
                message: `show login tapp (${getUrlParameters().forcelogin === '1' ? 'forcelogin' : 'no tapp found'})`,
                customNumber: tappId
            });

            showLogin();
            return;
        }

        if (!tapp) {
            consoleLogger.warn('No Tapp found!');

            Dialog.show(Dialog.type.ALERT, {
                message: `The Tapp "${tappId}" does not exist on the location "${chaynsInfo.LocationID}" or you have not the right permissions to see it.`
            });

            logger.warning({
                message: 'no tapp found',
                customNumber: tappId,
                fileName: 'custom-tapp.js',
                section: 'loadTapp'
            });
            return;
        }

        if (tappId === LOGIN_TAPP.id || (tapp.requiresLogin && !validateTobitAccessToken(tobitAccessToken))) {
            logger.info({
                message: 'show login tapp',
                customNumber: tappId
            });

            showLogin();
        } else {
            loadTapp(tappId);
        }
    } catch (e) {
        consoleLogger.error(e);
        logger.error({
            message: 'Init of ChaynsWebLight failed.',
            customNumeber: tappId,
            fileName: 'chayns-web.js',
            section: 'init',
            ex: {
                message: e.message,
                stackTrace: e.stack
            }
        });
    }
}

document.addEventListener('DOMContentLoaded', () => startup(), false);
<commit_msg>Fix init gets called if loadLocation failed<commit_after>import logger from 'chayns-logger';
import loadTapp, { getTappById } from './tapp/custom-tapp';
import { loadLocation, loadTapps } from './chayns-info';
import { setDynamicStyle } from './ui/dynamic-style';
import Navigation from './ui/navigation';
import { validateTobitAccessToken, getUrlParameters, stringisEmptyOrWhitespace } from './utils/helper';
import { decodeTobitAccessToken } from './utils/convert';
import { setTobitAccessToken, getTobitAccessToken } from './json-native-calls/calls/index';
import { showLogin } from './login';
import ConsoleLogger from './utils/console-logger';

import { DEFAULT_LOCATIONID, DEFAULT_TAPPID } from './constants/defaults';
import LOGIN_TAPP from './constants/login-tapp';
import TAPPIDS from './constants/tapp-ids';
import Dialog from './ui/dialog/dialog';

const consoleLogger = new ConsoleLogger('(chayns-web.js)');

function startup() {
    let tappId = parseInt(getUrlParameters().tappid, 10);
    let locationId = parseInt(getUrlParameters().locationid, 10);

    if (tappId === -7) {
        tappId = -2;
    }

    logger.info({
        message: 'ChaynsWebLight requested',
        locationId,
        customNumber: tappId,
    });

    const parameterAccessToken = getUrlParameters().accesstoken;
    if (!stringisEmptyOrWhitespace(parameterAccessToken) && validateTobitAccessToken(parameterAccessToken)) {
        const decodedToken = decodeTobitAccessToken(parameterAccessToken);
        locationId = decodedToken.LocationID;
        tappId = DEFAULT_TAPPID;

        setTobitAccessToken(parameterAccessToken);
        logger.info({
            message: 'accessToken as URLParameter',
            personId: decodedToken.PersonID,
        });

        if (decodedToken.roles.indexOf('tobitBuha') !== -1) {
            Navigation.disableTappId(TAPPIDS.INTERCOM);
        }
    } else if (!locationId || !tappId) {
        let url = `${location.href}${location.href.indexOf('?') === -1 ? '?' : '&'}`;

        if (!locationId) {
            url += `${url.endsWith('&') || url.endsWith('?') ? '' : '&'}locationid=${DEFAULT_LOCATIONID}`;
        }

        if (!tappId) {
            url += `${url.endsWith('&') || url.endsWith('?') ? '' : '&'}tappId=${DEFAULT_TAPPID}`;
        }
        location.href = url;
        return;
    }

    Navigation.init();

    loadLocation(locationId)
        .then((success) => {
            if (success) {
                setDynamicStyle();
                init(tappId);
            }
        });
}

export async function init(tappId) {
    try {
        await loadTapps();

        const getTobitAccessTokenRes = await getTobitAccessToken();
        const tobitAccessToken = getTobitAccessTokenRes.data.tobitAccessToken;

        const tapp = getTappById(tappId);

        if ((!tapp && !validateTobitAccessToken(tobitAccessToken)) || getUrlParameters().forcelogin === '1') {
            logger.info({
                message: `show login tapp (${getUrlParameters().forcelogin === '1' ? 'forcelogin' : 'no tapp found'})`,
                customNumber: tappId
            });

            showLogin();
            return;
        }

        if (!tapp) {
            consoleLogger.warn('No Tapp found!');

            Dialog.show(Dialog.type.ALERT, {
                message: `The Tapp "${tappId}" does not exist on the location "${chaynsInfo.LocationID}" or you have not the right permissions to see it.`
            });

            logger.warning({
                message: 'no tapp found',
                customNumber: tappId,
                fileName: 'custom-tapp.js',
                section: 'loadTapp'
            });
            return;
        }

        if (tappId === LOGIN_TAPP.id || (tapp.requiresLogin && !validateTobitAccessToken(tobitAccessToken))) {
            logger.info({
                message: 'show login tapp',
                customNumber: tappId
            });

            showLogin();
        } else {
            loadTapp(tappId);
        }
    } catch (e) {
        consoleLogger.error(e);
        logger.error({
            message: 'Init of ChaynsWebLight failed.',
            customNumeber: tappId,
            fileName: 'chayns-web.js',
            section: 'init',
            ex: {
                message: e.message,
                stackTrace: e.stack
            }
        });
    }
}

document.addEventListener('DOMContentLoaded', () => startup(), false);
<|endoftext|>


<commit_before>/**
 * @fileoverview
 * @author FE개발팀
 * @dependency type.js
 */

(function(ne) {
    'use strict';
    if (!ne) {
        ne = window.ne = {};
    }

    /**
     * 파라메터로 전달된 객체나 어레이를 순회하며 데이터를 콜백함수에 전달한다.
     * @param {*} obj 순회할 객체
     * @param {Function} iteratee 데이터가 전달될 콜백함수
     * @param {*} [context] 콜백함수의 컨텍스트
     **/
    var forEach = function(obj, iteratee, context) {
        var key,
            t;

        if (ne.isArray(obj)) {
            for (key = 0, t = obj.length; key < t; key++) {
                iteratee.call(context || null, obj[key], key, obj);
            }
        } else {
            for (key in obj) {
                if (obj.hasOwnProperty(key)) {
                    iteratee.call(context || null, obj[key], key, obj);
                }
            }
        }
    };

    /**
     * 파라메터로 전달된 객체나 어레이를 순회하며 콜백을 실행한 리턴값을 배열로 만들어 리턴한다.
     * @param {*} obj
     * @param {Function} iteratee
     * @param {*} context
     * @returns {Array}
     */
    var map = function(obj, iteratee, context) {
        var resultArray = [],
            key,
            t;

        if (ne.isArray(obj)) {
            for (key = 0, t = obj.length; key < t; key++) {
                resultArray.push(iteratee.call(context || null, obj[key], key, obj));
            }
        }
        else {
            for (key in obj) {
                if (obj.hasOwnProperty(key)) {
                    resultArray.push(iteratee.call(context || null, obj[key], key, obj));
                }
            }
        }

        return resultArray;
    };

    /**
     * 파라메터로 전달된 객체나 어레이를 순회하며 콜백을 실행한 리턴값을 다음 콜백의 첫번째 인자로 넘겨준다.
     * @param {*} obj
     * @param {Function} iteratee
     * @param {*} context
     * @returns {*}
     */
    var reduce = function(obj, iteratee, context) {
        var keys,
            index = 0,
            length,
            store,
            t;

        if (!ne.isArray(obj)) {
            keys = ne.keys(obj);
        }

        length = keys ? keys.length : obj.length;

        store = obj[keys ? keys[index++] : index++];

        for (; index < length; index++) {
            store = iteratee.call(context || null, store, obj[keys ? keys[index] : index]);
        }

        return store
    };

    ne.forEach = forEach;
    ne.map = map;
    ne.reduce = reduce;

})(window.ne);<commit_msg>주석추가.<commit_after>/**
 * @fileoverview
 * @author FE개발팀
 * @dependency type.js
 */

(function(ne) {
    'use strict';
    if (!ne) {
        ne = window.ne = {};
    }

    /**
     * 파라메터로 전달된 객체나 어레이를 순회하며 데이터를 콜백함수에 전달한다.
     * @param {*} obj 순회할 객체
     * @param {Function} iteratee 데이터가 전달될 콜백함수
     * @param {*} [context] 콜백함수의 컨텍스트
     **/
    var forEach = function(obj, iteratee, context) {
        var key,
            t;

        if (ne.isArray(obj)) {
            for (key = 0, t = obj.length; key < t; key++) {
                iteratee.call(context || null, obj[key], key, obj);
            }
        } else {
            for (key in obj) {
                if (obj.hasOwnProperty(key)) {
                    iteratee.call(context || null, obj[key], key, obj);
                }
            }
        }
    };

    /**
     * 파라메터로 전달된 객체나 어레이를 순회하며 콜백을 실행한 리턴값을 배열로 만들어 리턴한다.
     * @param {*} obj 순회할 객체
     * @param {Function} iteratee 데이터가 전달될 콜백함수
     * @param {*} [context] 콜백함수의 컨텍스트
     * @returns {Array}
     * @example
     * map([0,1,2,3], function(value) {
     *     return value + 1;
     * });
     *
     * => [1,2,3,4];
     */
    var map = function(obj, iteratee, context) {
        var resultArray = [],
            key,
            t;

        if (ne.isArray(obj)) {
            for (key = 0, t = obj.length; key < t; key++) {
                resultArray.push(iteratee.call(context || null, obj[key], key, obj));
            }
        }
        else {
            for (key in obj) {
                if (obj.hasOwnProperty(key)) {
                    resultArray.push(iteratee.call(context || null, obj[key], key, obj));
                }
            }
        }

        return resultArray;
    };

    /**
     * 파라메터로 전달된 객체나 어레이를 순회하며 콜백을 실행한 리턴값을 다음 콜백의 첫번째 인자로 넘겨준다.
     * @param {*} obj 순회할 객체
     * @param {Function} iteratee 데이터가 전달될 콜백함수
     * @param {*} [context] 콜백함수의 컨텍스트
     * @returns {*}
     * @example
     * map([0,1,2,3], function(stored, value) {
     *     return stored + value;
     * });
     *
     * => 6;
     */
    var reduce = function(obj, iteratee, context) {
        var keys,
            index = 0,
            length,
            store,
            t;

        if (!ne.isArray(obj)) {
            keys = ne.keys(obj);
        }

        length = keys ? keys.length : obj.length;

        store = obj[keys ? keys[index++] : index++];

        for (; index < length; index++) {
            store = iteratee.call(context || null, store, obj[keys ? keys[index] : index]);
        }

        return store
    };

    ne.forEach = forEach;
    ne.map = map;
    ne.reduce = reduce;

})(window.ne);<|endoftext|>


<commit_before>const embeddedApi = (doc) => {
  const script = doc.createElement('script')
  script.textContent =
`(function () {
  var open = window.open
  var childWindows = []
  window.open = function () { var win = open.apply(window, arguments); childWindows.push(win); return win; }
  window.addEventListener("beforeunload", function() { childWindows.forEach(function(win) { win.close() }) })
  var origin = '${window.location.origin}'
  var parent = window.parent
  document.addEventListener("mouseup", function () {
    parent.postMessage({ type: "mouseup" }, origin)
  })
  document.addEventListener("mousemove", function (e) {
    parent.postMessage({ type: "mousemove", x: e.screenX, y: e.screenY }, origin)
  })
  document.addEventListener("click", function (e) {
    parent.postMessage({ type: "click" }, origin)
  })
  window.addEventListener("error", function (e) {
    parent.postMessage({ type: "error", message: e.error.message }, origin)
  })
  window.addEventListener("message", function (e) {
    if (e.data.type === "debug") {
      var button = document.querySelector(".elm-mini-controls-button")
      if (button) button.click()
    }
  })

  var oldLog = console.log
  console.log = function () {
    var firstArg = arguments[0]
    if (arguments.length === 1 && typeof firstArg === 'string' && firstArg.indexOf(': ') !== -1) {
      var split = firstArg.split(': ')
      var tag = split[0]
      var body = split.slice(1).join(': ')
      parent.postMessage({ type: 'log', log: { tag: tag, body: body } }, origin)
    }
    oldLog.apply(this, arguments)
  }
  delete window.parent
}())`

  const style = doc.createElement('style')
  style.textContent =
`.elm-overlay { z-index: 999999999999 !important; }
.elm-mini-controls { display: none !important; }`

  doc.head.appendChild(script)
  doc.head.appendChild(style)
}

const onReady = (doc, random) => {
  const script = doc.createElement('script')
  script.textContent =
`function __ellie_onReady_${random}(cb) {
  function completed() {
    document.removeEventListener("DOMContentLoaded", completed)
    window.removeEventListener("load", completed)
    cb()
  }
  if (document.readyState === "complete" || ( document.readyState !== "loading" && !document.documentElement.doScroll)) {
    setTimeout(completed)
  } else {
    document.addEventListener("DOMContentLoaded", completed)
    window.addEventListener("load", completed)
  }
}`
  doc.head.appendChild(script)
}

const wrapOnReady = (random, script) => {
  return '__ellie_onReady_' + random + '(function () {' + script + '})'
}

const parser = new DOMParser()

export default ({ htmlCode, embedApi, sourceScript }) => {
  return new Promise(function (resolve, reject) {
    try {
      const doc = parser.parseFromString(htmlCode, 'text/html')
      const random = Math.floor(9007199254740991 * Math.random())

      doc.querySelectorAll('script').forEach(el => {
        if (el.getAttribute('src') !== null && !el.textContent.trim()) return
        el.textContent = wrapOnReady(random, el.textContent)
      })

      if (embedApi) embeddedApi(doc)
      onReady(doc, random)

      const div = doc.createElement('div')
      div.innerHTML = sourceScript
      doc.body.prepend(div.children[0])
      var blob = new Blob([doc.documentElement.outerHTML], { type: 'text/html' })
      resolve(URL.createObjectURL(blob))
    } catch (error) {
      reject(error)
    }
  })
}
<commit_msg>Replaced prepend with insertBefore. Fixes #32 (#33)<commit_after>const embeddedApi = (doc) => {
  const script = doc.createElement('script')
  script.textContent =
`(function () {
  var open = window.open
  var childWindows = []
  window.open = function () { var win = open.apply(window, arguments); childWindows.push(win); return win; }
  window.addEventListener("beforeunload", function() { childWindows.forEach(function(win) { win.close() }) })
  var origin = '${window.location.origin}'
  var parent = window.parent
  document.addEventListener("mouseup", function () {
    parent.postMessage({ type: "mouseup" }, origin)
  })
  document.addEventListener("mousemove", function (e) {
    parent.postMessage({ type: "mousemove", x: e.screenX, y: e.screenY }, origin)
  })
  document.addEventListener("click", function (e) {
    parent.postMessage({ type: "click" }, origin)
  })
  window.addEventListener("error", function (e) {
    parent.postMessage({ type: "error", message: e.error.message }, origin)
  })
  window.addEventListener("message", function (e) {
    if (e.data.type === "debug") {
      var button = document.querySelector(".elm-mini-controls-button")
      if (button) button.click()
    }
  })

  var oldLog = console.log
  console.log = function () {
    var firstArg = arguments[0]
    if (arguments.length === 1 && typeof firstArg === 'string' && firstArg.indexOf(': ') !== -1) {
      var split = firstArg.split(': ')
      var tag = split[0]
      var body = split.slice(1).join(': ')
      parent.postMessage({ type: 'log', log: { tag: tag, body: body } }, origin)
    }
    oldLog.apply(this, arguments)
  }
  delete window.parent
}())`

  const style = doc.createElement('style')
  style.textContent =
`.elm-overlay { z-index: 999999999999 !important; }
.elm-mini-controls { display: none !important; }`

  doc.head.appendChild(script)
  doc.head.appendChild(style)
}

const onReady = (doc, random) => {
  const script = doc.createElement('script')
  script.textContent =
`function __ellie_onReady_${random}(cb) {
  function completed() {
    document.removeEventListener("DOMContentLoaded", completed)
    window.removeEventListener("load", completed)
    cb()
  }
  if (document.readyState === "complete" || ( document.readyState !== "loading" && !document.documentElement.doScroll)) {
    setTimeout(completed)
  } else {
    document.addEventListener("DOMContentLoaded", completed)
    window.addEventListener("load", completed)
  }
}`
  doc.head.appendChild(script)
}

const wrapOnReady = (random, script) => {
  return '__ellie_onReady_' + random + '(function () {' + script + '})'
}

const parser = new DOMParser()

export default ({ htmlCode, embedApi, sourceScript }) => {
  return new Promise(function (resolve, reject) {
    try {
      const doc = parser.parseFromString(htmlCode, 'text/html')
      const random = Math.floor(9007199254740991 * Math.random())

      doc.querySelectorAll('script').forEach(el => {
        if (el.getAttribute('src') !== null && !el.textContent.trim()) return
        el.textContent = wrapOnReady(random, el.textContent)
      })

      if (embedApi) embeddedApi(doc)
      onReady(doc, random)

      const div = doc.createElement('div')
      div.innerHTML = sourceScript
      const firstChild = doc.body.children[0]
      doc.body.insertBefore(div.children[0], firstChild)
      var blob = new Blob([doc.documentElement.outerHTML], { type: 'text/html' })
      resolve(URL.createObjectURL(blob))
    } catch (error) {
      reject(error)
    }
  })
}
<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react'
import {Table, Button} from 'react-bootstrap'
import autobind from 'autobind-decorator'

import Form from 'components/Form'
import Messages from 'components/Messages'
import Autocomplete from 'components/Autocomplete'
import ButtonToggleGroup from 'components/ButtonToggleGroup'
import History from 'components/History'

import API from 'api'
import {Position, Organization, Person} from 'models'

import REMOVE_ICON from 'resources/delete.png'

export default class PositionForm extends Component {
	static propTypes = {
		position: PropTypes.object.isRequired,
		edit: PropTypes.bool,
		error: PropTypes.object,
		success: PropTypes.object,
	}
	static contextTypes = {
		app: PropTypes.object
	}

	render() {
		let {position, error, success, edit} = this.props

		error = this.props.error || (this.state && this.state.error)

		let relationshipPositionType = position.type === 'PRINCIPAL' ? 'ADVISOR' : 'PRINCIPAL'
		let currentUser = this.context.app.state.currentUser

		let orgSearchQuery = {}
		let personSearchQuery = {}
		if (position.type === 'ADVISOR' || position.type === 'SUPER_USER' || position.type === 'ADMINISTRATOR') {
			orgSearchQuery.type = 'ADVISOR_ORG'
			personSearchQuery.role = 'ADVISOR'
			if (currentUser && currentUser.position && currentUser.position.type === 'SUPER_USER') {
				orgSearchQuery.parentOrgId = currentUser.position.organization.id
				orgSearchQuery.parentOrgRecursively = true
			}
		} else if (position.type === 'PRINCIPAL') {
			orgSearchQuery.type = 'PRINCIPAL_ORG'
			personSearchQuery.role = 'PRINCIPAL'
		}

		return (
			<Form
				formFor={position}
				onChange={this.onChange}
				onSubmit={this.onSubmit}
				submitText="Save position"
				horizontal
			>

				<Messages error={error} success={success} />

{edit ? "Edit Position" : "Create a new Position"}

				<fieldset>

					<Form.Field id="type" disabled={this.props.edit}>
						<ButtonToggleGroup>
							<Button id="typeAdvisorButton" value="ADVISOR">NATO (Billet)</Button>
							<Button id="typePrincipalButton" value="PRINCIPAL">Principal (Tashkil)</Button>
						</ButtonToggleGroup>
					</Form.Field>

					<Form.Field id="status" >
						<ButtonToggleGroup>
							<Button id="statusActiveButton" value="ACTIVE">Active</Button>
							<Button id="statusInactiveButton" value="INACTIVE">Inactive</Button>
						</ButtonToggleGroup>
					</Form.Field>

					<Form.Field id="organization">
						<Autocomplete
							placeholder="Select the organization for this position"
							objectType={Organization}
							fields="id, longName, shortName"
							template={org => {org.shortName} - {org.longName}}
							queryParams={orgSearchQuery}
							valueKey="shortName"
						/>
					</Form.Field>

					{position.type === 'PRINCIPAL' ?
						<Form.Field id="code" label="Tashkil Code" placeholder="Postion ID or Number" />
						:
						<Form.Field id="code" label="Billet Code" placeholder="Postion ID or Number" />
					}

					<Form.Field id="name" label="Position Name" placeholder="Name/Description of Position"/>

					<Form.Field id="person">
						<Autocomplete valueKey="name"
							placeholder="Select the person in this position"
							url="/api/people/search"
							queryParams={personSearchQuery}
						/>
					</Form.Field>

					{position.type !== 'PRINCIPAL' &&
						<Form.Field id="permissions">
							<ButtonToggleGroup>
								<Button id="permsAdvisorButton" value="ADVISOR">Advisor</Button>
								<Button id="permsSuperUserButton" value="SUPER_USER">Super User</Button>
								{currentUser && currentUser.isAdmin() &&
									<Button id="permsAdminButton" value="ADMINISTRATOR">Administrator</Button>
								}
							</ButtonToggleGroup>
						</Form.Field>
					}

				</fieldset>

				<fieldset>
					<legend>Assigned {position.type === 'PRINCIPAL' ? 'advisor' : 'advisee'}</legend>

					{position.type === 'PRINCIPAL' ?

Who is this person advised by?

						:

Who does this person advise?

					}

					<Form.Field id="associatedPositions">
						<Autocomplete
							placeholder={'Start typing to search for ' + (position.type === 'PRINCIPAL' ? 'an advisor' : 'a principal') + ' position...'}
							objectType={Position}
							fields={'id, name, code, type, person { id, name, rank }'}
							template={pos =>
								{pos.name} - {pos.code} ({(pos.person) ? pos.person.name : empty})
							}
							onChange={this.addPositionRelationship}
							clearOnSelect={true}
							queryParams={{type: relationshipPositionType, matchPersonName: true}} />

									Name
									Position
									Org

								{Position.map(position.associatedPositions, relPos => {
									let person = new Person(relPos.person)
									return (

												{person && }

											{person && person.name}
											{relPos.name}
											{relPos.organization && relPos.organization.shortName}

									)
								})}

					</Form.Field>
				</fieldset>

				<fieldset>
					<legend>Additional information</legend>
					<Form.Field id="location">
						<Autocomplete valueKey="name" placeholder="Start typing to find a location where this Position will operate from..." url="/api/locations/search" />
					</Form.Field>
				</fieldset>
			</Form>
		)
	}

	@autobind
	addPositionRelationship(newRelatedPos)  {
		let position = this.props.position
		let rels = position.associatedPositions

		if (!rels.find(relPos => relPos.id === newRelatedPos.id)) {
			let newRels = rels.slice()
			newRels.push(new Position(newRelatedPos))

			position.associatedPositions = newRels
			this.onChange()
		}
	}

	@autobind
	removePositionRelationship(relToDelete) {
		let position = this.props.position
		let rels = position.associatedPositions
		let index = rels.findIndex(rel => rel.id === relToDelete.id)

		if (index !== -1) {
			rels.splice(index, 1)
			this.onChange()
		}
	}

	@autobind
	onChange() {
		this.forceUpdate()
	}

	@autobind
	onSubmit(event) {
		let {position, edit} = this.props
		position = Object.assign({}, position)

		if (position.type !== 'PRINCIPAL') {
			position.type = position.permissions || 'ADVISOR'
		}
		delete position.permissions
		position.organization = {id: position.organization.id}
		position.person = (position.person && position.person.id) ? {id: position.person.id} : null
		position.code = position.code || null //Need to null out empty position codes

		let url = `/api/positions/${edit ? 'update' : 'new'}`
		API.send(url, position, {disableSubmits: true})
			.then(response => {
				if (response.id) {
					position.id = response.id
				}

				History.replace(Position.pathForEdit(position), false)
				History.push(Position.pathFor(position), {success: 'Saved Position', skipPageLeaveWarning: true})
			}).catch(error => {
				this.setState({error: error})
				window.scrollTo(0, 0)
			})
	}
}
<commit_msg>fixes #542: renme advisor permission to user<commit_after>import React, {Component, PropTypes} from 'react'
import {Table, Button} from 'react-bootstrap'
import autobind from 'autobind-decorator'

import Form from 'components/Form'
import Messages from 'components/Messages'
import Autocomplete from 'components/Autocomplete'
import ButtonToggleGroup from 'components/ButtonToggleGroup'
import History from 'components/History'

import API from 'api'
import {Position, Organization, Person} from 'models'

import REMOVE_ICON from 'resources/delete.png'

export default class PositionForm extends Component {
	static propTypes = {
		position: PropTypes.object.isRequired,
		edit: PropTypes.bool,
		error: PropTypes.object,
		success: PropTypes.object,
	}
	static contextTypes = {
		app: PropTypes.object
	}

	render() {
		let {position, error, success, edit} = this.props

		error = this.props.error || (this.state && this.state.error)

		let relationshipPositionType = position.type === 'PRINCIPAL' ? 'ADVISOR' : 'PRINCIPAL'
		let currentUser = this.context.app.state.currentUser

		let orgSearchQuery = {}
		let personSearchQuery = {}
		if (position.type === 'ADVISOR' || position.type === 'SUPER_USER' || position.type === 'ADMINISTRATOR') {
			orgSearchQuery.type = 'ADVISOR_ORG'
			personSearchQuery.role = 'ADVISOR'
			if (currentUser && currentUser.position && currentUser.position.type === 'SUPER_USER') {
				orgSearchQuery.parentOrgId = currentUser.position.organization.id
				orgSearchQuery.parentOrgRecursively = true
			}
		} else if (position.type === 'PRINCIPAL') {
			orgSearchQuery.type = 'PRINCIPAL_ORG'
			personSearchQuery.role = 'PRINCIPAL'
		}

		return (
			<Form
				formFor={position}
				onChange={this.onChange}
				onSubmit={this.onSubmit}
				submitText="Save position"
				horizontal
			>

				<Messages error={error} success={success} />

{edit ? "Edit Position" : "Create a new Position"}

				<fieldset>

					<Form.Field id="type" disabled={this.props.edit}>
						<ButtonToggleGroup>
							<Button id="typeAdvisorButton" value="ADVISOR">NATO (Billet)</Button>
							<Button id="typePrincipalButton" value="PRINCIPAL">Principal (Tashkil)</Button>
						</ButtonToggleGroup>
					</Form.Field>

					<Form.Field id="status" >
						<ButtonToggleGroup>
							<Button id="statusActiveButton" value="ACTIVE">Active</Button>
							<Button id="statusInactiveButton" value="INACTIVE">Inactive</Button>
						</ButtonToggleGroup>
					</Form.Field>

					<Form.Field id="organization">
						<Autocomplete
							placeholder="Select the organization for this position"
							objectType={Organization}
							fields="id, longName, shortName"
							template={org => {org.shortName} - {org.longName}}
							queryParams={orgSearchQuery}
							valueKey="shortName"
						/>
					</Form.Field>

					{position.type === 'PRINCIPAL' ?
						<Form.Field id="code" label="Tashkil Code" placeholder="Postion ID or Number" />
						:
						<Form.Field id="code" label="Billet Code" placeholder="Postion ID or Number" />
					}

					<Form.Field id="name" label="Position Name" placeholder="Name/Description of Position"/>

					<Form.Field id="person">
						<Autocomplete valueKey="name"
							placeholder="Select the person in this position"
							url="/api/people/search"
							queryParams={personSearchQuery}
						/>
					</Form.Field>

					{position.type !== 'PRINCIPAL' &&
						<Form.Field id="permissions">
							<ButtonToggleGroup>
								<Button id="permsAdvisorButton" value="ADVISOR">User</Button>
								<Button id="permsSuperUserButton" value="SUPER_USER">Super User</Button>
								{currentUser && currentUser.isAdmin() &&
									<Button id="permsAdminButton" value="ADMINISTRATOR">Administrator</Button>
								}
							</ButtonToggleGroup>
						</Form.Field>
					}

				</fieldset>

				<fieldset>
					<legend>Assigned {position.type === 'PRINCIPAL' ? 'advisor' : 'advisee'}</legend>

					{position.type === 'PRINCIPAL' ?

Who is this person advised by?

						:

Who does this person advise?

					}

					<Form.Field id="associatedPositions">
						<Autocomplete
							placeholder={'Start typing to search for ' + (position.type === 'PRINCIPAL' ? 'an advisor' : 'a principal') + ' position...'}
							objectType={Position}
							fields={'id, name, code, type, person { id, name, rank }'}
							template={pos =>
								{pos.name} - {pos.code} ({(pos.person) ? pos.person.name : empty})
							}
							onChange={this.addPositionRelationship}
							clearOnSelect={true}
							queryParams={{type: relationshipPositionType, matchPersonName: true}} />

									Name
									Position
									Org

								{Position.map(position.associatedPositions, relPos => {
									let person = new Person(relPos.person)
									return (

												{person && }

											{person && person.name}
											{relPos.name}
											{relPos.organization && relPos.organization.shortName}

									)
								})}

					</Form.Field>
				</fieldset>

				<fieldset>
					<legend>Additional information</legend>
					<Form.Field id="location">
						<Autocomplete valueKey="name" placeholder="Start typing to find a location where this Position will operate from..." url="/api/locations/search" />
					</Form.Field>
				</fieldset>
			</Form>
		)
	}

	@autobind
	addPositionRelationship(newRelatedPos)  {
		let position = this.props.position
		let rels = position.associatedPositions

		if (!rels.find(relPos => relPos.id === newRelatedPos.id)) {
			let newRels = rels.slice()
			newRels.push(new Position(newRelatedPos))

			position.associatedPositions = newRels
			this.onChange()
		}
	}

	@autobind
	removePositionRelationship(relToDelete) {
		let position = this.props.position
		let rels = position.associatedPositions
		let index = rels.findIndex(rel => rel.id === relToDelete.id)

		if (index !== -1) {
			rels.splice(index, 1)
			this.onChange()
		}
	}

	@autobind
	onChange() {
		this.forceUpdate()
	}

	@autobind
	onSubmit(event) {
		let {position, edit} = this.props
		position = Object.assign({}, position)

		if (position.type !== 'PRINCIPAL') {
			position.type = position.permissions || 'ADVISOR'
		}
		delete position.permissions
		position.organization = {id: position.organization.id}
		position.person = (position.person && position.person.id) ? {id: position.person.id} : null
		position.code = position.code || null //Need to null out empty position codes

		let url = `/api/positions/${edit ? 'update' : 'new'}`
		API.send(url, position, {disableSubmits: true})
			.then(response => {
				if (response.id) {
					position.id = response.id
				}

				History.replace(Position.pathForEdit(position), false)
				History.push(Position.pathFor(position), {success: 'Saved Position', skipPageLeaveWarning: true})
			}).catch(error => {
				this.setState({error: error})
				window.scrollTo(0, 0)
			})
	}
}
<|endoftext|>


<commit_before>var w = screen.width * 0.30,
h = screen.height * 0.40,
r = 380,
x = d3.scale.linear().range([0, r]),
y = d3.scale.linear().range([0, r]),
p = 15,
label_rad = 25,
node,
root,
fc1,fc2,fc3,
chart_dyn,
chart_type;

if (typeof String.prototype.startsWith != 'function') {
    // see below for better implementation!
    String.prototype.startsWith = function (str){
        return this.indexOf(str) == 0;
    };
}

var colorMap = {"Wet Storage": "#1f77b4",
                "Dry Storage": "#aec7e8",
                "Repository": "#ffbb78",
                "Reprocessed Fuel": "#2ca02c"
               }

function colorPicker(s) {
    var c = "white";
    for (var key in colorMap) {
        if (s.startsWith(key)) {
            c = colorMap[key];
            break;
        };
    };
    return c;
}

function wrap(text, width) {
    text.each(function() {
        var text = d3.select(this),
        lines = text.text().split(/\n/).reverse(),
        line,
        lineNumber = 0,
        lineHeight = 1.1, // ems
        x = text.attr("x"),
        y = text.attr("y"),
        dy = parseFloat(text.attr("dy")),
        tspan = text.text(null).append("tspan").attr("x", x)
            .attr("y", y).attr("dy", dy + "em");
        lineNumber = - Math.floor(lines.length / 2);
        while (line = lines.pop()) {
            tspan = text.append("tspan").attr("x", x)
                .attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em")
                .text(line);
        }
    });
}

var pack = d3.layout.pack()
    .size([r, r])
    .value(function(d) { return d.size;})
    .padding(p);

function load_data(chart_node,json_data)
{
    d3.json(json_data, function(data) {
        node = root = data;
        var nodes = pack.nodes(root);
        chart_node.selectAll("circle")
            .remove();
        chart_node.selectAll("circle")
            .data(nodes)
            .enter().append("svg:circle")
            .attr("class", function(d) { return d.children ? "parent" : "child"; })
            .attr("cx", function(d) { return d.x; })
            .attr("cy", function(d) { return d.y; })
            .attr("r", function(d) { return d.r; })
            .style("stroke-width",function(d) {if (d.children && !chart_dyn && d.children[0].children)
                                               {return 0}; return 1;})
            .style("fill", function(d){return colorPicker(d.name)});

        chart_node.selectAll("text")
            .remove();
        chart_node.selectAll("text")
            .data(nodes)
            .enter().append("svg:text")
            .attr("class", function(d) { return d.children ? "parent" : "child"; })
            .attr("x", function(d) { return d.x; })
            .attr("y", function(d) { if (d.children) {return d.y - d.r - 20;}; return d.y; })
            .attr("dy", ".35em")
            .attr("text-anchor", "middle")
            .style("opacity", function(d) { return d.r > label_rad ? 1 : 0; })
            .text(function(d) { return d.name; })
            .call(wrap);
    });
}

function add_info(chart_id)
{

    var new_chart = d3.select(chart_id + " svg")
        .attr("width", w)
        .attr("height", h)
        .append("svg:g")
        .attr("transform", "translate(" + (w - r) / 2 + "," + (h - r) / 2 + ")");

    return new_chart;
}

function load_static(kind)
{
    var cost_ver = "";

    if (kind == "cost")
    {
        cost_ver = "-new";
    }
    load_data(fc1,"info-raw-data-run1" + cost_ver + "-2000_2050_2100-" + kind + ".json");
    load_data(fc2,"info-raw-data-run3" + cost_ver + "-2000_2050_2100-" + kind + ".json");
    load_data(fc3,"info-raw-data-run5" + cost_ver + "-2000_2050_2100-" + kind + ".json");
}

function load_fcs(kind,year) {
    var cost_ver = "";

    if (kind == "cost")
    {
        cost_ver = "-new";
    }
    load_data(fc1,"years/info-raw-data-run1" + cost_ver + "-" + year + "-" + kind + ".json");
    load_data(fc2,"years/info-raw-data-run3" + cost_ver + "-" + year + "-" + kind + ".json");
    load_data(fc3,"years/info-raw-data-run5" + cost_ver + "-" + year + "-" + kind + ".json");
}

function yearUpdate(year) {
    document.querySelector('#yearlabel').value = year;
    load_fcs(chart_type,year);
}

function info(dynamic,kind)
{
    chart_type = kind;
    chart_dyn = dynamic;

    fc1 = add_info("#chart1");
    fc2 = add_info("#chart2");
    fc3 = add_info("#chart3");

    if (dynamic)
    {
        load_fcs(kind,2000);
    }
    else
    {
        load_static(kind);
    }
}

<commit_msg>Try splitting data for value only<commit_after>var w = screen.width * 0.30,
h = screen.height * 0.40,
r = 380,
x = d3.scale.linear().range([0, r]),
y = d3.scale.linear().range([0, r]),
p = 15,
label_rad = 25,
node,
root,
fc1,fc2,fc3,
chart_dyn,
chart_type;

if (typeof String.prototype.startsWith != 'function') {
    // see below for better implementation!
    String.prototype.startsWith = function (str){
        return this.indexOf(str) == 0;
    };
}

var colorMap = {"Wet Storage": "#1f77b4",
                "Dry Storage": "#aec7e8",
                "Repository": "#ffbb78",
                "Reprocessed Fuel": "#2ca02c"
               }

function colorPicker(s) {
    var c = "white";
    for (var key in colorMap) {
        if (s.startsWith(key)) {
            c = colorMap[key];
            break;
        };
    };
    return c;
}

function wrap(text, width) {
    text.each(function() {
        var text = d3.select(this),
        lines = text.text().split(/\n/).reverse(),
        line,
        lineNumber = 0,
        lineHeight = 1.1, // ems
        x = text.attr("x"),
        y = text.attr("y"),
        dy = parseFloat(text.attr("dy")),
        tspan = text.text(null).append("tspan").attr("x", x)
            .attr("y", y).attr("dy", dy + "em");
        lineNumber = - Math.floor(lines.length / 2);
        while (line = lines.pop()) {
            tspan = text.append("tspan").attr("x", x)
                .attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em")
                .text(line);
        }
    });
}

var pack = d3.layout.pack()
    .size([r, r])
    .value(function(d) { return d.size;})
    .padding(p);

function load_data(chart_node,json_data)
{
    d3.json(json_data, function(data) {
        node = root = data;
        var nodes = pack.nodes(root);
        chart_node.selectAll("circle")
            .remove();
        chart_node.selectAll("circle")
            .data(nodes)
            .enter().append("svg:circle")
            .attr("class", function(d) { return d.children ? "parent" : "child"; })
            .attr("cx", function(d) { return d.x; })
            .attr("cy", function(d) { return d.y; })
            .attr("r", function(d) { return d.r; })
            .style("stroke-width",function(d) {if (d.children && !chart_dyn && d.children[0].children)
                                               {return 0}; return 1;})
            .style("fill", function(d){return colorPicker(d.name)});

        chart_node.selectAll("text")
            .remove();
        chart_node.selectAll("text")
            .data(nodes)
            .enter().append("svg:text")
            .attr("class", function(d) { return d.children ? "parent" : "child"; })
            .attr("x", function(d) { return d.x; })
            .attr("y", function(d) { if (d.children) {return d.y - d.r - 20;}; return d.y; })
            .attr("dy", ".35em")
            .attr("text-anchor", "middle")
            .style("opacity", function(d) { return d.r > label_rad ? 1 : 0; })
            .text(function(d) { return d.name.split("\n")[1]; })
            .call(wrap);
    });
}

function add_info(chart_id)
{

    var new_chart = d3.select(chart_id + " svg")
        .attr("width", w)
        .attr("height", h)
        .append("svg:g")
        .attr("transform", "translate(" + (w - r) / 2 + "," + (h - r) / 2 + ")");

    return new_chart;
}

function load_static(kind)
{
    var cost_ver = "";

    if (kind == "cost")
    {
        cost_ver = "-new";
    }
    load_data(fc1,"info-raw-data-run1" + cost_ver + "-2000_2050_2100-" + kind + ".json");
    load_data(fc2,"info-raw-data-run3" + cost_ver + "-2000_2050_2100-" + kind + ".json");
    load_data(fc3,"info-raw-data-run5" + cost_ver + "-2000_2050_2100-" + kind + ".json");
}

function load_fcs(kind,year) {
    var cost_ver = "";

    if (kind == "cost")
    {
        cost_ver = "-new";
    }
    load_data(fc1,"years/info-raw-data-run1" + cost_ver + "-" + year + "-" + kind + ".json");
    load_data(fc2,"years/info-raw-data-run3" + cost_ver + "-" + year + "-" + kind + ".json");
    load_data(fc3,"years/info-raw-data-run5" + cost_ver + "-" + year + "-" + kind + ".json");
}

function yearUpdate(year) {
    document.querySelector('#yearlabel').value = year;
    load_fcs(chart_type,year);
}

function info(dynamic,kind)
{
    chart_type = kind;
    chart_dyn = dynamic;

    fc1 = add_info("#chart1");
    fc2 = add_info("#chart2");
    fc3 = add_info("#chart3");

    if (dynamic)
    {
        load_fcs(kind,2000);
    }
    else
    {
        load_static(kind);
    }
}

<|endoftext|>


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

// Import the Firebase SDK for Google Cloud Functions.
const functions = require('firebase-functions');
// Import and initialize the Firebase Admin SDK.
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const gcs = require('@google-cloud/storage')();
const vision = require('@google-cloud/vision')();
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');

// Adds a message that welcomes new users into the chat.
exports.addWelcomeMessages = functions.auth.user().onCreate(event => {
  const user = event.data;
  console.log('A new user signed in for the first time.');
  const fullName = user.displayName || 'Anonymous';

  // Saves the new welcome message into the database
  // which then displays it in the FriendlyChat clients.
  return admin.database().ref('messages').push({
    name: 'Firebase Bot',
    photoUrl: '/images/firebase-logo.png', // Firebase logo
    text: `${fullName} signed in for the first time! Welcome!`
  }).then(() => console.log('Welcome message written to database.'));
});

// Checks if uploaded images are flagged as Adult or Violence and if so blurs them.
exports.blurOffensiveImages = functions.storage.object().onChange(event => {
  const object = event.data;
  // Exit if this is a deletion or a deploy event.
  if (object.resourceState === 'not_exists') {
    return console.log('This is a deletion event.');
  } else if (!object.name) {
    return console.log('This is a deploy event.');
  }

  const image = {
    source: {imageUri: `gs://${object.bucket}/${object.name}`}
  };

  // Check the image content using the Cloud Vision API.
  return vision.safeSearchDetection(image).then(batchAnnotateImagesResponse => {
    const safeSearchResult = batchAnnotateImagesResponse[0].safeSearchAnnotation;
    if (safeSearchResult.adult === 'LIKELY' ||
        safeSearchResult.adult === 'VERY_LIKELY' ||
        safeSearchResult.violence === 'LIKELY' ||
        safeSearchResult.violence === 'VERY_LIKELY') {
      console.log('The image', object.name, 'has been detected as inappropriate.');
      return blurImage(object.name, object.bucket);
    } else {
      console.log('The image', object.name,'has been detected as OK.');
    }
  });
});

// Blurs the given image located in the given bucket using ImageMagick.
function blurImage(filePath, bucketName) {
  const tempLocalFile = path.join(os.tmpdir(), path.basename(filePath));
  const messageId = filePath.split(path.sep)[1];
  const bucket = gcs.bucket(bucketName);

  // Download file from bucket.
  return bucket.file(filePath).download({destination: tempLocalFile})
      .then(() => {
        console.log('Image has been downloaded to', tempLocalFile);
        // Blur the image using ImageMagick.
        return spawn('convert', [tempLocalFile, '-channel', 'RGBA', '-blur', '0x24', tempLocalFile]);
      }).then(() => {
        console.log('Image has been blurred');
        // Uploading the Blurred image back into the bucket.
        return bucket.upload(tempLocalFile, {destination: filePath});
      }).then(() => {
        console.log('Blurred image has been uploaded to', filePath);
        // Deleting the local file to free up disk space.
        fs.unlinkSync(tempLocalFile);
        console.log('Deleted local file.');
        // Indicate that the message has been moderated.
        return admin.database().ref(`/messages/${messageId}`).update({moderated: true});
      }).then(() => {
        console.log('Marked the image as moderated in the database.');
      });
}

// Sends a notifications to all users when a new message is posted.
exports.sendNotifications = functions.database.ref('/messages/{messageId}').onWrite(event => {
  const snapshot = event.data;
  // Only send a notification when a message has been created.
  if (snapshot.previous.val()) {
    return;
  }

  // Notification details.
  const text = snapshot.val().text;
  const payload = {
    notification: {
      title: `${snapshot.val().name} posted ${text ? 'a message' : 'an image'}`,
      body: text ? (text.length <= 100 ? text : text.substring(0, 97) + '...') : '',
      icon: snapshot.val().photoUrl || '/images/profile_placeholder.png',
      click_action: `https://${functions.config().firebase.authDomain}`
    }
  };

  // Get the list of device tokens.
  return admin.database().ref('fcmTokens').once('value').then(allTokens => {
    if (allTokens.val()) {
      // Listing all tokens.
      const tokens = Object.keys(allTokens.val());

      // Send notifications to all tokens.
      return admin.messaging().sendToDevice(tokens, payload).then(response => {
        // For each message check if there was an error.
        const tokensToRemove = [];
        response.results.forEach((result, index) => {
          const error = result.error;
          if (error) {
            console.error('Failure sending notification to', tokens[index], error);
            // Cleanup the tokens who are not registered anymore.
            if (error.code === 'messaging/invalid-registration-token' ||
                error.code === 'messaging/registration-token-not-registered') {
              tokensToRemove.push(allTokens.ref.child(tokens[index]).remove());
            }
          }
        });
        return Promise.all(tokensToRemove);
      });
    }
  });
});
<commit_msg>Using Types for Cloud Vision API Likelyness<commit_after>/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Import the Firebase SDK for Google Cloud Functions.
const functions = require('firebase-functions');
// Import and initialize the Firebase Admin SDK.
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const gcs = require('@google-cloud/storage')();
const Vision = require('@google-cloud/vision');
const vision = new Vision();
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');

// Adds a message that welcomes new users into the chat.
exports.addWelcomeMessages = functions.auth.user().onCreate(event => {
  const user = event.data;
  console.log('A new user signed in for the first time.');
  const fullName = user.displayName || 'Anonymous';

  // Saves the new welcome message into the database
  // which then displays it in the FriendlyChat clients.
  return admin.database().ref('messages').push({
    name: 'Firebase Bot',
    photoUrl: '/images/firebase-logo.png', // Firebase logo
    text: `${fullName} signed in for the first time! Welcome!`
  }).then(() => console.log('Welcome message written to database.'));
});

// Checks if uploaded images are flagged as Adult or Violence and if so blurs them.
exports.blurOffensiveImages = functions.storage.object().onChange(event => {
  const object = event.data;
  // Exit if this is a deletion or a deploy event.
  if (object.resourceState === 'not_exists') {
    return console.log('This is a deletion event.');
  } else if (!object.name) {
    return console.log('This is a deploy event.');
  }

  const image = {
    source: {imageUri: `gs://${object.bucket}/${object.name}`}
  };

  // Check the image content using the Cloud Vision API.
  return vision.safeSearchDetection(image).then(batchAnnotateImagesResponse => {
    const safeSearchResult = batchAnnotateImagesResponse[0].safeSearchAnnotation;
    const Likelihood = Vision.types.Likelihood;
    if (Likelihood[safeSearchResult.adult] >= Likelihood.LIKELY ||
        Likelihood[safeSearchResult.violence] >= Likelihood.LIKELY) {
      console.log('The image', object.name, 'has been detected as inappropriate.');
      return blurImage(object.name, object.bucket);
    } else {
      console.log('The image', object.name,'has been detected as OK.');
    }
  });
});

// Blurs the given image located in the given bucket using ImageMagick.
function blurImage(filePath, bucketName) {
  const tempLocalFile = path.join(os.tmpdir(), path.basename(filePath));
  const messageId = filePath.split(path.sep)[1];
  const bucket = gcs.bucket(bucketName);

  // Download file from bucket.
  return bucket.file(filePath).download({destination: tempLocalFile})
      .then(() => {
        console.log('Image has been downloaded to', tempLocalFile);
        // Blur the image using ImageMagick.
        return spawn('convert', [tempLocalFile, '-channel', 'RGBA', '-blur', '0x24', tempLocalFile]);
      }).then(() => {
        console.log('Image has been blurred');
        // Uploading the Blurred image back into the bucket.
        return bucket.upload(tempLocalFile, {destination: filePath});
      }).then(() => {
        console.log('Blurred image has been uploaded to', filePath);
        // Deleting the local file to free up disk space.
        fs.unlinkSync(tempLocalFile);
        console.log('Deleted local file.');
        // Indicate that the message has been moderated.
        return admin.database().ref(`/messages/${messageId}`).update({moderated: true});
      }).then(() => {
        console.log('Marked the image as moderated in the database.');
      });
}

// Sends a notifications to all users when a new message is posted.
exports.sendNotifications = functions.database.ref('/messages/{messageId}').onWrite(event => {
  const snapshot = event.data;
  // Only send a notification when a message has been created.
  if (snapshot.previous.val()) {
    return;
  }

  // Notification details.
  const text = snapshot.val().text;
  const payload = {
    notification: {
      title: `${snapshot.val().name} posted ${text ? 'a message' : 'an image'}`,
      body: text ? (text.length <= 100 ? text : text.substring(0, 97) + '...') : '',
      icon: snapshot.val().photoUrl || '/images/profile_placeholder.png',
      click_action: `https://${functions.config().firebase.authDomain}`
    }
  };

  // Get the list of device tokens.
  return admin.database().ref('fcmTokens').once('value').then(allTokens => {
    if (allTokens.val()) {
      // Listing all tokens.
      const tokens = Object.keys(allTokens.val());

      // Send notifications to all tokens.
      return admin.messaging().sendToDevice(tokens, payload).then(response => {
        // For each message check if there was an error.
        const tokensToRemove = [];
        response.results.forEach((result, index) => {
          const error = result.error;
          if (error) {
            console.error('Failure sending notification to', tokens[index], error);
            // Cleanup the tokens who are not registered anymore.
            if (error.code === 'messaging/invalid-registration-token' ||
                error.code === 'messaging/registration-token-not-registered') {
              tokensToRemove.push(allTokens.ref.child(tokens[index]).remove());
            }
          }
        });
        return Promise.all(tokensToRemove);
      });
    }
  });
});
<|endoftext|>


<commit_before>// as of 2014-08-14, Niantic have returned to minifying the javascript. This means we no longer get the nemesis object
// and it's various member objects, functions, etc.
// so we need to extract some essential parameters from the code for IITC to use

window.niantic_params = {}

window.extractFromStock = function() {

  //TODO: need to search through the stock intel minified functions/data structures for the required variables
  // just as a *very* quick fix, test the theory with hard-coded variable names

  // extract the former nemesis.dashboard.config.CURRENT_VERSION from the code
  var re = new RegExp('[a-z]=[a-z].getData\\(\\);[a-z].v="([a-f0-9]{40})";');
  var func = od.prototype.vg.toString();
  var match = re.exec(func);
  niantic_params.CURRENT_VERSION = match[1];

}
<commit_msg>version code extraction: rather than hard-coded function name, iterate through all munged (i.e. 1 or 2 letter) functions, then the munged functions within the prototype this should, in theory, be reasonably robust against Niantic site updates.<commit_after>// as of 2014-08-14, Niantic have returned to minifying the javascript. This means we no longer get the nemesis object
// and it's various member objects, functions, etc.
// so we need to extract some essential parameters from the code for IITC to use

window.extractFromStock = function() {
  window.niantic_params = {}

  //TODO: need to search through the stock intel minified functions/data structures for the required variables
  // just as a *very* quick fix, test the theory with hard-coded variable names

  // extract the former nemesis.dashboard.config.CURRENT_VERSION from the code
  var reVersion = new RegExp('[a-z]=[a-z].getData\\(\\);[a-z].v="([a-f0-9]{40})";');

  var minified = new RegExp('^[a-zA-Z][a-zA-Z0-9]$');

  for (var topLevel in window) {
    if (minified.test(topLevel)) {
      // a minified object - check for minified prototype entries

      // the object has a prototype - iterate through the properties of that
      if (window[topLevel] && window[topLevel].prototype) {
        for (var secLevel in window[topLevel].prototype) {
          if (minified.test(secLevel)) {

            // looks like we've found an object of the format "XX.prototype.YY"...

            var item = window[topLevel].prototype[secLevel];

            if (item && typeof(item) == "function") {
              // a function - test it against the relevant regular expressions
              var funcStr = item.toString();

              var match = reVersion.exec(funcStr);
              if (match) {
                console.log('Found former CURRENT_VERSION in '+topLevel+'.prototype.'+secLevel);
                niantic_params.CURRENT_VERSION = match[1];
              }

            }

          }
        }

      }
    }
  }

  if (niantic_params.CURRENT_VERSION === undefined) {
    dialog({
      title: 'IITC Broken',
      html: '
IITC failed to extract the required varsion parameter from the intel site
'
           +'
This can happen after Niantic update the standard intel site. A fix will be needed from the IITC developers.
',
    });

    throw('Error: IITC failed to extract CURRENT_VERSION string - cannot continue');
  }

}

<|endoftext|>


<commit_before>var exec = require('child_process').exec;

Hooks.addMenuItem("Actions/Ruby/Evaluate/Annotate", "cmd-opt-e", function () {
  var current = Document.current();

  current.performSave();

  if (current.isUntitled()) {
    Alert.show("Please save file before evaluating ruby code.");
    return;
  }

  Recipe.run(function (recipe) {
    var path = current.path();

    exec('xmpfilter -q -a ' + path, function (err, stdout, stderr) {
      if (err) {
        Alert.show('oops: ' + err);
        return false;
      }

      Recipe.run(function (recipe) {
        var rng = new Range(recipe.length);
        recipe.replaceTextInRange(rng, stdout);
      })
    })
  })
})

Hooks.addMenuItem("Actions/Ruby/Evaluate/Annotate and emit stdout", "cmd-opt-shift-e", function () {
  var current = Document.current();

  current.performSave();

  if (current.isUntitled()) {
    Alert.show("Please save file before evaluating ruby code.");
    return;
  }

  Recipe.run(function (recipe) {
    var path = current.path();

    exec('xmpfilter -a ' + path, function (err, stdout, stderr) {
      if (err) {
        Alert.show('oops: ' + err);
        return false;
      }

      Recipe.run(function (recipe) {
        var rng = new Range(recipe.length);
        recipe.replaceTextInRange(rng, stdout);
      });
    });
  });
});
<commit_msg>May the lint gods be appeased<commit_after>var exec = require('child_process').exec;

Hooks.addMenuItem("Actions/Ruby/Evaluate/Annotate", "cmd-opt-e", function () {
  var current = Document.current();

  current.performSave();

  if (current.isUntitled()) {
    Alert.show("Please save file before evaluating ruby code.");
    return;
  }

  Recipe.run(function (recipe) {
    var path = current.path();

    exec('xmpfilter -q -a ' + path, function (err, stdout, stderr) {
      if (err) {
        Alert.show('oops: ' + err);
        return false;
      }

      Recipe.run(function (recipe) {
        var rng = new Range(recipe.length);
        recipe.replaceTextInRange(rng, stdout);
      });
    });
  });
});

Hooks.addMenuItem("Actions/Ruby/Evaluate/Annotate and emit stdout", "cmd-opt-shift-e", function () {
  var current = Document.current();

  current.performSave();

  if (current.isUntitled()) {
    Alert.show("Please save file before evaluating ruby code.");
    return;
  }

  Recipe.run(function (recipe) {
    var path = current.path();

    exec('xmpfilter -a ' + path, function (err, stdout, stderr) {
      if (err) {
        Alert.show('oops: ' + err);
        return false;
      }

      Recipe.run(function (recipe) {
        var rng = new Range(recipe.length);
        recipe.replaceTextInRange(rng, stdout);
      });
    });
  });
});
<|endoftext|>


<commit_before>/*
 *	Initial setup
 */

"use strict" // Otherwise we're stuck with ES5

const LOCAL_HOST = 3000;

// Variables required for Markov Chain generation
var input = [];
var firstWords = [];
var currentWord = "";

// Variables required for bottom
var currentTopic;
var currentToken;

// Set up modules
var express = require("express");
var request = require("request");
var bodyParser = require("body-parser");
var cheerio = require('cheerio');
var client = require('redis').createClient(process.env.REDIS_URL);

// Set up app
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.cachedData = { "post": "" }; // Basic format for JSON response
app.loggedIn = false; // Indicates whether app has login cookie for ETI

// Set up routing for API
var routes = require("./routes/routes.js")(app);

// Set up server
var server = app.listen(process.env.PORT || LOCAL_HOST, () => {
	console.log(process.env.USERNAME + "-bot is sentient and ready to shitpost");
});

/**
	*		Redis db handler
	*/

client.on("connect", () => {
		// Attempt to get "quotes" array from Redis
		client.lrange("quotes", 0, -1, (error, items) => {
			if (error) {
				// TODO: Store emergency vesper.txt somewhere in repo and use that instead
				throw error;
			}
			else {
				input = items;
				app.generateMarkovChain();
			}
		});
});

/**
  * Markov chain methods
	*/

app.generateMarkovChain = function(shouldReturn) {
	var output = [];

	app.createArrays();

	// Pick random first word to start with
	currentWord = firstWords[Math.floor((Math.random() * firstWords.length))];

	for (let i = 0, len = app.getPostLength(); i < len; i++) {
		output.push(currentWord);

		var nextWord = app.generateNextWord();

		if (nextWord) {
			currentWord = nextWord;
		}
		else {
			currentWord = "";
		}
	}

	app.cachedData.post = output.join(" ").trim();

	if (shouldReturn) {
		return app.cachedData.post;
	}
};

app.getPostLength = function() {
	return input[Math.floor((Math.random() * input.length))].length;
};

app.createArrays = function() {
	// Create array containing first word of each sentence
	for (let i = 0, len = input.length; i < len; i++) {
		let sentence = input[i];
		let firstWord = sentence.split(" ")[0];
		firstWords.push(firstWord);
	}
};

app.generateNextWord = function() {
	var tempArray = [];
	// Iterate over input array to find instances of current word
	for (let i = 0, len = input.length - 1; i < len; i++) {
		let sentenceToCheck = input[i].split(" ");

		for (let j = 0, len = sentenceToCheck.length; j < len; j++) {
			let wordToCheck = sentenceToCheck[j];
			// create array of words that are likely to follow current word
			if (wordToCheck === currentWord) {
				// Make sure that item at index i + 1 exists
				if (j < len - 1) {
					let nextWord = sentenceToCheck[j + 1];
					tempArray.push(nextWord);
				}
				else {
					// reached end of array - do nothing
				}
			}
		}
	}

	let rnd = Math.floor((Math.random() * tempArray.length));

	if (tempArray[rnd]) {
		return tempArray[rnd];
	}

	else {
		return;
	}
};

/**
  *		Method which allows us to add new quotes from pastebin raw links
  */

app.addNewQuotes = function(url) {
	request.get(url, ((error, response, body) => {
		if (!error && response.statusCode == 200) {
			// Ignore blank lines,
			var quotes = body.split("\r\n").filter((line) => line && line.indexOf("<") == -1 && line.charAt(0) !== "<");

			client.lrange("quotes", 0, -1, (error, items) => {
				if (error) {
					throw error;
				}
				else {
					// Update local & disk cache
					input = input.concat(quotes);
					client.rpush.apply(client, ["quotes"].concat(quotes).concat(() => { console.log("Quotes stored to redis") }));
				}
			});

		}

	}));
};

/**
  *		Log into ETI using environment vars as credentials
  */

app.loginToBlueSite = function() {
	const LOGIN_URL = "https://endoftheinter.net/";
	const formData = { b: process.env.USERNAME, p: process.env.PASSWORD };

	request.post({

		headers: {"content-type": "application/x-www-form-urlencoded"},
		url: LOGIN_URL,
		form: formData,
		jar: app.cookieJar

	}, (error, response, body) => {

			// After successful login, ETI will attempt to redirect you to homepage
			if (!error && response.statusCode === 302) {
					app.getTopicList();
			}

			else {
				console.log("Login failed.");
				throw error;
			}
	});
};

app.getTopicList = function() {
	var LUE_TOPICS = "https://boards.endoftheinter.net/topics/LUE";

	request({

		url: LUE_TOPICS,
		jar: app.cookieJar

	}
	, (error, response, body) => {

		if (!error && response.statusCode === 200) {

			var $ = cheerio.load(response);
			var topicList = $('.grid tbody tr');
			// Pick random topic to pester. The -1 / +1 here looks goofy, but is required to make sure we don't get 0 as output
			var target = topicList[Math(Math.floor((Math.random() * topicList.length - 1)) + 1)];
			var topicHref = target('td a')[0].attr('href');

			console.log("Scraped href: " + topicHref);

			app.getMessageList(topicHref);
		}

		else {
			console.log("Topic list GET failed.");
			throw error;
		}

	});
};

app.getMessageList = function(url) {

	request({

		url: url,
		jar: app.cookieJar

	}, (error, response, body) => {

		if (!error && response.statusCode === 200) {

			var $ = cheerio.load(response);
			// Can't make POST requests without the value of this token, scraped from quickpost area
			currentToken = $('.quickpost input[name="h"]').value();
			app.contributeToDiscussion();
		}

		else {
			console.log("Topic list GET failed.");
			throw error;
		}

	});
};

app.contributeToDiscussion = function() {
	const QUICKPOST_URL = "http://boards.endoftheinter.net/async-post.php";

	var formData = {};
			formData.topic = currentTopic;
			formData.h = currentToken;
			formData.message = app.generateMarkovChain(true); // Pass true to get return value
			formData.submit = "Post Message";

	request.post({

		url: QUICKPOST_URL,
		form: formData,
		jar: app.cookieJar

	}, (error, response, body) => {

			if (!error && response.statusCode === 200) {
				console.log("Post successful");
			}

			else {
				console.log("Post unsuccessful: code ", response.statusCode);
				throw error;
			}

	});
};<commit_msg>Fix typo<commit_after>/*
 *	Initial setup
 */

"use strict" // Otherwise we're stuck with ES5

const LOCAL_HOST = 3000;

// Variables required for Markov Chain generation
var input = [];
var firstWords = [];
var currentWord = "";

// Variables required for bottom
var currentTopic;
var currentToken;

// Set up modules
var express = require("express");
var request = require("request");
var bodyParser = require("body-parser");
var cheerio = require('cheerio');
var client = require('redis').createClient(process.env.REDIS_URL);

// Set up app
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.cachedData = { "post": "" }; // Basic format for JSON response
app.loggedIn = false; // Indicates whether app has login cookie for ETI

// Set up routing for API
var routes = require("./routes/routes.js")(app);

// Set up server
var server = app.listen(process.env.PORT || LOCAL_HOST, () => {
	console.log(process.env.USERNAME + "-bot is sentient and ready to shitpost");
});

/**
	*		Redis db handler
	*/

client.on("connect", () => {
		// Attempt to get "quotes" array from Redis
		client.lrange("quotes", 0, -1, (error, items) => {
			if (error) {
				// TODO: Store emergency vesper.txt somewhere in repo and use that instead
				throw error;
			}
			else {
				input = items;
				app.generateMarkovChain();
			}
		});
});

/**
  * Markov chain methods
	*/

app.generateMarkovChain = function(shouldReturn) {
	var output = [];

	app.createArrays();

	// Pick random first word to start with
	currentWord = firstWords[Math.floor((Math.random() * firstWords.length))];

	for (let i = 0, len = app.getPostLength(); i < len; i++) {
		output.push(currentWord);

		var nextWord = app.generateNextWord();

		if (nextWord) {
			currentWord = nextWord;
		}
		else {
			currentWord = "";
		}
	}

	app.cachedData.post = output.join(" ").trim();

	if (shouldReturn) {
		return app.cachedData.post;
	}
};

app.getPostLength = function() {
	return input[Math.floor((Math.random() * input.length))].length;
};

app.createArrays = function() {
	// Create array containing first word of each sentence
	for (let i = 0, len = input.length; i < len; i++) {
		let sentence = input[i];
		let firstWord = sentence.split(" ")[0];
		firstWords.push(firstWord);
	}
};

app.generateNextWord = function() {
	var tempArray = [];
	// Iterate over input array to find instances of current word
	for (let i = 0, len = input.length - 1; i < len; i++) {
		let sentenceToCheck = input[i].split(" ");

		for (let j = 0, len = sentenceToCheck.length; j < len; j++) {
			let wordToCheck = sentenceToCheck[j];
			// create array of words that are likely to follow current word
			if (wordToCheck === currentWord) {
				// Make sure that item at index i + 1 exists
				if (j < len - 1) {
					let nextWord = sentenceToCheck[j + 1];
					tempArray.push(nextWord);
				}
				else {
					// reached end of array - do nothing
				}
			}
		}
	}

	let rnd = Math.floor((Math.random() * tempArray.length));

	if (tempArray[rnd]) {
		return tempArray[rnd];
	}

	else {
		return;
	}
};

/**
  *		Method which allows us to add new quotes from pastebin raw links
  */

app.addNewQuotes = function(url) {
	request.get(url, ((error, response, body) => {
		if (!error && response.statusCode == 200) {
			// Ignore blank lines,
			var quotes = body.split("\r\n").filter((line) => line && line.indexOf("<") == -1 && line.charAt(0) !== "<");

			client.lrange("quotes", 0, -1, (error, items) => {
				if (error) {
					throw error;
				}
				else {
					// Update local & disk cache
					input = input.concat(quotes);
					client.rpush.apply(client, ["quotes"].concat(quotes).concat(() => { console.log("Quotes stored to redis") }));
				}
			});

		}

	}));
};

/**
  *		Log into ETI using environment vars as credentials
  */

app.loginToBlueSite = function() {
	const LOGIN_URL = "https://endoftheinter.net/";
	const formData = { b: process.env.USERNAME, p: process.env.PASSWORD };

	request.post({

		headers: {"content-type": "application/x-www-form-urlencoded"},
		url: LOGIN_URL,
		form: formData,
		jar: app.cookieJar

	}, (error, response, body) => {

			// After successful login, ETI will attempt to redirect you to homepage
			if (!error && response.statusCode === 302) {
					app.getTopicList();
			}

			else {
				console.log("Login failed.");
				throw error;
			}
	});
};

app.getTopicList = function() {
	var LUE_TOPICS = "https://boards.endoftheinter.net/topics/LUE";

	request({

		url: LUE_TOPICS,
		jar: app.cookieJar

	}
	, (error, response, body) => {

		if (!error && response.statusCode === 200) {

			var $ = cheerio.load(response);
			var topicList = $('.grid tbody tr');
			// Pick random topic to pester. The -1 / +1 here looks goofy, but is required to make sure we don't get 0 as output
			var target = topicList[Math.floor((Math.random() * topicList.length - 1)) + 1)];
			var topicHref = target('td a')[0].attr('href');

			console.log("Scraped href: " + topicHref);

			app.getMessageList(topicHref);
		}

		else {
			console.log("Topic list GET failed.");
			throw error;
		}

	});
};

app.getMessageList = function(url) {

	request({

		url: url,
		jar: app.cookieJar

	}, (error, response, body) => {

		if (!error && response.statusCode === 200) {

			var $ = cheerio.load(response);
			// Can't make POST requests without the value of this token, scraped from quickpost area
			currentToken = $('.quickpost input[name="h"]').value();
			app.contributeToDiscussion();
		}

		else {
			console.log("Topic list GET failed.");
			throw error;
		}

	});
};

app.contributeToDiscussion = function() {
	const QUICKPOST_URL = "http://boards.endoftheinter.net/async-post.php";

	var formData = {};
			formData.topic = currentTopic;
			formData.h = currentToken;
			formData.message = app.generateMarkovChain(true); // Pass true to get return value
			formData.submit = "Post Message";

	request.post({

		url: QUICKPOST_URL,
		form: formData,
		jar: app.cookieJar

	}, (error, response, body) => {

			if (!error && response.statusCode === 200) {
				console.log("Post successful");
			}

			else {
				console.log("Post unsuccessful: code ", response.statusCode);
				throw error;
			}

	});
};<|endoftext|>


<commit_before>var path = require('path');
var fs = require('fs');
var proxy = require('./lib');
var util = require('./util');
var config = util.config;
var argvs = util.argvs;
var rulesUtil = require('./lib/rules/util');

function parseHosts(hostsPath) {
	if (hostsPath) {
		try {
			rulesUtil.setPublicHosts(fs.readFileSync(path.resolve(hostsPath), {encoding: 'utf8'}));
		} catch(e) {}
	}

	rulesUtil.loadHosts();
}

function start(options) {
	if (options.plugins) {
		options.plugins = options.plugins.split(',').map(function(plugin) {
			return /[^\w-]/i.test(plugin) ? path.resolve(plugin.trim()) : plugin;
		});
	}

	for (var i in argvs) {
		config[i] = options[i] || config[i];
	}

	var port = config.port;
	if (Array.isArray(config.ports)) {
		config.ports.forEach(function(name) {
			config[name] = ++port;
		});
	}

	var app = proxy(options.port, options.plugins);
	require('util')._extend(app, config);

	try {
		require(app.uipath || './biz/webui/app')(app);
		util.installTianma();
	} catch(e) {}
	return app;
}

module.exports = function init(options) {
	options = options || {};
	parseHosts(options.hosts);
	return start(options);
};<commit_msg>update config<commit_after>var path = require('path');
var fs = require('fs');
var proxy = require('./lib');
var util = require('./util');
var config = util.config;
var argvs = util.argvs;
var rulesUtil = require('./lib/rules/util');

function parseHosts(hostsPath) {
	if (hostsPath) {
		try {
			rulesUtil.setPublicHosts(fs.readFileSync(path.resolve(hostsPath), {encoding: 'utf8'}));
		} catch(e) {}
	}

	rulesUtil.loadHosts();
}

function start(options) {
	var app = proxy(options.port, options.plugins);
	require('util')._extend(app, config);

	try {
		require(app.uipath || './biz/webui/app')(app);
		util.installTianma();
	} catch(e) {}
	return app;
}

function updateConfig(options) {
	if (options.plugins) {
		options.plugins = options.plugins.split(',').map(function(plugin) {
			return /[^\w-]/i.test(plugin) ? path.resolve(plugin.trim()) : plugin;
		});
	}

	for (var i in argvs) {
		config[i] = options[i] || config[i];
	}

	var port = config.port;
	if (Array.isArray(config.ports)) {
		config.ports.forEach(function(name) {
			config[name] = ++port;
		});
	}
}

module.exports = function init(options) {
	options = options || {};
	updateConfig(options);
	parseHosts(options.hosts);
	return start(options);
};<|endoftext|>