<commit_before>(function () {

    var View = Backbone.View.extend({
        events: {
            "click .chan": "chanClick",
            "click .channel_name_title": "sortChannelsByNameClick",
            "click .users_title": "sortChannelsByUsersClick"
        },

        initialize: function (options) {
            var text = {
                channel_name: '' + _kiwi.global.i18n.translate('client_applets_chanlist_channelname').fetch() + '',
                users: '' + _kiwi.global.i18n.translate('client_applets_chanlist_users').fetch() + '',
                topic: _kiwi.global.i18n.translate('client_applets_chanlist_topic').fetch()
            };
            this.$el = $(_.template($('#tmpl_channel_list').html().trim(), text));

            this.channels = [];

            // Sort the table
            this.order = '';

            // Waiting to add the table back into the DOM?
            this.waiting = false;
        },

        render: function (override_channels) {
            var table = $('table', this.$el),
                tbody = table.children('tbody:first').detach(),
                that = this,
                channels_length = this.channels.length,
                icon_asc = '  ',
                icon_desc = '  ',
                i;

            if (override_channels != undefined) {
                that.channels = override_channels;
                tbody.remove();
                this.sorting_channels = true;
            } else {
                that.channels = this.sortChannels(this.channels, this.order);
            }

            // Clean the sorting icon and add the new one
            $('.applet_chanlist .users_title').find('span').remove();
            $('.applet_chanlist .channel_name_title').find('span').remove();
            switch (this.order) {
                case 'user_desc':
                default:
                    $('.users_title').append(icon_desc);
                    break;
                case 'user_asc':
                    $('.users_title').append(icon_asc);
                    break;
                case 'name_asc':
                    $('.channel_name_title').append(icon_asc);
                    break;
                case 'name_desc':
                    $('.channel_name_title').append(icon_desc);
                    break;
            }

            tbody.children().each(function (idx, child) {
                if (that.channels[idx].channel === $(child.querySelector('.chan')).data('channel')) {
                    that.channels[idx].dom = tbody[0].removeChild(child);
                }
            });

            for (i = 0; i < channels_length; i++) {
                tbody[0].appendChild(this.channels[i].dom);
            }
            table[0].appendChild(tbody[0]);
        },

        chanClick: function (event) {
            if (event.target) {
                _kiwi.gateway.join(null, $(event.target).data('channel'));
            } else {
                // IE...
                _kiwi.gateway.join(null, $(event.srcElement).data('channel'));
            }
        },

        sortChannelsByNameClick: function (event) {
            // Revert the sorting to switch between orders
            if (this.order == 'name_asc') {
                this.order = 'name_desc';
            } else {
                this.order = 'name_asc';
            }

            this.sortChannelsClick(this.order);
        },

        sortChannelsByUsersClick: function (event) {
            // Revert the sorting to switch between orders
            if (this.order == 'user_desc') {
                this.order = 'user_asc';
            } else {
                this.order = 'user_desc';
            }

            this.sortChannelsClick(this.order);
        },

        sortChannelsClick: function(order) {
            var that = this,
                channels = this.sortChannels(that.channels, order);

            this.render(channels);
        },

        sortChannels: function (channels, order) {
            var counter = 0,
                sort_channels = [],
                new_channels = [];

            // First we create a light copy of the channels object to do the sorting
            _.each(channels, function (chan) {
                sort_channels.push({'counter': counter, 'num_users': chan.num_users, 'channel': chan.channel});

                counter += 1;
            });

            // Second, we apply the sorting
            sort_channels.sort(function (a, b) {
                switch (order) {
                    case 'user_asc':
                        return a.num_users - b.num_users;
                        break;
                    case 'user_desc':
                        return b.num_users - a.num_users;
                        break;
                    case 'name_asc':
                        if (a.channel.toLowerCase() > b.channel.toLowerCase()) return 1;
                        if (a.channel.toLowerCase() < b.channel.toLowerCase()) return -1;
                        break;
                    case 'name_desc':
                        if (a.channel.toLowerCase()  b.channel.toLowerCase()) return -1;
                        break;
                    default:
                        return b.num_users - a.num_users;
                        break;
                }
                return 0;
            });

            // Third, we re-shuffle the chanlist according to the sort order
            _.each(sort_channels, function (chan) {
                new_channels.push(channels[chan.counter]);
            });

            return new_channels;
        }
    });

    var Applet = Backbone.Model.extend({
        initialize: function () {
            this.set('title', _kiwi.global.i18n.translate('client_applets_chanlist_channellist').fetch());
            this.view = new View();

            this.network = _kiwi.global.components.Network();
            this.network.on('onlist_channel', this.onListChannel, this);
            this.network.on('onlist_start', this.onListStart, this);
        },

        // New channels to add to our list
        onListChannel: function (event) {
            this.addChannel(event.chans);
        },

        // A new, fresh channel list starting
        onListStart: function (event) {
            // TODO: clear out our existing list
        },

        addChannel: function (channels) {
            var that = this;

            // If we're sorting channels, dont rebuild the channel list
            if(this.view.sorting_channels) return;

            if (!_.isArray(channels)) {
                channels = [channels];
            }
            _.each(channels, function (chan) {
                var row;
                row = document.createElement("tr");
                row.innerHTML = '' + _.escape(chan.channel) + '	' + chan.num_users + '	' + formatIRCMsg(_.escape(chan.topic)) + '	';
                chan.dom = row;
                that.view.channels.push(chan);
            });

            if (!that.view.waiting) {
                that.view.waiting = true;
                _.defer(function () {
                    that.view.render();
                    that.view.waiting = false;
                });
            }
        },

        dispose: function () {
            this.view.channels = null;
            this.view.unbind();
            this.view.$el.html('');
            this.view.remove();
            this.view = null;

            // Remove any network event bindings
            this.network.off();
        }
    });

    _kiwi.model.Applet.register('kiwi_chanlist', Applet);
})();<commit_msg>Forgotten case<commit_after>(function () {

    var View = Backbone.View.extend({
        events: {
            "click .chan": "chanClick",
            "click .channel_name_title": "sortChannelsByNameClick",
            "click .users_title": "sortChannelsByUsersClick"
        },

        initialize: function (options) {
            var text = {
                channel_name: '' + _kiwi.global.i18n.translate('client_applets_chanlist_channelname').fetch() + '',
                users: '' + _kiwi.global.i18n.translate('client_applets_chanlist_users').fetch() + '',
                topic: _kiwi.global.i18n.translate('client_applets_chanlist_topic').fetch()
            };
            this.$el = $(_.template($('#tmpl_channel_list').html().trim(), text));

            this.channels = [];

            // Sort the table
            this.order = '';

            // Waiting to add the table back into the DOM?
            this.waiting = false;
        },

        render: function (override_channels) {
            var table = $('table', this.$el),
                tbody = table.children('tbody:first').detach(),
                that = this,
                channels_length = this.channels.length,
                icon_asc = '  ',
                icon_desc = '  ',
                i;

            if (override_channels != undefined) {
                that.channels = override_channels;
                tbody.remove();
                this.sorting_channels = true;
            } else {
                that.channels = this.sortChannels(this.channels, this.order);
            }

            // Clean the sorting icon and add the new one
            $('.applet_chanlist .users_title').find('span').remove();
            $('.applet_chanlist .channel_name_title').find('span').remove();
            switch (this.order) {
                case 'user_desc':
                default:
                    $('.users_title').append(icon_desc);
                    break;
                case 'user_asc':
                    $('.users_title').append(icon_asc);
                    break;
                case 'name_asc':
                    $('.channel_name_title').append(icon_asc);
                    break;
                case 'name_desc':
                    $('.channel_name_title').append(icon_desc);
                    break;
            }

            tbody.children().each(function (idx, child) {
                if (that.channels[idx].channel === $(child.querySelector('.chan')).data('channel')) {
                    that.channels[idx].dom = tbody[0].removeChild(child);
                }
            });

            for (i = 0; i < channels_length; i++) {
                tbody[0].appendChild(this.channels[i].dom);
            }
            table[0].appendChild(tbody[0]);
        },

        chanClick: function (event) {
            if (event.target) {
                _kiwi.gateway.join(null, $(event.target).data('channel'));
            } else {
                // IE...
                _kiwi.gateway.join(null, $(event.srcElement).data('channel'));
            }
        },

        sortChannelsByNameClick: function (event) {
            // Revert the sorting to switch between orders
            if (this.order == 'name_asc') {
                this.order = 'name_desc';
            } else {
                this.order = 'name_asc';
            }

            this.sortChannelsClick(this.order);
        },

        sortChannelsByUsersClick: function (event) {
            // Revert the sorting to switch between orders
            if (this.order == 'user_desc' || this.order == '') {
                this.order = 'user_asc';
            } else {
                this.order = 'user_desc';
            }

            this.sortChannelsClick(this.order);
        },

        sortChannelsClick: function(order) {
            var that = this,
                channels = this.sortChannels(that.channels, order);

            this.render(channels);
        },

        sortChannels: function (channels, order) {
            var counter = 0,
                sort_channels = [],
                new_channels = [];

            // First we create a light copy of the channels object to do the sorting
            _.each(channels, function (chan) {
                sort_channels.push({'counter': counter, 'num_users': chan.num_users, 'channel': chan.channel});

                counter += 1;
            });

            // Second, we apply the sorting
            sort_channels.sort(function (a, b) {
                switch (order) {
                    case 'user_asc':
                        return a.num_users - b.num_users;
                        break;
                    case 'user_desc':
                        return b.num_users - a.num_users;
                        break;
                    case 'name_asc':
                        if (a.channel.toLowerCase() > b.channel.toLowerCase()) return 1;
                        if (a.channel.toLowerCase() < b.channel.toLowerCase()) return -1;
                        break;
                    case 'name_desc':
                        if (a.channel.toLowerCase()  b.channel.toLowerCase()) return -1;
                        break;
                    default:
                        return b.num_users - a.num_users;
                        break;
                }
                return 0;
            });

            // Third, we re-shuffle the chanlist according to the sort order
            _.each(sort_channels, function (chan) {
                new_channels.push(channels[chan.counter]);
            });

            return new_channels;
        }
    });

    var Applet = Backbone.Model.extend({
        initialize: function () {
            this.set('title', _kiwi.global.i18n.translate('client_applets_chanlist_channellist').fetch());
            this.view = new View();

            this.network = _kiwi.global.components.Network();
            this.network.on('onlist_channel', this.onListChannel, this);
            this.network.on('onlist_start', this.onListStart, this);
        },

        // New channels to add to our list
        onListChannel: function (event) {
            this.addChannel(event.chans);
        },

        // A new, fresh channel list starting
        onListStart: function (event) {
            // TODO: clear out our existing list
        },

        addChannel: function (channels) {
            var that = this;

            // If we're sorting channels, dont rebuild the channel list
            if(this.view.sorting_channels) return;

            if (!_.isArray(channels)) {
                channels = [channels];
            }
            _.each(channels, function (chan) {
                var row;
                row = document.createElement("tr");
                row.innerHTML = '' + _.escape(chan.channel) + '	' + chan.num_users + '	' + formatIRCMsg(_.escape(chan.topic)) + '	';
                chan.dom = row;
                that.view.channels.push(chan);
            });

            if (!that.view.waiting) {
                that.view.waiting = true;
                _.defer(function () {
                    that.view.render();
                    that.view.waiting = false;
                });
            }
        },

        dispose: function () {
            this.view.channels = null;
            this.view.unbind();
            this.view.$el.html('');
            this.view.remove();
            this.view = null;

            // Remove any network event bindings
            this.network.off();
        }
    });

    _kiwi.model.Applet.register('kiwi_chanlist', Applet);
})();<|endoftext|>


