<commit_before>import 'babel-polyfill';

import _ from 'lodash';
import path from 'path';
import del from 'delete';
import { Generator as SpriteGenerator } from 'league-sprites';
import { saveFile, zipItems } from './utils';
import { outputLog } from './log';
import * as statsd from './statsd';
import { findAndUpdateMongoDocument, saveMongoDocument } from './db';
import ItemSetDocument from './models/item_set';
import ChampionDocument from './models/champion';
import ItemDocument from './models/item';
import PatchVersionDocument from './models/patch_version';
import config from './config';

const PROD = config.env === 'production';

const DATA_GETTERS = {
  /* eslint-disable global-require */
  riot: require('./sources/riot.js').default,
  championgg: require('./sources/championgg.js').default,
  probuilds: require('./sources/probuilds.js').default,
  /* eslint-enable global-require */
};
const getDatas = source => DATA_GETTERS[source];

const formatSkills = (skills) => {
  let skillStr = '';
  const ults = [6, 12, 16];
  _.forEach(ults, (ult, ultIndex) => {
    // 0 => slice 0 to 6
    // 1 => slice 7 to 12
    // 2 => slice 13 to 16
    const group = _.slice(skills, ults[ultIndex - 1] || 0, ults[ultIndex]);
    const skill = _.chain(group)
      .countBy()
      .toPairs()
      .sortBy(1)
      .reverse()
      .map(0)
      .value()[0];
    skillStr += skill;
    if (ultIndex < ults.length - 1) {
      skillStr += ' > ';
    }
  });
  return skillStr;
};
const formatItemsFromId = items => items.map(i => ({
  count: 1,
  id: i,
}));

const run = () => new Promise(async (resolve, reject) => {
  // eslint-disable-next-line global-require
  const version = require('../package.json').version;
  console.log(`Version : ${version}.`);

  // == REQUESTS : Start.

  const datas = {};
  const sources = Object.keys(DATA_GETTERS);
  // eslint-disable-next-line no-restricted-syntax
  for (const source of sources) {
    outputLog(`Getting ${source} datas ...`);
    try {
      const getDatasPromise = getDatas(source);
      // eslint-disable-next-line no-await-in-loop
      datas[source] = await getDatasPromise();
    } catch (e) {
      reject(e);
      return;
    }
    outputLog(`Getting ${source} datas : done !`);
  }

  // == REQUESTS : Done.

  if (!PROD) {
    outputLog('Deleting last tmp folder ...');
  }
  try {
    del.sync(path.join(config.path.sets.outputFolder, config.path.sets.saveFolderTmp));
  } catch (e) {
    reject(e);
    return;
  }
  if (!PROD) {
    outputLog('Deleting last tmp folder : done !');
  }

  const riotPatch = datas.riot.patch;
  const championGGPatch = datas.championgg.patch;
  // Only save the datas in the database if the Riot patch and the ChampionGG patch are equal
  // It prevents datas conflicts
  if (riotPatch.startsWith(championGGPatch)) {
    if (!PROD) {
      outputLog('Riot patch equals ChampionGG patch !');
    }
    // Saving the champions, items and patch version in the database
    const champions = datas.riot.champions;
    if (!PROD) {
      outputLog('Saving the champions in the database ...');
    }
    await Promise.all(_.map(champions, async (champion) => {
      try {
        await findAndUpdateMongoDocument(ChampionDocument, { id: champion.id }, champion);
      } catch (e) {
        reject(e);
        return false; // break; equivalent for lodash
      }
      return true; // Just because the iteration needs a return
    }));
    if (!PROD) {
      outputLog('Saving the champions in the database : done !');
    }
    const items = datas.riot.items;
    if (!PROD) {
      outputLog('Saving the items in the database ...');
    }
    await Promise.all(_.map(items, async (item) => {
      try {
        await findAndUpdateMongoDocument(ItemDocument, { id: item.id }, item);
      } catch (e) {
        reject(e);
        return false; // break; equivalent for lodash
      }
      return true; // Just because the iteration needs a return
    }));
    if (!PROD) {
      outputLog('Saving the items in the database : done !');
    }
    if (!PROD) {
      outputLog('Saving the patch version in the database ...');
    }
    try {
      const patchVersionDoc = {
        patchVersion: riotPatch,
        importDate: Date.now(),
      };
      await findAndUpdateMongoDocument(PatchVersionDocument, {
        patchVersion: riotPatch,
      }, patchVersionDoc);
    } catch (e) {
      reject(e);
      return;
    }
    if (!PROD) {
      outputLog('Saving the patch version in the database : done !');
    }
  } else if (!PROD) {
    outputLog(`Riot patch : ${riotPatch}, ChampionGG patch ; ${championGGPatch} : not saving the champions/items`);
  }

  // Temp list of SetSchema (./models/item_sets.js)
  let itemSetsList = [];

  const sets = datas.championgg.sets.map((champData) => {
    const champion = _(datas.riot.champions).find(champ => champ.id === champData.champId);
    if (!champion) {
      console.error(`champion not found, id : ${champData.champId}`);
    }
    const newChampData = champData;
    newChampData.champion = champion;
    return newChampData;
  });

  const sortedSets = _.sortBy(sets, 'champion.key');

  // Saving item sets
  outputLog('Generating and saving the sets ...');
  // eslint-disable-next-line no-restricted-syntax
  for (const champData of sortedSets) {
    if (!PROD) {
      outputLog(`Generating ${champData.champion.key}/${champData.role} ...`);
    }
    const trinketItems = [
      '3340', // Warding Totem
      '3341', // Sweeping Lens
      '3363', // Farsight Alteration
    ];
    const consumeItems = [
      '2003', // Health Potion
      '2055', // Control Ward
      '2031', // Refillable Potion
      '2032', // Hunter's Potion
      '2033', // Corrupting Potion
      '2138', // Elixir of Iron
      '2139', // Elixir of Sorcery
      '2140', // Elixir of Wrath
    ];
    /* eslint-disable max-len */
    try {
      // eslint-disable-next-line prefer-template
      let skills = formatSkills(champData.skills.highestCount.order) + ` (${champData.skills.highestCount.winrate}% win - ${champData.skills.highestCount.games} games)`;
      if (formatSkills(champData.skills.highestCount.order) !== formatSkills(champData.skills.highestWinrate.order)) {
        // eslint-disable-next-line prefer-template
        skills += ' - ' + formatSkills(champData.skills.highestWinrate.order) + ` (${champData.skills.highestWinrate.winrate}% win - ${champData.skills.highestWinrate.games} games)`;
      }
      const fileData = {
        title: `${riotPatch} ${champData.role} (LISG)`,
        champion: champData.champion.key,
        role: champData.role,
        blocks: [{
          items: champData.firstItems ? formatItemsFromId([...champData.firstItems.highestCount.items.map(i => i.toString()), ...trinketItems]) : formatItemsFromId(trinketItems),
          type: champData.firstItems ? `Most frequent starters (${champData.firstItems.highestCount.winrate}% win - ${champData.firstItems.highestCount.games} games)` : 'Most frequent starters not found',
        }, {
          items: champData.firstItems ? formatItemsFromId([...champData.firstItems.highestWinrate.items.map(i => i.toString()), ...trinketItems]) : formatItemsFromId(trinketItems),
          type: champData.firstItems ? `Highest win rate starters (${champData.firstItems.highestWinrate.winrate}% win - ${champData.firstItems.highestWinrate.games} games)` : 'Highest win rate starters not found',
        }, {
          items: champData.items ? formatItemsFromId(champData.items.highestCount.items.map(i => i.toString())) : formatItemsFromId(trinketItems),
          type: champData.items ? `Most frequent build (${champData.items.highestCount.winrate}% win - ${champData.items.highestCount.games} games)` : 'Most frequent build not found',
        }, {
          items: champData.items ? formatItemsFromId(champData.items.highestWinrate.items.map(i => i.toString())) : formatItemsFromId(trinketItems),
          type: champData.items ? `Highest win rate build (${champData.items.highestWinrate.winrate}% win - ${champData.items.highestWinrate.games} games)` : 'Highest win rate build not found',
        }, {
          items: champData.trinkets ? formatItemsFromId([champData.trinkets.highestCount.item, ..._.without(trinketItems, champData.trinkets.highestCount.item), ...consumeItems]) : formatItemsFromId(consumeItems),
          // eslint-disable-next-line prefer-template
          type: champData.trinkets ? 'Consumables | ' + _.find(datas.riot.items, item => Number(item.id) === Number(champData.trinkets.highestCount.item)).name + ' : ' + champData.trinkets.highestCount.winrate + '% win - ' + champData.trinkets.highestCount.games + ' games' : 'Trinkets not found',
        }, {
          // TODO: Combine the items appearing twice or thrice in a row
          items: (datas.probuilds) ? formatItemsFromId(_.without(_.dropWhile(datas.probuilds.builds[champData.champion.key].build, item => item), undefined)) : formatItemsFromId(consumeItems),
          type: (datas.probuilds) ? `ProBuilds build order | ${skills}` : `ProBuilds items unavailable | ${skills}`,
        }],
      };
      const fileContent = {
        title: fileData.title,
        type: 'custom',
        map: 'any',
        mode: 'any',
        priority: false,
        sortrank: 1,
        champion: fileData.champion,
        blocks: fileData.blocks,
      };
      // eslint-disable-next-line no-await-in-loop
      await saveFile(path.join(config.path.sets.saveFolderTmp, config.path.sets.saveFolder, champData.champion.key, 'Recommended', `${riotPatch} ${champData.role}.json`), JSON.stringify(fileContent, null, '  '));
      itemSetsList.push({
        title: fileData.title,
        champion: fileData.champion,
        role: fileData.role,
        isCustom: false,
        author: null,
        itemBlocks: fileData.blocks,
      });
    } catch (e) {
      reject(e);
      return;
    }
    /* eslint-enable max-len */
    if (!PROD) {
      outputLog(`Generating ${champData.champion.key}/${champData.role} : done !`);
    }
  }
  statsd.setGeneratedBuildsCount(sortedSets.length);
  outputLog(`Generating and saving the sets : done ! (total: ${sortedSets.length})`);

  itemSetsList = _.sortBy(itemSetsList, itemSet => itemSet.champion);

  if (!PROD) {
    outputLog('Saving the sets in the database ...');
  }
  const itemSet = new ItemSetDocument({
    generationDate: Date.now(),
    patchVersion: riotPatch,
    sets: itemSetsList,
  });
  await saveMongoDocument(itemSet);
  if (!PROD) {
    outputLog('Saving the sets in the database : done !');
  }

  outputLog('Saving the sets : done !');

  outputLog('Zipping the sets ...');
  await zipItems();
  outputLog('Zipping the sets : done !');

  if (config.generateSprites) {
    outputLog('Generating the sprites ...');

    const sprites = ['champions', 'items'];

    // eslint-disable-next-line no-restricted-syntax
    for (const spriteType of sprites) {
      let dataType = '';
      switch (spriteType) {
        case 'champions':
          dataType = 'ChampionIcon';
          break;
        case 'items':
          dataType = 'ItemIcon';
          break;
        default:
          reject(new Error(`Unknown sprite type : ${spriteType}`));
          return;
      }
      const generatorOpts = {
        dataType,
        apiKey: config.key.riot,
        region: 'euw',
        patch: riotPatch,
        stylesheetFormat: 'css',
        stylesheetLayout: 'horizontal',
        downloadFolder: path.join(
          config.path.sprites.outputFolder,
          config.path.sprites.downloadFolder,
        ),
        spritePath: path.join(
          config.path.sprites.outputFolder,
          config.path.sprites.spritesheetFolderTmp,
          config.path.sprites.spritesheetName[spriteType],
        ),
        spriteLink: config.path.sprites.spritesheetLink[spriteType],
        stylesheetPath: path.join(
          config.path.sprites.outputFolder,
          config.path.sprites.spritesheetFolder,
          config.path.sprites.stylesheetName[spriteType],
        ),
        finalSpritesheetFolder: path.join(
          config.path.sprites.outputFolder,
          config.path.sprites.spritesheetFolder,
        ),
      };

      try {
        outputLog(`Generating the ${dataType} sprites ...`);
        const spritesGenerator = new SpriteGenerator(generatorOpts);
        // eslint-disable-next-line no-await-in-loop
        await spritesGenerator.generate();
        outputLog(`Generating the ${dataType} sprites : done !`);
      } catch (e) {
        reject(e);
        return;
      }
    }

    outputLog('Generation : done !');
  } else {
    outputLog('Not generating the sprites.');
  }

  resolve();
});

