<commit_before>function onInstall(e) {
  onOpen(e);
  // Perform additional setup as needed.
}

function onOpen(e) {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Fact Widget')
      .addItem('Create Widget', 'createWidget')
      .addSeparator()
      .addToUi();
}

function createWidget() {
  // Retreive the spreadsheet currently open
  // Everything will break unless "Sheet1" is open, which contains the facts
  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  // Go to the second sheet, which contains the various organizations' info
  var orgSheet = sheet.getSheetByName('org_info')

  //This gets all the cells of the fact selected
  var row = sheet.getActiveCell().getRow();
  // This, for now, defaults to the top organization in "org_info"
  var org_values = orgSheet.getSheetValues(2, 1, 1, 3);
  // Get the values for the selected fact
  var values = sheet.getSheetValues(row, 1, 1, 14);

  // Create the widget from the "widget_template.html" file
  var t = HtmlService.createTemplateFromFile('widget_template');
  // No idea what this is
  t.stype = 'application/ld+json';

  // TODO: put these in order, so we can easily add fields without
  // screwing up the column numbers.

  // "org_info" page, "OrgURL" column
  t.org_url = org_values[0][2];
  // "org_info" page, "LogoImage" column
  t.logo_image = org_values[0][1];
  // "org_info" page, "MaxRating" column
  t.max_rating = org_values[0][0];
  // "Sheet1" page, "SpeakerImage" column
  t.speaker_image = values[0][5];
  // "Sheet1" page, "Statement" column
  t.title = values[0][1];
  // "Sheet1" page, "Speaker" column
  t.speaker = values[0][3];
  // "Sheet1" page, "InfoSource" column
  t.speaker_context = values[0][6];
  // "Sheet1" page, "Link" column
  t.link = values[0][11];
  // "Sheet1" page, "PubDate" column
  t.date = values[0][12];
  // "Sheet1" page, "Statement" column (again?)
  t.fact = values[0][1];
  // "Sheet1" page, "Date" column
  // Convert date to format 'Friday, September 21, 2015
  var date = new Date(values[0][2]);
  var ordinal_day = getOrdinal(date.getDay);
  t.fact_date = Utilities.formatDate(date, 'EST', "EEEEEEE, MMMMMM '"+ordinal_day+"', yyyy");
  // "Sheet1" page, "SpeakerTitle" column
  t.speaker_title = values[0][13];
  // "Sheet1" page, "SourceName" colum
  t.source_name = values[0][12]
  // "Sheet1" page, "RatingText" column...twice
  rating_text = values[0][9]
  t.rating_text = values[0][9];
  // "Sheet1" page, "RatingDescription" column
  rating_description = values[0][8];
  // "Sheet1" page, "RatingImage" column
  rating_image = values[0][10];
  // "Sheet1" page, "Rating" column
  rating_number = values[0][7];

  // Check to make sure the rating is not higher than the most allowed
  // by the organization
  if (rating_number != null && rating_number > 0) {
    t.rating_num = rating_number;
  }
  else {
    // This should probably fail spectacularly instead of random number
    t.rating_num = -1;
  }

  // Organization image plus, if available, rating image.
  // Goes in the top right-hand corner.
  // TODO: use rating_description when no rating_image specified?
  t.rating_summary = "help"
  if (rating_image != "") {
     t.rating_summary = '';
  } else if (rating_text != "") {
      t.rating_summary = 'Rating: ' + rating_text + ''
  }
  else {
      t.rating_summary = 'Rating: ' + rating_description + '';
  }

  // Get the shareable image for the sharing links
  //t.shareable_image = getShareableImage(t.speaker, t.title, t.speaker_image, rating_image).image_url;

  // Get the final HTML
  output = t.evaluate().getContent();

  // Make the box to show the code for embedding
  var html = HtmlService.createTemplateFromFile('menu_template');
  html.div_html = output;
  var html_out = html.evaluate()
      .setSandboxMode(HtmlService.SandboxMode.IFRAME)
      .setWidth(400)
      .setHeight(300);

  // Show the view on the screen
  SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
      .showModalDialog(html_out, 'Widget Embed Code');
}

function testGetShareableImage(){
  getShareableImage("Martin O'Malley", "this is a \"fake\" test", "http://static.politifact.com.s3.amazonaws.com/politifact%2Fmugs%2Ftrump_1.jpg", "http://static.politifact.com.s3.amazonaws.com/rulings%2Ftom-pantsonfire.gif");
}

function getShareableImage(speaker, statement, speakerImage, ratingImage){
  var encodedSpeaker = encodeURIComponent(speaker);
  var encodedStatement = encodeURIComponent(statement);
  var encodedSpeakerImage = encodeURIComponent(speakerImage);
  var encodedRatingImage = encodeURIComponent(ratingImage);

  var payload = {
      "@context": "http://schema.org",
      "@type": ["Review", "ClaimReview"],
      "datePublished": "2014-07-23",
      "url": "http://www.politifact.com/texas/statements/2014/jul/23/rick-perry/rick-perry-claim-about-3000-homicides-illegal-immi/",
      "author": {
        "@type": "Organization",
        "url": "http://www.politifact.com/"
      },
      "claimReviewed": "More than 3,000 homicides were committed by \"illegal aliens\" over the past six years.",
      "claimReviewSiteLogo": "http://static.politifact.com/mediapage/jpgs/politifact-logo-big.jpg",
      "reviewRating": {
        "@type": "Rating",
        "ratingValue": 1,
        "bestRating": 6,
        "image": "http://static.politifact.com.s3.amazonaws.com/rulings/tom-pantsonfire.gif"
      },
      "itemReviewed": {
        "@type": "CreativeWork",
        "author": {
          "@type": "Person",
          "name": "Rich Perry",
          "title": "Former Governor of Texas",
          "image": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Gov._Perry_CPAC_February_2015.jpg/440px-Gov._Perry_CPAC_February_2015.jpg",
          "sameAs": [
            "https://en.wikipedia.org/wiki/Rick_Perry",
            "https://rickperry.org/"
          ]
        },
        "datePublished": "2014-07-17",
        "sourceName": "The St. Petersburg Times"
      }
    }

  var url = "https://fact-reporter.herokuapp.com/generate";
  var options = {
    "method": "post",
    "payload": JSON.stringify(payload)
  }

  var response = UrlFetchApp.fetch(url, options);
  var responseText = response.getContentText();
  Logger.log(responseText);

  return JSON.parse(response.getContentText());
}

// found here http://forums.shopify.com/categories/2/posts/29259

var getOrdinal = function(n) {
   var s=["th","st","nd","rd"],
       v=n%100;
   return n+(s[(v-20)%10]||s[v]||s[0]);
}<commit_msg>fixed column numbers<commit_after>function onInstall(e) {
  onOpen(e);
  // Perform additional setup as needed.
}

function onOpen(e) {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Fact Widget')
      .addItem('Create Widget', 'createWidget')
      .addSeparator()
      .addToUi();
}

function createWidget() {
  // Retreive the spreadsheet currently open
  // Everything will break unless "Sheet1" is open, which contains the facts
  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  // Go to the second sheet, which contains the various organizations' info
  var orgSheet = sheet.getSheetByName('org_info')

  //This gets all the cells of the fact selected
  var row = sheet.getActiveCell().getRow();
  // This, for now, defaults to the top organization in "org_info"
  var org_values = orgSheet.getSheetValues(2, 1, 1, 3);
  // Get the values for the selected fact
  var values = sheet.getSheetValues(row, 1, 1, 14);

  // Create the widget from the "widget_template.html" file
  var t = HtmlService.createTemplateFromFile('widget_template');
  // No idea what this is
  t.stype = 'application/ld+json';

  // TODO: put these in order, so we can easily add fields without
  // screwing up the column numbers.

  // "org_info" page, "OrgURL" column
  t.org_url = org_values[0][2];
  // "org_info" page, "LogoImage" column
  t.logo_image = org_values[0][1];
  // "org_info" page, "MaxRating" column
  t.max_rating = org_values[0][0];
  // "Sheet1" page, "SpeakerImage" column
  t.speaker_image = values[0][5];
  // "Sheet1" page, "Statement" column
  t.title = values[0][1];
  // "Sheet1" page, "Speaker" column
  t.speaker = values[0][3];
  // "Sheet1" page, "InfoSource" column
  t.speaker_context = values[0][6];
  // "Sheet1" page, "Link" column
  t.link = values[0][11];
  // "Sheet1" page, "PubDate" column
  t.date = values[0][12];
  // "Sheet1" page, "Statement" column (again?)
  t.fact = values[0][1];
  // "Sheet1" page, "Date" column
  // Convert date to format 'Friday, September 21, 2015
  var date = new Date(values[0][2]);
  var ordinal_day = getOrdinal(date.getDay());

  t.fact_date = Utilities.formatDate(date, 'EST', "EEEEEEE, MMMMMM '"+ordinal_day+"', yyyy");
  // "Sheet1" page, "SpeakerTitle" column
  t.speaker_title = values[0][12];
  // "Sheet1" page, "SourceName" colum
  t.source_name = values[0][13]
  // "Sheet1" page, "RatingText" column...twice
  rating_text = values[0][9]
  t.rating_text = values[0][9];
  // "Sheet1" page, "RatingDescription" column
  rating_description = values[0][8];
  // "Sheet1" page, "RatingImage" column
  rating_image = values[0][10];
  // "Sheet1" page, "Rating" column
  rating_number = values[0][7];

  // Check to make sure the rating is not higher than the most allowed
  // by the organization
  if (rating_number != null && rating_number > 0) {
    t.rating_num = rating_number;
  }
  else {
    // This should probably fail spectacularly instead of random number
    t.rating_num = -1;
  }

  // Organization image plus, if available, rating image.
  // Goes in the top right-hand corner.
  // TODO: use rating_description when no rating_image specified?
  t.rating_summary = "help"
  if (rating_image != "") {
     t.rating_summary = '';
  } else if (rating_text != "") {
      t.rating_summary = 'Rating: ' + rating_text + ''
  }
  else {
      t.rating_summary = 'Rating: ' + rating_description + '';
  }

  // Get the shareable image for the sharing links
  //t.shareable_image = getShareableImage(t.speaker, t.title, t.speaker_image, rating_image).image_url;

  // Get the final HTML
  output = t.evaluate().getContent();

  // Make the box to show the code for embedding
  var html = HtmlService.createTemplateFromFile('menu_template');
  html.div_html = output;
  var html_out = html.evaluate()
      .setSandboxMode(HtmlService.SandboxMode.IFRAME)
      .setWidth(400)
      .setHeight(300);

  // Show the view on the screen
  SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
      .showModalDialog(html_out, 'Widget Embed Code');
}

function testGetShareableImage(){
  getShareableImage("Martin O'Malley", "this is a \"fake\" test", "http://static.politifact.com.s3.amazonaws.com/politifact%2Fmugs%2Ftrump_1.jpg", "http://static.politifact.com.s3.amazonaws.com/rulings%2Ftom-pantsonfire.gif");
}

function getShareableImage(speaker, statement, speakerImage, ratingImage){
  var encodedSpeaker = encodeURIComponent(speaker);
  var encodedStatement = encodeURIComponent(statement);
  var encodedSpeakerImage = encodeURIComponent(speakerImage);
  var encodedRatingImage = encodeURIComponent(ratingImage);

  var payload = {
      "@context": "http://schema.org",
      "@type": ["Review", "ClaimReview"],
      "datePublished": "2014-07-23",
      "url": "http://www.politifact.com/texas/statements/2014/jul/23/rick-perry/rick-perry-claim-about-3000-homicides-illegal-immi/",
      "author": {
        "@type": "Organization",
        "url": "http://www.politifact.com/"
      },
      "claimReviewed": "More than 3,000 homicides were committed by \"illegal aliens\" over the past six years.",
      "claimReviewSiteLogo": "http://static.politifact.com/mediapage/jpgs/politifact-logo-big.jpg",
      "reviewRating": {
        "@type": "Rating",
        "ratingValue": 1,
        "bestRating": 6,
        "image": "http://static.politifact.com.s3.amazonaws.com/rulings/tom-pantsonfire.gif"
      },
      "itemReviewed": {
        "@type": "CreativeWork",
        "author": {
          "@type": "Person",
          "name": "Rich Perry",
          "title": "Former Governor of Texas",
          "image": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Gov._Perry_CPAC_February_2015.jpg/440px-Gov._Perry_CPAC_February_2015.jpg",
          "sameAs": [
            "https://en.wikipedia.org/wiki/Rick_Perry",
            "https://rickperry.org/"
          ]
        },
        "datePublished": "2014-07-17",
        "sourceName": "The St. Petersburg Times"
      }
    }

  var url = "https://fact-reporter.herokuapp.com/generate";
  var options = {
    "method": "post",
    "payload": JSON.stringify(payload)
  }

  var response = UrlFetchApp.fetch(url, options);
  var responseText = response.getContentText();
  Logger.log(responseText);

  return JSON.parse(response.getContentText());
}