<commit_before>import { start, turn } from 'actions'
import Lightcycle from 'components/Lightcycle'
import Lightribbon from 'components/Lightribbon'
import MenuButton from 'components/MenuButton'
import useClassName from 'hooks/useClassName'
import useEventListener from 'hooks/useEventListener'
import usePreloadImages from 'hooks/usePreloadImages'
import useStore from 'hooks/useStore'
import useStoreDispatch from 'hooks/useStoreDispatch'
import backgroundPanel from 'img/background-panel.svg'
import React, { useCallback, useRef } from 'react'
import lightcycleImages from 'utils/lightcycleImages'

import styles from './Arena.module.css'

export default function Arena() {
  usePreloadImages([backgroundPanel, ...Object.values(lightcycleImages)])

  const { arena } = useStore()
  const dispatch = useStoreDispatch()

  const onStart = useCallback(() => dispatch(start()), [dispatch])

  const arenaRef = useRef()
  useKeyControls(arena.started)
  useTouchControls(arena.started, arenaRef)

  const Arena = useClassName(styles.arena)
  const Background = useClassName([styles.background, arena.started !== null && styles.backgroundStarted])
  const StartButton = useClassName(styles.startButton, MenuButton)

  return (
    <Arena ref={arenaRef}>
      <Background style={{ backgroundImage: `url(${backgroundPanel})` }} />

      {Object.entries(arena.lightribbons).map(([id, { points }]) => (
        <Lightribbon key={id} color={arena.players[id] ? arena.players[id].color : 'white'} points={points} />
      ))}
      {Object.entries(arena.lightcycles).map(([id, { position, direction, speed, dead }]) => (
        <Lightcycle
          key={id}
          name={arena.players[id] ? arena.players[id].name : 'NULL'}
          color={arena.players[id] ? arena.players[id].color : 'white'}
          position={position}
          direction={direction}
          speed={speed}
          dead={dead}
        />
      ))}

      {arena.started === null ? <StartButton onClick={onStart}>START</StartButton> : null}
    </Arena>
  )
}

function useTurnCallback() {
  const dispatch = useStoreDispatch()
  return useCallback((direction) => dispatch(turn(direction)), [dispatch])
}

function useKeyControls(started) {
  const onTurn = useTurnCallback()

  const onKeyDown = useCallback(
    (event) => {
      if (!started) return

      switch (event.key) {
        case 'ArrowUp':
        case 'w':
          event.preventDefault()
          return onTurn('up')
        case 'ArrowLeft':
        case 'a':
          event.preventDefault()
          return onTurn('left')
        case 'ArrowRight':
        case 'd':
          event.preventDefault()
          return onTurn('right')
        case 'ArrowDown':
        case 's':
          event.preventDefault()
          return onTurn('down')
      }
    },
    [started],
  )
  useEventListener('keydown', onKeyDown)
}

function useTouchControls(started, arenaRef) {
  const onTurn = useTurnCallback()

  const turnFromCenterOffset = useCallback(
    (xFromCenter, yFromCenter) => {
      const xDistance = Math.abs(xFromCenter)
      const yDistance = Math.abs(yFromCenter)

      if (xDistance < yDistance) {
        if (yFromCenter < 0) {
          return onTurn('up')
        } else {
          return onTurn('down')
        }
      } else {
        if (xFromCenter < 0) {
          return onTurn('left')
        } else {
          return onTurn('right')
        }
      }
    },
    [onTurn],
  )

  const onTouchStart = useCallback(
    (event) => {
      if (!started) return

      const touch = event.changedTouches[0]
      if (!touch) return

      event.preventDefault()

      const rect = event.currentTarget.getBoundingClientRect()
      const x = touch.clientX - rect.left
      const y = touch.clientY - rect.top
      const xFromCenter = x - rect.width / 2
      const yFromCenter = y - rect.height / 2

      turnFromCenterOffset(xFromCenter, yFromCenter)
    },
    [started, turnFromCenterOffset],
  )

  const onMouseDown = useCallback(
    (event) => {
      if (!started) return

      const rect = event.currentTarget.getBoundingClientRect()

      const x = event.clientX - rect.left
      const y = event.clientY - rect.top
      const xFromCenter = x - rect.width / 2
      const yFromCenter = y - rect.height / 2

      turnFromCenterOffset(xFromCenter, yFromCenter)
    },
    [started, turnFromCenterOffset],
  )

  useEventListener('touchstart', onTouchStart, arenaRef.current)
  useEventListener('mousedown', onMouseDown, arenaRef.current)

  return arenaRef
}
<commit_msg>fixed missing hook dependency in arena<commit_after>import { start, turn } from 'actions'
import Lightcycle from 'components/Lightcycle'
import Lightribbon from 'components/Lightribbon'
import MenuButton from 'components/MenuButton'
import useClassName from 'hooks/useClassName'
import useEventListener from 'hooks/useEventListener'
import usePreloadImages from 'hooks/usePreloadImages'
import useStore from 'hooks/useStore'
import useStoreDispatch from 'hooks/useStoreDispatch'
import backgroundPanel from 'img/background-panel.svg'
import React, { useCallback, useRef } from 'react'
import lightcycleImages from 'utils/lightcycleImages'

import styles from './Arena.module.css'

export default function Arena() {
  usePreloadImages([backgroundPanel, ...Object.values(lightcycleImages)])

  const { arena } = useStore()
  const dispatch = useStoreDispatch()

  const onStart = useCallback(() => dispatch(start()), [dispatch])

  const arenaRef = useRef()
  useKeyControls(arena.started)
  useTouchControls(arena.started, arenaRef)

  const Arena = useClassName(styles.arena)
  const Background = useClassName([styles.background, arena.started !== null && styles.backgroundStarted])
  const StartButton = useClassName(styles.startButton, MenuButton)

  return (
    <Arena ref={arenaRef}>
      <Background style={{ backgroundImage: `url(${backgroundPanel})` }} />

      {Object.entries(arena.lightribbons).map(([id, { points }]) => (
        <Lightribbon key={id} color={arena.players[id] ? arena.players[id].color : 'white'} points={points} />
      ))}
      {Object.entries(arena.lightcycles).map(([id, { position, direction, speed, dead }]) => (
        <Lightcycle
          key={id}
          name={arena.players[id] ? arena.players[id].name : 'NULL'}
          color={arena.players[id] ? arena.players[id].color : 'white'}
          position={position}
          direction={direction}
          speed={speed}
          dead={dead}
        />
      ))}

      {arena.started === null ? <StartButton onClick={onStart}>START</StartButton> : null}
    </Arena>
  )
}

function useTurnCallback() {
  const dispatch = useStoreDispatch()
  return useCallback((direction) => dispatch(turn(direction)), [dispatch])
}

function useKeyControls(started) {
  const onTurn = useTurnCallback()

  const onKeyDown = useCallback(
    (event) => {
      if (!started) return

      switch (event.key) {
        case 'ArrowUp':
        case 'w':
          event.preventDefault()
          return onTurn('up')
        case 'ArrowLeft':
        case 'a':
          event.preventDefault()
          return onTurn('left')
        case 'ArrowRight':
        case 'd':
          event.preventDefault()
          return onTurn('right')
        case 'ArrowDown':
        case 's':
          event.preventDefault()
          return onTurn('down')
      }
    },
    [started, onTurn],
  )
  useEventListener('keydown', onKeyDown)
}

function useTouchControls(started, arenaRef) {
  const onTurn = useTurnCallback()

  const turnFromCenterOffset = useCallback(
    (xFromCenter, yFromCenter) => {
      const xDistance = Math.abs(xFromCenter)
      const yDistance = Math.abs(yFromCenter)

      if (xDistance < yDistance) {
        if (yFromCenter < 0) {
          return onTurn('up')
        } else {
          return onTurn('down')
        }
      } else {
        if (xFromCenter < 0) {
          return onTurn('left')
        } else {
          return onTurn('right')
        }
      }
    },
    [onTurn],
  )

  const onTouchStart = useCallback(
    (event) => {
      if (!started) return

      const touch = event.changedTouches[0]
      if (!touch) return

      event.preventDefault()

      const rect = event.currentTarget.getBoundingClientRect()
      const x = touch.clientX - rect.left
      const y = touch.clientY - rect.top
      const xFromCenter = x - rect.width / 2
      const yFromCenter = y - rect.height / 2

      turnFromCenterOffset(xFromCenter, yFromCenter)
    },
    [started, turnFromCenterOffset],
  )

  const onMouseDown = useCallback(
    (event) => {
      if (!started) return

      const rect = event.currentTarget.getBoundingClientRect()

      const x = event.clientX - rect.left
      const y = event.clientY - rect.top
      const xFromCenter = x - rect.width / 2
      const yFromCenter = y - rect.height / 2

      turnFromCenterOffset(xFromCenter, yFromCenter)
    },
    [started, turnFromCenterOffset],
  )

  useEventListener('touchstart', onTouchStart, arenaRef.current)
  useEventListener('mousedown', onMouseDown, arenaRef.current)

  return arenaRef
}
<|endoftext|>