export default run;
<commit_msg>fix: handle zipping errors<commit_after>import 'babel-polyfill';

import _ from 'lodash';
import path from 'path';
import del from 'delete';
import { Generator as SpriteGenerator } from 'league-sprites';
import { saveFile, zipItems } from './utils';
import { outputLog } from './log';
import * as statsd from './statsd';
import { findAndUpdateMongoDocument, saveMongoDocument } from './db';
import ItemSetDocument from './models/item_set';
import ChampionDocument from './models/champion';
import ItemDocument from './models/item';
import PatchVersionDocument from './models/patch_version';
import config from './config';

const PROD = config.env === 'production';

const DATA_GETTERS = {
  /* eslint-disable global-require */
  riot: require('./sources/riot.js').default,
  championgg: require('./sources/championgg.js').default,
  probuilds: require('./sources/probuilds.js').default,
  /* eslint-enable global-require */
};
const getDatas = source => DATA_GETTERS[source];

const formatSkills = (skills) => {
  let skillStr = '';
  const ults = [6, 12, 16];
  _.forEach(ults, (ult, ultIndex) => {
    // 0 => slice 0 to 6
    // 1 => slice 7 to 12
    // 2 => slice 13 to 16
    const group = _.slice(skills, ults[ultIndex - 1] || 0, ults[ultIndex]);
    const skill = _.chain(group)
      .countBy()
      .toPairs()
      .sortBy(1)
      .reverse()
      .map(0)
      .value()[0];
    skillStr += skill;
    if (ultIndex < ults.length - 1) {
      skillStr += ' > ';
    }
  });
  return skillStr;
};
const formatItemsFromId = items => items.map(i => ({
  count: 1,
  id: i,
}));

const run = () => new Promise(async (resolve, reject) => {
  // eslint-disable-next-line global-require
  const version = require('../package.json').version;
  console.log(`Version : ${version}.`);

  // == REQUESTS : Start.

  const datas = {};
  const sources = Object.keys(DATA_GETTERS);
  // eslint-disable-next-line no-restricted-syntax
  for (const source of sources) {
    outputLog(`Getting ${source} datas ...`);
    try {
      const getDatasPromise = getDatas(source);
      // eslint-disable-next-line no-await-in-loop
      datas[source] = await getDatasPromise();
    } catch (e) {
      reject(e);
      return;
    }
    outputLog(`Getting ${source} datas : done !`);
  }

  // == REQUESTS : Done.

  if (!PROD) {
    outputLog('Deleting last tmp folder ...');
  }
  try {
    del.sync(path.join(config.path.sets.outputFolder, config.path.sets.saveFolderTmp));
  } catch (e) {
    reject(e);
    return;
  }
  if (!PROD) {
    outputLog('Deleting last tmp folder : done !');
  }

  const riotPatch = datas.riot.patch;
  const championGGPatch = datas.championgg.patch;
  // Only save the datas in the database if the Riot patch and the ChampionGG patch are equal
  // It prevents datas conflicts
  if (riotPatch.startsWith(championGGPatch)) {
    if (!PROD) {
      outputLog('Riot patch equals ChampionGG patch !');
    }
    // Saving the champions, items and patch version in the database
    const champions = datas.riot.champions;
    if (!PROD) {
      outputLog('Saving the champions in the database ...');
    }
    await Promise.all(_.map(champions, async (champion) => {
      try {
        await findAndUpdateMongoDocument(ChampionDocument, { id: champion.id }, champion);
      } catch (e) {
        reject(e);
        return false; // break; equivalent for lodash
      }
      return true; // Just because the iteration needs a return
    }));
    if (!PROD) {
      outputLog('Saving the champions in the database : done !');
    }
    const items = datas.riot.items;
    if (!PROD) {
      outputLog('Saving the items in the database ...');
    }
    await Promise.all(_.map(items, async (item) => {
      try {
        await findAndUpdateMongoDocument(ItemDocument, { id: item.id }, item);
      } catch (e) {
        reject(e);
        return false; // break; equivalent for lodash
      }
      return true; // Just because the iteration needs a return
    }));
    if (!PROD) {
      outputLog('Saving the items in the database : done !');
    }
    if (!PROD) {
      outputLog('Saving the patch version in the database ...');
    }
    try {
      const patchVersionDoc = {
        patchVersion: riotPatch,
        importDate: Date.now(),
      };
      await findAndUpdateMongoDocument(PatchVersionDocument, {
        patchVersion: riotPatch,
      }, patchVersionDoc);
    } catch (e) {
      reject(e);
      return;
    }
    if (!PROD) {
      outputLog('Saving the patch version in the database : done !');
    }
  } else if (!PROD) {
    outputLog(`Riot patch : ${riotPatch}, ChampionGG patch ; ${championGGPatch} : not saving the champions/items`);
  }

  // Temp list of SetSchema (./models/item_sets.js)
  let itemSetsList = [];

  const sets = datas.championgg.sets.map((champData) => {
    const champion = _(datas.riot.champions).find(champ => champ.id === champData.champId);
    if (!champion) {
      console.error(`champion not found, id : ${champData.champId}`);
    }
    const newChampData = champData;
    newChampData.champion = champion;
    return newChampData;
  });

  const sortedSets = _.sortBy(sets, 'champion.key');

  // Saving item sets
  outputLog('Generating and saving the sets ...');
  // eslint-disable-next-line no-restricted-syntax
  for (const champData of sortedSets) {
    if (!PROD) {
      outputLog(`Generating ${champData.champion.key}/${champData.role} ...`);
    }
    const trinketItems = [
      '3340', // Warding Totem
      '3341', // Sweeping Lens
      '3363', // Farsight Alteration
    ];
    const consumeItems = [
      '2003', // Health Potion
      '2055', // Control Ward
      '2031', // Refillable Potion
      '2032', // Hunter's Potion
      '2033', // Corrupting Potion
      '2138', // Elixir of Iron
      '2139', // Elixir of Sorcery
      '2140', // Elixir of Wrath
    ];
    /* eslint-disable max-len */
    try {
      // eslint-disable-next-line prefer-template
      let skills = formatSkills(champData.skills.highestCount.order) + ` (${champData.skills.highestCount.winrate}% win - ${champData.skills.highestCount.games} games)`;
      if (formatSkills(champData.skills.highestCount.order) !== formatSkills(champData.skills.highestWinrate.order)) {
        // eslint-disable-next-line prefer-template
        skills += ' - ' + formatSkills(champData.skills.highestWinrate.order) + ` (${champData.skills.highestWinrate.winrate}% win - ${champData.skills.highestWinrate.games} games)`;
      }
      const fileData = {
        title: `${riotPatch} ${champData.role} (LISG)`,
        champion: champData.champion.key,
        role: champData.role,
        blocks: [{
          items: champData.firstItems ? formatItemsFromId([...champData.firstItems.highestCount.items.map(i => i.toString()), ...trinketItems]) : formatItemsFromId(trinketItems),
          type: champData.firstItems ? `Most frequent starters (${champData.firstItems.highestCount.winrate}% win - ${champData.firstItems.highestCount.games} games)` : 'Most frequent starters not found',
        }, {
          items: champData.firstItems ? formatItemsFromId([...champData.firstItems.highestWinrate.items.map(i => i.toString()), ...trinketItems]) : formatItemsFromId(trinketItems),
          type: champData.firstItems ? `Highest win rate starters (${champData.firstItems.highestWinrate.winrate}% win - ${champData.firstItems.highestWinrate.games} games)` : 'Highest win rate starters not found',
        }, {
          items: champData.items ? formatItemsFromId(champData.items.highestCount.items.map(i => i.toString())) : formatItemsFromId(trinketItems),
          type: champData.items ? `Most frequent build (${champData.items.highestCount.winrate}% win - ${champData.items.highestCount.games} games)` : 'Most frequent build not found',
        }, {
          items: champData.items ? formatItemsFromId(champData.items.highestWinrate.items.map(i => i.toString())) : formatItemsFromId(trinketItems),
          type: champData.items ? `Highest win rate build (${champData.items.highestWinrate.winrate}% win - ${champData.items.highestWinrate.games} games)` : 'Highest win rate build not found',
        }, {
          items: champData.trinkets ? formatItemsFromId([champData.trinkets.highestCount.item, ..._.without(trinketItems, champData.trinkets.highestCount.item), ...consumeItems]) : formatItemsFromId(consumeItems),
          // eslint-disable-next-line prefer-template
          type: champData.trinkets ? 'Consumables | ' + _.find(datas.riot.items, item => Number(item.id) === Number(champData.trinkets.highestCount.item)).name + ' : ' + champData.trinkets.highestCount.winrate + '% win - ' + champData.trinkets.highestCount.games + ' games' : 'Trinkets not found',
        }, {
          // TODO: Combine the items appearing twice or thrice in a row
          items: (datas.probuilds) ? formatItemsFromId(_.without(_.dropWhile(datas.probuilds.builds[champData.champion.key].build, item => item), undefined)) : formatItemsFromId(consumeItems),
          type: (datas.probuilds) ? `ProBuilds build order | ${skills}` : `ProBuilds items unavailable | ${skills}`,
        }],
      };
      const fileContent = {
        title: fileData.title,
        type: 'custom',
        map: 'any',
        mode: 'any',
        priority: false,
        sortrank: 1,
        champion: fileData.champion,
        blocks: fileData.blocks,
      };
      // eslint-disable-next-line no-await-in-loop
      await saveFile(path.join(config.path.sets.saveFolderTmp, config.path.sets.saveFolder, champData.champion.key, 'Recommended', `${riotPatch} ${champData.role}.json`), JSON.stringify(fileContent, null, '  '));
      itemSetsList.push({
        title: fileData.title,
        champion: fileData.champion,
        role: fileData.role,
        isCustom: false,
        author: null,
        itemBlocks: fileData.blocks,
      });
    } catch (e) {
      reject(e);
      return;
    }
    /* eslint-enable max-len */
    if (!PROD) {
      outputLog(`Generating ${champData.champion.key}/${champData.role} : done !`);
    }
  }
  statsd.setGeneratedBuildsCount(sortedSets.length);
  outputLog(`Generating and saving the sets : done ! (total: ${sortedSets.length})`);

  itemSetsList = _.sortBy(itemSetsList, itemSet => itemSet.champion);

  if (!PROD) {
    outputLog('Saving the sets in the database ...');
  }
  const itemSet = new ItemSetDocument({
    generationDate: Date.now(),
    patchVersion: riotPatch,
    sets: itemSetsList,
  });
  await saveMongoDocument(itemSet);
  if (!PROD) {
    outputLog('Saving the sets in the database : done !');
  }

  outputLog('Saving the sets : done !');

  outputLog('Zipping the sets ...');
  try {
    await zipItems();
  } catch (e) {
    reject(e);
    return;
  }
  outputLog('Zipping the sets : done !');

  if (config.generateSprites) {
    outputLog('Generating the sprites ...');

    const sprites = ['champions', 'items'];

    // eslint-disable-next-line no-restricted-syntax
    for (const spriteType of sprites) {
      let dataType = '';
      switch (spriteType) {
        case 'champions':
          dataType = 'ChampionIcon';
          break;
        case 'items':
          dataType = 'ItemIcon';
          break;
        default:
          reject(new Error(`Unknown sprite type : ${spriteType}`));
          return;
      }
      const generatorOpts = {
        dataType,
        apiKey: config.key.riot,
        region: 'euw',
        patch: riotPatch,
        stylesheetFormat: 'css',
        stylesheetLayout: 'horizontal',
        downloadFolder: path.join(
          config.path.sprites.outputFolder,
          config.path.sprites.downloadFolder,
        ),
        spritePath: path.join(
          config.path.sprites.outputFolder,
          config.path.sprites.spritesheetFolderTmp,
          config.path.sprites.spritesheetName[spriteType],
        ),
        spriteLink: config.path.sprites.spritesheetLink[spriteType],
        stylesheetPath: path.join(
          config.path.sprites.outputFolder,
          config.path.sprites.spritesheetFolder,
          config.path.sprites.stylesheetName[spriteType],
        ),
        finalSpritesheetFolder: path.join(
          config.path.sprites.outputFolder,
          config.path.sprites.spritesheetFolder,
        ),
      };

      try {
        outputLog(`Generating the ${dataType} sprites ...`);
        const spritesGenerator = new SpriteGenerator(generatorOpts);
        // eslint-disable-next-line no-await-in-loop
        await spritesGenerator.generate();
        outputLog(`Generating the ${dataType} sprites : done !`);
      } catch (e) {
        reject(e);
        return;
      }
    }

    outputLog('Generation : done !');
  } else {
    outputLog('Not generating the sprites.');
  }

  resolve();
});