// found here http://forums.shopify.com/categories/2/posts/29259

var getOrdinal = function(n) {
   var s=["th","st","nd","rd"],
       v=n%100;
   return n+(s[(v-20)%10]||s[v]||s[0]);
}<|endoftext|>


<commit_before>var d3 = require('d3');

AFRAME.registerShader('geojson-texture', {
    schema: {
        projection: {
            default: "#projection",
            type: "selector"
        },
        color: {
            default: "#fff",
            type: "color"
        },
        width: {
            default: 2048
        },
        height: {
            default: 1024
        }
    },

    init: function(data) {
        this.material = new THREE.MeshBasicMaterial({
                side: THREE.DoubleSide,
                transparent: true,
                opacity: 0,
                depthWrite: false
            })

        data.projection.addEventListener("geojson-projection-generated", e => {

            var texture = this.generate(e.detail.features, data)

            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            texture.offset.x = 0.5

            this.material.map = texture
            this.material.opacity = 1
            this.material.transparent = true

            this.material.needsUpdate = true

            this.texture = texture
            this.update(data)
            //this.el.emit('material-texture-loaded', {texture: this.texture});
        })
    },
    update: function (data) {

        //AFRAME.utils.material.updateMap(this, data);
        this.material.needsUpdate = true
    },
    generate: function(countries, data) {

        var width = data.width
        var height = data.height

        const INITIAL_ROTATE = [0, 0]

        const id = "_geojson-canvas"

        const projection = d3.geoEquirectangular()
            .scale(height / Math.PI)
            .translate([width / 2, height / 2])
            .rotate(INITIAL_ROTATE)
        const mapPath = d3.geoPath(projection)

        var canvas = d3
            .select("body")
            .append("canvas")
            .attr("id", id)
            .attr("width", `${width}px`)
            .attr("height", `${height}px`)
        var context = d3.select(`#${id}`).node().getContext("2d"),
            contextPath = mapPath.context(context);

        countries.forEach((c, i) => {
            context.save();
            context.beginPath()
            context.fillStyle = `rgba(255,0,${i},0.1)`
            contextPath(c);
            context.stroke()
            context.fill();
            context.restore();
        })

        const texture = new THREE.CanvasTexture(canvas.node());

        //canvas.remove();
        // probably not remove it
        // https://bl.ocks.org/dongli/e9291c411cd7ed409e71bcd14d681952

        return texture;
    }
});<commit_msg>remove unused geojso-texture<commit_after><|endoftext|>


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

import { all, call, put, select, take, takeEvery } from 'redux-saga/effects';
import { URLS } from 'common/urls';
import { activeProjectSelector } from 'controllers/user';
import {
  fetchParentItems,
  fetchParentLaunch,
  launchSelector,
  namespaceSelector,
  queryParametersSelector,
} from 'controllers/testItem';
import { createFetchPredicate, fetchDataAction } from 'controllers/fetch';
import {
  launchIdSelector,
  pagePropertiesSelector,
  pathnameChangedSelector,
} from 'controllers/pages';
import { PAGE_KEY, SIZE_KEY } from 'controllers/pagination';
import { SORTING_KEY } from 'controllers/sorting';
import { unselectAllItemsAction } from 'controllers/groupOperations';
import { FETCH_GLOBAL_INTEGRATIONS_SUCCESS } from 'controllers/plugins/constants';
import { globalIntegrationsSelector } from 'controllers/plugins';
import { COMMAND_GET_CLUSTERS } from 'controllers/plugins/uiExtensions/constants';
import {
  CLEAR_CLUSTER_ITEMS,
  clusterItemsSagas,
  selectedClusterItemsSelector,
} from './clusterItems';
import { FETCH_CLUSTERS, NAMESPACE, RELOAD_CLUSTERS } from './constants';
import { setPageLoadingAction } from './actionCreators';

function* fetchClusters(payload = {}) {
  const { refresh = false } = payload;
  const launchId = yield select(launchIdSelector);
  const parentLaunch = yield select(launchSelector);
  const project = yield select(activeProjectSelector);
  const isPathNameChanged = yield select(pathnameChangedSelector);
  const selectedItems = yield select(selectedClusterItemsSelector);
  let integrations = yield select(globalIntegrationsSelector);
  if (!integrations.length) {
    const response = yield take(FETCH_GLOBAL_INTEGRATIONS_SUCCESS);
    integrations = response.payload;
  }
  if (selectedItems.length) {
    yield put(unselectAllItemsAction(NAMESPACE)());
  }
  if (isPathNameChanged && !refresh) {
    yield put(setPageLoadingAction(true));
  }
  if (!parentLaunch) {
    yield call(fetchParentItems);
  } else {
    yield call(fetchParentLaunch, { payload: { project, launchId } });
  }

  const namespace = yield select(namespaceSelector);
  const query = yield select(queryParametersSelector, namespace);
  const supportedIntegration = integrations.find(
    (integration) =>
      integration &&
      integration.integrationType &&
      integration.integrationType.details &&
      integration.integrationType.details.metadata &&
      integration.integrationType.details.metadata.supportedFeatures &&
      integration.integrationType.details.metadata.supportedFeatures.includes(
        'uniqueErrorsClusters',
      ),
  );

  let url;
  const requestParams = {};
  if (supportedIntegration) {
    url = URLS.projectIntegrationByIdCommand(
      project,
      supportedIntegration.id,
      COMMAND_GET_CLUSTERS,
    );
    requestParams.method = 'PUT';
    const uniqueErrorsParams = yield select(pagePropertiesSelector, NAMESPACE);
    requestParams.data = {
      launchId,
      ...uniqueErrorsParams,
      pageNumber: query[PAGE_KEY],
      pageSize: query[SIZE_KEY],
    };
  } else {
    url = URLS.clusterByLaunchId(project, launchId, {
      [PAGE_KEY]: query[PAGE_KEY],
      [SIZE_KEY]: query[SIZE_KEY],
      [SORTING_KEY]: query[SORTING_KEY],
    });
  }
  yield put(fetchDataAction(NAMESPACE)(url, requestParams));

  if (isPathNameChanged && !refresh) {
    const waitEffects = [take(createFetchPredicate(NAMESPACE))];
    yield all(waitEffects);
    yield put(setPageLoadingAction(false));
  }
}

function* reloadClusters() {
  yield put({ type: CLEAR_CLUSTER_ITEMS });
  yield call(fetchClusters, { refresh: true });
}

function* watchFetchClusters() {
  yield takeEvery(FETCH_CLUSTERS, fetchClusters);
}

function* watchReloadClusters() {
  yield takeEvery(RELOAD_CLUSTERS, reloadClusters);
}