<commit_before>/**
 *
 *
 * @copyright 2017 Government of Canada
 * @license MIT
 * @author igboyes
 *
 */

import { call, put, takeEvery, takeLatest } from "redux-saga/effects";

import virusesAPI from "./api";
import { setPending } from "../wrappers";
import {
    FIND_VIRUSES,
    GET_VIRUS,
    GET_VIRUS_HISTORY,
    CREATE_VIRUS,
    EDIT_VIRUS,
    REMOVE_VIRUS,
    ADD_ISOLATE,
    EDIT_ISOLATE,
    REMOVE_ISOLATE,
    ADD_SEQUENCE,
    EDIT_SEQUENCE,
    REMOVE_SEQUENCE,
    REVERT,
    SET_APP_PENDING,
    UNSET_APP_PENDING
}  from "../actionTypes";

export function* watchViruses () {
    yield takeLatest(FIND_VIRUSES.REQUESTED, findViruses);
    yield takeLatest(GET_VIRUS.REQUESTED, getVirus);
    yield takeLatest(GET_VIRUS_HISTORY.REQUESTED, getVirusHistory);
    yield takeEvery(CREATE_VIRUS.REQUESTED, createVirus);
    yield takeEvery(EDIT_VIRUS.REQUESTED, editVirus);
    yield takeEvery(REMOVE_VIRUS.REQUESTED, removeVirus);
    yield takeEvery(ADD_ISOLATE.REQUESTED, addIsolate);
    yield takeEvery(EDIT_ISOLATE.REQUESTED, editIsolate);
    yield takeEvery(REMOVE_ISOLATE.REQUESTED, removeIsolate);
    yield takeEvery(ADD_SEQUENCE.REQUESTED, addSequence);
    yield takeEvery(EDIT_SEQUENCE.REQUESTED, editSequence);
    yield takeEvery(REMOVE_SEQUENCE.REQUESTED, removeSequence);
    yield takeEvery(REVERT.REQUESTED, revert);
}

export function* findViruses (action) {
    yield put({type: SET_APP_PENDING});

    try {
        const response = yield call(virusesAPI.find, action.term, action.page);
        yield put({type: FIND_VIRUSES.SUCCEEDED, data: response.body});
    } catch (error) {
        yield put({type: FIND_VIRUSES.FAILED}, error);
    }

    yield put({type: UNSET_APP_PENDING});
}

export function* getVirus (action) {
    yield setPending(function* () {
        try {
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: GET_VIRUS.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: GET_VIRUS.FAILED, error: error});
        }
    }, action);
}

export function* getVirusHistory (action) {
    yield setPending(function* () {
        try {
            const response = yield call(virusesAPI.getHistory, action.virusId);
            yield put({type: GET_VIRUS_HISTORY.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: GET_VIRUS_HISTORY.FAILED, error: error});
        }
    }, action);
}

export function* createVirus (action) {
    yield setPending(function* () {
        try {
            const response = yield call(virusesAPI.create, action.name, action.abbreviation);
            yield put({type: CREATE_VIRUS.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: CREATE_VIRUS.FAILED, error: error});
        }
    }, action);
}

export function* editVirus (action) {
    yield setPending(function* (action) {
        try {
            yield virusesAPI.edit(action.virusId, action.name, action.abbreviation);
            const response = yield virusesAPI.get(action.virusId);
            yield put({type: EDIT_VIRUS.SUCCEEDED, data: response.body});
        } catch (error) {
            if (error.response.status === 409) {
                yield put({type: EDIT_VIRUS.FAILED, message: error.response.body.message});
            } else{
                throw error;
            }
        }
    }, action);
}

export function* removeVirus (action) {
    yield setPending(function* () {
        try {
            yield call(virusesAPI.remove, action.virusId);
            yield call(action.history.push, "/viruses");
            yield put({type: REMOVE_VIRUS.SUCCEEDED});
        } catch (error) {
            yield put({type: REMOVE_VIRUS.FAILED, error: error});
        }
    });
}

export function* addIsolate (action) {
    yield setPending(function* (action) {
        try {
            yield call(virusesAPI.addIsolate, action.virusId, action.sourceType, action.sourceName);
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: ADD_ISOLATE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: ADD_ISOLATE.FAILED, error: error});
        }
    }, action);
}

export function* editIsolate (action) {
    yield setPending(function* (action) {
        try {
            yield call(virusesAPI.editIsolate, action.virusId, action.isolateId, action.sourceType, action.sourceName);
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: EDIT_ISOLATE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: EDIT_ISOLATE.FAILED, error: error});
        }
    }, action);
}

export function* removeIsolate (action) {
    yield setPending(function* (action) {
        try {
            yield call(virusesAPI.removeIsolate, action.virusId, action.isolateId);
            yield call(action.onSuccess);
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: REMOVE_ISOLATE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: REMOVE_ISOLATE.FAILED, error: error});
        }
    }, action);
}

export function* addSequence (action) {
    yield setPending(function* (action) {
        try {
            yield call(
                virusesAPI.addSequence,
                action.virusId,
                action.isolateId,
                action.sequenceId,
                action.definition,
                action.host,
                action.sequence
            );
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: ADD_SEQUENCE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: ADD_SEQUENCE.FAILED, error: error});
        }
    }, action);
}

export function* editSequence (action) {
    yield setPending(function* (action) {
        try {
            yield call(
                virusesAPI.editSequence,
                action.virusId,
                action.isolateId,
                action.sequenceId,
                action.definition,
                action.host,
                action.sequence
            );
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: EDIT_SEQUENCE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: EDIT_SEQUENCE.FAILED, error: error});
        }
    }, action);
}

export function* removeSequence (action) {
    yield setPending(function* (action) {
        try {
            yield call(virusesAPI.removeSequence, action.virusId, action.isolateId, action.sequenceId);
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: REMOVE_SEQUENCE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: REMOVE_SEQUENCE.FAILED, error: error});
        }
    }, action);
}

export function* revert (action) {
    yield setPending(function* (action) {
        try {
            yield call(virusesAPI.revert, action.virusId, action.version);

            const virusResponse = yield call(virusesAPI.get, action.virusId);
            const historyResponse = yield call(virusesAPI.getHistory, action.virusId);

            yield put({type: REVERT.SUCCEEDED, detail: virusResponse.body, history: historyResponse.body});
        } catch (error) {
            yield put({type: REVERT.FAILED, error: error});
        }
    }, action)
}
<commit_msg>Throttle findViruses requests using sagas<commit_after>/**
 *
 *
 * @copyright 2017 Government of Canada
 * @license MIT
 * @author igboyes
 *
 */

import { call, put, takeEvery, takeLatest, throttle } from "redux-saga/effects";

import virusesAPI from "./api";
import { setPending } from "../wrappers";
import {
    FIND_VIRUSES,
    GET_VIRUS,
    GET_VIRUS_HISTORY,
    CREATE_VIRUS,
    EDIT_VIRUS,
    REMOVE_VIRUS,
    ADD_ISOLATE,
    EDIT_ISOLATE,
    REMOVE_ISOLATE,
    ADD_SEQUENCE,
    EDIT_SEQUENCE,
    REMOVE_SEQUENCE,
    REVERT,
    SET_APP_PENDING,
    UNSET_APP_PENDING
}  from "../actionTypes";

export function* watchViruses () {
    yield throttle(150, FIND_VIRUSES.REQUESTED, findViruses);
    yield takeLatest(GET_VIRUS.REQUESTED, getVirus);
    yield takeLatest(GET_VIRUS_HISTORY.REQUESTED, getVirusHistory);
    yield takeEvery(CREATE_VIRUS.REQUESTED, createVirus);
    yield takeEvery(EDIT_VIRUS.REQUESTED, editVirus);
    yield takeEvery(REMOVE_VIRUS.REQUESTED, removeVirus);
    yield takeEvery(ADD_ISOLATE.REQUESTED, addIsolate);
    yield takeEvery(EDIT_ISOLATE.REQUESTED, editIsolate);
    yield takeEvery(REMOVE_ISOLATE.REQUESTED, removeIsolate);
    yield takeEvery(ADD_SEQUENCE.REQUESTED, addSequence);
    yield takeEvery(EDIT_SEQUENCE.REQUESTED, editSequence);
    yield takeEvery(REMOVE_SEQUENCE.REQUESTED, removeSequence);
    yield takeEvery(REVERT.REQUESTED, revert);
}

export function* findViruses (action) {
    yield put({type: SET_APP_PENDING});

    try {
        const response = yield call(virusesAPI.find, action.term, action.page);
        yield put({type: FIND_VIRUSES.SUCCEEDED, data: response.body});
    } catch (error) {
        yield put({type: FIND_VIRUSES.FAILED}, error);
    }

    yield put({type: UNSET_APP_PENDING});
}

export function* getVirus (action) {
    yield setPending(function* () {
        try {
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: GET_VIRUS.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: GET_VIRUS.FAILED, error: error});
        }
    }, action);
}

export function* getVirusHistory (action) {
    yield setPending(function* () {
        try {
            const response = yield call(virusesAPI.getHistory, action.virusId);
            yield put({type: GET_VIRUS_HISTORY.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: GET_VIRUS_HISTORY.FAILED, error: error});
        }
    }, action);
}

export function* createVirus (action) {
    yield setPending(function* () {
        try {
            const response = yield call(virusesAPI.create, action.name, action.abbreviation);
            yield put({type: CREATE_VIRUS.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: CREATE_VIRUS.FAILED, error: error});
        }
    }, action);
}

export function* editVirus (action) {
    yield setPending(function* (action) {
        try {
            yield virusesAPI.edit(action.virusId, action.name, action.abbreviation);
            const response = yield virusesAPI.get(action.virusId);
            yield put({type: EDIT_VIRUS.SUCCEEDED, data: response.body});
        } catch (error) {
            if (error.response.status === 409) {
                yield put({type: EDIT_VIRUS.FAILED, message: error.response.body.message});
            } else{
                throw error;
            }
        }
    }, action);
}