export default run;
<|endoftext|>


<commit_before>
import vec2 from '../vec2'
import Curve from './curve'
import AABB from '../aabb'
import {EPSILON} from '../constants'

class EllipseArc extends Curve {

  /**
   * @param {number[]} center - Center of ellipse
   * @param {number} rx - Radius along X
   * @param {number} ry - Radius along Y
   * @param {number} start - Start angle in radians
   * @param {number} end - End angle in radians
   * @param {number} xrot - Rotation of ellipse w.r.t. global X-axis
   * @param {boolean} ccw - Counter Clock Wise
   */
  constructor(center, rx, ry, start, end, xrot, ccw) {

    super();

    /**
     * @type {number[]}
     */
    this.center = center;
    /**
     * @type {number}
     */
    this.rx = rx;
    /**
     * @type {number}
     */
    this.ry = ry;
    /**
     * @type {number}
     */
    this.start = start;
    /**
     * @type {number}
     */
    this.end = end;
    /**
     * @type {boolean}
     */
    this.ccw = ccw;

    /**
     * Angle between the X axis of ellipse and global X-axis
     * @type {number}
     */
    this.xrot = xrot;

  }

  /**
   * Returns total angular span of this arc. The value is unsigned. It takes
   * into consideration the winding direction (cw/ccw) and start-end angles
   * @returns {number}
   */
  getAngleSpan() {
    let span;
    if(this.start < this.end) {
      if(this.ccw) {
        span = 2*Math.PI - (this.end-this.start);
      } else {
        span = this.end-this.start;
      }
    } else {
      if(this.ccw) {
        span = this.start-this.end;
      } else {
        span = 2*Math.PI - (this.start-this.end);
      }
    }
    return span;
  }

  /**
   * @returns {AABB}
   */
  aabb() {
    let span = this.getAngleSpan();

    if(span >= 3*Math.PI/2) {
      return new AABB({
        min : vec2.sub(this.center, [this.rx,this.ry]),
        max : vec2.add(this.center, [this.rx,this.ry])
      });
    } else if(span < Math.PI/2) {
      let ps = this.evaluate(this.start);
      let pe = this.evaluate(this.end);
      return new AABB({
        min : vec2.low(ps,pe),
        max : vec2.high(ps,pe)
      });
    } else {

      /**
       *                                ---> cw
       *                         S                      E
       *
       *     |---------------------------------------------------------|
       *     0             PI/2         PI           3*PI/2           2*PI
       *
       *                         E                      S
       *                                <--- ccw
       */
      let extremes = [];

      let PI = Math.PI;
      let keyAngles = [PI/2,PI,3*PI/2];
      for(let keyAngle of keyAngles) {
        let included = false;
        if(this.start < this.end) {
          if(this.start <= keyAngle && keyAngle <= this.end) { // Inside S <-> E
            included = !this.ccw;
          } else { // Outside S <-> E
            included = this.ccw;
          }
        } else {
          if(this.end <= keyAngle && keyAngle <= this.start) { // Inside E <-> S
            included = this.ccw;
          } else { // Outside E <-> S
            included = !this.ccw;
          }
        }
        if(included) {
          extremes.push(this.evaluate(keyAngle));
        }
      }

      if(this.start < this.end) {
        if(this.ccw) {
          extremes.push(this.evaluate(0));
        }
      } else {
        if(!this.ccw) {
          extremes.push(this.evaluate(0));
        }
      }

      extremes.push(this.evaluate(this.start));
      extremes.push(this.evaluate(this.end));
      return new AABB({
        min : vec2.low(...extremes),
        max : vec2.high(...extremes)
      });
    }
  }

  /**
   * Evaluate point on arc at angle t
   * @param {number} t - Angle in radians
   * @returns {Point2D}
   */
  evaluate(t) {
    let [cx,cy] = this.center;
    let {rx,ry} = this;
    let phi = this.xrot;
    if(phi !== 0) {
      return [
        cx + rx * Math.cos(t) * Math.cos(phi) - ry * Math.sin(t) * Math.sin(phi),
        cy + ry * Math.cos(t) * Math.sin(phi) + ry * Math.sin(t) * Math.cos(phi)
      ];
    } else {
      return [
        cx + rx * Math.cos(t),
        cy + ry * Math.sin(t)
      ];
    }
  }

  /**
   * @returns {ZCanvas~PathDefinition}
   */
  toCanvasPathDef() {
    let [cx,cy] = this.center;
    let [x1,y1] = this.evaluate(this.start);
    return {
      type : 'path',
      curveseq : [
        ['M',x1,y1],
        ['E',cx,cy,this.rx,this.ry, this.xrot,
          this.start,this.end, this.ccw?1:0]
      ]
    };
  }