export function* uniqueErrorsSagas() {
  yield all([watchFetchClusters(), clusterItemsSagas(), watchReloadClusters()]);
}
<commit_msg>EPMRPP-74073 || fix unique errors page data obtaining (#2983)<commit_after>/*
 * Copyright 2021 EPAM Systems
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { all, call, put, select, take, takeEvery } from 'redux-saga/effects';
import { URLS } from 'common/urls';
import { activeProjectSelector } from 'controllers/user';
import {
  fetchParentItems,
  fetchParentLaunch,
  launchSelector,
  namespaceSelector,
  queryParametersSelector,
} from 'controllers/testItem';
import { createFetchPredicate, fetchDataAction } from 'controllers/fetch';
import {
  launchIdSelector,
  pagePropertiesSelector,
  pathnameChangedSelector,
} from 'controllers/pages';
import { PAGE_KEY, SIZE_KEY } from 'controllers/pagination';
import { SORTING_KEY } from 'controllers/sorting';
import { unselectAllItemsAction } from 'controllers/groupOperations';
import {
  FETCH_GLOBAL_INTEGRATIONS_SUCCESS,
  NAMESPACE as PLUGINS_NAMESPACE,
} from 'controllers/plugins/constants';
import { globalIntegrationsSelector, pluginsSelector } from 'controllers/plugins';

import { COMMAND_GET_CLUSTERS } from 'controllers/plugins/uiExtensions/constants';
import {
  CLEAR_CLUSTER_ITEMS,
  clusterItemsSagas,
  selectedClusterItemsSelector,
} from './clusterItems';
import { FETCH_CLUSTERS, NAMESPACE, RELOAD_CLUSTERS } from './constants';
import { setPageLoadingAction } from './actionCreators';

function* getIntegration() {
  // TODO: In the future plugins with js parts should not depend on integrations, only on plugins.
  // TODO: This should be removed when common getFile plugin command will be presented in all plugins with js files.
  let integrations = yield select(globalIntegrationsSelector);
  if (!integrations.length) {
    const response = yield take(FETCH_GLOBAL_INTEGRATIONS_SUCCESS);
    integrations = response.payload;
  }
  const supportedIntegration = integrations.find(
    (item) =>
      item &&
      item.integrationType &&
      item.integrationType.details &&
      item.integrationType.details.metadata &&
      item.integrationType.details.metadata.supportedFeatures &&
      item.integrationType.details.metadata.supportedFeatures.includes('uniqueErrorsClusters'),
  );

  let plugins = yield select(pluginsSelector);
  if (!plugins.length) {
    const response = yield take(createFetchPredicate(PLUGINS_NAMESPACE));
    plugins = response.payload;
  }
  const plugin = plugins.find((item) => item.name === supportedIntegration.name);

  return plugin.enabled && supportedIntegration;
}

function* fetchClusters(payload = {}) {
  const { refresh = false } = payload;
  const launchId = yield select(launchIdSelector);
  const parentLaunch = yield select(launchSelector);
  const project = yield select(activeProjectSelector);
  const isPathNameChanged = yield select(pathnameChangedSelector);
  const selectedItems = yield select(selectedClusterItemsSelector);

  if (selectedItems.length) {
    yield put(unselectAllItemsAction(NAMESPACE)());
  }
  if (isPathNameChanged && !refresh) {
    yield put(setPageLoadingAction(true));
  }
  if (!parentLaunch) {
    yield call(fetchParentItems);
  } else {
    yield call(fetchParentLaunch, { payload: { project, launchId } });
  }

  const namespace = yield select(namespaceSelector);
  const query = yield select(queryParametersSelector, namespace);

  let url;
  const requestParams = {};
  const integration = yield getIntegration();
  if (integration) {
    url = URLS.projectIntegrationByIdCommand(project, integration.id, COMMAND_GET_CLUSTERS);
    requestParams.method = 'PUT';
    const uniqueErrorsParams = yield select(pagePropertiesSelector, NAMESPACE);
    requestParams.data = {
      launchId,
      ...uniqueErrorsParams,
      pageNumber: query[PAGE_KEY],
      pageSize: query[SIZE_KEY],
    };
  } else {
    url = URLS.clusterByLaunchId(project, launchId, {
      [PAGE_KEY]: query[PAGE_KEY],
      [SIZE_KEY]: query[SIZE_KEY],
      [SORTING_KEY]: query[SORTING_KEY],
    });
  }
  yield put(fetchDataAction(NAMESPACE)(url, requestParams));

  if (isPathNameChanged && !refresh) {
    const waitEffects = [take(createFetchPredicate(NAMESPACE))];
    yield all(waitEffects);
    yield put(setPageLoadingAction(false));
  }
}

function* reloadClusters() {
  yield put({ type: CLEAR_CLUSTER_ITEMS });
  yield call(fetchClusters, { refresh: true });
}

function* watchFetchClusters() {
  yield takeEvery(FETCH_CLUSTERS, fetchClusters);
}

function* watchReloadClusters() {
  yield takeEvery(RELOAD_CLUSTERS, reloadClusters);
}

export function* uniqueErrorsSagas() {
  yield all([watchFetchClusters(), clusterItemsSagas(), watchReloadClusters()]);
}
<|endoftext|>


<commit_before>/*
 * changes to previous injection implementations
 * - no support for data-injection anymore, switch to new data-inject
 * - no support for data-href-next anymore, switch to data-inject: next-href
 * - XXX: add support for forms, see remnants in inject1 and ajaxify
 */
define([
    "jquery",
    "../core/parser",
    "../core/logger",
    "../lib/ajax",
    "../registry",
    "URIjs/URI",
    "jquery_ext", // for :scrollable for autoLoading-visible
    "URIjs/jquery.URI"
], function($, Parser, logger, ajax, registry, URI) {
    var log = logger.getLogger('pat.inject'),
        parser = new Parser("inject");

    //parser.add_argument('selector', 'body');
    parser.add_argument('selector');
    //XXX: (yet) unsupported: parser.add_argument('target', '$selector');
    parser.add_argument('target');
    parser.add_argument('type');
    parser.add_argument('next-href');
    //XXX: (yet) unsupported: parser.add_argument('source', '$selector');
    parser.add_argument('source');
    // XXX: this should not be here but the parser would bail on
    // unknown parameters and expand/collapsible need to pass the url
    // to us
    parser.add_argument('url');
    parser.add_argument('class');

    var _ = {
        name: "inject",
        trigger: "a.pat-inject, form.pat-inject",
        init: function($el, opts) {
            if ($el.length > 1)
                return $el.each(function() { _.init($(this), opts); });

            var cfgs = _.extractConfig($el, opts);
            $el.data('patterns.inject', cfgs);

            // In case next-href is specified the anchor's href will
            // be set to it after the injection is triggered. In case
            // the next href already exists, we do not activate the
            // injection but instead just change the anchors href.
            //
            // XXX: This is used in only one project for linked
            // fullcalendars, it's sanity is wonky and we should
            // probably solve it differently. -- Maybe it's cool
            // after all.
            var $nexthref = $(cfgs[0].nextHref);
            if ($el.is('a') && $nexthref.length > 0) {
                log.debug('Skipping as next href already exists', $nexthref);
                // XXX: reconsider how the injection enters exhausted state
                return $el.attr({href: (window.location.href.split('#')[0] || '') +
                                 cfgs[0].nextHref});
            }

            // setup event handlers
            if ($el.is('a'))
                $el.on("click.pat-inject", _.onClick);
            else if ($el.is('form'))
                $el.on("submit.pat-inject", _.onSubmit);

            // XXX: hack to support the old autoLoading-visible class
            if ($el.hasClass("autoLoading-visible"))
                _._initAutoloadVisible($el);

            log.debug('initialised:', $el);

            return $el;
        },
        destroy: function($el) {
            $el.off('.pat-inject');
            $el.data('patterns.inject', null);
            return $el;
        },
        onClick: function(ev) {
            var cfgs = $(this).data('patterns.inject'),
                $el = $(this);
            if (ev)
                ev.preventDefault();
            $el.trigger('patterns-inject-triggered');
            _.execute(cfgs, $el);
        },
        onSubmit: function(ev) {
            var cfgs = $(this).data('patterns.inject'),
                $el = $(this);
            if (ev)
                ev.preventDefault();
            $el.trigger('patterns-inject-triggered');
            _.execute(cfgs, $el);
        },
        extractConfig: function($el, opts) {
            opts = $.extend({}, opts);

            var urlparts, cfgs, defaultSelector;
            // opts has priority, fallback to href/action
            opts.url = opts.url || $el.attr('href') || $el.attr('action') || "";

            // separate selector from url
            urlparts = opts.url.split('#');
            opts.url = urlparts[0];

            // if no selector, check for selector as part of original url
            defaultSelector = urlparts[1] && '#' + urlparts[1] || 'body';

            if (urlparts.length > 2) {
                log.warn('Ignoring additional source ids:', urlparts.slice(2));
            }

            cfgs = parser.parse($el, opts, true);
            cfgs.forEach(function(cfg) {
                cfg.selector = cfg.selector || defaultSelector;
            });
            return cfgs;
        },
        // verify and post-process config
        // XXX: this should return a command instead of messing around on the config
        verifyConfig: function(cfgs) {
            var url = cfgs[0].url;

            // verification for each cfg in the array needs to succeed
            return cfgs.every(function(cfg) {
                // in case of multi-injection, all injections need to use
                // the same url
                if (cfg.url !== url) {
                    log.error('Unsupported different urls for multi-inject');
                    return false;
                }

                // defaults
                cfg.source = cfg.source || cfg.selector;
                cfg.target = cfg.target || cfg.selector;

                if (!_._extractModifiers(cfg))
                    return false;

                // make sure target exist
                cfg.$target = cfg.$target || $(cfg.target);
                if (cfg.$target.length === 0) {
                    if (!cfg.target) {
                        log.error('Need target selector', cfg);
                        return false;
                    }
                    cfg.$target = _._createTarget(cfg.target);
                    cfg.$injected = cfg.$target;
                }
                return true;
            });
        },
        _extractModifiers: function(cfg) {
            var source_re = /^(.+?)(::element)?$/,
                target_re = /^(.+?)(::element)?(::after|::before)?$/,
                source_match = source_re.exec(cfg.source),
                target_match = target_re.exec(cfg.target),
                targetMod, targetPosition;

            // source content or element?
            cfg.source = source_match[1];
            // XXX: turn into source processor
            cfg.sourceMod = source_match[2] ? "element" : "content";

            // will be added while the ajax request is in progress
            cfg.targetLoadClasses = "injecting";

            // target content or element?
            targetMod = target_match[2] ? "element" : "content";
            cfg.target = target_match[1];
            cfg.targetLoadClasses += " injecting-" + targetMod;

            // position relative to target
            targetPosition = (target_match[3] || "::").slice(2);
            if (targetPosition)
                cfg.targetLoadClasses += " injecting-" + targetPosition;

            cfg.action = targetMod + targetPosition;

            // Once we start detecting illegal combinations, we'll
            // return false in case of error
            return true;
        },

        // create a target that matches the selector
        //
        // XXX: so far we only support #target and create a div with
        // that id appended to the body.
        _createTarget: function(selector) {
            var $target;
            if (selector.slice(0,1) !== '#') {
                log.error('only id supported for non-existing target');
                return null;
            }
            $target = $('
').attr({id: selector.slice(1)});
            $('body').append($target);
            return $target;
        },
        execute: function(cfgs, $el) {
            // get a kinda deep copy, we scribble on it
            cfgs = cfgs.map(function(cfg) {
                return $.extend({}, cfg);
            });

            // XXX: this need to get functional, returning a command
            // for internal use, instead of passing on cfgs
            if (!_.verifyConfig(cfgs))
                return;

            // possibility for spinners on targets
            cfgs.forEach(function(cfg) {
                cfg.$target.addClass(cfg.targetLoadClasses);
            });

            var onSuccess = function(ev) {
                var data = ev && ev.jqxhr && ev.jqxhr.responseText;
                if (!data) {
                    log.warn('No response content, aborting', ev);
                    return;
                }
                // list of $source objects, one for each cfg
                var sources = cfgs.map(function(cfg) { return cfg.source; }),
                    sources$ = _._sourcesFromHtml(data, cfgs[0].url, sources);

                cfgs.forEach(function(cfg, idx) {
                    var $source = sources$[idx];

                    if (cfg.sourceMod === "content")
                        $source = $source.contents();

                    // perform injection
                    cfg.$target.each(function() {
                        var $target = $(this),
                            $src = $source.clone(),
                            $injected = cfg.$injected || $src;
                        if (_._inject($src, $target, cfg.action, cfg["class"])) {
                            $injected.data('pat-injected', {origin: cfg.url});
                            $injected.addClass(cfg["class"])
                                .trigger('patterns-injected', cfg);
                        }
                    });
                });

                if (cfgs[0].nextHref) {
                    $el.attr({href: (window.location.href.split('#')[0] || '') +
                              cfgs[0].nextHref});
                    _.destroy($el);

                    // XXX: this used to be the case, but I don't see
                    // why that would be a good idea.
                    //
                    // jump to new href target
                    //if (!$el.hasClass("autoLoading-visible"))
                    //    window.location.href = $el.attr('href');
                }
                $el.off('pat-ajax-success.pat-inject');
            };

            $el.on('pat-ajax-success.pat-inject', onSuccess);

            ajax($el, {
                url: cfgs[0].url
            });
        },
        _inject: function($source, $target, action, classes) {
            // action to jquery method mapping, except for "content"
            // and "element"
            var method = {
                contentbefore: "prepend",
                contentafter:  "append",
                elementbefore: "before",
                elementafter:  "after"
            }[action];

            if ($source.length === 0) {
                log.warn('Aborting injection, source not found:', $source);
                return false;
            }
            if ($target.length === 0) {
                log.warn('Aborting injection, target not found:', $target);
                return false;
            }

            if (action === "content")
                $target.empty().append($source);
            else if (action === "element")
                $target.replaceWith($source);
            else
                $target[method]($source);

            return true;
        },
        _sourcesFromHtml: function(html, url, sources) {
            var $html = _._parseRawHtml(html, url);
            return sources.map(function(source) {
                if (source === "body")
                    source = "#__original_body";

                var $source = $html.find(source);

                if ($source.length === 0)
                    log.warn('No source elements for selector:', source, $html);

                return $source;
            });
        },

        _link_attributes: {
            A: "href",
            FORM: "action",
            IMG: "img"
        },

        _parseRawHtml: function(html, url) {
            url = url || "";

            // remove script tags and head and replace body by a div
            var clean_html = html
                    .replace(/


<commit_before>    /*

    entityManager.js

    A module which handles arbitrary entity-management for "Asteroids"

    We create this module as a single global object, and initialise it
    with suitable 'data' and 'methods'.

    "Private" properties are denoted by an underscore prefix convention.

    */

    "use strict";

    // Tell jslint not to complain about my use of underscore prefixes (nomen),
    // my flattening of some indentation (white), or my use of incr/decr ops
    // (plusplus).
    //
    /*jslint nomen: true, white: true, plusplus: true*/

    var entityManager = {

    // "PRIVATE" DATA

    _rocks   : [],
    _bullets : [],
    _ships   : [],

    _terrain : [],

    _bShowRocks : true,

    cameraOffset: [0,0],
    trueOffset: [100,100],
    mouseOffset: [0,0],
    cameraRotation: 0,
    cameraZoom: 1,
    lockCamera: false,

    // "PRIVATE" METHODS
    _generateRocks : function() {
        var i,
            NUM_ROCKS = 4;

        for (i = 0; i < NUM_ROCKS; ++i) {
            this.generateRock();
        }
    },

_generateTerrain : function() {

    var sL = g_settings.seaLevel;
    var minangl = Math.PI/30;
    var maxangl = Math.PI/2.2;
    var terr = new Terrain({
	"minX":-10000,
	"maxX": 10000,
	"minY": 300,
	"maxY": sL/2,
	"minLength": 32,
	"maxLength": 256,
	"minAngle": Math.PI/30,
	"maxAngle": Math.PI/2.2
	});
    this._terrain = terr;
},

getTerrain : function () {
    return this._terrain;
},

_findNearestShip : function(posX, posY) {
    var closestShip = null,
        closestIndex = -1,
        closestSq = 1000 * 1000;

    for (var i = 0; i < this._ships.length; ++i) {

        var thisShip = this._ships[i];
        var shipPos = thisShip.getPos();
        var distSq = util.wrappedDistSq(
            shipPos.posX, shipPos.posY,
            posX, posY,
            g_canvas.width, g_canvas.height);

        if (distSq < closestSq) {
            closestShip = thisShip;
            closestIndex = i;
            closestSq = distSq;
        }
    }
    return {
        theShip : closestShip,
        theIndex: closestIndex
    };
},

_forEachOf: function(aCategory, fn) {
    for (var i = 0; i < aCategory.length; ++i) {
        fn.call(aCategory[i]);
    }
},

// PUBLIC METHODS

// A special return value, used by other objects,
// to request the blessed release of death!
//
KILL_ME_NOW : -1,

// Some things must be deferred until after initial construction
// i.e. thing which need `this` to be defined.
//
deferredSetup : function () {
    this._categories = [this._rocks, this._bullets, this._ships,this._terrain];
},

init: function() {
    if (g_settings.enableRocks){
	console.log("generating rocks");
	this._generateRocks();
	}
    this._generateTerrain();
    //this._generateShip();
},

fireBullet: function(cx, cy, velX, velY, rotation) {
    this._bullets.push(new Bullet({
        cx   : cx,
        cy   : cy,
        velX : velX,
        velY : velY,

        rotation : rotation
    }));
},

generateRock : function(descr) {
    this._rocks.push(new Rock(descr));
},

generateShip : function(descr) {
    this._ships.push(new Ship(descr));
},

killNearestShip : function(xPos, yPos) {
    var theShip = this._findNearestShip(xPos, yPos).theShip;
    if (theShip) {
        theShip.kill();
    }
},

yoinkNearestShip : function(xPos, yPos) {
    var theShip = this._findNearestShip(xPos, yPos).theShip;
    if (theShip) {
        theShip.setPos(xPos, yPos);
    }
},

resetShips: function() {
    this._forEachOf(this._ships, Ship.prototype.reset);
},

haltShips: function() {
    this._forEachOf(this._ships, Ship.prototype.halt);
},

toggleRocks: function() {
    this._bShowRocks = !this._bShowRocks;
},

updateCamera: function () {

    if (eatKey(g_settings.keys.KEY_CAMERA_LOCK)) {
        this.lockCamera = !this.lockCamera;
    }
    if (keys[g_settings.keys.KEY_CAMERA_ZOOMIN]) {
	this.cameraZoom *= g_settings.cameraZoomRate;
    }
    if (keys[g_settings.keys.KEY_CAMERA_ZOOMOUT]) {
	this.cameraZoom /= g_settings.cameraZoomRate;
    }
    if (keys[g_settings.keys.KEY_CAMERA_ROTATE_CLOCKWISE]) {
	this.cameraRotation += g_settings.cameraRotateRate;
    }
    if (keys[g_settings.keys.KEY_CAMERA_ROTATE_COUNTERCLOCKWISE]) {
	this.cameraRotation -= g_settings.cameraRotateRate;
    }
    if (keys[g_settings.keys.KEY_CAMERA_UP]) {
	this.cameraOffset = util.vecPlus(this.cameraOffset,util.mulVecByScalar(g_settings.cameraMoveRate/this.cameraZoom,util.rotateVector([0,1], -this.cameraRotation)));
    }
    if (keys[g_settings.keys.KEY_CAMERA_DOWN]) {
	this.cameraOffset = util.vecPlus(this.cameraOffset,util.mulVecByScalar(g_settings.cameraMoveRate/this.cameraZoom,util.rotateVector([0,-1], -this.cameraRotation)));
    }
    if (keys[g_settings.keys.KEY_CAMERA_LEFT]) {
	this.cameraOffset = util.vecPlus(this.cameraOffset,util.mulVecByScalar(g_settings.cameraMoveRate/this.cameraZoom,util.rotateVector([1,0], -this.cameraRotation)));
    }
    if (keys[g_settings.keys.KEY_CAMERA_RIGHT]) {
	this.cameraOffset = util.vecPlus(this.cameraOffset,util.mulVecByScalar(g_settings.cameraMoveRate/this.cameraZoom,util.rotateVector([-1,0], -this.cameraRotation)));
    }
    if (keys[g_settings.keys.KEY_CAMERA_RESET]) {
	this.cameraOffset = [0,0]
	this.cameraRotation = 0;
	this.cameraZoom = 1;
    this.lockCamera = false;
	}

    if(this._ships[0]){
        var s = this._ships[0];
    if(!this.lockCamera){
        this.offset = [-s.cx + g_canvas.width/2,-s.cy + g_canvas.height/2];
    }
	this.trueOffset = util.vecPlus(this.offset,this.cameraOffset);
	this.trueOffset = util.vecPlus(this.trueOffset,util.rotateVector(util.mulVecByScalar(1/this.cameraZoom,this.mouseOffset),-this.cameraRotation));
    }

},

update: function(du) {

    for (var c = 0; c < this._categories.length; ++c) {

        var aCategory = this._categories[c];
        var i = 0;

        while (i < aCategory.length) {

            var status = aCategory[i].update(du);

            if (status === this.KILL_ME_NOW) {
                // remove the dead guy, and shuffle the others down to
                // prevent a confusing gap from appearing in the array
		spatialManager.unregister(aCategory[i]);
                aCategory.splice(i,1);

            }
            else {
                ++i;
            }
        }
    }

    if (g_settings.enableRocks && this._rocks.length === 0) this._generateRocks();

},

getMainShip: function() {
    return this._ships[0];
    },

render: function(ctx) {
    var debugX = 10, debugY = 100;
    ctx.save();
    if(this._ships[0]){
        var s = this._ships[0];
        //ctx.translate(-this.trueOffset[0],-this.trueOffset[1]);
	ctx.translate(g_canvas.width/2,g_canvas.height/2);
	ctx.rotate(this.cameraRotation);
	ctx.scale(this.cameraZoom,this.cameraZoom);
	ctx.translate(-g_canvas.width/2,-g_canvas.height/2);
    ctx.translate(this.trueOffset[0],this.trueOffset[1]);
	//console.log((s.cx) + " "  + (s.cy));
    }
    Stars.render(ctx);
    this._terrain.render(ctx);
    for (var c = 0; c < this._categories.length; ++c) {

        var aCategory = this._categories[c];

        if (!this._bShowRocks &&
            aCategory == this._rocks)
            continue;

        for (var i = 0; i < aCategory.length; ++i) {

            aCategory[i].render(ctx);
            //debug.text(".", debugX + i * 10, debugY);

        }
        debugY += 10;
    }
    ctx.restore();
},

}

// Some deferred setup which needs the object to have been created first
entityManager.deferredSetup();

<commit_msg>added clearShips function to entity manager<commit_after>    /*

    entityManager.js

    A module which handles arbitrary entity-management for "Asteroids"

    We create this module as a single global object, and initialise it
    with suitable 'data' and 'methods'.

    "Private" properties are denoted by an underscore prefix convention.

    */

    "use strict";

    // Tell jslint not to complain about my use of underscore prefixes (nomen),
    // my flattening of some indentation (white), or my use of incr/decr ops
    // (plusplus).
    //
    /*jslint nomen: true, white: true, plusplus: true*/

    var entityManager = {

    // "PRIVATE" DATA

    _rocks   : [],
    _bullets : [],
    _ships   : [],

    _terrain : [],

    _bShowRocks : true,

    cameraOffset: [0,0],
    trueOffset: [100,100],
    mouseOffset: [0,0],
    cameraRotation: 0,
    cameraZoom: 1,
    lockCamera: false,

    // "PRIVATE" METHODS
    _generateRocks : function() {
        var i,
            NUM_ROCKS = 4;

        for (i = 0; i < NUM_ROCKS; ++i) {
            this.generateRock();
        }
    },

_generateTerrain : function() {

    var sL = g_settings.seaLevel;
    var minangl = Math.PI/30;
    var maxangl = Math.PI/2.2;
    var terr = new Terrain({
	"minX":-10000,
	"maxX": 10000,
	"minY": 300,
	"maxY": sL/2,
	"minLength": 32,
	"maxLength": 256,
	"minAngle": Math.PI/30,
	"maxAngle": Math.PI/2.2
	});
    this._terrain = terr;
},

getTerrain : function () {
    return this._terrain;
},

_findNearestShip : function(posX, posY) {
    var closestShip = null,
        closestIndex = -1,
        closestSq = 1000 * 1000;

    for (var i = 0; i < this._ships.length; ++i) {

        var thisShip = this._ships[i];
        var shipPos = thisShip.getPos();
        var distSq = util.wrappedDistSq(
            shipPos.posX, shipPos.posY,
            posX, posY,
            g_canvas.width, g_canvas.height);

        if (distSq < closestSq) {
            closestShip = thisShip;
            closestIndex = i;
            closestSq = distSq;
        }
    }
    return {
        theShip : closestShip,
        theIndex: closestIndex
    };
},

_forEachOf: function(aCategory, fn) {
    for (var i = 0; i < aCategory.length; ++i) {
        fn.call(aCategory[i]);
    }
},

// PUBLIC METHODS

// A special return value, used by other objects,
// to request the blessed release of death!
//
KILL_ME_NOW : -1,

// Some things must be deferred until after initial construction
// i.e. thing which need `this` to be defined.
//
deferredSetup : function () {
    this._categories = [this._rocks, this._bullets, this._ships,this._terrain];
},

init: function() {
    if (g_settings.enableRocks){
	console.log("generating rocks");
	this._generateRocks();
	}
    this._generateTerrain();
    //this._generateShip();
},

fireBullet: function(cx, cy, velX, velY, rotation) {
    this._bullets.push(new Bullet({
        cx   : cx,
        cy   : cy,
        velX : velX,
        velY : velY,

        rotation : rotation
    }));
},

generateRock : function(descr) {
    this._rocks.push(new Rock(descr));
},

generateShip : function(descr) {
    this._ships.push(new Ship(descr));
},

killNearestShip : function(xPos, yPos) {
    var theShip = this._findNearestShip(xPos, yPos).theShip;
    if (theShip) {
        theShip.kill();
    }
},

yoinkNearestShip : function(xPos, yPos) {
    var theShip = this._findNearestShip(xPos, yPos).theShip;
    if (theShip) {
        theShip.setPos(xPos, yPos);
    }
},

resetShips: function() {
    this._forEachOf(this._ships, Ship.prototype.reset);
},

haltShips: function() {
    this._forEachOf(this._ships, Ship.prototype.halt);
},

clearShips: function() {
    this._ships.map(function(x){ if(x){ x.kill()}});
},

toggleRocks: function() {
    this._bShowRocks = !this._bShowRocks;
},

updateCamera: function () {

    if (eatKey(g_settings.keys.KEY_CAMERA_LOCK)) {
        this.lockCamera = !this.lockCamera;
    }
    if (keys[g_settings.keys.KEY_CAMERA_ZOOMIN]) {
	this.cameraZoom *= g_settings.cameraZoomRate;
    }
    if (keys[g_settings.keys.KEY_CAMERA_ZOOMOUT]) {
	this.cameraZoom /= g_settings.cameraZoomRate;
    }
    if (keys[g_settings.keys.KEY_CAMERA_ROTATE_CLOCKWISE]) {
	this.cameraRotation += g_settings.cameraRotateRate;
    }
    if (keys[g_settings.keys.KEY_CAMERA_ROTATE_COUNTERCLOCKWISE]) {
	this.cameraRotation -= g_settings.cameraRotateRate;
    }
    if (keys[g_settings.keys.KEY_CAMERA_UP]) {
	this.cameraOffset = util.vecPlus(this.cameraOffset,util.mulVecByScalar(g_settings.cameraMoveRate/this.cameraZoom,util.rotateVector([0,1], -this.cameraRotation)));
    }
    if (keys[g_settings.keys.KEY_CAMERA_DOWN]) {
	this.cameraOffset = util.vecPlus(this.cameraOffset,util.mulVecByScalar(g_settings.cameraMoveRate/this.cameraZoom,util.rotateVector([0,-1], -this.cameraRotation)));
    }
    if (keys[g_settings.keys.KEY_CAMERA_LEFT]) {
	this.cameraOffset = util.vecPlus(this.cameraOffset,util.mulVecByScalar(g_settings.cameraMoveRate/this.cameraZoom,util.rotateVector([1,0], -this.cameraRotation)));
    }
    if (keys[g_settings.keys.KEY_CAMERA_RIGHT]) {
	this.cameraOffset = util.vecPlus(this.cameraOffset,util.mulVecByScalar(g_settings.cameraMoveRate/this.cameraZoom,util.rotateVector([-1,0], -this.cameraRotation)));
    }
    if (keys[g_settings.keys.KEY_CAMERA_RESET]) {
	this.cameraOffset = [0,0]
	this.cameraRotation = 0;
	this.cameraZoom = 1;
    this.lockCamera = false;
	}

    if(this._ships[0]){
        var s = this._ships[0];
    if(!this.lockCamera){
        this.offset = [-s.cx + g_canvas.width/2,-s.cy + g_canvas.height/2];
    }
	this.trueOffset = util.vecPlus(this.offset,this.cameraOffset);
	this.trueOffset = util.vecPlus(this.trueOffset,util.rotateVector(util.mulVecByScalar(1/this.cameraZoom,this.mouseOffset),-this.cameraRotation));
    }

},

update: function(du) {

    for (var c = 0; c < this._categories.length; ++c) {

        var aCategory = this._categories[c];
        var i = 0;

        while (i < aCategory.length) {

            var status = aCategory[i].update(du);

            if (status === this.KILL_ME_NOW) {
                // remove the dead guy, and shuffle the others down to
                // prevent a confusing gap from appearing in the array
		spatialManager.unregister(aCategory[i]);
                aCategory.splice(i,1);

            }
            else {
                ++i;
            }
        }
    }

    if (g_settings.enableRocks && this._rocks.length === 0) this._generateRocks();

},

getMainShip: function() {
    return this._ships[0];
    },

render: function(ctx) {
    var debugX = 10, debugY = 100;
    ctx.save();
    if(this._ships[0]){
        var s = this._ships[0];
        //ctx.translate(-this.trueOffset[0],-this.trueOffset[1]);
	ctx.translate(g_canvas.width/2,g_canvas.height/2);
	ctx.rotate(this.cameraRotation);
	ctx.scale(this.cameraZoom,this.cameraZoom);
	ctx.translate(-g_canvas.width/2,-g_canvas.height/2);
    ctx.translate(this.trueOffset[0],this.trueOffset[1]);
	//console.log((s.cx) + " "  + (s.cy));
    }
    Stars.render(ctx);
    this._terrain.render(ctx);
    for (var c = 0; c < this._categories.length; ++c) {

        var aCategory = this._categories[c];

        if (!this._bShowRocks &&
            aCategory == this._rocks)
            continue;

        for (var i = 0; i < aCategory.length; ++i) {

            aCategory[i].render(ctx);
            //debug.text(".", debugX + i * 10, debugY);

        }
        debugY += 10;
    }
    ctx.restore();
},

}

// Some deferred setup which needs the object to have been created first
entityManager.deferredSetup();

<|endoftext|>


<commit_before>'use strict';

var Cloud = function (game) {
	Phaser.Sprite.call(this, game, 0, 0, 'cloud', 0);

	this.anchor.setTo(0.5, 0.5);

	this.game.physics.arcade.enableBody(this);

	this.body.allowGravity = false;
	this.body.immovable = true;
};

Cloud.prototype = Object.create(Phaser.Sprite.prototype);
Cloud.prototype.constructor = Cloud;

Cloud.prototype.update = function () {
	this.checkOffScreen();
};

Cloud.prototype.reset = function (isInitial) {
	var data = this.generateNewData(isInitial);

	this.x = data.x;
	this.y = data.y;
	this.frame = data.frame;
	this.body.velocity.x = data.velocity;

	this.exists = true;
};

Cloud.prototype.generateNewData = function (isInitial) {

	var result = {
		velocity: this.game.rnd.integerInRange(10, 50) * (this.game.rnd.frac() > 0.5 ? -1 : 1),
		y: this.game.rnd.integerInRange(10, 500),
		frame: this.game.rnd.integerInRange(0, 2)
	};

	if (isInitial) {
		result.x = this.game.rnd.integerInRange(0, this.game.world.width);
	}
	else if (result.velocity > 0) {
		result.x = this.game.rnd.integerInRange(-500, -100);
	} else {
		result.x = this.game.rnd.integerInRange(this.game.world.width + 100, this.game.world.width + 500);
	}

	return result;
};

Cloud.prototype.checkOffScreen = function () {
	if (this.exists && (
		(this.x < -this.width && this.body.velocity.x < 0) ||
		(this.x > this.game.world.width+this.width && this.body.velocity.x > 0)
	)) {
		this.reset();
	}
};

module.exports = Cloud;
<commit_msg>Animated clouds.<commit_after>'use strict';

var Cloud = function (game) {
	Phaser.Sprite.call(this, game, 0, 0, 'cloud', 0);

	this.anchor.setTo(0.5, 0.5);

	this.game.physics.arcade.enableBody(this);

	this.body.allowGravity = false;
	this.body.immovable = true;
};

Cloud.prototype = Object.create(Phaser.Sprite.prototype);
Cloud.prototype.constructor = Cloud;

Cloud.prototype.update = function () {
	this.checkOffScreen();
};

Cloud.prototype.reset = function (isInitial) {
	var data = this.generateNewData(isInitial);

	this.x = data.x;
	this.y = data.y;
	this.frame = data.frame;
	this.body.velocity.x = data.velocity;

	var deltaY = this.game.rnd.integerInRange(-10, 10);
	var delay = this.game.rnd.integerInRange(0, 100);

	this.game.add.tween(this).to({ y: data.y + deltaY }, 350, Phaser.Easing.Linear.NONE, true, delay, 10000, true);

	this.exists = true;
};

Cloud.prototype.generateNewData = function (isInitial) {

	var result = {
		velocity: this.game.rnd.integerInRange(10, 50) * (this.game.rnd.frac() > 0.5 ? -1 : 1),
		y: this.game.rnd.integerInRange(10, 500),
		frame: this.game.rnd.integerInRange(0, 2)
	};

	if (isInitial) {
		result.x = this.game.rnd.integerInRange(0, this.game.world.width);
	}
	else if (result.velocity > 0) {
		result.x = this.game.rnd.integerInRange(-500, -100);
	} else {
		result.x = this.game.rnd.integerInRange(this.game.world.width + 100, this.game.world.width + 500);
	}

	return result;
};

Cloud.prototype.checkOffScreen = function () {
	if (this.exists && (
		(this.x < -this.width && this.body.velocity.x < 0) ||
		(this.x > this.game.world.width+this.width && this.body.velocity.x > 0)
	)) {
		this.reset();
	}
};

module.exports = Cloud;
<|endoftext|>


<commit_before>var util = require('../helpers/util')
var uiutil = require('../helpers/ui')
var traceHelper = require('../helpers/traceHelper')
var ethutil = require('ethereumjs-util')
var Web3 = require('web3')

function web3VmProvider () {
  var self = this
  this.web3 = new Web3()
  this.vm
  this.vmTraces = {}
  this.txs = {}
  this.txsReceipt = {}
  this.processingHash
  this.processingAddress
  this.processingIndex
  this.previousDepth = 0
  this.incr = 0
  this.eth = {}
  this.debug = {}
  this.eth.getCode = function (address, cb) { return self.getCode(address, cb) }
  this.eth.getTransaction = function (hash, cb) { return self.getTransaction(hash, cb) }
  this.eth.getTransactionReceipt = function (hash, cb) { return self.getTransactionReceipt(hash, cb) }
  this.eth.getTransactionFromBlock = function (blockNumber, txIndex, cb) { return self.getTransactionFromBlock(blockNumber, txIndex, cb) }
  this.eth.getBlockNumber = function (cb) { return self.getBlockNumber(cb) }
  this.debug.traceTransaction = function (hash, options, cb) { return self.traceTransaction(hash, options, cb) }
  this.debug.storageRangeAt = function (blockNumber, txIndex, address, start, end, maxLength, cb) { return self.storageRangeAt(blockNumber, txIndex, address, start, end, maxLength, cb) }
  this.debug.preimage = function (hashedKey, cb) { return self.preimage(hashedKey, cb) }
  this.providers = { 'HttpProvider': function (url) {} }
  this.currentProvider = {'host': 'vm provider'}
  this.storageCache = {}
  this.sha3Preimages = {}
}

web3VmProvider.prototype.setVM = function (vm) {
  var self = this
  this.vm = vm
  this.vm.on('step', function (data) {
    self.pushTrace(self, data)
  })
  this.vm.on('afterTx', function (data) {
    self.txProcessed(self, data)
  })
  this.vm.on('beforeTx', function (data) {
    self.txWillProcess(self, data)
  })
}

web3VmProvider.prototype.releaseCurrentHash = function () {
  var ret = this.processingHash
  this.processingHash = undefined
  return ret
}

web3VmProvider.prototype.txWillProcess = function (self, data) {
  self.incr++
  self.processingHash = util.hexConvert(data.hash())
  self.vmTraces[self.processingHash] = {
    gas: '0x0',
    return: '0x0',
    structLogs: []
  }
  var tx = {}
  tx.hash = self.processingHash
  tx.from = util.hexConvert(data.getSenderAddress())
  if (data.to && data.to.length) {
    tx.to = util.hexConvert(data.to)
  }
  this.processingAddress = tx.to
  tx.data = util.hexConvert(data.data)
  tx.input = util.hexConvert(data.input)
  tx.gas = util.hexConvert(data.gas)
  if (data.value) {
    tx.value = util.hexConvert(data.value)
  }
  self.txs[self.processingHash] = tx
  self.txsReceipt[self.processingHash] = tx
  self.storageCache[self.processingHash] = {}
  if (tx.to) {
    self.vm.stateManager.dumpStorage(tx.to, function (storage) {
      self.storageCache[self.processingHash][tx.to] = storage
    })
  }
  this.processingIndex = 0
}

web3VmProvider.prototype.txProcessed = function (self, data) {
  var lastOp = self.vmTraces[self.processingHash].structLogs[self.processingIndex - 1]
  lastOp.error = lastOp.op !== 'RETURN' && lastOp.op !== 'STOP'
  self.vmTraces[self.processingHash].gas = '0x' + data.gasUsed.toString(16)
  if (data.createdAddress) {
    var address = util.hexConvert(data.createdAddress)
    self.vmTraces[self.processingHash].return = address
    self.txsReceipt[self.processingHash].contractAddress = address
  } else {
    self.vmTraces[self.processingHash].return = util.hexConvert(data.vm.return)
  }
  this.processingIndex = null
  this.processingAddress = null
  this.previousDepth = 0
}

web3VmProvider.prototype.pushTrace = function (self, data) {
  var depth = data.depth + 1 // geth starts the depth from 1
  if (!self.processingHash) {
    console.log('no tx processing')
    return
  }
  if (this.previousDepth > depth) {
    // returning from context, set error it is not STOP, RETURN
    var previousopcode = self.vmTraces[self.processingHash].structLogs[this.processingIndex - 1]
    previousopcode.invalidDepthChange = previousopcode.op !== 'RETURN' && previousopcode.op !== 'STOP'
  }
  var step = {
    stack: util.hexListConvert(data.stack),
    memory: util.formatMemory(data.memory),
    storage: data.storage,
    op: data.opcode.name,
    pc: data.pc,
    gasCost: data.opcode.fee.toString(),
    gas: data.gasLeft.toString(),
    depth: depth,
    error: data.error === false ? undefined : data.error
  }
  self.vmTraces[self.processingHash].structLogs.push(step)
  if (traceHelper.newContextStorage(step)) {
    if (step.op === 'CREATE') {
      this.processingAddress = traceHelper.contractCreationToken(this.processingIndex)
      this.storageCache[this.processingHash][this.processingAddress] = {}
    } else {
      this.processingAddress = uiutil.normalizeHex(step.stack[step.stack.length - 2])
      if (!self.storageCache[self.processingHash][this.processingAddress]) {
        self.vm.stateManager.dumpStorage(this.processingAddress, function (storage) {
          self.storageCache[self.processingHash][self.processingAddress] = storage
        })
      }
    }
  }
  if (traceHelper.isSHA3Instruction(step)) {
    var sha3Input = getSha3Input(step.stack, step.memory)
    var preimage = sha3Input
    var imageHash = ethutil.sha3('0x' + sha3Input).toString('hex')
    self.sha3Preimages[imageHash] = {
      'preimage': preimage
    }
  }
  this.processingIndex++
  this.previousDepth = depth
}

web3VmProvider.prototype.getCode = function (address, cb) {
  this.vm.stateManager.getContractCode(address, function (error, result) {
    cb(error, util.hexConvert(result))
  })
}

web3VmProvider.prototype.setProvider = function (provider) {}

web3VmProvider.prototype.traceTransaction = function (txHash, options, cb) {
  if (this.vmTraces[txHash]) {
    if (cb) {
      cb(null, this.vmTraces[txHash])
    }
    return this.vmTraces[txHash]
  } else {
    if (cb) {
      cb('unable to retrieve traces ' + txHash, null)
    }
  }
}

web3VmProvider.prototype.storageRangeAt = function (blockNumber, txIndex, address, start, maxLength, cb) { // txIndex is the hash in the case of the VM
  // we don't use the range params here
  if (this.storageCache[txIndex] && this.storageCache[txIndex][address]) {
    var storage = this.storageCache[txIndex][address]
    return cb(null, {
      storage: JSON.parse(JSON.stringify(storage)),
      nextKey: null
    })
  } else {
    cb('unable to retrieve storage ' + txIndex + ' ' + address)
  }
}

web3VmProvider.prototype.getBlockNumber = function (cb) { cb(null, 'vm provider') }

web3VmProvider.prototype.getTransaction = function (txHash, cb) {
  if (this.txs[txHash]) {
    if (cb) {
      cb(null, this.txs[txHash])
    }
    return this.txs[txHash]
  } else {
    if (cb) {
      cb('unable to retrieve tx ' + txHash, null)
    }
  }
}

web3VmProvider.prototype.getTransactionReceipt = function (txHash, cb) {
  // same as getTransaction but return the created address also
  if (this.txsReceipt[txHash]) {
    if (cb) {
      cb(null, this.txsReceipt[txHash])
    }
    return this.txsReceipt[txHash]
  } else {
    if (cb) {
      cb('unable to retrieve txReceipt ' + txHash, null)
    }
  }
}

web3VmProvider.prototype.getTransactionFromBlock = function (blockNumber, txIndex, cb) {
  var mes = 'not supposed to be needed by remix in vmmode'
  console.log(mes)
  if (cb) {
    cb(mes, null)
  }
}

web3VmProvider.prototype.preimage = function (hashedKey, cb) {
  hashedKey = hashedKey.replace('0x', '')
  cb(null, this.sha3Preimages[hashedKey] !== undefined ? this.sha3Preimages[hashedKey].preimage : null)
}

function getSha3Input (stack, memory) {
  var memoryStart = stack[stack.length - 1]
  var memoryLength = stack[stack.length - 2]
  var memStartDec = (new ethutil.BN(memoryStart.replace('0x', ''), 16)).toString(10)
  memoryStart = parseInt(memStartDec) * 2
  var memLengthDec = (new ethutil.BN(memoryLength.replace('0x', ''), 16).toString(10))
  memoryLength = parseInt(memLengthDec) * 2

  var i = Math.floor(memoryStart / 32)
  var maxIndex = Math.floor(memoryLength / 32)
  if (!memory[i]) {
    return emptyFill(memoryLength)
  }
  var sha3Input = memory[i].slice(memoryStart - 32 * i)
  i++
  while (i < maxIndex) {
    sha3Input += memory[i] ? memory[i] : emptyFill(32)
    i++
  }
  if (sha3Input.length < memoryLength) {
    var leftSize = memoryLength - sha3Input.length
    sha3Input += memory[i] ? memory[i].slice(0, leftSize) : emptyFill(leftSize)
  }
  return sha3Input
}

function emptyFill (size) {
  return (new Array(size)).join('0')
}

module.exports = web3VmProvider
<commit_msg>add logs to transaction receipt<commit_after>var util = require('../helpers/util')
var uiutil = require('../helpers/ui')
var traceHelper = require('../helpers/traceHelper')
var ethutil = require('ethereumjs-util')
var Web3 = require('web3')

function web3VmProvider () {
  var self = this
  this.web3 = new Web3()
  this.vm
  this.vmTraces = {}
  this.txs = {}
  this.txsReceipt = {}
  this.processingHash
  this.processingAddress
  this.processingIndex
  this.previousDepth = 0
  this.incr = 0
  this.eth = {}
  this.debug = {}
  this.eth.getCode = function (address, cb) { return self.getCode(address, cb) }
  this.eth.getTransaction = function (hash, cb) { return self.getTransaction(hash, cb) }
  this.eth.getTransactionReceipt = function (hash, cb) { return self.getTransactionReceipt(hash, cb) }
  this.eth.getTransactionFromBlock = function (blockNumber, txIndex, cb) { return self.getTransactionFromBlock(blockNumber, txIndex, cb) }
  this.eth.getBlockNumber = function (cb) { return self.getBlockNumber(cb) }
  this.debug.traceTransaction = function (hash, options, cb) { return self.traceTransaction(hash, options, cb) }
  this.debug.storageRangeAt = function (blockNumber, txIndex, address, start, end, maxLength, cb) { return self.storageRangeAt(blockNumber, txIndex, address, start, end, maxLength, cb) }
  this.debug.preimage = function (hashedKey, cb) { return self.preimage(hashedKey, cb) }
  this.providers = { 'HttpProvider': function (url) {} }
  this.currentProvider = {'host': 'vm provider'}
  this.storageCache = {}
  this.sha3Preimages = {}
}

web3VmProvider.prototype.setVM = function (vm) {
  var self = this
  this.vm = vm
  this.vm.on('step', function (data) {
    self.pushTrace(self, data)
  })
  this.vm.on('afterTx', function (data) {
    self.txProcessed(self, data)
  })
  this.vm.on('beforeTx', function (data) {
    self.txWillProcess(self, data)
  })
}

web3VmProvider.prototype.releaseCurrentHash = function () {
  var ret = this.processingHash
  this.processingHash = undefined
  return ret
}

web3VmProvider.prototype.txWillProcess = function (self, data) {
  self.incr++
  self.processingHash = util.hexConvert(data.hash())
  self.vmTraces[self.processingHash] = {
    gas: '0x0',
    return: '0x0',
    structLogs: []
  }
  var tx = {}
  tx.hash = self.processingHash
  tx.from = util.hexConvert(data.getSenderAddress())
  if (data.to && data.to.length) {
    tx.to = util.hexConvert(data.to)
  }
  this.processingAddress = tx.to
  tx.data = util.hexConvert(data.data)
  tx.input = util.hexConvert(data.input)
  tx.gas = util.hexConvert(data.gas)
  if (data.value) {
    tx.value = util.hexConvert(data.value)
  }
  self.txs[self.processingHash] = tx
  self.txsReceipt[self.processingHash] = tx
  self.storageCache[self.processingHash] = {}
  if (tx.to) {
    self.vm.stateManager.dumpStorage(tx.to, function (storage) {
      self.storageCache[self.processingHash][tx.to] = storage
    })
  }
  this.processingIndex = 0
}

web3VmProvider.prototype.txProcessed = function (self, data) {
  var lastOp = self.vmTraces[self.processingHash].structLogs[self.processingIndex - 1]
  lastOp.error = lastOp.op !== 'RETURN' && lastOp.op !== 'STOP'
  self.vmTraces[self.processingHash].gas = '0x' + data.gasUsed.toString(16)

  var logs = []
  for (var l in data.vm.logs) {
    var log = data.vm.logs[l]
    logs.push({
      data: log[2].toString('hex'),
      topics: [log[1][0].toString('hex')],
      rawVMResponse: log
    })
  }
  self.txsReceipt[self.processingHash].logs = logs

  if (data.createdAddress) {
    var address = util.hexConvert(data.createdAddress)
    self.vmTraces[self.processingHash].return = address
    self.txsReceipt[self.processingHash].contractAddress = address
  } else {
    self.vmTraces[self.processingHash].return = util.hexConvert(data.vm.return)
  }
  this.processingIndex = null
  this.processingAddress = null
  this.previousDepth = 0
}

web3VmProvider.prototype.pushTrace = function (self, data) {
  var depth = data.depth + 1 // geth starts the depth from 1
  if (!self.processingHash) {
    console.log('no tx processing')
    return
  }
  if (this.previousDepth > depth) {
    // returning from context, set error it is not STOP, RETURN
    var previousopcode = self.vmTraces[self.processingHash].structLogs[this.processingIndex - 1]
    previousopcode.invalidDepthChange = previousopcode.op !== 'RETURN' && previousopcode.op !== 'STOP'
  }
  var step = {
    stack: util.hexListConvert(data.stack),
    memory: util.formatMemory(data.memory),
    storage: data.storage,
    op: data.opcode.name,
    pc: data.pc,
    gasCost: data.opcode.fee.toString(),
    gas: data.gasLeft.toString(),
    depth: depth,
    error: data.error === false ? undefined : data.error
  }
  self.vmTraces[self.processingHash].structLogs.push(step)
  if (traceHelper.newContextStorage(step)) {
    if (step.op === 'CREATE') {
      this.processingAddress = traceHelper.contractCreationToken(this.processingIndex)
      this.storageCache[this.processingHash][this.processingAddress] = {}
    } else {
      this.processingAddress = uiutil.normalizeHex(step.stack[step.stack.length - 2])
      if (!self.storageCache[self.processingHash][this.processingAddress]) {
        self.vm.stateManager.dumpStorage(this.processingAddress, function (storage) {
          self.storageCache[self.processingHash][self.processingAddress] = storage
        })
      }
    }
  }
  if (traceHelper.isSHA3Instruction(step)) {
    var sha3Input = getSha3Input(step.stack, step.memory)
    var preimage = sha3Input
    var imageHash = ethutil.sha3('0x' + sha3Input).toString('hex')
    self.sha3Preimages[imageHash] = {
      'preimage': preimage
    }
  }
  this.processingIndex++
  this.previousDepth = depth
}

web3VmProvider.prototype.getCode = function (address, cb) {
  this.vm.stateManager.getContractCode(address, function (error, result) {
    cb(error, util.hexConvert(result))
  })
}

web3VmProvider.prototype.setProvider = function (provider) {}

web3VmProvider.prototype.traceTransaction = function (txHash, options, cb) {
  if (this.vmTraces[txHash]) {
    if (cb) {
      cb(null, this.vmTraces[txHash])
    }
    return this.vmTraces[txHash]
  } else {
    if (cb) {
      cb('unable to retrieve traces ' + txHash, null)
    }
  }
}

web3VmProvider.prototype.storageRangeAt = function (blockNumber, txIndex, address, start, maxLength, cb) { // txIndex is the hash in the case of the VM
  // we don't use the range params here
  if (this.storageCache[txIndex] && this.storageCache[txIndex][address]) {
    var storage = this.storageCache[txIndex][address]
    return cb(null, {
      storage: JSON.parse(JSON.stringify(storage)),
      nextKey: null
    })
  } else {
    cb('unable to retrieve storage ' + txIndex + ' ' + address)
  }
}

web3VmProvider.prototype.getBlockNumber = function (cb) { cb(null, 'vm provider') }

web3VmProvider.prototype.getTransaction = function (txHash, cb) {
  if (this.txs[txHash]) {
    if (cb) {
      cb(null, this.txs[txHash])
    }
    return this.txs[txHash]
  } else {
    if (cb) {
      cb('unable to retrieve tx ' + txHash, null)
    }
  }
}

web3VmProvider.prototype.getTransactionReceipt = function (txHash, cb) {
  // same as getTransaction but return the created address also
  if (this.txsReceipt[txHash]) {
    if (cb) {
      cb(null, this.txsReceipt[txHash])
    }
    return this.txsReceipt[txHash]
  } else {
    if (cb) {
      cb('unable to retrieve txReceipt ' + txHash, null)
    }
  }
}

web3VmProvider.prototype.getTransactionFromBlock = function (blockNumber, txIndex, cb) {
  var mes = 'not supposed to be needed by remix in vmmode'
  console.log(mes)
  if (cb) {
    cb(mes, null)
  }
}

web3VmProvider.prototype.preimage = function (hashedKey, cb) {
  hashedKey = hashedKey.replace('0x', '')
  cb(null, this.sha3Preimages[hashedKey] !== undefined ? this.sha3Preimages[hashedKey].preimage : null)
}

function getSha3Input (stack, memory) {
  var memoryStart = stack[stack.length - 1]
  var memoryLength = stack[stack.length - 2]
  var memStartDec = (new ethutil.BN(memoryStart.replace('0x', ''), 16)).toString(10)
  memoryStart = parseInt(memStartDec) * 2
  var memLengthDec = (new ethutil.BN(memoryLength.replace('0x', ''), 16).toString(10))
  memoryLength = parseInt(memLengthDec) * 2

  var i = Math.floor(memoryStart / 32)
  var maxIndex = Math.floor(memoryLength / 32)
  if (!memory[i]) {
    return emptyFill(memoryLength)
  }
  var sha3Input = memory[i].slice(memoryStart - 32 * i)
  i++
  while (i < maxIndex) {
    sha3Input += memory[i] ? memory[i] : emptyFill(32)
    i++
  }
  if (sha3Input.length < memoryLength) {
    var leftSize = memoryLength - sha3Input.length
    sha3Input += memory[i] ? memory[i].slice(0, leftSize) : emptyFill(leftSize)
  }
  return sha3Input
}

function emptyFill (size) {
  return (new Array(size)).join('0')
}

module.exports = web3VmProvider
<|endoftext|>


<commit_before>var gulp = require('gulp');
var run = require('gulp-run');
var plumber = require('gulp-plumber');
var sourcemaps = require('gulp-sourcemaps');
var concat = require('gulp-concat');
var runSeq = require('run-sequence');
var sass = require('gulp-sass');
var livereload = require('gulp-livereload');
var rename = require('gulp-rename');
var mocha = require('gulp-mocha');
var babel = require('gulp-babel');

// Live reload
gulp.task('reload', function() {
    livereload.reload();
})

// Default
gulp.task('default', function() {
    livereload.listen();
    gulp.start('build');

    gulp.watch(['client/pre-build/app.js', 'client/pre-build/**/*.js'], function() {
        runSeq('buildJS', 'reload');
    });

    gulp.watch(['client/pre-build/app.scss', 'client/pre-build/**/*.scss'], function() {
        runSeq('buildCSS', 'reload');
    });

    // Reload when a template (.html) file changes.
    gulp.watch(['client/**/*.html', 'server/*.html'], ['reload']);

    gulp.watch(['server/**/*.js'], ['testServerJS']);

});

// Database seed
gulp.task('seedDB', function() {
    run('node seed.js').exec();
});

// Build tasks
//// Build all
gulp.task('build', function() {
    runSeq(['buildJS', 'buildCSS']);
});

gulp.task('buildJS', function() {
    return gulp.src(['./client/pre-build/app.js', './client/pre-build/**/*.js'])
        .pipe(plumber())
        .pipe(sourcemaps.init())
        .pipe(babel({
			presets: ['es2015']
		}))
        .pipe(concat('build.js'))
        .pipe(sourcemaps.write())
        .pipe(gulp.dest('./client/build'));
});

gulp.task('buildCSS', function() {
    return gulp.src('./client/pre-build/app.scss')
        .pipe(plumber())
        .pipe(sass())
        .pipe(rename('build.css'))
        .pipe(gulp.dest('./client/build'));
});

// Testing
gulp.task('testServerJS', function() {
    return gulp.src('./server/**/*.spec.js', {
            read: false
        })
        .pipe(mocha({
            reporter: 'spec'
        }));
});
<commit_msg>Removed depricated gulp-run module. Now using child_process.exec().<commit_after>var gulp = require('gulp');
var plumber = require('gulp-plumber');
var sourcemaps = require('gulp-sourcemaps');
var concat = require('gulp-concat');
var runSeq = require('run-sequence');
var sass = require('gulp-sass');
var livereload = require('gulp-livereload');
var rename = require('gulp-rename');
var mocha = require('gulp-mocha');
var babel = require('gulp-babel');
var exec = require('child_process').exec;
const chalk = require('chalk');

// Live reload
gulp.task('reload', function() {
    livereload.reload();
})

// Default
gulp.task('default', function() {
    livereload.listen();
    gulp.start('build');

    gulp.watch(['client/pre-build/app.js', 'client/pre-build/**/*.js'], function() {
        runSeq('buildJS', 'reload');
    });

    gulp.watch(['client/pre-build/app.scss', 'client/pre-build/**/*.scss'], function() {
        runSeq('buildCSS', 'reload');
    });

    // Reload when a template (.html) file changes.
    gulp.watch(['client/**/*.html', 'server/*.html'], ['reload']);

    gulp.watch(['server/**/*.js'], ['testServerJS']);

});

// Database seed
gulp.task('seedDB', function(cb) {

    exec('node seed.js', (err, stdout, stderr) => {
        if (err) {
            console.error(chalk.red(err));
            process.exit(err.code);
        }
        console.log(chalk.green(stdout));
        console.log(chalk.red(stderr));
        process.exit(0);
    });

});

// Build tasks
//// Build all
gulp.task('build', function() {
    runSeq(['buildJS', 'buildCSS']);
});

gulp.task('buildJS', function() {
    return gulp.src(['./client/pre-build/app.js', './client/pre-build/**/*.js'])
        .pipe(plumber())
        .pipe(sourcemaps.init())
        .pipe(babel({
			presets: ['es2015']
		}))
        .pipe(concat('build.js'))
        .pipe(sourcemaps.write())
        .pipe(gulp.dest('./client/build'));
});

gulp.task('buildCSS', function() {
    return gulp.src('./client/pre-build/app.scss')
        .pipe(plumber())
        .pipe(sass())
        .pipe(rename('build.css'))
        .pipe(gulp.dest('./client/build'));
});

// Testing
gulp.task('testServerJS', function() {
    return gulp.src('./server/**/*.spec.js', {
            read: false
        })
        .pipe(mocha({
            reporter: 'spec'
        }));
});
<|endoftext|>


<commit_before>'use strict';

const constants = require('./generator-constants'),
    ANGULAR_DIR = constants.ANGULAR_DIR;

module.exports = {
    cleanupOldFiles: cleanupOldFiles,
    cleanupOldServerFiles: cleanupOldServerFiles
};
/**
 * Removes files that where generated in previous JHipster versions and therefore need to be removed
 */
function cleanupOldFiles(generator, javaDir, testDir) {
    if (generator.isJhipsterVersionLessThan('3.2.0')) {
        //removeFile and removeFolder methods should be called here for files and folders to cleanup
        generator.removeFile(ANGULAR_DIR + 'components/form/uib-pager.config.js');
        generator.removeFile(ANGULAR_DIR + 'components/form/uib-pagination.config.js');
    }
}

/**
 * Removes server files that where generated in previous JHipster versions and therefore need to be removed
 */
function cleanupOldServerFiles(generator, javaDir, testDir) {
    if (generator.isJhipsterVersionLessThan('3.5.0')) {
        generator.removeFile(javaDir + 'domain/util/JSR310DateTimeSerializer.java');
        generator.removeFile(javaDir + 'domain/util/JSR310LocalDateDeserializer.java');
    }
    if (generator.isJhipsterVersionLessThan('3.6.0')) {
        generator.removeFile(javaDir + 'config/HerokuDatabaseConfiguration.java');
    }
    if (generator.isJhipsterVersionLessThan('3.6.2')) {
        generator.removeFile(javaDir + 'config/JacksonConfiguration.java');
    }

}
<commit_msg>update remove file for Jackson<commit_after>'use strict';

const constants = require('./generator-constants'),
    ANGULAR_DIR = constants.ANGULAR_DIR;

module.exports = {
    cleanupOldFiles: cleanupOldFiles,
    cleanupOldServerFiles: cleanupOldServerFiles
};
/**
 * Removes files that where generated in previous JHipster versions and therefore need to be removed
 */
function cleanupOldFiles(generator, javaDir, testDir) {
    if (generator.isJhipsterVersionLessThan('3.2.0')) {
        //removeFile and removeFolder methods should be called here for files and folders to cleanup
        generator.removeFile(ANGULAR_DIR + 'components/form/uib-pager.config.js');
        generator.removeFile(ANGULAR_DIR + 'components/form/uib-pagination.config.js');
    }
}

/**
 * Removes server files that where generated in previous JHipster versions and therefore need to be removed
 */
function cleanupOldServerFiles(generator, javaDir, testDir) {
    if (generator.isJhipsterVersionLessThan('3.5.0')) {
        generator.removeFile(javaDir + 'domain/util/JSR310DateTimeSerializer.java');
        generator.removeFile(javaDir + 'domain/util/JSR310LocalDateDeserializer.java');
    }
    if (generator.isJhipsterVersionLessThan('3.6.0')) {
        generator.removeFile(javaDir + 'config/HerokuDatabaseConfiguration.java');
    }
    if (generator.isJhipsterVersionLessThan('3.8.1')) {
        generator.removeFile(javaDir + 'config/JacksonConfiguration.java');
    }

}
<|endoftext|>


<commit_before>import React, { useEffect, useState, useRef } from 'react';
import { View, StyleSheet, StatusBar, Platform } from 'react-native';
import { useSelector } from 'react-redux';
import {
  NavigationContainer,
  DefaultTheme as NavigationDefaultTheme,
  DarkTheme as NavigationDarkTheme,
  useLinking,
} from '@react-navigation/native';
import { getStateFromPath } from '@react-navigation/core';
import analytics from '@react-native-firebase/analytics';
import {
  DefaultTheme as PaperDefaultTheme,
  DarkTheme as PaperDarkTheme,
  Provider as PaperProvider,
} from 'react-native-paper';
import SplashScreen from 'react-native-splash-screen';
import FlashMessage from 'react-native-flash-message';
import AppNavigator from '../../navigations/AppNavigator';
import AuthNavigator from '../../navigations/AuthNavigator';
import Loader from '../../components/Loader';
import ModalRoot from '../../containers/ModalRoot';
import PXSnackbar from '../../components/PXSnackbar';
import { THEME_TYPES, SCREENS } from '../../common/constants';
import { globalStyleVariables } from '../../styles';
import usePrevious from '../../common/hooks/usePrevious';

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});

const getActiveRouteName = (state) => {
  const route = state.routes[state.index];

  if (route.state) {
    // Dive into nested navigators
    return getActiveRouteName(route.state);
  }

  return route.name;
};

const App = () => {
  const [initialState, setInitialState] = useState();
  const [navigationIsReady, setNavigationIsReady] = useState(false);
  const rehydrated = useSelector((state) => state.auth.rehydrated);
  const user = useSelector((state) => state.auth.user);
  const initialRouteName = useSelector(
    (state) => state.initialScreenSettings.routeName,
  );
  const themeName = useSelector((state) => state.theme.name);
  const navigationRef = useRef();
  const routeNameRef = useRef();
  const prevRehydrated = usePrevious(rehydrated);

  const { getInitialState } = useLinking(navigationRef, {
    prefixes: [
      'https://www.pixiv.net/en',
      'https://www.pixiv.net',
      'http://www.pixiv.net',
      'http://www.pixiv.net/en',
      'https://touch.pixiv.net',
      'pixiv://',
    ],
    config: {
      [SCREENS.Detail]: 'artworks/:illustId',
      [SCREENS.NovelDetail]: 'novel/show.php',
      [SCREENS.UserDetail]: 'users/:uid',
      // workaround to handle deep link to one screen with multiple path
      [`${SCREENS.Detail}-1`]: 'illusts/:illustId',
      [`${SCREENS.Detail}-2`]: 'member_illust.php',
      [`${SCREENS.NovelDetail}-1`]: 'novels/:novelId',
      [`${SCREENS.UserDetail}-1`]: 'member.php',
      [SCREENS.Login]: 'account/login',
    },
    getStateFromPath: (path, options) => {
      const state = getStateFromPath(path, options);
      const newRoutes = [...state.routes];
      // eslint-disable-next-line prefer-destructuring
      newRoutes[0].name = newRoutes[0].name.split('-')[0];
      return {
        ...state,
        routes: [
          // {
          //   name: SCREENS.Main, // Load drawer navigation first
          // },
          ...newRoutes,
        ],
      };
    },
  });

  useEffect(() => {
    Promise.race([
      getInitialState(),
      new Promise((resolve) =>
        // Timeout in 150ms if `getInitialState` doesn't resolve
        // Workaround for https://github.com/facebook/react-native/issues/25675
        setTimeout(resolve, 150),
      ),
    ])
      .catch((e) => {
        console.error('Error getting initial state ', e);
      })
      .then((state) => {
        if (state !== undefined) {
          setInitialState(state);
        }

        setNavigationIsReady(true);
      });
  }, [getInitialState]);

  useEffect(() => {
    if (rehydrated && navigationIsReady) {
      const state = navigationRef.current.getRootState();
      // Save the initial route name
      routeNameRef.current = getActiveRouteName(state);
    }
  }, [rehydrated, navigationIsReady]);

  useEffect(() => {
    if (!prevRehydrated && rehydrated) {
      SplashScreen.hide();
    }
  }, [prevRehydrated, rehydrated]);

  const handleOnNavigationStateChange = (state) => {
    const previousRouteName = routeNameRef.current;
    const currentRouteName = getActiveRouteName(state);
    if (previousRouteName !== currentRouteName) {
      analytics().logScreenView({
        screen_name: currentRouteName,
        screen_class: currentRouteName,
      });
    }
    routeNameRef.current = currentRouteName;
  };

  let renderComponent;
  let theme;
  const extraColorsConfig = {
    primary: globalStyleVariables.PRIMARY_COLOR,
    activeTint:
      themeName === THEME_TYPES.DARK
        ? '#000000'
        : globalStyleVariables.PRIMARY_COLOR,
    headerBackground:
      themeName === THEME_TYPES.DARK
        ? '#1a1a1a'
        : globalStyleVariables.PRIMARY_COLOR,
    modalTitleBackground:
      themeName === THEME_TYPES.DARK ? '#1a1a1a' : '#E9EBEE',
    bottomTabBarBackground:
      themeName === THEME_TYPES.DARK
        ? PaperDarkTheme.colors.surface
        : globalStyleVariables.PRIMARY_COLOR,
  };
  if (themeName === THEME_TYPES.DARK) {
    theme = {
      ...PaperDarkTheme,
      ...NavigationDarkTheme,
      colors: {
        ...PaperDarkTheme.colors,
        ...NavigationDarkTheme.colors,
        ...extraColorsConfig,
      },
    };
  } else {
    theme = {
      ...PaperDefaultTheme,
      ...NavigationDefaultTheme,
      colors: {
        ...PaperDefaultTheme.colors,
        ...NavigationDefaultTheme.colors,
        ...extraColorsConfig,
      },
    };
  }
  if (!rehydrated || !navigationIsReady) {
    renderComponent = <Loader />;
  } else if (user) {
    renderComponent = <AppNavigator initialRouteName={initialRouteName} />;
  } else {
    renderComponent = <AuthNavigator />;
  }
  return (
    <PaperProvider theme={theme}>
      {(!rehydrated || !navigationIsReady) && <Loader />}
      {rehydrated && navigationIsReady && (
        <NavigationContainer
          ref={navigationRef}
          initialState={initialState}
          onStateChange={handleOnNavigationStateChange}
        >
          <View style={styles.container}>
            <StatusBar
              barStyle={
                Platform.OS === 'ios' && themeName === THEME_TYPES.LIGHT
                  ? 'dark-content'
                  : 'light-content'
              }
              backgroundColor={
                themeName === THEME_TYPES.DARK
                  ? PaperDarkTheme.colors.surface
                  : 'rgb(33,123,178)'
              }
              // translucent
              animated
            />
            {renderComponent}
            <FlashMessage />
            <ModalRoot />
            <PXSnackbar />
          </View>
        </NavigationContainer>
      )}
    </PaperProvider>
  );
};

export default App;
<commit_msg>Fix deep linking stacks<commit_after>import React, { useEffect, useState, useRef } from 'react';
import { View, StyleSheet, StatusBar, Platform } from 'react-native';
import { useSelector } from 'react-redux';
import {
  NavigationContainer,
  DefaultTheme as NavigationDefaultTheme,
  DarkTheme as NavigationDarkTheme,
  useLinking,
} from '@react-navigation/native';
import { getStateFromPath } from '@react-navigation/core';
import analytics from '@react-native-firebase/analytics';
import {
  DefaultTheme as PaperDefaultTheme,
  DarkTheme as PaperDarkTheme,
  Provider as PaperProvider,
} from 'react-native-paper';
import SplashScreen from 'react-native-splash-screen';
import FlashMessage from 'react-native-flash-message';
import AppNavigator from '../../navigations/AppNavigator';
import AuthNavigator from '../../navigations/AuthNavigator';
import Loader from '../../components/Loader';
import ModalRoot from '../../containers/ModalRoot';
import PXSnackbar from '../../components/PXSnackbar';
import { THEME_TYPES, SCREENS } from '../../common/constants';
import { globalStyleVariables } from '../../styles';
import usePrevious from '../../common/hooks/usePrevious';

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});

const getActiveRouteName = (state) => {
  const route = state.routes[state.index];

  if (route.state) {
    // Dive into nested navigators
    return getActiveRouteName(route.state);
  }

  return route.name;
};

const App = () => {
  const [initialState, setInitialState] = useState();
  const [navigationIsReady, setNavigationIsReady] = useState(false);
  const rehydrated = useSelector((state) => state.auth.rehydrated);
  const user = useSelector((state) => state.auth.user);
  const initialRouteName = useSelector(
    (state) => state.initialScreenSettings.routeName,
  );
  const themeName = useSelector((state) => state.theme.name);
  const navigationRef = useRef();
  const routeNameRef = useRef();
  const prevRehydrated = usePrevious(rehydrated);

  const { getInitialState } = useLinking(navigationRef, {
    prefixes: [
      'https://www.pixiv.net/en',
      'https://www.pixiv.net',
      'http://www.pixiv.net',
      'http://www.pixiv.net/en',
      'https://touch.pixiv.net',
      'pixiv://',
    ],
    config: {
      [SCREENS.Detail]: 'artworks/:illustId',
      [SCREENS.NovelDetail]: 'novel/show.php',
      [SCREENS.UserDetail]: 'users/:uid',
      // workaround to handle deep link to one screen with multiple path
      [`${SCREENS.Detail}-1`]: 'illusts/:illustId',
      [`${SCREENS.Detail}-2`]: 'member_illust.php',
      [`${SCREENS.NovelDetail}-1`]: 'novels/:novelId',
      [`${SCREENS.UserDetail}-1`]: 'member.php',
      [SCREENS.Login]: 'account/login',
    },
    getStateFromPath: (path, options) => {
      const state = getStateFromPath(path, options);
      const newRoutes = [...state.routes];
      // eslint-disable-next-line prefer-destructuring
      newRoutes[0].name = newRoutes[0].name.split('-')[0];
      let routes;
      if (user) {
        routes = [
          {
            name: SCREENS.Main, // Load tab navigation first
          },
          ...newRoutes,
        ];
      } else {
        routes = newRoutes;
      }
      return {
        ...state,
        routes,
      };
    },
  });

  useEffect(() => {
    Promise.race([
      getInitialState(),
      new Promise((resolve) =>
        // Timeout in 150ms if `getInitialState` doesn't resolve
        // Workaround for https://github.com/facebook/react-native/issues/25675
        setTimeout(resolve, 150),
      ),
    ])
      .catch((e) => {
        console.error('Error getting initial state ', e);
      })
      .then((state) => {
        if (state !== undefined) {
          setInitialState(state);
        }

        setNavigationIsReady(true);
      });
  }, [getInitialState]);

  useEffect(() => {
    if (rehydrated && navigationIsReady) {
      const state = navigationRef.current.getRootState();
      // Save the initial route name
      routeNameRef.current = getActiveRouteName(state);
    }
  }, [rehydrated, navigationIsReady]);

  useEffect(() => {
    if (!prevRehydrated && rehydrated) {
      SplashScreen.hide();
    }
  }, [prevRehydrated, rehydrated]);

  const handleOnNavigationStateChange = (state) => {
    const previousRouteName = routeNameRef.current;
    const currentRouteName = getActiveRouteName(state);
    if (previousRouteName !== currentRouteName) {
      analytics().logScreenView({
        screen_name: currentRouteName,
        screen_class: currentRouteName,
      });
    }
    routeNameRef.current = currentRouteName;
  };

  let renderComponent;
  let theme;
  const extraColorsConfig = {
    primary: globalStyleVariables.PRIMARY_COLOR,
    activeTint:
      themeName === THEME_TYPES.DARK
        ? '#000000'
        : globalStyleVariables.PRIMARY_COLOR,
    headerBackground:
      themeName === THEME_TYPES.DARK
        ? '#1a1a1a'
        : globalStyleVariables.PRIMARY_COLOR,
    modalTitleBackground:
      themeName === THEME_TYPES.DARK ? '#1a1a1a' : '#E9EBEE',
    bottomTabBarBackground:
      themeName === THEME_TYPES.DARK
        ? PaperDarkTheme.colors.surface
        : globalStyleVariables.PRIMARY_COLOR,
  };
  if (themeName === THEME_TYPES.DARK) {
    theme = {
      ...PaperDarkTheme,
      ...NavigationDarkTheme,
      colors: {
        ...PaperDarkTheme.colors,
        ...NavigationDarkTheme.colors,
        ...extraColorsConfig,
      },
    };
  } else {
    theme = {
      ...PaperDefaultTheme,
      ...NavigationDefaultTheme,
      colors: {
        ...PaperDefaultTheme.colors,
        ...NavigationDefaultTheme.colors,
        ...extraColorsConfig,
      },
    };
  }
  if (!rehydrated || !navigationIsReady) {
    renderComponent = <Loader />;
  } else if (user) {
    renderComponent = <AppNavigator initialRouteName={initialRouteName} />;
  } else {
    renderComponent = <AuthNavigator />;
  }

  return (
    <PaperProvider theme={theme}>
      {(!rehydrated || !navigationIsReady) && <Loader />}
      {rehydrated && navigationIsReady && (
        <NavigationContainer
          ref={navigationRef}
          initialState={initialState}
          onStateChange={handleOnNavigationStateChange}
        >
          <View style={styles.container}>
            <StatusBar
              barStyle={
                Platform.OS === 'ios' && themeName === THEME_TYPES.LIGHT
                  ? 'dark-content'
                  : 'light-content'
              }
              backgroundColor={
                themeName === THEME_TYPES.DARK
                  ? PaperDarkTheme.colors.surface
                  : 'rgb(33,123,178)'
              }
              // translucent
              animated
            />
            {renderComponent}
            <FlashMessage />
            <ModalRoot />
            <PXSnackbar />
          </View>
        </NavigationContainer>
      )}
    </PaperProvider>
  );
};

export default App;
<|endoftext|>


<commit_before>// Description:
//   Youtube Feeds
//
// Dependencies:
//   None
//
// Configuration:
//   None
//
//// Commands:
//   hubot yf add <username>
//   hubot yf remove <username>
//   hubot yf list
//
// Author:
//   Eluinhost

module.exports = function(robot) {

    robot.respond(/yf add(.*?)$/i, function(msg) {
        var name = msg.match[1];
    });

    robot.respond(/yf remove(.*?)$/i, function(msg) {
        var name = msg.match[1];
    });

    robot.respond(/yf list$/i, function(msg) {
        var name = msg.match[1];
    });
};<commit_msg>feat: Basic structure<commit_after>// Description:
//   Youtube Feeds
//
// Dependencies:
//   None
//
// Configuration:
//   None
//
//// Commands:
//   hubot yf add <username>
//   hubot yf remove <username>
//   hubot yf list
//
// Author:
//   Eluinhost

var Youtube = require('youtube-api');

module.exports = function(robot) {

    var notifcations = getNotifications();

    /**
     * @returns {Array} list of all saved notifications
     */
    function getNotifications() {
        var list = robot.brain.get('youtube-feed.notifications');
        return list || [];
    }

    /**
     * @param user
     * @param channel
     * @constructor
     */
    function YoutubeNotification(user, channel) {
        this.user = user;
        this.channel = channel;
    }

    /**
     * @param id
     * @param link
     * @constructor
     */
    function YoutubeVideo(id, link) {
        this.id = id;
        this.link = link;
    }

    /**
     * @param {String} user
     * @returns {YoutubeVideo[]}
     */
    function getYoutubeVideos(user) {
        robot.http('https://gdata.youtube.com/feeds/api/users/' + user + '/uploads?alt=json')
            .header('Accept', 'application/json')
            .get(function (err, res, body) {
                if (err) return;
                var videos = [];
                JSON.parse(body).feed.entry.forEach(function(element) {
                    videos.push(new YoutubeVideo(element.id, element.link[0]));
                });
                return videos;
            });
    }

    function saveNotifications() {
        robot.brain.set('youtube-feed.users', notifcations);
    }

    /**
     * @param {YoutubeNotification} not
     * @return {bool} true if added, false if was already in list
     */
    function addNotification(not) {
        // TODO check if notification is already in list
        notifcations.push(user);
        saveNotifications();
        return true;
    }

    /**
     * @param {YoutubeNotification} not
     * @return {bool} true if removed, false if not in list
     */
    function removeNotification(not) {
        //TODO remove the notification
        saveNotifications();
        return true;
    }

    /**
     * @param {YoutubeNotification} not
     */
    function checkForNewVideos(not) {
        var videos = getYoutubeVideos(not.user);

        //TODO check against last version and send messages for new videos
    }

    function checkAll() {
        notifcations.forEach(checkForNewVideos);
    }

    robot.respond(/yf add(.*?)$/i, function(msg) {
        var name = msg.match[1];
        if(addNotification(new YoutubeNotification(name, msg.room))) {
            msg.reply('Added notifications for: ' + name);
        } else {
            msg.reply(name + ' is already set for notifications in this channel');
        }
    });

    robot.respond(/yf remove(.*?)$/i, function(msg) {
        var name = msg.match[1];
        if(removeNotification(new YoutubeNotification(name, msg.room))) {
            msg.reply('Removed notifications for: ' + name);
        } else {
            msg.reply(name + ' is not set for notifications in this channel');
        }
    });

    robot.respond(/yf list$/i, function(msg) {
        if(notifcations.length === 0) {
            msg.reply('No notifications set for this channel');
            return;
        }
        var userList = notifcations.map(function(element) {
            return element.user;
        }).join(', ');

        msg.reply('Notifications for: ' + userList);
    });
};<|endoftext|>