export function* removeVirus (action) {
    yield setPending(function* () {
        try {
            yield call(virusesAPI.remove, action.virusId);
            yield call(action.history.push, "/viruses");
            yield put({type: REMOVE_VIRUS.SUCCEEDED});
        } catch (error) {
            yield put({type: REMOVE_VIRUS.FAILED, error: error});
        }
    });
}

export function* addIsolate (action) {
    yield setPending(function* (action) {
        try {
            yield call(virusesAPI.addIsolate, action.virusId, action.sourceType, action.sourceName);
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: ADD_ISOLATE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: ADD_ISOLATE.FAILED, error: error});
        }
    }, action);
}

export function* editIsolate (action) {
    yield setPending(function* (action) {
        try {
            yield call(virusesAPI.editIsolate, action.virusId, action.isolateId, action.sourceType, action.sourceName);
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: EDIT_ISOLATE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: EDIT_ISOLATE.FAILED, error: error});
        }
    }, action);
}

export function* removeIsolate (action) {
    yield setPending(function* (action) {
        try {
            yield call(virusesAPI.removeIsolate, action.virusId, action.isolateId);
            yield call(action.onSuccess);
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: REMOVE_ISOLATE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: REMOVE_ISOLATE.FAILED, error: error});
        }
    }, action);
}

export function* addSequence (action) {
    yield setPending(function* (action) {
        try {
            yield call(
                virusesAPI.addSequence,
                action.virusId,
                action.isolateId,
                action.sequenceId,
                action.definition,
                action.host,
                action.sequence
            );
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: ADD_SEQUENCE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: ADD_SEQUENCE.FAILED, error: error});
        }
    }, action);
}

export function* editSequence (action) {
    yield setPending(function* (action) {
        try {
            yield call(
                virusesAPI.editSequence,
                action.virusId,
                action.isolateId,
                action.sequenceId,
                action.definition,
                action.host,
                action.sequence
            );
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: EDIT_SEQUENCE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: EDIT_SEQUENCE.FAILED, error: error});
        }
    }, action);
}

export function* removeSequence (action) {
    yield setPending(function* (action) {
        try {
            yield call(virusesAPI.removeSequence, action.virusId, action.isolateId, action.sequenceId);
            const response = yield call(virusesAPI.get, action.virusId);
            yield put({type: REMOVE_SEQUENCE.SUCCEEDED, data: response.body});
        } catch (error) {
            yield put({type: REMOVE_SEQUENCE.FAILED, error: error});
        }
    }, action);
}

export function* revert (action) {
    yield setPending(function* (action) {
        try {
            yield call(virusesAPI.revert, action.virusId, action.version);

            const virusResponse = yield call(virusesAPI.get, action.virusId);
            const historyResponse = yield call(virusesAPI.getHistory, action.virusId);

            yield put({type: REVERT.SUCCEEDED, detail: virusResponse.body, history: historyResponse.body});
        } catch (error) {
            yield put({type: REVERT.FAILED, error: error});
        }
    }, action)
}
<|endoftext|>


<commit_before>Template.task.helpers({
    getUsername: function () {
        if (this.together) {
            return 'Together'
        }
        return this.username;
    },
    getCategory: function () {
        for (var i = 0; i < Categories.length; i++) {
            if (Categories[i].name === this.category) {
                return Categories[i].title + '：';
            }
        }
        return '';
    },
    infoActive: function () {
        return this.info !== '';
    }
});

Template.task.events({
    'click .toggle-checked': function () {
        Meteor.call('updateTask', this._id, {checked: !this.checked});
    },
    'click .info': function () {
        AntiModals.overlay('infoModal', {
            data: this
        });
    },
    'click .delete': function () {
        if (!confirm('确定删除该任务？')) {
            return;
        }
        Meteor.call('deleteTask', this._id);
    }
});<commit_msg>Update info active.<commit_after>Template.task.helpers({
    getUsername: function () {
        if (this.together) {
            return 'Together'
        }
        return this.username;
    },
    getCategory: function () {
        for (var i = 0; i < Categories.length; i++) {
            if (Categories[i].name === this.category) {
                return Categories[i].title + '：';
            }
        }
        return '';
    },
    infoActive: function () {
        return this.info && this.info !== '';
    }
});

Template.task.events({
    'click .toggle-checked': function () {
        Meteor.call('updateTask', this._id, {checked: !this.checked});
    },
    'click .info': function () {
        AntiModals.overlay('infoModal', {
            data: this
        });
    },
    'click .delete': function () {
        if (!confirm('确定删除该任务？')) {
            return;
        }
        Meteor.call('deleteTask', this._id);
    }
});<|endoftext|>


<commit_before>angular.module('uiRouterSample.console', [
  'ui.router'
])

.config(
  [          '$stateProvider', '$urlRouterProvider',
    function ($stateProvider,   $urlRouterProvider) {

      $stateProvider

        /////////////////
        // Home Screen //
        /////////////////

        .state('console', {
          url: '/console',
          views: {

            '': {
              templateUrl: 'app/console/console.html',
              controller: ['$scope', '$state', '$rootScope', '$http',
                function (  $scope,   $state, $rootScope, $http) {

                  $rootScope.enableConfiguration = "disabled";

                  alert("console-16");

                  $http.get("assets/data/console-data.txt")
                  .success(function(data) {
                    //$scope.consolegrid.data = data;
                    alert("http complete" + data);
                  });

                  $scope.consolegrid = { enableRowSelection: true, enableRowHeaderSelection: false };

                  $scope.consolegrid.columnDefs = [
                    { name: 'Applicant Name', field: 'name', width: "18%" },
                    { name: 'Gender', field: 'gender', width: "10%" },
                    { name: 'Dependants', field: 'dependant', width: "10%" },

                    { name: 'Entry Offer', field: 'offer', width: "13%", enableFiltering: false,
                      cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex)
                      {
                        if(row.entity.offerStatus === 'OK') { return 'status-ok'; }
                        else if(row.entity.offerStatus === 'Inactive')  { return 'status-inactive'; }
                        else if(row.entity.offerStatus === 'Rejected')  { return 'status-error'; }
                      }
                    },
                    { name: 'Resident Country', field: 'country', width: "13%" },
                    { name: 'English Score', field: 'englishScore', width: "13%", enableFiltering: false,
                      cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex)
                      {
                        if(row.entity.englishScoreStatus === 'HIGH') { return 'status-ok'; }
                        else if(row.entity.englishScoreStatus === 'MEDIUM')  { return 'status-inactive'; }
                        else if(row.entity.englishScoreStatus === 'LOW')  { return 'status-error'; }
                      }
                    },
                    { name: 'Days Remaining', field: 'daysRemaining', width: "12%", cellClass: "console-text-center" },
                    { name: 'Status', field: 'applicantStatus', width: "11%", enableFiltering: false,
                      cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex)
                      {
                        if(row.entity.applicantStatus === 'APPROVED') { return 'status-ok'; }
                        else if(row.entity.applicantStatus === 'ON-HOLD')  { return 'status-hold'; }
                        else if(row.entity.applicantStatus === 'REJECTED')  { return 'status-error'; }
                      }
                    }
                  ];

                  $scope.consolegrid.multiSelect = false;
                  $scope.consolegrid.modifierKeysToMultiSelect = false;
                  $scope.consolegrid.noUnselect = false;

                  $scope.consolegrid.onRegisterApi = function ( gridApi) {
                    $scope.gridApi = gridApi;
                    gridApi.selection.on.rowSelectionChanged($scope, function(row){
                      if(row.isSelected)
                      {
                        if(row.entity && row.entity.name)
                        {
                          //Save the selected application into singleton
                          //singleton.setConsoleRow(row);
                          $rootScope.enableConfiguration = "enabled";
                        }
                      }
                    });
                  };

                  $scope.toggleRowSelection = function() {
                    $scope.gridApi.selection.clearSelectedRows();
                    $scope.consolegrid.enableRowSelection = !$scope.consolegrid.enableRowSelection;
                    $scope.gridApi.core.notifyDataChange( uiGridConstants.dataChange.OPTIONS);
                  };

                }]
            },

            'navigation-bar@': {
              templateUrl: 'app/navbar/console-navbar.html'
            }
          }
        })
        ;
    }
  ]
);
<commit_msg>Update console.js<commit_after>angular.module('uiRouterSample.console', [
  'ui.router'
])