  /**
   * Create circular arc that starts from pA, ends at pC and passes through pB
   * @param {Point2D} pA Start point
   * @param {Point2D} pB Through point
   * @param {Point2D} pC End point
   * @returns {EllipseArc|null}
   */
  static circularArcFrom3Points(pA,pB,pC) {
    let ax = pA[0], ay = pA[1];
    let bx = pB[0], by = pB[1];
    let cx = pC[0], cy = pC[1];

    // Ref: https://en.wikipedia.org/wiki/Circumscribed_circle#Circumcenter_coordinates
    let D = 2 * (ax * (by-cy) + bx * (cy-ay) + cx * (ay-by));
    if(Math.abs(D) < EPSILON) {
      return null;
    }
    let x = ((ax * ax + ay * ay) * (by - cy) +
      (bx * bx + by * by) * (cy - ay) +
      (cx * cx + cy * cy) * (ay - by))/D;
    let y = ((ax * ax + ay * ay) * (cx - bx) +
      (bx * bx + by * by) * (ax - cx) +
      (cx * cx + cy * cy) * (bx - ax))/D;
    let center = [x,y];

    let startAngle = EllipseArc.getCircleAngle(center, pA),
      throughAngle = EllipseArc.getCircleAngle(center, pB),
      endAngle = EllipseArc.getCircleAngle(center, pC);

    let ccw;

    /**
     *                                ---> cw
     *
     *
     *  (A)     T(1)        S           T(2)           E          T(3)
     *
     *     |---------------------------------------------------------|
     *     0                           PI                           2*PI
     *
     *  (B)     T(1)        E           T(2)           S          T(3)
     *
     *
     *                                <--- ccw
     */

    if(startAngle < endAngle) { // case A
      if(0 <= throughAngle && throughAngle < startAngle) { // A:1
        ccw = true;
      } else if(startAngle < throughAngle && throughAngle < endAngle) { // A:2
        ccw = false;
      } else if(endAngle < throughAngle && throughAngle <= 2*Math.PI) { // A:3
        ccw = true;
      }
    } else { // case B
      if(0 <= throughAngle && throughAngle < endAngle) { // B:1
        ccw = false;
      } else if(endAngle < throughAngle && throughAngle < startAngle) { // B:2
        ccw = true;
      } else if(startAngle < throughAngle && throughAngle <= 2*Math.PI) { // B:3
        ccw = false;
      }
    }

    let radius = vec2.dist(pA, center);

    return new EllipseArc(center, radius, radius, startAngle, endAngle, ccw);
  }

  static circularArcFrom2PointsAndRadius(pA, pB, radius, sideflag) {

  }

  static getCircleAngle(center, pt) {
    let dot = vec2.dot([1,0], vec2.unit(vec2.sub(pt, center)));
    if(pt[1] > center[1]) {
      return wrapAngle(Math.acos(dot));
    } else {
      return wrapAngle(2*Math.PI - Math.acos(dot));
    }
  }
}

function wrapAngle(angle) {
  while(angle < 0) {
    angle = angle + 2*Math.PI;
  }
  while(angle > 2*Math.PI) {
    angle = angle - 2*Math.PI;
  }
  return angle;
}

export default EllipseArc;<commit_msg>fix an oversight from previous change<commit_after>
import vec2 from '../vec2'
import Curve from './curve'
import AABB from '../aabb'
import {EPSILON} from '../constants'

class EllipseArc extends Curve {

  /**
   * @param {number[]} center - Center of ellipse
   * @param {number} rx - Radius along X
   * @param {number} ry - Radius along Y
   * @param {number} start - Start angle in radians
   * @param {number} end - End angle in radians
   * @param {number} xrot - Rotation of ellipse w.r.t. global X-axis
   * @param {boolean} ccw - Counter Clock Wise
   */
  constructor(center, rx, ry, start, end, xrot, ccw) {

    super();

    /**
     * @type {number[]}
     */
    this.center = center;
    /**
     * @type {number}
     */
    this.rx = rx;
    /**
     * @type {number}
     */
    this.ry = ry;
    /**
     * @type {number}
     */
    this.start = start;
    /**
     * @type {number}
     */
    this.end = end;
    /**
     * @type {boolean}
     */
    this.ccw = ccw;

    /**
     * Angle between the X axis of ellipse and global X-axis
     * @type {number}
     */
    this.xrot = xrot;

  }

  /**
   * Returns total angular span of this arc. The value is unsigned. It takes
   * into consideration the winding direction (cw/ccw) and start-end angles
   * @returns {number}
   */
  getAngleSpan() {
    let span;
    if(this.start < this.end) {
      if(this.ccw) {
        span = 2*Math.PI - (this.end-this.start);
      } else {
        span = this.end-this.start;
      }
    } else {
      if(this.ccw) {
        span = this.start-this.end;
      } else {
        span = 2*Math.PI - (this.start-this.end);
      }
    }
    return span;
  }

  /**
   * @returns {AABB}
   */
  aabb() {
    let span = this.getAngleSpan();

    if(span >= 3*Math.PI/2) {
      return new AABB({
        min : vec2.sub(this.center, [this.rx,this.ry]),
        max : vec2.add(this.center, [this.rx,this.ry])
      });
    } else if(span < Math.PI/2) {
      let ps = this.evaluate(this.start);
      let pe = this.evaluate(this.end);
      return new AABB({
        min : vec2.low(ps,pe),
        max : vec2.high(ps,pe)
      });
    } else {

      /**
       *                                ---> cw
       *                         S                      E
       *
       *     |---------------------------------------------------------|
       *     0             PI/2         PI           3*PI/2           2*PI
       *
       *                         E                      S
       *                                <--- ccw
       */
      let extremes = [];

      let PI = Math.PI;
      let keyAngles = [PI/2,PI,3*PI/2];
      for(let keyAngle of keyAngles) {
        let included = false;
        if(this.start < this.end) {
          if(this.start <= keyAngle && keyAngle <= this.end) { // Inside S <-> E
            included = !this.ccw;
          } else { // Outside S <-> E
            included = this.ccw;
          }
        } else {
          if(this.end <= keyAngle && keyAngle <= this.start) { // Inside E <-> S
            included = this.ccw;
          } else { // Outside E <-> S
            included = !this.ccw;
          }
        }
        if(included) {
          extremes.push(this.evaluate(keyAngle));
        }
      }

      if(this.start < this.end) {
        if(this.ccw) {
          extremes.push(this.evaluate(0));
        }
      } else {
        if(!this.ccw) {
          extremes.push(this.evaluate(0));
        }
      }

      extremes.push(this.evaluate(this.start));
      extremes.push(this.evaluate(this.end));
      return new AABB({
        min : vec2.low(...extremes),
        max : vec2.high(...extremes)
      });
    }
  }

  /**
   * Evaluate point on arc at angle t
   * @param {number} t - Angle in radians
   * @returns {Point2D}
   */
  evaluate(t) {
    let [cx,cy] = this.center;
    let {rx,ry} = this;
    let phi = this.xrot;
    if(phi !== 0) {
      return [
        cx + rx * Math.cos(t) * Math.cos(phi) - ry * Math.sin(t) * Math.sin(phi),
        cy + ry * Math.cos(t) * Math.sin(phi) + ry * Math.sin(t) * Math.cos(phi)
      ];
    } else {
      return [
        cx + rx * Math.cos(t),
        cy + ry * Math.sin(t)
      ];
    }
  }

  /**
   * @returns {ZCanvas~PathDefinition}
   */
  toCanvasPathDef() {
    let [cx,cy] = this.center;
    let [x1,y1] = this.evaluate(this.start);
    return {
      type : 'path',
      curveseq : [
        ['M',x1,y1],
        ['E',cx,cy,this.rx,this.ry, this.xrot,
          this.start,this.end, this.ccw?1:0]
      ]
    };
  }

  /**
   * Create circular arc that starts from pA, ends at pC and passes through pB
   * @param {Point2D} pA Start point
   * @param {Point2D} pB Through point
   * @param {Point2D} pC End point
   * @returns {EllipseArc|null}
   */
  static circularArcFrom3Points(pA,pB,pC) {
    let ax = pA[0], ay = pA[1];
    let bx = pB[0], by = pB[1];
    let cx = pC[0], cy = pC[1];

    // Ref: https://en.wikipedia.org/wiki/Circumscribed_circle#Circumcenter_coordinates
    let D = 2 * (ax * (by-cy) + bx * (cy-ay) + cx * (ay-by));
    if(Math.abs(D) < EPSILON) {
      return null;
    }
    let x = ((ax * ax + ay * ay) * (by - cy) +
      (bx * bx + by * by) * (cy - ay) +
      (cx * cx + cy * cy) * (ay - by))/D;
    let y = ((ax * ax + ay * ay) * (cx - bx) +
      (bx * bx + by * by) * (ax - cx) +
      (cx * cx + cy * cy) * (bx - ax))/D;
    let center = [x,y];

    let startAngle = EllipseArc.getCircleAngle(center, pA),
      throughAngle = EllipseArc.getCircleAngle(center, pB),
      endAngle = EllipseArc.getCircleAngle(center, pC);

    let ccw;

    /**
     *                                ---> cw
     *
     *
     *  (A)     T(1)        S           T(2)           E          T(3)
     *
     *     |---------------------------------------------------------|
     *     0                           PI                           2*PI
     *
     *  (B)     T(1)        E           T(2)           S          T(3)
     *
     *
     *                                <--- ccw
     */

    if(startAngle < endAngle) { // case A
      if(0 <= throughAngle && throughAngle < startAngle) { // A:1
        ccw = true;
      } else if(startAngle < throughAngle && throughAngle < endAngle) { // A:2
        ccw = false;
      } else if(endAngle < throughAngle && throughAngle <= 2*Math.PI) { // A:3
        ccw = true;
      }
    } else { // case B
      if(0 <= throughAngle && throughAngle < endAngle) { // B:1
        ccw = false;
      } else if(endAngle < throughAngle && throughAngle < startAngle) { // B:2
        ccw = true;
      } else if(startAngle < throughAngle && throughAngle <= 2*Math.PI) { // B:3
        ccw = false;
      }
    }

    let radius = vec2.dist(pA, center);

    return new EllipseArc(center, radius, radius, 0, startAngle, endAngle, ccw);
  }

  static circularArcFrom2PointsAndRadius(pA, pB, radius, sideflag) {

  }

  static getCircleAngle(center, pt) {
    let dot = vec2.dot([1,0], vec2.unit(vec2.sub(pt, center)));
    if(pt[1] > center[1]) {
      return wrapAngle(Math.acos(dot));
    } else {
      return wrapAngle(2*Math.PI - Math.acos(dot));
    }
  }
}

function wrapAngle(angle) {
  while(angle < 0) {
    angle = angle + 2*Math.PI;
  }
  while(angle > 2*Math.PI) {
    angle = angle - 2*Math.PI;
  }
  return angle;
}

export default EllipseArc;<|endoftext|>


<commit_before>#! /usr/bin/env node

var express = require('express'),
    os = require("os"),
    hostname = os.hostname(),
    app = express(),
    path = require('path'),
    bodyParser = require('body-parser'),
    colors = require('colors'),
    cjson = require('cjson'),
    Gpio;                    // Constructor function for Gpio objects.

/// mock gpio
function GpioMock(gpio, direction) {
  this.direction = direction;
  this.gpio = gpio;
  this.writeSync = (state) => {
    this.state = state;
    console.log(colors.grey("[INFO]"), "Setting mocked gpio state:", this.state, "for gpio", this.gpio);
    return;
  }
}
///

if (process.env.NODE_ENV ==='production') {
  Gpio = require('onoff').Gpio;
}
else {
  Gpio = GpioMock;
}

const conf = cjson.load("../config/config.json");
if (!conf.devices) {
  throw new Error("Configuration file is missing a devices property.");
}
if (!Array.isArray(conf.devices) || conf.devices.length < 1) {
  throw new Error("Configuration file is missing at least one device configuration.");
}

//settings
const SPRINKLER_BASE_URI = 'sprinklers';
// parse application/json
app.use(bodyParser.json())

// enable CORS
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

/*
 * Filter the sprinkler object for serialization
 *
 * @param spinkler [object] the sprinkler object
 * @returns the filtered object
 */
const _toObject = (sprinkler) => {
  return {
    uri: sprinkler.uri,
    id: sprinkler.id,
    name: sprinkler.name,
    gpio: sprinkler.gpio.gpio,
    isActive: sprinkler.isActive
  }
}

// inits
var sprinklers = [];
var init = () => {
  console.log(colors.grey("[INFO] Initializing sprinkler pins."));
  for (var i = 0; i < conf.devices.length; i++) {
    var sprinkler = {
      uri: '/' + path.join(SPRINKLER_BASE_URI, i.toString()),
      id: i,
      name: conf.devices[i].name,
      gpio: new Gpio(conf.devices[i].gpio, 'out'),
      isActive: conf.devices[i].isActivebyDefault || false
    };
    console.log(colors.grey("[INFO] Initializing", JSON.stringify(_toObject(sprinkler))));
    sprinkler.gpio.writeSync(1);
    sprinklers.push(sprinkler);
  }
  console.log(colors.grey("[INFO] Initialized", sprinklers.length, "sprinklers"));
}

/*
 * A matcher function for spinkler matching
 *
 * @returns true if sprinkler matches input
 */
const matchSprinkler = function(sprinkler) {
  return sprinkler.id === Number(this);
};

const plotDate = () => {
  return new Date().toISOString();
}

// list all sprinklers on GET /
app.get('/', function(req, res) {
  var services = {
    [SPRINKLER_BASE_URI] : {
      uri: '/' + SPRINKLER_BASE_URI + '/'
    }
  }
  res.status(200);
  res.json(services);
});

// retrieve information for a particular sprinkler or a list of sprinklers
app.get('/' + path.join(SPRINKLER_BASE_URI, ':id?'), (req, res) => {
  if(!req.params.id) {
    // send a list of all sprinklers
    res.status(200);
    var ret = [];
    for (var i = 0; i < sprinklers.length; i++) {
      ret.push(_toObject(sprinklers[i]));
    }
    return res.json(ret);
  }
  //else lets return the sprinkler
  var sprinkler = sprinklers.find(matchSprinkler, req.params.id);
  if (!sprinkler) {
    var err = new Error("Object not found");
    res.status(404);
    return res.json({error : err.message});
  }
  res.status(200);
  return res.json(_toObject(sprinkler));
});

app.post('/' + path.join(SPRINKLER_BASE_URI, ':id?'), (req, res) => {
  if(!req.params.id) {
    // send a list of all sprinklers
    var err = new Error("You can not create sprinklers.. I mean.. how would you?");
    res.status(400);
    return res.json({error : err.message});
  }
  //else lets return the sprinkler
  var sprinkler = sprinklers.find(matchSprinkler, req.params.id);

  if (!sprinkler) {
    var err = new Error('Object not found');
    res.status(404);
    return res.json({error : err.message});
  }

  var isActive = (req.body.isActive === true) || (req.body.isactive === true);
  if(req.body.hasOwnProperty('isActive') || req.body.hasOwnProperty('isactive')) {
    sprinkler.isActive = isActive;
    sprinkler.gpio.writeSync(isActive ? 0 : 1);
    res.status(200);
  }

  if(req.body.hasOwnProperty('name')) {
    sprinkler.name = req.body.name;
    res.status(200);
  }

  if (res.statusCode === 200) {
    console.log(colors.grey(plotDate(), "[LOG]"), "new gpio state:", _toObject(sprinkler));
    return res.json(_toObject(sprinkler));
  }

  var err = new Error('No processable payload in request body');
  res.status(400);
  return res.json({error : err.message});
});

var server = app.listen(process.env.PORT || conf.port || 3000, () => {
  console.log(colors.green("[INFO]"), "Server running on PORT", server.address().port);
});

// actual inits
init();
<commit_msg>feat(init): initialize with respeting is ActiveByDefault settings, read actual state on GET before response<commit_after>#! /usr/bin/env node

var express = require('express'),
    os = require("os"),
    hostname = os.hostname(),
    app = express(),
    path = require('path'),
    bodyParser = require('body-parser'),
    colors = require('colors'),
    cjson = require('cjson'),
    Gpio;                    // Constructor function for Gpio objects.

/// mock gpio
function GpioMock(gpio, direction) {
  this.direction = direction;
  this.gpio = gpio;
  this.writeSync = (state) => {
    this.state = state;
    console.log(colors.grey("[INFO]"), "Setting mocked gpio state:", this.state, "for gpio", this.gpio);
    return;
  }
}
///

if (process.env.NODE_ENV ==='production') {
  Gpio = require('onoff').Gpio;
}
else {
  Gpio = GpioMock;
}

const conf = cjson.load("../config/config.json");
if (!conf.devices) {
  throw new Error("Configuration file is missing a devices property.");
}
if (!Array.isArray(conf.devices) || conf.devices.length < 1) {
  throw new Error("Configuration file is missing at least one device configuration.");
}

//settings
const SPRINKLER_BASE_URI = 'sprinklers';
// parse application/json
app.use(bodyParser.json())

// enable CORS
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

/*
 * Filter the sprinkler object for serialization
 *
 * @param spinkler [object] the sprinkler object
 * @returns the filtered object
 */
const _toObject = (sprinkler) => {
  return {
    uri: sprinkler.uri,
    id: sprinkler.id,
    name: sprinkler.name,
    gpio: sprinkler.gpio.gpio,
    isActive: sprinkler.isActive
  }
}

// inits
var sprinklers = [];
var init = () => {
  console.log(colors.grey("[INFO] Initializing sprinkler pins."));
  for (var i = 0; i < conf.devices.length; i++) {
    var device = conf.devices[i];
    var sprinkler = {
      uri: '/' + path.join(SPRINKLER_BASE_URI, i.toString()),
      id: i,
      name: device.name,
      gpio: new Gpio(device.gpio, 'out'),
      isActive: device.isActiveByDefault || false
    };
    console.log(colors.grey("[INFO] Initializing", JSON.stringify(_toObject(sprinkler))));
    sprinkler.gpio.writeSync(sprinkler.isActive?0:1);
    sprinklers.push(sprinkler);
  }
  console.log(colors.grey("[INFO] Initialized", sprinklers.length, "sprinklers"));
}

/*
 * A matcher function for spinkler matching
 *
 * @returns true if sprinkler matches input
 */
const matchSprinkler = function(sprinkler) {
  return sprinkler.id === Number(this);
};

const plotDate = () => {
  return new Date().toISOString();
}

// list all sprinklers on GET /
app.get('/', function(req, res) {
  var services = {
    [SPRINKLER_BASE_URI] : {
      uri: '/' + SPRINKLER_BASE_URI + '/'
    }
  }
  res.status(200);
  res.json(services);
});

// retrieve information for a particular sprinkler or a list of sprinklers
app.get('/' + path.join(SPRINKLER_BASE_URI, ':id?'), (req, res) => {
  if(!req.params.id) {
    // send a list of all sprinklers
    res.status(200);
    var ret = [];
    for (var i = 0; i < sprinklers.length; i++) {
      ret.push(_toObject(sprinklers[i]));
    }
    return res.json(ret);
  }
  //else lets return the sprinkler
  var sprinkler = sprinklers.find(matchSprinkler, req.params.id);
  if (!sprinkler) {
    var err = new Error("Object not found");
    res.status(404);
    return res.json({error : err.message});
  }
  // get the actual status
  sprinkler.isActive = !sprinkler.gpio.readSync();
  res.status(200);
  return res.json(_toObject(sprinkler));
});