.config(
  [          '$stateProvider', '$urlRouterProvider',
    function ($stateProvider,   $urlRouterProvider) {

      $stateProvider

        /////////////////
        // Home Screen //
        /////////////////

        .state('console', {
          url: '/console',
          views: {

            '': {
              templateUrl: 'app/console/console.html',
              controller: ['$scope', '$state', '$rootScope', '$http',
                function (  $scope,   $state, $rootScope, $http) {

                  $rootScope.enableConfiguration = "disabled";

                  alert("console-17");

                  // $http.get("assets/data/console-data.txt")
                  // .success(function(data) {
                  //   //$scope.consolegrid.data = data;
                  //   alert("http complete" + data);
                  // });

                  $scope.consolegrid.data = [
  {
    "name": "Ethel Price",
    "country": "Scotland",
    "gender": "female",
    "dependant": "spouse",
    "offer": "EMPLOYER",
    "offerStatus": "OK",
    "englishScore": "92",
    "englishScoreStatus": "HIGH",
    "daysRemaining": "183",
    "applicantStatus": "APPROVED"
  }

];

                  $scope.consolegrid = { enableRowSelection: true, enableRowHeaderSelection: false };

                  $scope.consolegrid.columnDefs = [
                    { name: 'Applicant Name', field: 'name', width: "18%" },
                    { name: 'Gender', field: 'gender', width: "10%" },
                    { name: 'Dependants', field: 'dependant', width: "10%" },

                    { name: 'Entry Offer', field: 'offer', width: "13%", enableFiltering: false,
                      cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex)
                      {
                        if(row.entity.offerStatus === 'OK') { return 'status-ok'; }
                        else if(row.entity.offerStatus === 'Inactive')  { return 'status-inactive'; }
                        else if(row.entity.offerStatus === 'Rejected')  { return 'status-error'; }
                      }
                    },
                    { name: 'Resident Country', field: 'country', width: "13%" },
                    { name: 'English Score', field: 'englishScore', width: "13%", enableFiltering: false,
                      cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex)
                      {
                        if(row.entity.englishScoreStatus === 'HIGH') { return 'status-ok'; }
                        else if(row.entity.englishScoreStatus === 'MEDIUM')  { return 'status-inactive'; }
                        else if(row.entity.englishScoreStatus === 'LOW')  { return 'status-error'; }
                      }
                    },
                    { name: 'Days Remaining', field: 'daysRemaining', width: "12%", cellClass: "console-text-center" },
                    { name: 'Status', field: 'applicantStatus', width: "11%", enableFiltering: false,
                      cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex)
                      {
                        if(row.entity.applicantStatus === 'APPROVED') { return 'status-ok'; }
                        else if(row.entity.applicantStatus === 'ON-HOLD')  { return 'status-hold'; }
                        else if(row.entity.applicantStatus === 'REJECTED')  { return 'status-error'; }
                      }
                    }
                  ];

                  $scope.consolegrid.multiSelect = false;
                  $scope.consolegrid.modifierKeysToMultiSelect = false;
                  $scope.consolegrid.noUnselect = false;

                  $scope.consolegrid.onRegisterApi = function ( gridApi) {
                    $scope.gridApi = gridApi;
                    gridApi.selection.on.rowSelectionChanged($scope, function(row){
                      if(row.isSelected)
                      {
                        if(row.entity && row.entity.name)
                        {
                          //Save the selected application into singleton
                          //singleton.setConsoleRow(row);
                          $rootScope.enableConfiguration = "enabled";
                        }
                      }
                    });
                  };

                  $scope.toggleRowSelection = function() {
                    $scope.gridApi.selection.clearSelectedRows();
                    $scope.consolegrid.enableRowSelection = !$scope.consolegrid.enableRowSelection;
                    $scope.gridApi.core.notifyDataChange( uiGridConstants.dataChange.OPTIONS);
                  };

                }]
            },

            'navigation-bar@': {
              templateUrl: 'app/navbar/console-navbar.html'
            }
          }
        })
        ;
    }
  ]
);
<|endoftext|>


<commit_before>import './Home.scss'
import path from 'path'
import OpenSubtitles from 'subtitler'
import React, { Component } from 'react'
import Promise from 'bluebird';
import Storage from 'electron-json-storage'
import List from '../components/List'
import Loading from '../components/Loading'
import Dropzone from '../components/Dropzone'
import Settings from '../components/Settings'
import EmptyList from '../components/EmptyList'
import SearchField from '../components/SearchField'
import { CheckFiles, ToBuffer, DownloadSubtitles } from '../scripts/Utility'
import { opensubtitles, addic7ed } from '../sources'

export default class Home extends Component {

	constructor(props) {
		super(props)
		this.state = {
			query: '',
			lang: 'eng',
			files: [],
			results: [],
			loading: false,
			dragging: false,
			searching: false,
			dropzoneText: 'Drop an episode or season…'
		}
		this.onDrop = this.onDrop.bind(this)
		this.onDragEnter = this.onDragEnter.bind(this)
		this.onDragLeave = this.onDragLeave.bind(this)
		this.onDragOver = this.onDragOver.bind(this)
		this.resetList = this.resetList.bind(this)
		this.onKeyPress = this.onKeyPress.bind(this)
		this.onQueryChange = this.onQueryChange.bind(this)
		this.searchForFiles = this.searchForFiles.bind(this)
		this.searchForTitle = this.searchForTitle.bind(this)
		this.onLanguageChange = this.onLanguageChange.bind(this)
	}

	setFileStatus(index, status) {
		if (this.state.files.length > 0) {
			this.setState({
				files: [
					...this.state.files.slice(0, index),
					{ ...this.state.files[index], status },
					...this.state.files.slice(index + 1),
				]
			})
		}
	}

	searchForFiles() {
		const files = this.state.files

		files.map((file, index) => {
			// Construct multiple sources
			const s1 = opensubtitles.searchFile(file, this.state.lang)
			const s2 = addic7ed.searchFile(file, this.state.lang)

			// The first source who comes with an results
			Promise.any([s1, s2])
				.then(({ subtitles, source, file }) => {

					console.log(subtitles)
					console.log(source)
					console.log(file)

					// Switch source for the right download function
					switch (source) {
						case 'addic7ed':
							console.log('Downloading from addic7ed...')
							return addic7ed.downloadFile(subtitles[0], file)
						case 'opensubtitles':
							console.log('Downloading from opensubtitles...')
							return opensubtitles.downloadFile(subtitles, file)
						default:
							return new Error('No subtitle downloaded.');
					}
				})
				.then(() => {
					this.setFileStatus(index, 'done')
				})
				.catch(error => {
					this.setFileStatus(index, 'failed')
					console.log(error)
				})
		})

	}

	searchForTitle(event) {

		// Prevent default form submit
		if (event) {
			event.preventDefault()
		}

		// Only do a search if there's a query
		if (this.state.query) {

			// Enable loading
			this.setState({
				loading: true,
				searching: true,
				results: []
			})

			// Construct multiple sources
			const s1 = opensubtitles.searchQuery(this.state.query, this.state.lang)
				.then((results => {
					this.setState((prevState, props) => ({
						results: [
							...prevState.results,
							...results.subtitles
						],
						loading: false
					}))
				}))
				.catch(error => {
					console.log(error);
					this.setState({
						loading: false
					})
				})

			const s2 = addic7ed.searchQuery(this.state.query, this.state.lang)
				.then((results => {
					this.setState((prevState, props) => ({
						results: [
							...prevState.results,
							...results.subtitles
						],
						loading: false
					}))
				}))
				.catch(error => {
					console.log(error);
					this.setState({
						loading: false
					})
				})

			// Promise.all([s1, s2])
			Promise.all([s2])
				.then(() => {
					this.setState({
						searching: false
					})
				})
				.catch(error => {
					console.error(error)
					this.setState({
						searching: false
					})
				})
		}
	}

	onDragEnter(event) {
		this.setState({
			dragging: true
		})
	}

	onDragLeave() {
		if (this.state.dragging) {
			this.setState({
				dragging: false
			})
		}
	}

	onDragOver() {
		if (!this.state.dragging) {
			this.setState({
				dragging: true
			})
		}
	}

	getFilePath(isDirectory, fileDropped) {
		if (isDirectory) {
			return fileDropped.path
		}
		else {
			return path.dirname(fileDropped.path)
		}
	}

	onDrop(event) {
		// Prevent Default
		event.preventDefault()

		// Get the dropped files
		const filesDropped = event.dataTransfer ? event.dataTransfer.files : event.target.files

		// Process dropped path
		const { files, isDirectory } = CheckFiles(filesDropped)

		// If files
		if (files.length > 0) {
			const filePath = this.getFilePath(isDirectory, filesDropped[0])
			const query = filePath.substr(filePath.lastIndexOf('/') + 1)

			if (this.state.files.length > 0) {
				//Add to current array
				this.setState({
					query: query,
					results: [],
					files: files,
					dragging: false
				}, () => {
					this.searchForFiles()
				})
			}
			else {
				// New Array with files
				this.setState({
					query: query,
					results: [],
					files: files,
					dragging: false
				}, () => {
					this.searchForFiles()
				})
			}

		}
		// If the file is too small, do nothing
		else {
			this.setState({
				dragging: false
			})
		}
	}

	onLanguageChange(lang) {
		Storage.set('language', lang, (error) => {
			if (error) throw error
		})

		this.setState({
			lang
		})

		// Search again
		if (this.state.results.length > 0) {
			this.searchForTitle()
		}
		else {
			// Set the new loading state and search again
			this.setState({
				files: this.state.files.map((file) => {
					return { ...file, status: 'loading' }
				})
			}, () => {
				this.searchForFiles()
			})

		}
	}

	onQueryChange(query) {
		this.setState({
			files: [],
			query: query,
		})
	}

	resetList() {
		this.setState({
			files: [],
			query: '',
			results: [],
			loading: false,
		})
	}

	onKeyPress(event) {
		if (event.keyCode === 27) {
			this.resetList()
		}
	}

	componentWillMount() {
		Storage.get('language', (error, lang) => {

			if (Object.keys(lang).length === 0 && lang.constructor === Object) {
				this.setState({
					lang: 'eng'
				})
			}
			else {
				this.setState({
					lang: lang
				})
			}
		})
	}

	componentDidMount() {
		document.addEventListener('keydown', this.onKeyPress)
	}

	componentWillUnmount() {
		document.removeEventListener('keydown', this.onKeyPress)
	}

	render() {
		// Content
		let content

		// Construct circle icon
		const circle = (
			<svg x="0px" y="0px" width="25px" height="25px" viewBox="0 0 25 25">
				<circle cx="12.5" cy="12.5" r="12.5" />
			</svg>
		)

		// If loading is true or if there are results and loading is true
		// (Loading state)
		if (this.state.loading) {
			content = <Loading />
		}
		// If there are results show the list with results
		// (TextSearch State)
		else if (this.state.results.length > 0) {
			content = <List textSearch={true} results={this.state.results} resetList={this.resetList} onDrop={this.onDrop} />
		}
		// If there are files dropped show the list with files
		// (FileSearch state)
		else if (this.state.files.length > 0) {
			content = <List fileSearch={true} results={this.state.files} resetList={this.resetList} onDrop={this.onDrop} />
		}
		// If the query is empty show the dropzone
		// (Home state)
		else if (this.state.query === '') {
			content = <Dropzone onDrop={this.onDrop} onDragEnter={this.onDragEnter} onDragLeave={this.onDragLeave} onDragOver={this.onDragOver} dragging={this.state.dragging} />
		}
		// Everything else, show an empty list
		// (Typing... state)
		else {
			content = <EmptyList />
		}

		// Render
		return (

				<SearchField
					resetList={this.resetList}
					submitForm={this.searchForTitle}
					changeQuery={this.onQueryChange}
					defaultValue={this.state.query}
					showReset={!this.state.visibleDropArea}
				/>
				<Settings
					query={this.state.query}
					selectedLanguage={this.state.lang}
					changeLanguage={this.onLanguageChange}
					results={this.state.results}
					files={this.state.files}
					resetList={this.resetList}
					searching={this.state.searching}
				/>
				<section className={`content-wrapper`}>
					{content}

		)
	}
}
<commit_msg>Working on Noting found dialog<commit_after>import "./Home.scss";
import { remote } from "electron";
import path from "path";
import OpenSubtitles from "subtitler";
import React, { Component } from "react";
import Promise from "bluebird";
import Storage from "electron-json-storage";
import List from "../components/List";
import Loading from "../components/Loading";
import Dropzone from "../components/Dropzone";
import Settings from "../components/Settings";
import EmptyList from "../components/EmptyList";
import SearchField from "../components/SearchField";
import { CheckFiles, ToBuffer, DownloadSubtitles } from "../scripts/Utility";
import { opensubtitles, addic7ed } from "../sources";