app.post('/' + path.join(SPRINKLER_BASE_URI, ':id?'), (req, res) => {
  if(!req.params.id) {
    // send a list of all sprinklers
    var err = new Error("You can not create sprinklers.. I mean.. how would you?");
    res.status(400);
    return res.json({error : err.message});
  }
  //else lets return the sprinkler
  var sprinkler = sprinklers.find(matchSprinkler, req.params.id);

  if (!sprinkler) {
    var err = new Error('Object not found');
    res.status(404);
    return res.json({error : err.message});
  }

  var isActive = (req.body.isActive === true) || (req.body.isactive === true);
  if(req.body.hasOwnProperty('isActive') || req.body.hasOwnProperty('isactive')) {
    sprinkler.isActive = isActive;
    sprinkler.gpio.writeSync(isActive ? 0 : 1);
    res.status(200);
  }

  if(req.body.hasOwnProperty('name')) {
    sprinkler.name = req.body.name;
    res.status(200);
  }

  if (res.statusCode === 200) {
    console.log(colors.grey(plotDate(), "[LOG]"), "new gpio state:", _toObject(sprinkler));
    return res.json(_toObject(sprinkler));
  }

  var err = new Error('No processable payload in request body');
  res.status(400);
  return res.json({error : err.message});
});

var server = app.listen(process.env.PORT || conf.port || 3000, () => {
  console.log(colors.green("[INFO]"), "Server running on PORT", server.address().port);
});

// actual inits
init();
<|endoftext|>