export default class Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      query: "",
      lang: "eng",
      files: [],
      results: [],
      loading: false,
      dragging: false,
      searching: false,
      dropzoneText: "Drop an episode or season…"
    };
    this.onDrop = this.onDrop.bind(this);
    this.onDragEnter = this.onDragEnter.bind(this);
    this.onDragLeave = this.onDragLeave.bind(this);
    this.onDragOver = this.onDragOver.bind(this);
    this.resetList = this.resetList.bind(this);
    this.onKeyPress = this.onKeyPress.bind(this);
    this.onQueryChange = this.onQueryChange.bind(this);
    this.searchForFiles = this.searchForFiles.bind(this);
    this.searchForTitle = this.searchForTitle.bind(this);
    this.onLanguageChange = this.onLanguageChange.bind(this);
    this.showNothingFoundDialog = this.showNothingFoundDialog.bind(this);
    this.disableNothingFoundDialog = this.disableNothingFoundDialog.bind(this);
  }

  setFileStatus(index, status) {
    if (this.state.files.length > 0) {
      this.setState({
        files: [
          ...this.state.files.slice(0, index),
          { ...this.state.files[index], status },
          ...this.state.files.slice(index + 1)
        ]
      });
    }
  }

  showNothingFoundDialog() {
    const dialog = remote.dialog;
    const options = {
      type: "question",
      buttons: ["OK", "Cancel"],
      checkboxLabel: "Do not show this message again.",
      checkboxChecked: false,
      message: `No subs in your chosen language.`,
      detail: `Sorry, no subs for ${this.state.query}. in your language. Would you like to try English?`
    };

    dialog.showMessageBox(options, (response, checkboxChecked) => {
      // Disable nothing found dialog
      if (checkboxChecked) {
        this.disableNothingFoundDialog();
      }

      // if buttons "OK" is clicked
      if (response === 0) {
        // Set language to english and search again.
        this.setState(
          {
            lang: "eng"
          },
          () => {
            this.searchForTitle();
          }
        );
      }
    });
  }

  disableNothingFoundDialog() {
    Storage.set("noting-found-window", false, error => {
      if (error) throw error;
    });
  }

  searchForFiles() {
    const files = this.state.files;

    files.map((file, index) => {
      // Construct multiple sources
      const s1 = opensubtitles.searchFile(file, this.state.lang);
      const s2 = addic7ed.searchFile(file, this.state.lang);

      // The first source who comes with an results
      Promise.any([s1, s2])
        .then(({ subtitles, source, file }) => {
          console.log(subtitles);
          console.log(source);
          console.log(file);

          // Switch source for the right download function
          switch (source) {
            case "addic7ed":
              console.log("Downloading from addic7ed...");
              return addic7ed.downloadFile(subtitles[0], file);
            case "opensubtitles":
              console.log("Downloading from opensubtitles...");
              return opensubtitles.downloadFile(subtitles, file);
            default:
              return new Error("No subtitle downloaded.");
          }
        })
        .then(() => {
          this.setFileStatus(index, "done");
        })
        .catch(error => {
          this.setFileStatus(index, "failed");
          console.log(error);
        });
    });
  }

  searchForTitle(event) {
    // Prevent default form submit
    if (event) {
      event.preventDefault();
    }

    // Only do a search if there's a query
    if (this.state.query) {
      // Enable loading
      this.setState({
        loading: true,
        searching: true,
        results: []
      });

      // Construct multiple sources
      const s1 = opensubtitles
        .searchQuery(this.state.query, this.state.lang)
        .then(results => {
          this.setState((prevState, props) => ({
            results: [...prevState.results, ...results.subtitles],
            loading: false
          }));
        })
        .catch(error => {
          console.log(error);
          this.setState({
            loading: false
          });
        });

      const s2 = addic7ed
        .searchQuery(this.state.query, this.state.lang)
        .then(results => {
          this.setState((prevState, props) => ({
            results: [...prevState.results, ...results.subtitles],
            loading: false
          }));
        })
        .catch(error => {
          console.log(error);
          this.setState({
            loading: false
          });
        });

      Promise.all([s1, s2])
        //   Promise.all([s2])
        .then(() => {
          this.setState({
            searching: false
          });
        })
        .then(() => {
          if (this.state.results.length === 0 && this.state.lang !== "eng") {
            this.showNothingFoundDialog();
          }
        })
        .catch(error => {
          console.error(error);
          this.setState({
            searching: false
          });
        });
    }
  }

  onDragEnter(event) {
    this.setState({
      dragging: true
    });
  }

  onDragLeave() {
    if (this.state.dragging) {
      this.setState({
        dragging: false
      });
    }
  }

  onDragOver() {
    if (!this.state.dragging) {
      this.setState({
        dragging: true
      });
    }
  }

  getFilePath(isDirectory, fileDropped) {
    if (isDirectory) {
      return fileDropped.path;
    } else {
      return path.dirname(fileDropped.path);
    }
  }

  onDrop(event) {
    // Prevent Default
    event.preventDefault();

    // Get the dropped files
    const filesDropped = event.dataTransfer
      ? event.dataTransfer.files
      : event.target.files;

    // Process dropped path
    const { files, isDirectory } = CheckFiles(filesDropped);

    // If files
    if (files.length > 0) {
      const filePath = this.getFilePath(isDirectory, filesDropped[0]);
      const query = filePath.substr(filePath.lastIndexOf("/") + 1);

      if (this.state.files.length > 0) {
        //Add to current array
        this.setState(
          {
            query: query,
            results: [],
            files: files,
            dragging: false
          },
          () => {
            this.searchForFiles();
          }
        );
      } else {
        // New Array with files
        this.setState(
          {
            query: query,
            results: [],
            files: files,
            dragging: false
          },
          () => {
            this.searchForFiles();
          }
        );
      }
    } else {
      // If the file is too small, do nothing
      this.setState({
        dragging: false
      });
    }
  }

  onLanguageChange(lang) {
    Storage.set("language", lang, error => {
      if (error) throw error;
    });

    this.setState({
      lang
    });

    // Search again
    if (this.state.results.length > 0) {
      this.searchForTitle();
    } else {
      // Set the new loading state and search again
      this.setState(
        {
          files: this.state.files.map(file => {
            return { ...file, status: "loading" };
          })
        },
        () => {
          this.searchForFiles();
        }
      );
    }
  }

  onQueryChange(query) {
    this.setState({
      files: [],
      query: query
    });
  }

  resetList() {
    this.setState({
      files: [],
      query: "",
      results: [],
      loading: false
    });
  }

  onKeyPress(event) {
    if (event.keyCode === 27) {
      this.resetList();
    }
  }

  componentWillMount() {
    Storage.get("language", (error, lang) => {
      if (Object.keys(lang).length === 0 && lang.constructor === Object) {
        this.setState({
          lang: "eng"
        });
      } else {
        this.setState({
          lang: lang
        });
      }
    });
  }

  componentDidMount() {
    document.addEventListener("keydown", this.onKeyPress);
  }

  componentWillUnmount() {
    document.removeEventListener("keydown", this.onKeyPress);
  }

  render() {
    // Content
    let content;

    // Construct circle icon
    const circle = (
      <svg x="0px" y="0px" width="25px" height="25px" viewBox="0 0 25 25">
        <circle cx="12.5" cy="12.5" r="12.5" />
      </svg>
    );

    // If loading is true or if there are results and loading is true
    // (Loading state)
    if (this.state.loading) {
      content = <Loading />;
    } else if (this.state.results.length > 0) {
      // If there are results show the list with results
      // (TextSearch State)
      content = (
        <List
          textSearch={true}
          results={this.state.results}
          resetList={this.resetList}
          onDrop={this.onDrop}
        />
      );
    } else if (this.state.files.length > 0) {
      // If there are files dropped show the list with files
      // (FileSearch state)
      content = (
        <List
          fileSearch={true}
          results={this.state.files}
          resetList={this.resetList}
          onDrop={this.onDrop}
        />
      );
    } else if (this.state.query === "") {
      // If the query is empty show the dropzone
      // (Home state)
      content = (
        <Dropzone
          onDrop={this.onDrop}
          onDragEnter={this.onDragEnter}
          onDragLeave={this.onDragLeave}
          onDragOver={this.onDragOver}
          dragging={this.state.dragging}
        />
      );
    } else {
      // Everything else, show an empty list
      // (Typing... state)
      content = <EmptyList />;
    }

    // Render
    return (

        <SearchField
          resetList={this.resetList}
          submitForm={this.searchForTitle}
          changeQuery={this.onQueryChange}
          defaultValue={this.state.query}
          showReset={!this.state.visibleDropArea}
        />
        <Settings
          query={this.state.query}
          selectedLanguage={this.state.lang}
          changeLanguage={this.onLanguageChange}
          results={this.state.results}
          files={this.state.files}
          resetList={this.resetList}
          searching={this.state.searching}
        />
        <section className={`content-wrapper`}>
          {content}

    );
  }
}
<|endoftext|>


<commit_before>var util = require('util');
var github = require('../../config/github');
var config = require('../../config/config');

var apiDone = function (res, next) {
  return function (err) {
    if (err) {
      return next(err);
    }
    res.send({success: true});
  };
};

exports.addRepo = function (req, res, next) {
  var done = apiDone(res, next);
  var user = req.user;
  var authCreds = {
    type: 'oauth',
    token: user.accessToken
  };
  var collaboratorData = {
    user: user.profile.login,
    repo: req.params.repo,
    collabuser: config.BOT_USERNAME
  };
  console.log('data', collaboratorData);
  github(authCreds).repos.addCollaborator(collaboratorData, function (err) {
    if (err) {
      return next(err);
    }
    user.repos = user.repos || [];
    user.repos.push(req.params.repo);
    user.save(done);
  });
};

exports.webhookAll = function (req, res, next) {
  console.log('Webhook!');
  console.log(JSON.stringify(util.inspect(req)));
  apiDone(res, next)();
}
<commit_msg>logging stuff<commit_after>var util = require('util');
var github = require('../../config/github');
var config = require('../../config/config');

var apiDone = function (res, next) {
  return function (err) {
    if (err) {
      return next(err);
    }
    res.send({success: true});
  };
};

exports.addRepo = function (req, res, next) {
  var done = apiDone(res, next);
  var user = req.user;
  var authCreds = {
    type: 'oauth',
    token: user.accessToken
  };
  var collaboratorData = {
    user: user.profile.login,
    repo: req.params.repo,
    collabuser: config.BOT_USERNAME
  };
  console.log('data', collaboratorData);
  github(authCreds).repos.addCollaborator(collaboratorData, function (err) {
    if (err) {
      return next(err);
    }
    user.repos = user.repos || [];
    user.repos.push(req.params.repo);
    user.save(done);
  });
};

exports.webhookAll = function (req, res, next) {
  console.log('Webhook!');
  console.log(req);
  apiDone(res, next)();
}
<|endoftext|>


<commit_before>// CartoDB SQL API
//
// all requests expect the following URL args:
// - `sql` {String} SQL to execute
//
// for private (read/write) queries:
// - OAuth. Must have proper OAuth 1.1 headers. For OAuth 1.1 spec see Google
//
// eg. /api/v1/?sql=SELECT 1 as one (with a load of OAuth headers or URL arguments)
//
// for public (read only) queries:
// - sql only, provided the subdomain exists in CartoDB and the table's sharing options are public
//
// eg. vizzuality.cartodb.com/api/v1/?sql=SELECT * from my_table
var express = require('express')
    , app      = express.createServer(
    express.logger({
        buffer: true,
        format: '[:date] :req[X-Real-IP] \033[90m:method\033[0m \033[36m:req[Host]:url\033[0m \033[90m:status :response-time ms -> :res[Content-Type]\033[0m'
    }))
    , Step        = require('step')
    , csv         = require('csv')
    , crypto      = require('crypto')
    , Meta        = require(global.settings.app_root + '/app/models/metadata')
    , oAuth       = require(global.settings.app_root + '/app/models/oauth')
    , PSQL        = require(global.settings.app_root + '/app/models/psql')
    , ApiKeyAuth  = require(global.settings.app_root + '/app/models/apikey_auth')
    , _           = require('underscore')
    , tableCache  = {};

app.use(express.bodyParser());
app.enable('jsonp callback');

// basic routing
app.all('/api/v1/sql',     function(req, res) { handleQuery(req, res) } );
app.all('/api/v1/sql.:f',  function(req, res) { handleQuery(req, res) } );
app.get('/api/v1/cachestatus',  function(req, res) { handleCacheStatus(req, res) } );

// request handlers
function handleQuery(req, res){

    // sanitize input
    var body      = (req.body) ? req.body : {};
    var sql       = req.query.q || body.q; // get and post
    var api_key   = req.query.api_key || body.api_key;
    var database  = req.query.database; // deprecate this in future
    var limit     = parseInt(req.query.rows_per_page);
    var offset    = parseInt(req.query.page);
    var format    = (req.query.format) ? req.query.format : null;
    var dp        = (req.query.dp) ? req.query.dp: '15';

    // validate input slightly
    dp        = (dp === "")        ? '15' : dp;
    format    = (format === "")   ? null : format;
    sql       = (sql === "")      ? null : sql;
    database  = (database === "") ? null : database;
    limit     = (_.isNumber(limit))  ? limit : null;
    offset    = (_.isNumber(offset)) ? offset * limit : null

    // setup step run
    var start = new Date().getTime();

    // initialise MD5 key of sql for cache lookups
    var sql_md5 = generateMD5(sql);

    try {
        if (!_.isString(sql)) throw new Error("You must indicate a sql query");
        var pg;

        // 1. Get database from redis via the username stored in the host header subdomain
        // 2. Run the request through OAuth to get R/W user id if signed
        // 3. Get the list of tables affected by the query
        // 4. Run query with r/w or public user
        // 5. package results and send back
        Step(
            function getDatabaseName(){
                Meta.getDatabase(req, this);
            },
            function setDBGetUser(err, data) {
                if (err) throw err;
                database = (data == "" || _.isNull(data)) ? database : data;

                if(api_key) {
                    ApiKeyAuth.verifyRequest(req, this);
                } else {
                    oAuth.verifyRequest(req, this);
                }
            },
            function queryExplain(err, user_id){
                if (err) throw err;
                // store postgres connection
                pg = new PSQL(user_id, database, limit, offset);

                // get all the tables from Cache or SQL
                if (!_.isNull(tableCache[sql_md5]) && !_.isUndefined(tableCache[sql_md5])){
                   tableCache[sql_md5].hits++;
                   return true;
                } else{
                    pg.query("SELECT CDB_QueryTables($quotesql$" + sql + "$quotesql$)", this);
                }
            },
            function queryResult(err, result){
                if (err) throw err;

                // store explain result in local Cache
                if (_.isUndefined(tableCache[sql_md5])){
                    tableCache[sql_md5] = result;
                    tableCache[sql_md5].hits = 1; //initialise hit counter
                }

                // TODO: refactor formats to external object
                if (format === 'geojson'){
                    sql = ['SELECT *, ST_AsGeoJSON(the_geom,',dp,') as the_geom FROM (', sql, ') as foo'].join("");
                }

                pg.query(sql, this);
            },
            function setHeaders(err, result){
                if (err) throw err;

                // configure headers for geojson/CSV
                res.header("Content-Disposition", getContentDisposition(format));
                res.header("Content-Type", getContentType(format));

                // allow cross site post
                setCrossDomain(res);

                // set cache headers
                res.header('Last-Modified', new Date().toUTCString());
                res.header('Cache-Control', 'no-cache,max-age=3600,must-revalidate, public');
                res.header('X-Cache-Channel', generateCacheKey(database, tableCache[sql_md5]));

                return result;
            },
            function packageResults(err, result){
                if (err) throw err;

                // TODO: refactor formats to external object
                if (format === 'geojson'){
                    toGeoJSON(result, res, this);
                } else if (format === 'csv'){
                    toCSV(result, res, this);
                } else {
                    var end = new Date().getTime();
                    return {
                        'time' : ((end - start)/1000),
                        'total_rows': result.rows.length,
                        'rows'      : result.rows
                    };
                }
            },
            function sendResults(err, out){
                if (err) throw err;

                // return to browser
                res.send(out);
            },
            function errorHandle(err, result){
                handleException(err, res);
            }
        );
    } catch (err) {
        console.log('[ERROR]\n' + err);
        handleException(err, res);
    }
}

function handleCacheStatus(req, res){
    var tableCacheValues = _.values(tableCache);
    var totalExplainHits = _.reduce(tableCacheValues, function(memo, res) { return memo + res.hits}, 0);
    var totalExplainKeys = tableCacheValues.length;

    res.send({explain: {hits: totalExplainHits, keys : totalExplainKeys }});
}

// helper functions
function toGeoJSON(data, res, callback){
    try{
        var out = {
            type: "FeatureCollection",
            features: []
        };

        _.each(data.rows, function(ele){
            var geojson = {
                type: "Feature",
                properties: { },
                geometry: { }
            };
            geojson.geometry = JSON.parse(ele["the_geom"]);
            delete ele["the_geom"];
            delete ele["the_geom_webmercator"];
            geojson.properties = ele;
            out.features.push(geojson);
        });

        // return payload
        callback(null, out);
    } catch (err) {
        callback(err,null);
    }
}

function toCSV(data, res, callback){
    try{
        // pull out keys for column headers
        var columns = _.keys(data.rows[0]);

        // stream the csv out over http
        csv()
          .from(data.rows)
          .toStream(res, {end: true, columns: columns, header: true});
        return true;
    } catch (err) {
        callback(err,null);
    }
}

function getContentDisposition(format){
    var ext = 'json';
    if (format === 'geojson'){
        ext = 'geojson';
    }
    if (format === 'csv'){
        ext = 'csv';
    }
    var time = new Date().toUTCString();
    return 'inline; filename=cartodb-query.' + ext + '; modification-date="' + time + '";';
}

function getContentType(format){
    var type = "application/json; charset=utf-8";
    if (format === 'csv'){
        type = "text/csv; charset=utf-8";
    }
    return type;
}

function setCrossDomain(res){
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
}

function generateCacheKey(database,tables){
    return database + ":" + tables.rows[0].cdb_querytables.split(/^\{(.*)\}$/)[1];
}

function generateMD5(data){
    var hash = crypto.createHash('md5');
    hash.update(data);
    return hash.digest('hex');
}

function handleException(err, res){
    var msg = (global.settings.environment == 'development') ? {error:[err.message], stack: err.stack} : {error:[err.message]}
    if (global.settings.environment !== 'test'){
        // TODO: email this Exception report
        console.log("EXCEPTION REPORT")
        console.log(err.message);
        console.log(err.stack);
    }

    // allow cross site post
    setCrossDomain(res);

    // if the exception defines a http status code, use that, else a 500
    if (!_.isUndefined(err.http_status)){
        res.send(msg, err.http_status);
    } else {
        res.send(msg, 400);
    }
}