<commit_before>// geojson preview module
ckan.module('agsview', function (jQuery, _) {
  console.log(jQuery.jquery);
  return {
    options: {
      table: '

{body}

',
      row:'
{key}	{value}
',
      style: {
        opacity: 0.7,
        fillOpacity: 0.1,
        weight: 2
      },
      i18n: {
        'error': _('An error occurred: %(text)s %(error)s')
      }
    },
    initialize: function () {
      var self = this;

      self.el.empty();
      self.el.append($("

").attr("id","map"));
      self.map = ckan.commonLeafletMap('map', this.options.map_config);

      // hack to make leaflet use a particular location to look for images
      L.Icon.Default.imagePath = this.options.site_url + 'img/leaflet';
      var path = this.options.path;
      if (path.match(/\/(?:MapServer|FeatureServer)\/\d{1,3}\/?$/)) {
          this.loadJson(path);
      } else if (path.match(/\/MapServer$/)) {
        this.loadDynamic(path);
      }
    },
    loadJson: function (path) {
      var self = this;
      this.layer =  L.esri.featureLayer({
          url: path
      })
      this.layer.addTo(map);
      this.getMetaData();
    },
    loadDynamic: function (path) {
      this.layer =  L.esri.dynamicMapLayer({
            url: path,
            opacity: 0.25,
            useCors: false
        });
        this.layer.addTo(map);
        this.getMetaData();
    },
    showError: function (jqXHR, textStatus, errorThrown) {
      if (textStatus == 'error' && jqXHR.responseText.length) {
        this.el.html(jqXHR.responseText);
      } else {
        this.el.html(this.i18n('error', {text: textStatus, error: errorThrown}));
      }
    },
    getMetaData: function () {
      this.layer.metadata(function(error, metadata){
        if (error) {
          throw error;
        }
        var extent = metadata.extent;
        var wkid = extent.spatialReference.latestWkid;
        var url = 'http://epsg.io/' + wkid + '.proj4';

        jQuery.ajax(url).done(function (d) {
          var prj = proj4(d);
          var bl = prj.inverse([extent.xmin, extent.ymin]);
          var tr = prj.inverse([extent.xmax, extent.ymax]);
          self.map.fitBounds([bl.reverse(), tr.reverse()]);
        })

        console.log(metadata);
      });
    },
    showPreview: function (geojsonFeature) {
      var self = this;
      var gjLayer = L.geoJson(geojsonFeature, {
        style: self.options.style,
        onEachFeature: function(feature, layer) {
          var body = '';
          if (feature.properties) {
            Object.keys(feature.properties).forEach(function(key){
              var value = feature.propertiesp[key];
              if (value != null && typeof value === 'object') {
                value = JSON.stringify(value);
              }
              body += L.Util.template(self.options.row, {key: key, value: value});
            });
            var popupContent = L.Util.template(self.options.table, {body: body});
            layer.bindPopup(popupContent);
          }
        }
      }).addTo(self.map);
      self.map.fitBounds(gjLayer.getBounds());
    }
  };
});
<commit_msg>working dynamic<commit_after>// geojson preview module
ckan.module('agsview', function (jQuery, _) {
  console.log(jQuery.jquery);
  return {
    options: {
      table: '

{body}

',
      row:'
{key}	{value}
',
      style: {
        opacity: 0.7,
        fillOpacity: 0.1,
        weight: 2
      },
      i18n: {
        'error': _('An error occurred: %(text)s %(error)s')
      }
    },
    initialize: function () {
      var self = this;

      self.el.empty();
      self.el.append($("

").attr("id","map"));
      self.map = ckan.commonLeafletMap('map', this.options.map_config);

      // hack to make leaflet use a particular location to look for images
      L.Icon.Default.imagePath = this.options.site_url + 'img/leaflet';
      var path = this.options.path;
      if (path.match(/\/(?:MapServer|FeatureServer)\/\d{1,3}\/?$/)) {
          this.loadJson(path);
      } else if (path.match(/\/MapServer$/)) {
        this.loadDynamic(path);
      }
    },
    loadJson: function (path) {
      var self = this;
      this.layer =  L.esri.featureLayer({
          url: path
      })
      this.layer.addTo(map);
      this.getMetaData();
    },
    loadDynamic: function (path) {
      this.layer =  L.esri.dynamicMapLayer({
            url: path,
            opacity: 0.25,
            useCors: false
        });
        this.layer.addTo(map);
        this.getMetaData();
    },
    showError: function (jqXHR, textStatus, errorThrown) {
      if (textStatus == 'error' && jqXHR.responseText.length) {
        this.el.html(jqXHR.responseText);
      } else {
        this.el.html(this.i18n('error', {text: textStatus, error: errorThrown}));
      }
    },
    getMetaData: function () {
      this.layer.metadata(function(error, metadata){
        if (error) {
          throw error;
        }
        var extent = metadata.extent || metadata.fullExtent;
        var wkid = extent.spatialReference.latestWkid;
        var url = 'http://epsg.io/' + wkid + '.proj4';

        jQuery.ajax(url).done(function (d) {
          var prj = proj4(d);
          var bl = prj.inverse([extent.xmin, extent.ymin]);
          var tr = prj.inverse([extent.xmax, extent.ymax]);
          self.map.fitBounds([bl.reverse(), tr.reverse()]);
        })

        console.log(metadata);
      });
    },
    showPreview: function (geojsonFeature) {
      var self = this;
      var gjLayer = L.geoJson(geojsonFeature, {
        style: self.options.style,
        onEachFeature: function(feature, layer) {
          var body = '';
          if (feature.properties) {
            Object.keys(feature.properties).forEach(function(key){
              var value = feature.propertiesp[key];
              if (value != null && typeof value === 'object') {
                value = JSON.stringify(value);
              }
              body += L.Util.template(self.options.row, {key: key, value: value});
            });
            var popupContent = L.Util.template(self.options.table, {body: body});
            layer.bindPopup(popupContent);
          }
        }
      }).addTo(self.map);
      self.map.fitBounds(gjLayer.getBounds());
    }
  };
});
<|endoftext|>


<commit_before>import test from 'ava';
import { GithubProvider } from '../src/github-repository-provider';

const REPOSITORY_NAME = 'arlac77/sync-test-repository';

test('provider', async t => {
  const provider = new GithubProvider(process.env.GH_TOKEN);
  const repository = await provider.repository(REPOSITORY_NAME);

  t.is(repository.name, REPOSITORY_NAME);

  const branches = await repository.branches();
  t.is(branches.get('master').name, 'master');

  const branch = await repository.branch('master');
  t.is(branch.name, 'master');
});

test('create branch', async t => {
  const provider = new GithubProvider(process.env.GH_TOKEN);
  const repository = await provider.repository(REPOSITORY_NAME);
  const branches = await repository.branches();

  //t.is(branches.get('master').name, 'master');

  const newName = `test-${branches.size}`;
  const branch = await repository.createBranch(newName);

  t.is(branch.name, newName);
});

test('create commit', async t => {
  const provider = new GithubProvider(process.env.GH_TOKEN);
  const repository = await provider.repository(REPOSITORY_NAME);

  const branches = await repository.branches();

  const newName = `test-${branches.size}`;
  const branch = await repository.createBranch(newName);

  const commit = await branch.commit('message text', [
    {
      path: `README.md`,
      content: `file content #${branches.size}`
    }
  ]);

  t.is(commit.ref, `refs/heads/${newName}`);
});
<commit_msg>test: use different branch names to enable parrallel test execution<commit_after>import test from 'ava';
import { GithubProvider } from '../src/github-repository-provider';

const REPOSITORY_NAME = 'arlac77/sync-test-repository';

test('provider', async t => {
  const provider = new GithubProvider(process.env.GH_TOKEN);
  const repository = await provider.repository(REPOSITORY_NAME);

  t.is(repository.name, REPOSITORY_NAME);

  const branches = await repository.branches();
  t.is(branches.get('master').name, 'master');

  const branch = await repository.branch('master');
  t.is(branch.name, 'master');
});

test('create branch', async t => {
  const provider = new GithubProvider(process.env.GH_TOKEN);
  const repository = await provider.repository(REPOSITORY_NAME);
  const branches = await repository.branches();

  //t.is(branches.get('master').name, 'master');

  const newName = `test-${branches.size}`;
  const branch = await repository.createBranch(newName);

  t.is(branch.name, newName);
});

test('create commit', async t => {
  const provider = new GithubProvider(process.env.GH_TOKEN);
  const repository = await provider.repository(REPOSITORY_NAME);

  const branches = await repository.branches();

  const newName = `commit-test-${branches.size}`;
  const branch = await repository.createBranch(newName);

  const commit = await branch.commit('message text', [
    {
      path: `README.md`,
      content: `file content #${branches.size}`
    }
  ]);

  t.is(commit.ref, `refs/heads/${newName}`);
});
<|endoftext|>


<commit_before>/*!
 import hbd.app
 import hbd.model
 import hbEvents
 import hb.directive
 */
define('module', ['hb', 'hb.compiler', 'hb.scope', 'hb.val', 'injector', 'interpolator', 'removeHTMLComments', 'each', 'ready', 'hb.debug', 'hb.eventStash', 'debounce', 'dispatcher', 'loader'],
    function (hb, compiler, scope, val, injector, interpolator, removeHTMLComments, each, ready, debug, events, debounce, dispatcher, loader) {
//TODO: make events private. get rid of public event cache.
        events.READY = 'ready';
        events.RESIZE = 'resize';

        var mod;

        function Module() {

            var self = this;
            self.name = 'h';
            self.bootWait = 10;

            var rootEl;
            var _injector = this.injector = injector();
            var _interpolator = this.interpolator = interpolator(_injector);
            var _compiler = compiler(self);
            var compile = _compiler.compile;
            var interpolate = _interpolator.invoke;
            var injectorVal = _injector.val.bind(_injector);
            var rootScope = scope(interpolate);
            var docReady = false;
            var onAppReady = function () {
                debug.log("\tloading " + loader.getPendingCount() + " files");
                val.init(self);// flushes it to the injector val.
                if (!docReady) {
                    debug.warn("--- bootstrap before docReady ---");
                }
                if (!self.element()) {
                    debug.log("%cINITIAL COMPILE", "color:#F60");
                    self.element(document.body);// always setups up on body unless set explicitly with app.element(el)
                } else {
                    debug.log("%RE-COMPILE", "color:#F60");
                    compile(rootEl, rootScope);
                }
                // self.fire(events.READY, self);
                // rootScope.$broadcast(events.HB_READY, self);
                rootScope.$apply();
            };
            ready(function() {
                debug.log("docReady");
                docReady = true;
            });
            rootScope.$ignoreInterpolateErrors = true;
            window.addEventListener('resize', function () {
                rootScope && rootScope.$broadcast(events.RESIZE);
            });
            injectorVal('$rootScope', rootScope);

            // injector supports a pre processor so we can make our services instantiate
            // on the first call.
            _injector.preProcessor = function (key, value) {
                if (value && value.isClass) {
                    // instantiate and then override.
                    // we only do this for services because they must be singletons.
                    return _injector.instantiate(value);
                }
            };

            /**
             * Searches through elements for a scope
             * @param el
             * @returns {*}
             */
            function findScope(el) {
                if (!el) {
                    return null;
                }
                if (el.scope) {
                    return el.scope;
                }
                return findScope(el.parentNode);
            }

            function findPendingIndex(name) {
                for(var i = 0; i < bootPending.length; i += 1) {
                    if (bootPending[i].name === name) {
                        return i;
                    }
                }
                return -1;
            }

            function bootstrap(bootName, options, callback) {
                debug.log("bootstrap " + bootName, options);
                if (options) {
                    for(var i in options) {
                        if(options.hasOwnProperty(i)) {
                            debug.warn('val("' + i + '", ' + (typeof options[i] === "string" ? '"' + options[i] + '"' : options[1]) + ');');
                            val(i, options[i]);// stored temporarily. Until the val.init these are not injectable.
                        }
                    }
                    val.init(self);// flushes it to the injector val.
                }
                onAppReady();
                callback();
            }

            function addChild(parentEl, htmlStr, overrideScope, data, prepend) {
                if (!htmlStr) {
                    return;
                }
                if (parentEl !== rootEl && rootEl.contains && !rootEl.contains(parentEl)) {
                    throw new Error(debug.errors.E12, rootEl);
                }
                var scope = overrideScope || findScope(parentEl), child;
                if (prepend) {
                    // used by repeat with asyncRender
                    parentEl.insertAdjacentHTML('afterbegin', removeHTMLComments(htmlStr));
                    child = parentEl.children[0];
                } else {
                    parentEl.insertAdjacentHTML('beforeend', removeHTMLComments(htmlStr));
                    child = parentEl.children[parentEl.children.length - 1];
                }
                return compileEl(child, overrideScope || scope, !!overrideScope, data);
            }

            function compileEl(el, scope, sameScope, data) {
                var s = sameScope && scope || scope.$new(), i;
                if (data) {
                    for (i in data) {
                        if (data.hasOwnProperty(i)) {
                            s[i] = data[i];
                        }
                    }
                }
                _compiler.link(el, s);
                compile(el, scope);
                return el;
            }

            function removeChild(childEl) {
                var list;
                if (childEl.scope) {
                    childEl.scope.$destroy();
                    childEl.scope = null;
                } else {
                    //TODO: need to look up if the element has child elements that have a scope.
                    // query for go-id.
                    list = childEl.querySelectorAll(self.name + '-id');
                    each(list, removeChild);
                }
                childEl.remove();
            }

            function element(el) {
                if (typeof el !== 'undefined') {
                    rootEl = el;
                    _compiler.link(rootEl, rootScope);
                    compile(rootEl, rootScope);
                }
                return rootEl;
            }

            function service(name, ClassRef) {
                if (ClassRef === undefined) {
                    return injectorVal(name);
                }
                ClassRef.isClass = true;
                return injectorVal(name, ClassRef);
            }

            self.events = events;
            self.bindingMarkup = ['{{', '}}'];
            self.elements = {};
            self.bootstrap = bootstrap;
            self.findScope = findScope;
            self.addChild = addChild;
            self.removeChild = removeChild;
            self.compile = compileEl;
            self.interpolate = interpolate;
            self.invoke = _injector.invoke.bind(_injector);
            self.element = element;
            self.val = injectorVal;
            self.factory = injectorVal;
            self.service = service;
            self.template = injectorVal;
            self.parseBinds = function (scope, str) {
                return _compiler.parseBinds(str, scope);
            };
            dispatcher(self);
            mod = self;
        }
        // force new is handy for unit tests to create a new module with the same name.
        return function (name) {
            if (!name) {
                throw Error("Bootstrap requires name");
            }
            debug.log('register ' + name);
            var app = mod || new Module();
            app.bootstrap(name);
            if (!app.val('$app')) {
                app.val('$app', app);
                app.val('$window', window);
            }

            return app;// all get reference back to the same module instance.
        };

    });
<commit_msg>hb module no nonger waits to bootstrap. it is immediate. compile checks to make sure it doesn't double digest directives.<commit_after>/*!
 import hbd.app
 import hbd.model
 import hbEvents
 import hb.directive
 */
define('module', ['hb', 'hb.compiler', 'hb.scope', 'hb.val', 'injector', 'interpolator', 'removeHTMLComments', 'each', 'ready', 'hb.debug', 'hb.eventStash', 'debounce', 'dispatcher', 'loader'],
    function (hb, compiler, scope, val, injector, interpolator, removeHTMLComments, each, ready, debug, events, debounce, dispatcher, loader) {
//TODO: make events private. get rid of public event cache.
        events.READY = 'ready';
        events.RESIZE = 'resize';

        var mod;

        function Module() {

            var self = this;
            self.name = 'h';
            self.bootWait = 10;

            var rootEl;
            var _injector = this.injector = injector();
            var _interpolator = this.interpolator = interpolator(_injector);
            var _compiler = compiler(self);
            var compile = _compiler.compile;
            var interpolate = _interpolator.invoke;
            var injectorVal = _injector.val.bind(_injector);
            var rootScope = scope(interpolate);
            var docReady = false;
            var onAppReady = function () {
                debug.log("\tloading " + loader.getPendingCount() + " files");
                val.init(self);// flushes it to the injector val.
                if (!docReady) {
                    debug.warn("--- bootstrap before docReady ---");
                }
                if (!self.element()) {
                    debug.log("%cINITIAL COMPILE", "color:#F60");
                    self.element(document.body);// always setups up on body unless set explicitly with app.element(el)
                } else {
                    debug.log("%RE-COMPILE", "color:#F60");
                    compile(rootEl, rootScope);
                }
                // self.fire(events.READY, self);
                // rootScope.$broadcast(events.HB_READY, self);
                rootScope.$apply();
            };
            ready(function() {
                debug.log("docReady");
                docReady = true;
            });
            rootScope.$ignoreInterpolateErrors = true;
            window.addEventListener('resize', function () {
                rootScope && rootScope.$broadcast(events.RESIZE);
            });
            injectorVal('$rootScope', rootScope);

            // injector supports a pre processor so we can make our services instantiate
            // on the first call.
            _injector.preProcessor = function (key, value) {
                if (value && value.isClass) {
                    // instantiate and then override.
                    // we only do this for services because they must be singletons.
                    return _injector.instantiate(value);
                }
            };

            /**
             * Searches through elements for a scope
             * @param el
             * @returns {*}
             */
            function findScope(el) {
                if (!el) {
                    return null;
                }
                if (el.scope) {
                    return el.scope;
                }
                return findScope(el.parentNode);
            }

            function findPendingIndex(name) {
                for(var i = 0; i < bootPending.length; i += 1) {
                    if (bootPending[i].name === name) {
                        return i;
                    }
                }
                return -1;
            }

            function bootstrap(bootName, options, callback) {
                debug.log("bootstrap " + bootName, options);
                if (options) {
                    for(var i in options) {
                        if(options.hasOwnProperty(i)) {
                            debug.warn('val("' + i + '", ' + (typeof options[i] === "string" ? '"' + options[i] + '"' : options[1]) + ');');
                            val(i, options[i]);// stored temporarily. Until the val.init these are not injectable.
                        }
                    }
                    val.init(self);// flushes it to the injector val.
                }
                onAppReady();
                if(callback) {
                    callback();
                }
            }

            function addChild(parentEl, htmlStr, overrideScope, data, prepend) {
                if (!htmlStr) {
                    return;
                }
                if (parentEl !== rootEl && rootEl.contains && !rootEl.contains(parentEl)) {
                    throw new Error(debug.errors.E12, rootEl);
                }
                var scope = overrideScope || findScope(parentEl), child;
                if (prepend) {
                    // used by repeat with asyncRender
                    parentEl.insertAdjacentHTML('afterbegin', removeHTMLComments(htmlStr));
                    child = parentEl.children[0];
                } else {
                    parentEl.insertAdjacentHTML('beforeend', removeHTMLComments(htmlStr));
                    child = parentEl.children[parentEl.children.length - 1];
                }
                return compileEl(child, overrideScope || scope, !!overrideScope, data);
            }

            function compileEl(el, scope, sameScope, data) {
                var s = sameScope && scope || scope.$new(), i;
                if (data) {
                    for (i in data) {
                        if (data.hasOwnProperty(i)) {
                            s[i] = data[i];
                        }
                    }
                }
                _compiler.link(el, s);
                compile(el, scope);
                return el;
            }

            function removeChild(childEl) {
                var list;
                if (childEl.scope) {
                    childEl.scope.$destroy();
                    childEl.scope = null;
                } else {
                    //TODO: need to look up if the element has child elements that have a scope.
                    // query for go-id.
                    list = childEl.querySelectorAll(self.name + '-id');
                    each(list, removeChild);
                }
                childEl.remove();
            }

            function element(el) {
                if (typeof el !== 'undefined') {
                    rootEl = el;
                    _compiler.link(rootEl, rootScope);
                    compile(rootEl, rootScope);
                }
                return rootEl;
            }

            function service(name, ClassRef) {
                if (ClassRef === undefined) {
                    return injectorVal(name);
                }
                ClassRef.isClass = true;
                return injectorVal(name, ClassRef);
            }

            self.events = events;
            self.bindingMarkup = ['{{', '}}'];
            self.elements = {};
            self.bootstrap = bootstrap;
            self.findScope = findScope;
            self.addChild = addChild;
            self.removeChild = removeChild;
            self.compile = compileEl;
            self.interpolate = interpolate;
            self.invoke = _injector.invoke.bind(_injector);
            self.element = element;
            self.val = injectorVal;
            self.factory = injectorVal;
            self.service = service;
            self.template = injectorVal;
            self.parseBinds = function (scope, str) {
                return _compiler.parseBinds(str, scope);
            };
            dispatcher(self);
            mod = self;
        }
        // force new is handy for unit tests to create a new module with the same name.
        return function (name) {
            if (!name) {
                throw Error("Bootstrap requires name");
            }
            debug.log('register ' + name);
            var app = mod || new Module();
            app.bootstrap(name);
            if (!app.val('$app')) {
                app.val('$app', app);
                app.val('$window', window);
            }

            return app;// all get reference back to the same module instance.
        };

    });
<|endoftext|>


<commit_before>/* jshint ignore:start */
import Ember from 'ember';

export default Ember.Route.extend({
  model: function (params) {

		function sleep(milliseconds) {
		  var start = new Date().getTime();
		  for (var i = 0; i < 1e7; i++) {
		    if ((new Date().getTime() - start) > milliseconds){
		      break;
		    }
		  }
		}

    async function bar() {
      console.log('TEST 2. bar is running now');
			sleep(3000);
      if (true) {
        return 'TEST 3. i am the value of bar';
      } else {
        throw new Error('TEST Error!');
      }
    }

    async function foo() {
      console.log('TEST 1. i totally work');
			try {
				let result = await bar();
				console.log(result);
				console.log('TEST 4. now I ran');
	    } catch (err) {
	      console.log('TEST THE ERROR: ', err);
	    }
    }

		foo();

    return this.store.find('post', params.post_id);
  }
});
/* jshint ignore:end */
<commit_msg>async await with ajax<commit_after>/* jshint ignore:start */
import Ember from 'ember';

export default Ember.Route.extend({
  model: function (params) {

    async function bar() {
      console.log('TEST 2. bar is running now');
        return Ember.$.ajax({
							url: '/api/v2/users',
							type: 'GET',
							contentType: 'application/json'
					});
      }

    async function foo() {
      console.log('TEST 1. i totally work');
			try {
				let result = await bar();
				console.log('TEST ajax result', result);
				console.log('TEST 4. now I ran');
	    } catch (err) {
	      console.log('TEST THE ERROR: ', err);
	    }
    }

		foo();

    return this.store.find('post', params.post_id);
  }
});
/* jshint ignore:end */
<|endoftext|>


<commit_before>/*
 * Copyright 2015 IBM Corp.
 *
 * 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.
 */
(function () {

    var JavaWrapper = require(EclairJS_Globals.NAMESPACE + '/JavaWrapper');
    var Logger = require(EclairJS_Globals.NAMESPACE + '/Logger');
    var Utils = require(EclairJS_Globals.NAMESPACE + '/Utils');

    /**
     * @constructor
     * @memberof module:eclairjs
     * @classdesc Configuration for a Spark application. Used to set various Spark parameters as key-value pairs.
     * Most of the time, you would create a SparkConf object with new SparkConf(),  parameters you set directly on the SparkConf
     * object take priority over system properties.
     * All setter methods in this class support chaining. For example, you can write new SparkConf().setMaster("local").setAppName("My app").
     * Note that once a SparkConf object is passed to Spark, it is cloned and can no longer be modified by the user.
     * Spark does not support modifying the configuration at runtime.
     */
    var SparkConf = function (conf) {
        var jvmObj = new org.apache.spark.SparkConf();
        this.logger = Logger.getLogger("SparkConf_js");
        JavaWrapper.call(this, jvmObj);
    };

    SparkConf.prototype = Object.create(JavaWrapper.prototype);

    SparkConf.prototype.constructor = SparkConf;

    /**
     * Set a name for your application.
     * @param {string} appName
     * @returns {module:eclairjs.SparkConf}
     */
    SparkConf.prototype.setAppName = function (appName) {
        this.getJavaObject().setAppName(appName);
        return this;
    };
    /**
     * The master URL to connect to, such as "local" to run locally with one thread,
     * "local[4]" to run locally with 4 cores, or "spark://master:7077" to run on a Spark standalone cluster.
     * @param {string} master
     * @returns {module:eclairjs.SparkConf}
     */
    SparkConf.prototype.setMaster = function (master) {
        this.getJavaObject().setMaster(master);
        return this;
    };

    module.exports = SparkConf;

})();

<commit_msg>Added SparkConf.set method<commit_after>/*
 * Copyright 2015 IBM Corp.
 *
 * 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.
 */
(function () {

    var JavaWrapper = require(EclairJS_Globals.NAMESPACE + '/JavaWrapper');
    var Logger = require(EclairJS_Globals.NAMESPACE + '/Logger');
    var Utils = require(EclairJS_Globals.NAMESPACE + '/Utils');

    /**
     * @constructor
     * @memberof module:eclairjs
     * @classdesc Configuration for a Spark application. Used to set various Spark parameters as key-value pairs.
     * Most of the time, you would create a SparkConf object with new SparkConf(),  parameters you set directly on the SparkConf
     * object take priority over system properties.
     * All setter methods in this class support chaining. For example, you can write new SparkConf().setMaster("local").setAppName("My app").
     * Note that once a SparkConf object is passed to Spark, it is cloned and can no longer be modified by the user.
     * Spark does not support modifying the configuration at runtime.
     */
    var SparkConf = function (conf) {
        var jvmObj = new org.apache.spark.SparkConf();
        this.logger = Logger.getLogger("SparkConf_js");
        JavaWrapper.call(this, jvmObj);
    };

    SparkConf.prototype = Object.create(JavaWrapper.prototype);

    SparkConf.prototype.constructor = SparkConf;

    /**
     * Set a name for your application.
     * @param {string} appName
     * @returns {module:eclairjs.SparkConf}
     */
    SparkConf.prototype.setAppName = function (appName) {
        this.getJavaObject().setAppName(appName);
        return this;
    };
    /**
     * The master URL to connect to, such as "local" to run locally with one thread,
     * "local[4]" to run locally with 4 cores, or "spark://master:7077" to run on a Spark standalone cluster.
     * @param {string} master
     * @returns {module:eclairjs.SparkConf}
     */
    SparkConf.prototype.setMaster = function (master) {
        this.getJavaObject().setMaster(master);
        return this;
    };
    /**
     * Wrapper of SparkConf.set method
     * @param {string} key
     * @param {string} value
     * @returns {module:eclairjs.SparkConf}
     */
    SparkConf.prototype.set = function (key, value) {
        this.getJavaObject().set(key, value);
        return this;
    };

    module.exports = SparkConf;

})();

<|endoftext|>


<commit_before>'use strict';

var log = require('../modules/log');

exports.command = function(callback) {
  var client = this;

  this.perform(function() {
    log.command('Starting the service...');

    client
      .deleteCookies()
      .init()
      .maximizeWindow()
      .waitForElementVisible('body', 1000,
        '  - Page is ready')
      .assert.visible('aside.sidebar',
        '  - Page has sidebar')
      .click('a#start', function() {
        console.log('     ⟡ Start button clicked');
      })
    ;
  });

  if (typeof callback === 'function') {
    callback.call(client);
  }

  return client;
};
<commit_msg>Add short pause after starting service<commit_after>'use strict';

var log = require('../modules/log');

exports.command = function(callback) {
  var client = this;

  this.perform(function() {
    log.command('Starting the service...');

    client
      .deleteCookies()
      .init()
      .maximizeWindow()
      .waitForElementVisible('body', 1000,
        '  - Page is ready')
      .assert.visible('aside.sidebar',
        '  - Page has sidebar')
      .click('a#start', function() {
        console.log('     ⟡ Start button clicked');
      })
      .pause(200)
    ;
  });

  if (typeof callback === 'function') {
    callback.call(client);
  }

  return client;
};
<|endoftext|>