module.exports = app;
<commit_msg>update tests with md5 fix<commit_after>// CartoDB SQL API
//
// all requests expect the following URL args:
// - `sql` {String} SQL to execute
//
// for private (read/write) queries:
// - OAuth. Must have proper OAuth 1.1 headers. For OAuth 1.1 spec see Google
//
// eg. /api/v1/?sql=SELECT 1 as one (with a load of OAuth headers or URL arguments)
//
// for public (read only) queries:
// - sql only, provided the subdomain exists in CartoDB and the table's sharing options are public
//
// eg. vizzuality.cartodb.com/api/v1/?sql=SELECT * from my_table
var express = require('express')
    , app      = express.createServer(
    express.logger({
        buffer: true,
        format: '[:date] :req[X-Real-IP] \033[90m:method\033[0m \033[36m:req[Host]:url\033[0m \033[90m:status :response-time ms -> :res[Content-Type]\033[0m'
    }))
    , Step        = require('step')
    , csv         = require('csv')
    , crypto      = require('crypto')
    , Meta        = require(global.settings.app_root + '/app/models/metadata')
    , oAuth       = require(global.settings.app_root + '/app/models/oauth')
    , PSQL        = require(global.settings.app_root + '/app/models/psql')
    , ApiKeyAuth  = require(global.settings.app_root + '/app/models/apikey_auth')
    , _           = require('underscore')
    , tableCache  = {};

app.use(express.bodyParser());
app.enable('jsonp callback');

// basic routing
app.all('/api/v1/sql',     function(req, res) { handleQuery(req, res) } );
app.all('/api/v1/sql.:f',  function(req, res) { handleQuery(req, res) } );
app.get('/api/v1/cachestatus',  function(req, res) { handleCacheStatus(req, res) } );

// request handlers
function handleQuery(req, res){

    // sanitize input
    var body      = (req.body) ? req.body : {};
    var sql       = req.query.q || body.q; // get and post
    var api_key   = req.query.api_key || body.api_key;
    var database  = req.query.database; // deprecate this in future
    var limit     = parseInt(req.query.rows_per_page);
    var offset    = parseInt(req.query.page);
    var format    = (req.query.format) ? req.query.format : null;
    var dp        = (req.query.dp) ? req.query.dp: '15';

    // validate input slightly
    dp        = (dp === "")        ? '15' : dp;
    format    = (format === "")   ? null : format;
    sql       = (sql === "")      ? null : sql;
    database  = (database === "") ? null : database;
    limit     = (_.isNumber(limit))  ? limit : null;
    offset    = (_.isNumber(offset)) ? offset * limit : null

    // setup step run
    var start = new Date().getTime();

    try {
        if (!_.isString(sql)) throw new Error("You must indicate a sql query");

        // initialise MD5 key of sql for cache lookups
        var sql_md5 = generateMD5(sql);

        // placeholder for connection
        var pg;

        // 1. Get database from redis via the username stored in the host header subdomain
        // 2. Run the request through OAuth to get R/W user id if signed
        // 3. Get the list of tables affected by the query
        // 4. Run query with r/w or public user
        // 5. package results and send back
        Step(
            function getDatabaseName(){
                Meta.getDatabase(req, this);
            },
            function setDBGetUser(err, data) {
                if (err) throw err;
                database = (data == "" || _.isNull(data)) ? database : data;

                if(api_key) {
                    ApiKeyAuth.verifyRequest(req, this);
                } else {
                    oAuth.verifyRequest(req, this);
                }
            },
            function queryExplain(err, user_id){
                if (err) throw err;
                // store postgres connection
                pg = new PSQL(user_id, database, limit, offset);

                // get all the tables from Cache or SQL
                if (!_.isNull(tableCache[sql_md5]) && !_.isUndefined(tableCache[sql_md5])){
                   tableCache[sql_md5].hits++;
                   return true;
                } else{
                    pg.query("SELECT CDB_QueryTables($quotesql$" + sql + "$quotesql$)", this);
                }
            },
            function queryResult(err, result){
                if (err) throw err;

                // store explain result in local Cache
                if (_.isUndefined(tableCache[sql_md5])){
                    tableCache[sql_md5] = result;
                    tableCache[sql_md5].hits = 1; //initialise hit counter
                }

                // TODO: refactor formats to external object
                if (format === 'geojson'){
                    sql = ['SELECT *, ST_AsGeoJSON(the_geom,',dp,') as the_geom FROM (', sql, ') as foo'].join("");
                }

                pg.query(sql, this);
            },
            function setHeaders(err, result){
                if (err) throw err;

                // configure headers for geojson/CSV
                res.header("Content-Disposition", getContentDisposition(format));
                res.header("Content-Type", getContentType(format));

                // allow cross site post
                setCrossDomain(res);

                // set cache headers
                res.header('Last-Modified', new Date().toUTCString());
                res.header('Cache-Control', 'no-cache,max-age=3600,must-revalidate, public');
                res.header('X-Cache-Channel', generateCacheKey(database, tableCache[sql_md5]));

                return result;
            },
            function packageResults(err, result){
                if (err) throw err;

                // TODO: refactor formats to external object
                if (format === 'geojson'){
                    toGeoJSON(result, res, this);
                } else if (format === 'csv'){
                    toCSV(result, res, this);
                } else {
                    var end = new Date().getTime();
                    return {
                        'time' : ((end - start)/1000),
                        'total_rows': result.rows.length,
                        'rows'      : result.rows
                    };
                }
            },
            function sendResults(err, out){
                if (err) throw err;

                // return to browser
                res.send(out);
            },
            function errorHandle(err, result){
                handleException(err, res);
            }
        );
    } catch (err) {
        console.log('[ERROR]\n' + err);
        handleException(err, res);
    }
}

function handleCacheStatus(req, res){
    var tableCacheValues = _.values(tableCache);
    var totalExplainHits = _.reduce(tableCacheValues, function(memo, res) { return memo + res.hits}, 0);
    var totalExplainKeys = tableCacheValues.length;

    res.send({explain: {hits: totalExplainHits, keys : totalExplainKeys }});
}

// helper functions
function toGeoJSON(data, res, callback){
    try{
        var out = {
            type: "FeatureCollection",
            features: []
        };

        _.each(data.rows, function(ele){
            var geojson = {
                type: "Feature",
                properties: { },
                geometry: { }
            };
            geojson.geometry = JSON.parse(ele["the_geom"]);
            delete ele["the_geom"];
            delete ele["the_geom_webmercator"];
            geojson.properties = ele;
            out.features.push(geojson);
        });

        // return payload
        callback(null, out);
    } catch (err) {
        callback(err,null);
    }
}

function toCSV(data, res, callback){
    try{
        // pull out keys for column headers
        var columns = _.keys(data.rows[0]);

        // stream the csv out over http
        csv()
          .from(data.rows)
          .toStream(res, {end: true, columns: columns, header: true});
        return true;
    } catch (err) {
        callback(err,null);
    }
}

function getContentDisposition(format){
    var ext = 'json';
    if (format === 'geojson'){
        ext = 'geojson';
    }
    if (format === 'csv'){
        ext = 'csv';
    }
    var time = new Date().toUTCString();
    return 'inline; filename=cartodb-query.' + ext + '; modification-date="' + time + '";';
}

function getContentType(format){
    var type = "application/json; charset=utf-8";
    if (format === 'csv'){
        type = "text/csv; charset=utf-8";
    }
    return type;
}

function setCrossDomain(res){
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
}

function generateCacheKey(database,tables){
    return database + ":" + tables.rows[0].cdb_querytables.split(/^\{(.*)\}$/)[1];
}

function generateMD5(data){
    var hash = crypto.createHash('md5');
    hash.update(data);
    return hash.digest('hex');
}

function handleException(err, res){
    var msg = (global.settings.environment == 'development') ? {error:[err.message], stack: err.stack} : {error:[err.message]}
    if (global.settings.environment !== 'test'){
        // TODO: email this Exception report
        console.log("EXCEPTION REPORT")
        console.log(err.message);
        console.log(err.stack);
    }

    // allow cross site post
    setCrossDomain(res);

    // if the exception defines a http status code, use that, else a 500
    if (!_.isUndefined(err.http_status)){
        res.send(msg, err.http_status);
    } else {
        res.send(msg, 400);
    }
}

module.exports = app;
<|endoftext|>


<commit_before>(function()
{
    if (!window.requestAnimationFrame)
    {
        window.requestAnimationFrame = window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        window.oRequestAnimationFrame      ||
        window.msRequestAnimationFrame     ||

        function(callback, element)
        {
            window.setTimeout(callback, 1000 / FRAME_RATE);
        }
    }
})();

function check(object) {
   if(!object || object === null) {
      console.error(object.constructor.name + " is NULL.");
      return false;
   } else {
      //console.group("Properties of " + object.constructor.name + ": ");
      console.log(object.constructor.name + " has been created.")
      return true;
   }
}
<commit_msg>Added collision checker and a quick box tester<commit_after>(function()
{
    if (!window.requestAnimationFrame)
    {
        window.requestAnimationFrame = window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        window.oRequestAnimationFrame      ||
        window.msRequestAnimationFrame     ||

        function(callback, element)
        {
            window.setTimeout(callback, 1000 / FRAME_RATE);
        }
    }
})();

function check(object) {
   if(!object || object === null) {
      console.error(object.constructor.name + " is NULL.");
      return false;
   } else {
      //console.group("Properties of " + object.constructor.name + ": ");
      console.log(object.constructor.name + " has been created.")
      return true;
   }
}

var collisionChecker= {
    quickBoxTest: function(boxA, boxB) {

    }
}
<|endoftext|>


<commit_before>define((require, exports, module) => {
  let TRHMasterData = require('app/core/master')
  return () => {
    return {
      consumable_id: null,
      num: null,
      get name () {
        return _.get(TRHMasterData.getMasterData('Consumable'), [this.consumable_id, 'name'], '暂未获取')
      },
      get description () {
        return _.get(TRHMasterData.getMasterData('Consumable'), [this.consumable_id, 'description'], '暂未获取')
      },
      get limitNum () {
        return _.get(TRHMasterData.getMasterData('Consumable'), [this.consumable_id, 'limitNum'], '暂未获取')
      }
    }
  }
})<commit_msg>delete item description<commit_after>define((require, exports, module) => {
  let TRHMasterData = require('app/core/master')
  return () => {
    return {
      consumable_id: null,
      num: null,
      get name () {
        return _.get(TRHMasterData.getMasterData('Consumable'), [this.consumable_id, 'name'], '暂未获取')
      },
      get limitNum () {
        return _.get(TRHMasterData.getMasterData('Consumable'), [this.consumable_id, 'limitNum'], '暂未获取')
      }
    }
  }
})<|endoftext|>