<commit_before>const scriptUtil = require('./script-util.js')
const path = require('path')

exports.default = async function (context) {
  if (
    context.electronPlatformName === 'win' ||
    context.electronPlatformName === 'linux'
  ) {
    return scriptUtil.executeCmd({}, 'npx', [
      'copyfiles',
      '-V',
      '-u',
      '5',
      path.resolve(context.outDir, '../apack.json'),
      context.appOutDir,
    ])
  }
}
<commit_msg>fix copy command arg<commit_after>const scriptUtil = require('./script-util.js')
const path = require('path')

exports.default = async function (context) {
  if (
    context.electronPlatformName === 'win' ||
    context.electronPlatformName === 'linux'
  ) {
    return scriptUtil.executeCmd({}, 'npx', [
      'copyfiles',
      '-V',
      '-f',
      path.resolve(context.outDir, '../apack.json'),
      context.appOutDir,
    ])
  }
}
<|endoftext|>


<commit_before>export { decoder };

const base64String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/** Mapping table for base64 (as Uint8) to index. */
let table_base64_Uint8_to_index = new Uint8Array( new ArrayBuffer(256) );
{
  for (let i = 0; i < table_base64_Uint8_to_index.length; ++i)
    table_base64_Uint8_to_index[ i ] = 255; // For identifying any non-base64 bytes.

  for (let i = 0; i < base64String.length; ++i)
    table_base64_Uint8_to_index[ base64String.codePointAt(i) ] = i;

  // Support decoding URL-safe base64 strings, as Node.js does.
  // See: https://en.wikipedia.org/wiki/Base64#URL_applications
  table_base64_Uint8_to_index['-'.charCodeAt(0)] = 62
  table_base64_Uint8_to_index['_'.charCodeAt(0)] = 63
}

/**
 *
 * @param  {ArrayBuffer} sourceBase64ArrayBuffer
 *   The input base64 data as ArrayBuffer. If the last bytes not enough 4 bytes, they will be discarded (will
 * not be decoded). If an input byte is not a legal base64 code (i.e. not A..Z, a..z, 0..0, +, /), the byte
 * will be skipped (as if it does not exist). So the input bytes can be separated by new line.
 *
 * @param  {Uint32} skipLineCount
 *   Skip how many lines in the source before decoding.
 *
 * @param  {ValueMax.Percentage.Aggregate} progressToYield
 *   Return this when every time yield.
 *
 * @param  {ValueMax.Percentage.Concrete}  progressToAdvance
 *   Increase this when every time advanced.
 *
 * @param  {Uint32} suspendByteCount
 *   Everytime so many bytes decoded, yield for releasing CPU time. Default is 1024 bytes.
 *
 * @yield {ValueMax.Percentage.Aggregate or Uint8Array}
 *   Yield ( value = progressYield ) when ( done = false ).
 *   Yield ( value = decoded data as Uint8Array ) when ( done = true ).
 */
function* decoder(
  sourceBase64ArrayBuffer, skipLineCount, progressToYield, progressToAdvance, suspendByteCount = 1024) {

  let byteCountAfterYield = 0;
  let hasEverYielded = false;  // True, if yielded at least once.

  function progress_accumulateOne_isNeedYield() {
    progressToAdvance.accumulation++;
    byteCountAfterYield++;

    if (byteCountAfterYield >= suspendByteCount) { // Every suspendByteCount, release CPU time.
      byteCountAfterYield = 0;
      hasEverYielded = true;
      return true;
    }
    return false;
  }

  let sourceByteLength = sourceBase64ArrayBuffer.byteLength;

  // Initialize progress.
  progressToAdvance.accumulation = 0;
  progressToAdvance.total = sourceByteLength;

  let sourceBytes = new Uint8Array( sourceBase64ArrayBuffer );
  let sourceIndex = 0;

  // Skip specified lines.
  {
    let skippedLineCount = 0;
    let rawByte;

    while (sourceIndex < sourceByteLength) {
      if (skippedLineCount >= skipLineCount)
        break;                  // Already skip enough lines.

      rawByte = sourceBytes[ sourceIndex++ ];

      if (progress_accumulateOne_isNeedYield()) // Every suspendByteCount, release CPU time.
        yield progressToYield;

      if (13 == rawByte) {      // "\r" (carriage return; CR)
        ++skippedLineCount;     // One line is skipped.

        // If a LF follows a CR, it is considered as CRLF sequence and viewed as the same one line.
        if ((sourceIndex < sourceByteLength) && (10 == sourceBytes[ sourceIndex ])) {
          ++sourceIndex;       // Skip it.
          if (progress_accumulateOne_isNeedYield()) // Every suspendByteCount, release CPU time.
            yield progressToYield;
        }

      } else {
        if (10 == rawByte)      // "\n" (new line; LF)
          ++skippedLineCount; // One line is skipped.
      }
    }
  }

  // Decoding base64 will result in a shorter data (about 75% (= 3 / 4) in size).
  let possibleBase64ByteLength = (sourceByteLength - sourceIndex);  // The skipped lines will not be decoded.
  let targetByteLength = Math.ceil(possibleBase64ByteLength * 0.75);
  let targetArrayBuffer = new ArrayBuffer( targetByteLength );
  let targetBytes = new Uint8Array( targetArrayBuffer );

  let resultByteCount = 0;  // Accumulate the real result byte count.

  {
    const BYTES_PER_DECODE_UNIT = 4; // A decode unit consists of 4 base64 encoded source bytes.
//    let encodedBytes = new Uint8Array( new ArrayBuffer( BYTES_PER_DECODE_UNIT ) );
    let encodedBytes = new Array( BYTES_PER_DECODE_UNIT );

    let j, encodedByte;
    while (sourceIndex < sourceByteLength) {

      // Extract 4 source bytes.
      j = 0;
      while (j < BYTES_PER_DECODE_UNIT) {
        if (sourceIndex >= sourceByteLength)
          break; // Decoding is done. (Ignore last non-4-bytes.)

        let encodedByte = table_base64_Uint8_to_index[ sourceBytes[ sourceIndex++ ] ];

        if (progress_accumulateOne_isNeedYield()) // Every suspendByteCount, release CPU time.
          yield progressToYield;

        if (255 === encodedByte)
          continue; // Skip any non-base64 bytes.

        encodedBytes[ j++ ] = encodedByte;
      }

      if (j != BYTES_PER_DECODE_UNIT)
        break; // Decoding is done. (Ignore last non-4-bytes.)

      targetBytes[resultByteCount++] =  (encodedBytes[ 0 ]       << 2) | (encodedBytes[ 1 ] >> 4);
      targetBytes[resultByteCount++] = ((encodedBytes[ 1 ] & 15) << 4) | (encodedBytes[ 2 ] >> 2);
      targetBytes[resultByteCount++] = ((encodedBytes[ 2 ] &  3) << 6) | (encodedBytes[ 3 ] & 63);
    }
  }

  // The resultBytes is a sub-range of target buffer.
  //
  // Because the source may have some non-base64 codes which will be ignored,
  // the result data may be less than target length.
  let resultBytes = new Uint8Array( targetArrayBuffer, 0, resultByteCount );

  if ((byteCountAfterYield > 0) || (false == hasEverYielded))
    yield progressToYield; // Report the progress has been 100%
  else
    ; // The last progress report is (just luckily) 100%. No need to report the progress again.

  return resultBytes;
}
<commit_msg>Update Base64ArrayBufferToUint8Array.js<commit_after>export { decoder };

const base64String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/** Mapping table for base64 (as Uint8) to index. */
let table_base64_Uint8_to_index = new Uint8Array( new ArrayBuffer(256) );
{
  for (let i = 0; i < table_base64_Uint8_to_index.length; ++i)
    table_base64_Uint8_to_index[ i ] = 255; // For identifying any non-base64 bytes.

  for (let i = 0; i < base64String.length; ++i)
    table_base64_Uint8_to_index[ base64String.codePointAt(i) ] = i;

  // Support decoding URL-safe base64 strings, as Node.js does.
  // See: https://en.wikipedia.org/wiki/Base64#URL_applications
  table_base64_Uint8_to_index['-'.charCodeAt(0)] = 62
  table_base64_Uint8_to_index['_'.charCodeAt(0)] = 63
}

/**
 *
 * @param  {ArrayBuffer} sourceBase64ArrayBuffer
 *   The input base64 data as ArrayBuffer. If the last bytes not enough 4 bytes, they will be discarded (will
 * not be decoded). If an input byte is not a legal base64 code (i.e. not A..Z, a..z, 0..0, +, /), the byte
 * will be skipped (as if it does not exist). So the input bytes can be separated by new line.
 *
 * @param  {Uint32} skipLineCount
 *   Skip how many lines in the source before decoding.
 *
 * @param  {ValueMax.Percentage.Aggregate} progressToYield
 *   Return this when every time yield.
 *
 * @param  {ValueMax.Percentage.Concrete}  progressToAdvance
 *   Increase this when every time advanced.
 *
 * @param  {Uint32} suspendByteCount
 *   Everytime so many bytes decoded, yield for releasing CPU time. Default is 1024 bytes.
 *
 * @yield {ValueMax.Percentage.Aggregate or Uint8Array}
 *   Yield ( value = progressYield ) when ( done = false ).
 *   Yield ( value = decoded data as Uint8Array ) when ( done = true ).
 */
function* decoder(
  sourceBase64ArrayBuffer, skipLineCount, progressToYield, progressToAdvance, suspendByteCount = 1024) {

  let byteCountAfterYield = 0;
  let hasEverYielded = false;  // True, if yielded at least once.

  function progress_accumulateOne_isNeedYield() {
    progressToAdvance.accumulation++;
    byteCountAfterYield++;

    if (byteCountAfterYield >= suspendByteCount) { // Every suspendByteCount, release CPU time.
      byteCountAfterYield = 0;
      hasEverYielded = true;
      return true;
    }
    return false;
  }

  let sourceByteLength = sourceBase64ArrayBuffer.byteLength;

  // Initialize progress.
  progressToAdvance.accumulation = 0;
  progressToAdvance.total = sourceByteLength;

  let sourceBytes = new Uint8Array( sourceBase64ArrayBuffer );
  let sourceIndex = 0;

  // Skip specified lines.
  {
    let skippedLineCount = 0;
    let rawByte;

    while (sourceIndex < sourceByteLength) {
      if (skippedLineCount >= skipLineCount)
        break;                  // Already skip enough lines.

      rawByte = sourceBytes[ sourceIndex++ ];

      if (progress_accumulateOne_isNeedYield()) // Every suspendByteCount, release CPU time.
        yield progressToYield;

      if (13 == rawByte) {      // "\r" (carriage return; CR)
        ++skippedLineCount;     // One line is skipped.

        // If a LF follows a CR, it is considered as CRLF sequence and viewed as the same one line.
        if ((sourceIndex < sourceByteLength) && (10 == sourceBytes[ sourceIndex ])) {
          ++sourceIndex;       // Skip it.
          if (progress_accumulateOne_isNeedYield()) // Every suspendByteCount, release CPU time.
            yield progressToYield;
        }

      } else {
        if (10 == rawByte)      // "\n" (new line; LF)
          ++skippedLineCount; // One line is skipped.
      }
    }
  }

  // Decoding base64 will result in a shorter data (about 75% (= 3 / 4) in size).
  let possibleBase64ByteLength = (sourceByteLength - sourceIndex);  // The skipped lines will not be decoded.
  let targetByteLength = Math.ceil(possibleBase64ByteLength * 0.75);
  let targetArrayBuffer = new ArrayBuffer( targetByteLength );
  let targetBytes = new Uint8Array( targetArrayBuffer );

  let resultByteCount = 0;  // Accumulate the real result byte count.

  {
    const BYTES_PER_DECODE_UNIT = 4; // A decode unit consists of 4 base64 encoded source bytes.
    let encodedBytes = new Uint8Array( new ArrayBuffer( BYTES_PER_DECODE_UNIT ) );
//    let encodedBytes = new Array( BYTES_PER_DECODE_UNIT );

    let j, encodedByte;
    while (sourceIndex < sourceByteLength) {

      // Extract 4 source bytes.
      j = 0;
      while (j < BYTES_PER_DECODE_UNIT) {
        if (sourceIndex >= sourceByteLength)
          break; // Decoding is done. (Ignore last non-4-bytes.)

        let encodedByte = table_base64_Uint8_to_index[ sourceBytes[ sourceIndex++ ] ];
// !!! ... Temp Remarked for performance test ... (2019/06/13)
//         if (progress_accumulateOne_isNeedYield()) // Every suspendByteCount, release CPU time.
//           yield progressToYield;

        if (255 === encodedByte)
          continue; // Skip any non-base64 bytes.

        encodedBytes[ j++ ] = encodedByte;
      }

      if (j != BYTES_PER_DECODE_UNIT)
        break; // Decoding is done. (Ignore last non-4-bytes.)

      targetBytes[resultByteCount++] =  (encodedBytes[ 0 ]       << 2) | (encodedBytes[ 1 ] >> 4);
      targetBytes[resultByteCount++] = ((encodedBytes[ 1 ] & 15) << 4) | (encodedBytes[ 2 ] >> 2);
      targetBytes[resultByteCount++] = ((encodedBytes[ 2 ] &  3) << 6) | (encodedBytes[ 3 ] & 63);
    }
  }

  // The resultBytes is a sub-range of target buffer.
  //
  // Because the source may have some non-base64 codes which will be ignored,
  // the result data may be less than target length.
  let resultBytes = new Uint8Array( targetArrayBuffer, 0, resultByteCount );

  if ((byteCountAfterYield > 0) || (false == hasEverYielded))
    yield progressToYield; // Report the progress has been 100%
  else
    ; // The last progress report is (just luckily) 100%. No need to report the progress again.

  return resultBytes;
}
<|endoftext|>


<commit_before>export default [
  {
    name: 'befolkning_hovedgruppe',
    query: {
      year: 'latest',
      tableName: 'befolkning_hovedgruppe',
      unit: ['prosent'],
      dimensions: [
        {
          name: 'innvkat5',
          variables: ['innvandrere']
        },
        {
          name: 'kjonn',
          variables: ['alle']
        }
      ]
    },
    drillDown: {
      page: 'befolkning',
      card: 'befolkning_hovedgruppe',
      buttonTitle: 'Gå til befolkningssammensetning'
    },
    chartKind: 'benchmark',
    compareWithSimilarRegions: true,
    additionalTitleParams: ['aar'],
    relevantFor: ['borough', 'municipality', 'county', 'commerceRegion'],
    title: params => {
      return `Innvandrere utgjorde i ${params.aar} ${params.share} av befolkningen`
    },
    subTitle: params => {
      return `For Norge var tallet ${params.share}`
    }
  },
  {
    name: 'flyktninger_befolkningsandel',
    query: {
      year: 'latest',
      tableName: 'bosatt_befolkning',
      unit: ['promille'],
      dimensions: [
        {
          name: 'bosetting',
          variables: ['bosatt_per_1000']
        }
      ]
    },
    drillDown: {
      page: 'befolkning',
      card: 'flyktninger_befolkningsandel',
      buttonTitle: 'Gå til andel bosatte'
    },
    chartKind: 'benchmark',
    compareWithSimilarRegions: true,
    additionalTitleParams: ['aar'],
    relevantFor: ['borough', 'municipality', 'county', 'commerceRegion'],
    title: params => {
      return `Bosatte flyktninger per innbygger i ${params.aar}`
    },
    subTitle: params => {
      return `For hele landet er tallet ${params.share}`
    },
  },
  {
    name: 'anmodning_vedtak',
    query: {
      year: ['2012', '2013', '2014', '2015', '2016'],
      tableName: 'bosatt_anmodede',
      unit: ['personer'],
      dimensions: [
        {
          name: 'bosetting',
          variables: ['anmodning', 'vedtak']
        }
      ]
    },
    drillDown: {
      page: 'befolkning',
      card: 'bosatt_anmodede',
      buttonTitle: 'Gå til bosettingsstatistikk'
    },
    chartKind: 'line',
    compareWithSimilarRegions: false,
    additionalTitleParams: [],
    relevantFor: ['municipality', 'county', 'commerceRegion'],
    title: params => {
      return `Anmodning og vedtak om bosetting over tid`
    },
    subTitle: params => {
      return null
    },
  },
  {
    name: 'tilskudd',
    query: {
      year: 'latest',
      tableName: 'tilskudd',
      unit: ['kroner'],
      dimensions: [
        {
          name: 'tilskuddTilKommuner',
          variables: ['totalt']
        }
      ]
    },
    drillDown: {
      page: 'tilskudd',
      card: 'tilskudd',
      buttonTitle: 'Gå til tilskudd'
    },
    chartKind: 'benchmark',
    compareWithSimilarRegions: true,
    additionalTitleParams: ['aar'],
    relevantFor: ['municipality', 'county', 'commerceRegion'],
    title: params => {
      return `IMDi utbetalte ${params.share} i tilskudd i ${params.aar}`
    },
    subTitle: params => {
      return null
    },
  },
  {
    name: 'innvandrere_intro_arbeid',
    query: {
      year: 'latest',
      tableName: 'intro_status_arbutd',
      unit: ['prosent'],
      dimensions: [
        {
          name: 'avslutta',
          variables: ['ettaar']
        },
        {
          name: 'avslstat4',
          variables: ['arbutd']
        },
        {
          name: 'kjonn',
          variables: ['alle']
        }
      ]
    },
    drillDown: {
      page: 'kvalifisering',
      card: 'status-etter-intro',
      buttonTitle: 'Gå til resultater fra introprogrammet'
    },
    chartKind: 'benchmark',
    compareWithSimilarRegions: true,
    additionalTitleParams: [],
    relevantFor: ['borough', 'municipality', 'county', 'commerceRegion'],
    title: params => {
      return `Deltakere som avsluttet introprogram i 2013 - andel i arbeid og utdanning i 2014`
    },
    subTitle: params => {
      return `Gjennomsnittet i Norge er ${params.share}`
    },
  },
  {
    name: 'i_arbeid',
    query: {
      year: 'latest',
      tableName: 'sysselsatte_innvkat',
      unit: ['prosent'],
      dimensions: [
        {
          name: 'innvkat3',
          variables: ['innvandrere', 'befolkningen_ellers']
        }
      ]
    },
    drillDown: {
      page: 'arbeid',
      card: 'sysselsatte-innvkat',
      buttonTitle: 'Gå til sysselsetting'
    },
    chartKind: 'bar',
    compareWithSimilarRegions: false,
    additionalTitleParams: ['innvkat3', 'aar'],
    relevantFor: ['borough', 'municipality', 'county', 'commerceRegion'],
    title: params => {
      return `${params.share} av ${params.innvkat3.replace('_', ' ')} var i arbeid i ${params.aar}`
    },
    subTitle: params => {
      return `For hele landet er tallet ${params.share}`
    },
  }
]
<commit_msg>Present simplified title if we're missing some data<commit_after>export default [
  {
    name: 'befolkning_hovedgruppe',
    query: {
      year: 'latest',
      tableName: 'befolkning_hovedgruppe',
      unit: ['prosent'],
      dimensions: [
        {
          name: 'innvkat5',
          variables: ['innvandrere']
        },
        {
          name: 'kjonn',
          variables: ['alle']
        }
      ]
    },
    drillDown: {
      page: 'befolkning',
      card: 'befolkning_hovedgruppe',
      buttonTitle: 'Gå til befolkningssammensetning'
    },
    chartKind: 'benchmark',
    compareWithSimilarRegions: true,
    additionalTitleParams: ['aar'],
    relevantFor: ['borough', 'municipality', 'county', 'commerceRegion'],
    title: params => {
      return `Innvandrere utgjorde i ${params.aar} ${params.share} av befolkningen`
    },
    subTitle: params => {
      return `For Norge var tallet ${params.share}`
    }
  },
  {
    name: 'flyktninger_befolkningsandel',
    query: {
      year: 'latest',
      tableName: 'bosatt_befolkning',
      unit: ['promille'],
      dimensions: [
        {
          name: 'bosetting',
          variables: ['bosatt_per_1000']
        }
      ]
    },
    drillDown: {
      page: 'befolkning',
      card: 'flyktninger_befolkningsandel',
      buttonTitle: 'Gå til andel bosatte'
    },
    chartKind: 'benchmark',
    compareWithSimilarRegions: true,
    additionalTitleParams: ['aar'],
    relevantFor: ['borough', 'municipality', 'county', 'commerceRegion'],
    title: params => {
      if (params.share) {
        return `Bosatte ${params.share} flyktninger per innbygger i ${params.aar}`
      }
      return `Bosatte flyktninger per innbygger i ${params.aar}`
    },
    subTitle: params => {
      return `For hele landet er tallet ${params.share}`
    },
  },
  {
    name: 'anmodning_vedtak',
    query: {
      year: ['2012', '2013', '2014', '2015', '2016'],
      tableName: 'bosatt_anmodede',
      unit: ['personer'],
      dimensions: [
        {
          name: 'bosetting',
          variables: ['anmodning', 'vedtak']
        }
      ]
    },
    drillDown: {
      page: 'befolkning',
      card: 'bosatt_anmodede',
      buttonTitle: 'Gå til bosettingsstatistikk'
    },
    chartKind: 'line',
    compareWithSimilarRegions: false,
    additionalTitleParams: [],
    relevantFor: ['municipality', 'county', 'commerceRegion'],
    title: params => {
      return `Anmodning og vedtak om bosetting over tid`
    },
    subTitle: params => {
      return null
    },
  },
  {
    name: 'tilskudd',
    query: {
      year: 'latest',
      tableName: 'tilskudd',
      unit: ['kroner'],
      dimensions: [
        {
          name: 'tilskuddTilKommuner',
          variables: ['totalt']
        }
      ]
    },
    drillDown: {
      page: 'tilskudd',
      card: 'tilskudd',
      buttonTitle: 'Gå til tilskudd'
    },
    chartKind: 'benchmark',
    compareWithSimilarRegions: true,
    additionalTitleParams: ['aar'],
    relevantFor: ['municipality', 'county', 'commerceRegion'],
    title: params => {
      return `IMDi utbetalte ${params.share} i tilskudd i ${params.aar}`
    },
    subTitle: params => {
      return null
    },
  },
  {
    name: 'innvandrere_intro_arbeid',
    query: {
      year: 'latest',
      tableName: 'intro_status_arbutd',
      unit: ['prosent'],
      dimensions: [
        {
          name: 'avslutta',
          variables: ['ettaar']
        },
        {
          name: 'avslstat4',
          variables: ['arbutd']
        },
        {
          name: 'kjonn',
          variables: ['alle']
        }
      ]
    },
    drillDown: {
      page: 'kvalifisering',
      card: 'status-etter-intro',
      buttonTitle: 'Gå til resultater fra introprogrammet'
    },
    chartKind: 'benchmark',
    compareWithSimilarRegions: true,
    additionalTitleParams: ['aar'],
    relevantFor: ['borough', 'municipality', 'county', 'commerceRegion'],
    title: params => {
      if (params.share) {
        return `${params.share} av deltakerne går direkte fra introprogram til arbeid`
      }
      const previousYear = Number(params.aar) - 1
      return `Deltakere som avsluttet introprogram i ${previousYear} - andel i arbeid og utdanning i ${params.aar}`
    },
    subTitle: params => {
      return `Gjennomsnittet i Norge er ${params.share}`
    },
  },
  {
    name: 'i_arbeid',
    query: {
      year: 'latest',
      tableName: 'sysselsatte_innvkat',
      unit: ['prosent'],
      dimensions: [
        {
          name: 'innvkat3',
          variables: ['innvandrere', 'befolkningen_ellers']
        }
      ]
    },
    drillDown: {
      page: 'arbeid',
      card: 'sysselsatte-innvkat',
      buttonTitle: 'Gå til sysselsetting'
    },
    chartKind: 'bar',
    compareWithSimilarRegions: false,
    additionalTitleParams: ['innvkat3', 'aar'],
    relevantFor: ['borough', 'municipality', 'county', 'commerceRegion'],
    title: params => {
      return `${params.share} av ${params.innvkat3.replace('_', ' ')} var i arbeid i ${params.aar}`
    },
    subTitle: params => {
      return `For hele landet er tallet ${params.share}`
    },
  }
]
<|endoftext|>


<commit_before>'use strict';

import React from 'react';
import {Link} from 'react-router';
import Component from '../components/component.react';
import {signOut} from '../users/actions';
import {flash} from '../flashMessages/actions';

class Header extends Component {

  constructor(props) {
    super(props);
    this.state = {
      menu: false,
      mobileMenu: false
    };
  }

  componentDidMount() {
    this.props.router.getLocation()
                     .addChangeListener(this.closeMenu.bind(this));
  }

  componentWillUnmount() {
    this.props.router.getLocation()
                     .removeChangeListener(this.closeMenu);
  }

  closeMenu() {
    if (this.isMounted)
      this.setState({
        menu: false,
        mobileMenu: false
      });
  }

  signOut() {
    signOut();

    flash('Successfuly signed out.');

    this.props.router.transitionTo('signin');
  }

  onDesktopMenuClick(e) {
    e.preventDefault();
    if (!this.state.mobileMenu)
      this.setState({
        menu: !this.state.menu,
        mobileMenu: false
      });
  }

  onMobileMenuClick(e) {
    e.preventDefault();
    this.setState({
      menu: !this.state.mobileMenu,
      mobileMenu: !this.state.mobileMenu
    });
  }

  render() {
    let className = ['dropdown'];
    let mobileClassName = ['navbar-collapse', 'collapse'];
    if (this.state.menu)
      className.push('open');
    if (this.state.mobileMenu)
      mobileClassName.push('in');

    let menu = [
      'dashboard', 'applications', 'messages',
      'templates', 'directory'
    ];
    let user = {};
    if (this.props.user) {
      user = this.props.user;
      if (user.role === 'admin') {
        menu.push('users');
        menu.push('phones');
        menu.push('inbox');
      }
    }

    return (

            <Link to="dashboard" className="navbar-brand">
              smsgw
            </Link>

            <button type="button"
                    className="navbar-toggle collapsed"
                    onClick={e => this.onMobileMenuClick(e)}>
              Toggle navigation

            </button>

                {menu.map(item => {
                  return
<Link to={item}>{item}</Link>
;
                })}

                   this.onDesktopMenuClick(e)}
                     className="dropdown-toggle"
                     role="button"
                     aria-expanded="false">

{user.firstName} {user.lastName}

{user.company}

{user.email}

<Link to="settings">Settings</Link>

                       this.signOut(e)}>Sign out

    );
  }

}

Header.propTypes = {
  router: React.PropTypes.func.isRequired
};

export default Header;
<commit_msg>Header: removing unmount check<commit_after>'use strict';

import React from 'react';
import {Link} from 'react-router';
import Component from '../components/component.react';
import {signOut} from '../users/actions';
import {flash} from '../flashMessages/actions';

class Header extends Component {

  constructor(props) {
    super(props);
    this.state = {
      menu: false,
      mobileMenu: false
    };
  }

  componentDidMount() {
    this.props.router.getLocation()
                     .addChangeListener(this.closeMenu.bind(this));
  }

  componentWillUnmount() {
    this.props.router.getLocation()
                     .removeChangeListener(this.closeMenu);
  }

  closeMenu() {
    this.setState({
      menu: false,
      mobileMenu: false
    });
  }

  signOut() {
    signOut();

    flash('Successfuly signed out.');

    this.props.router.transitionTo('signin');
  }

  onDesktopMenuClick(e) {
    e.preventDefault();
    if (!this.state.mobileMenu)
      this.setState({
        menu: !this.state.menu,
        mobileMenu: false
      });
  }

  onMobileMenuClick(e) {
    e.preventDefault();
    this.setState({
      menu: !this.state.mobileMenu,
      mobileMenu: !this.state.mobileMenu
    });
  }

  render() {
    let className = ['dropdown'];
    let mobileClassName = ['navbar-collapse', 'collapse'];
    if (this.state.menu)
      className.push('open');
    if (this.state.mobileMenu)
      mobileClassName.push('in');

    let menu = [
      'dashboard', 'applications', 'messages',
      'templates', 'directory'
    ];
    let user = {};
    if (this.props.user) {
      user = this.props.user;
      if (user.role === 'admin') {
        menu.push('users');
        menu.push('phones');
        menu.push('inbox');
      }
    }

    return (

            <Link to="dashboard" className="navbar-brand">
              smsgw
            </Link>

            <button type="button"
                    className="navbar-toggle collapsed"
                    onClick={e => this.onMobileMenuClick(e)}>
              Toggle navigation

            </button>

                {menu.map(item => {
                  return
<Link to={item}>{item}</Link>
;
                })}

                   this.onDesktopMenuClick(e)}
                     className="dropdown-toggle"
                     role="button"
                     aria-expanded="false">

{user.firstName} {user.lastName}

{user.company}

{user.email}

<Link to="settings">Settings</Link>

                       this.signOut(e)}>Sign out

    );
  }

}

Header.propTypes = {
  router: React.PropTypes.func.isRequired
};

export default Header;
<|endoftext|>


<commit_before>// Conventions
//	1) All Views must have their HTML element tags
//      include a CSS class named .view.
// 	2) Before registering routes with router,
//      the viewmodels should exist.
// ----------------------------------------------
define(['jquery', 'underscore','sammy', 'presenter','config', 'routeMediator'],
    function ($, _, Sammy, presenter, config, routeMediator) {
        var
            window = config.window,
            logger = config.logger,
            isRedirecting = false,

            sammy = new Sammy.Application(function () {
                if (Sammy.Title) {
                    this.use(Sammy.Title);
                    this.setTitle(config.title);
                }else {
                    logger.warning('Sammy.Title is not loaded.');
                }
                this.get('', function () {
                    this.app.runRoute('get', startupUrl);
                });
            }),

            startupUrl = '',

            register = function (options) {
                if (options.routes) {
                    _.each(options.routes, function (route) {
                        registerRoute(route.route, route.title, route.callback, options.view, route.group);
                    });
                    return;
                }

                registerRoute(options.route, options.title, options.callback, options.view, options.group);
            },

            registerRoute = function (route, title, callback, view, group) {
                if (!callback) {
                    throw Error('callback must be specified.');
                }
                //var hash = new RegExp('#\\/' + route + '.*')
                //var hash = new RegExp('\\^' + route + '$.*')

                sammy.get(route, function (context) {
                    //context is 'this'
                    callback(context.params);
                    $('.view').hide();
                    presenter.transitionTo($(view), context.path, group);
                    //context.$element().append('
hello
') //PAPA: for testing
                    this.title(title);
                });
            },

            navigateTo = function (url) {
                //window.location.href = url;
                sammy.setLocation(url); //TODO: test this
            },

            registerBeforeLeaving = function () {
                sammy.before(/.*/, function () {
                    // Can cancel the route if this returns false
                    var
                        context = this,
                        response = routeMediator.canLeave();
                    if (!isRedirecting && !response.val) {
                        isRedirecting = true;
                        logger.warning(response.message);

                        // Keep hash url the same in address bar
                        window.history.back();
                        //this.redirect('#/Sessions');

                    } else {
                        isRedirecting = false;
                    }
                    return response.val;
                });

            },

            run = function (url) {
                startupUrl = url
                registerBeforeLeaving();
                sammy.run();
                navigateTo(url);
            };

        return {
            navigateTo: navigateTo,
            register: register,
            run: run
        };
    });
<commit_msg>Whitepsace fixes<commit_after>// Conventions
//	1) All Views must have their HTML element tags
//      include a CSS class named .view.
// 	2) Before registering routes with router,
//      the viewmodels should exist.
// ----------------------------------------------
define(['jquery', 'underscore','sammy', 'presenter','config', 'routeMediator'],
    function ($, _, Sammy, presenter, config, routeMediator) {
        var
            window = config.window,
            logger = config.logger,
            isRedirecting = false,
            startupUrl = '',

            sammy = new Sammy.Application(function () {
                if (Sammy.Title) {
                    this.use(Sammy.Title);
                    this.setTitle(config.title);
                }else {
                    logger.warning('Sammy.Title is not loaded.');
                }
                this.get('', function () {
                    this.app.runRoute('get', startupUrl);
                });
            }),

            register = function (options) {
                if (options.routes) {
                    _.each(options.routes, function (route) {
                        registerRoute(route.route, route.title, route.callback, options.view, route.group);
                    });
                    return;
                }

                registerRoute(options.route, options.title, options.callback, options.view, options.group);
            },

            registerRoute = function (route, title, callback, view, group) {
                if (!callback) {
                    throw Error('callback must be specified.');
                }
                //var hash = new RegExp('#\\/' + route + '.*')
                //var hash = new RegExp('\\^' + route + '$.*')

                sammy.get(route, function (context) {
                    //context is 'this'
                    callback(context.params);
                    $('.view').hide();
                    presenter.transitionTo($(view), context.path, group);
                    //context.$element().append('
hello
') //PAPA: for testing
                    this.title(title);
                });
            },

            navigateTo = function (url) {
                //window.location.href = url;
                sammy.setLocation(url); //TODO: test this
            },

            registerBeforeLeaving = function () {
                sammy.before(/.*/, function () {
                    // Can cancel the route if this returns false
                    var
                        context = this,
                        response = routeMediator.canLeave();

                    if (!isRedirecting && !response.val) {
                        isRedirecting = true;
                        logger.warning(response.message);
                        // Keep hash url the same in address bar
                        window.history.back();
                        //this.redirect('#/Sessions');
                    }
                    else {
                        isRedirecting = false;
                    }
                    return response.val;
                });
            },

            run = function (url) {
                startupUrl = url;
                registerBeforeLeaving();
                sammy.run();
                navigateTo(url);
            };

        return {
            navigateTo: navigateTo,
            register: register,
            run: run
        };
    });<|endoftext|>


<commit_before>/* Client Side JavaScript */

/* Init window */
function init() {

	var socket = io.connect('/client'),
	    avatars = {},
	    big_avatars = {},
	    _me = {};

	function update_me(data) {
		if(data.mypresence) {
			_me.mypresence = data.mypresence;
			_me.network = data.network;
			_me.address = data.address;
		}
	}

	function escape(str) { return $('').text(str).html(); }

	/* */
	socket.on('status-reply', function(backends) {
		var b;
		for(b in backends) if(backends.hasOwnProperty(b)) {
			$('#backends').html('');
		}
	});

	/* Timer to update backends */
	function backends_loop() {
		socket.emit('status');
		setTimeout(backends_loop, 10000);
	}
	backends_loop();

	/* Get avatar */
	function get_avatar(email, fn) {
		if(avatars[email] && big_avatars[email]) return fn(avatars[email], big_avatars[email]);
		function do_set_gravatar(email, url, options) {
			if(options && (options.s >= 50) ) {
				big_avatars[email] = url;
			} else {
				avatars[email] = url;
			}
			if(big_avatars[email] && avatars[email]) {
				fn(avatars[email], big_avatars[email]);
			} else {
				socket.once('set-gravatar', do_set_gravatar);
				socket.emit('get-gravatar', email, {s: '200', d:'identicon', r: 'pg'}, false);
			}
		}
		socket.once('set-gravatar', do_set_gravatar);
		socket.emit('get-gravatar', email, {s: '32', d:'identicon', r: 'pg'}, false);
	}

	// set cookie if/when receiving api key
	socket.once('joined', function (apikey) {
		$.cookie('the_magic_oulu_cookie', apikey, { expires: 365, path: '/' });
		console.log('Client joined, magic cookie set with apikey '+ apikey);
		$('#apikey').val(apikey);
	});

	socket.on('rejected-apikey', function () {
		console.log('api key rejected, requesting new api key from server');
		socket.emit('create');
	});

	// request api key if cookie not found
	if (! $.cookie('the_magic_oulu_cookie')) {
		console.log('Requesting api key from server');
		socket.emit('create');
	} else {
		console.log('Existing cookie found, sending apikey to server');
		socket.emit('join',  $.cookie('the_magic_oulu_cookie'));
	};

        function handle_msg(data) {
	    console.log("Handling new MSG.");
	    get_avatar(data['address'], function(url, bigurl) {
		function img() {
		    if(url) return '';
		    return '';
		}

		update_me(data);

		$('#ircrows').prepend('
<div style="float: left; margin-right: 8px;"'+img()+'

'+ data.channel +'
'+
				      escape(HHmm(data.time))+
				      ' <'+
				      escape(data.presence)+
				      '> '+
				      make_urls(escape(data.msg))+
				      '

');
		$('.ircrow').fadeIn('slow');
		if(url) $('.imgurl').imgPreview({ imgCSS: { width: 200 } });
		if (data.msg.match(/(.*).(jpg|gif|jpeg|png)$/)) {
		    $('.imgurl').imgPreview({ imgCSS: { width: 200 } });
		};
	    });
	}

	// receive line from IRC
	socket.on('icecap-event', function (name, data) {
		console.log("icecap-event received: '" + name + "'");
		if(name == 'msg') {
		    handle_msg(data);
		};
		if(name == 'channel_presence_added') {
			function escape(str) { return $('').text(str).html(); }
			$('#ircrows').prepend('
'+
                    escape(HHmm(data.time))+ ' '+
                    escape(data.presence)+
                    ' joined'+
                    '

');
			$('.ircrow').fadeIn('slow');
		};
		if(name == 'channel_presence_removed') {
			function escape(str) { return $('').text(str).html(); }
			$('#ircrows').prepend('
'+
                    escape(HHmm(data.time))+ ' '+
                    escape(data.presence)+
                    ' left'+
                    '

');
			$('.ircrow').fadeIn('slow');
		};

	});

	// send line to IRC
	$('#sendmsgform').submit(function (event) {
		event.preventDefault();
	        handle_msg({ 'time': new Date().getTime(), 'presence': 'Me', 'network' : 'freenode', 'channel' : '#node.js', 'msg': $('#prompt').val() });
		socket.emit('icecap.command', 'msg', { 'network' : 'freenode', 'channel' : '#node.js', 'msg': $('#prompt').val() } );

		// clear the text field
		$('#prompt').val('');
	});

	// preferences menu
	$('#commit-button').click(function() {
		$('.modal').slideToggle('slow', function() {
			socket.emit('icecap.command', 'presence set', {'network' : 'freenode', 'mypresence' : 'dgfrtr', 'real_name' : 'derp' } );
			$.cookie('the_magic_oulu_cookie', $('#apikey').val(), { expires: 365, path: '/' });
 		});
	});

	$('#toggle-button').click(function() {
		$('.modal').slideToggle('slow', function() {
 		});
	});

	$('#timelinetab').click(function() {
		$('.tabcontent').hide();
		$('#ircrows').show();
		$('.tab').removeClass('active');
		$('#timelinetab').addClass('active');
	});

	$('#guidetab').click(function() {
		$('.tabcontent').hide();
		$('#guide').show();
		$('.tab').removeClass('active');
		$('#guidetab').addClass('active');
	});

}

// jquery
$(document).ready(function() {
	init();
});

/* EOF */
<commit_msg>Updated<commit_after>/* Client Side JavaScript */

/* Init window */
function init() {

	var socket = io.connect('/client'),
	    avatars = {},
	    big_avatars = {},
	    _me = {'networks':{}};

	function update_me(data) {
		// Select first mypresence
		if((!_me.mypresence) && data.mypresence) {
			_me.mypresence = data.mypresence;
			_me.network = data.network;
			_me.address = data.address;
		}
	}

	function escape(str) { return $('').text(str).html(); }

	/* */
	socket.on('status-reply', function(backends) {
		var b;
		for(b in backends) if(backends.hasOwnProperty(b)) {
			$('#backends').html('');
		}
	});

	/* Timer to update backends */
	function backends_loop() {
		socket.emit('status');
		setTimeout(backends_loop, 10000);
	}
	backends_loop();

	/* Get avatar */
	function get_avatar(email, fn) {
		if(avatars[email] && big_avatars[email]) return fn(avatars[email], big_avatars[email]);
		function do_set_gravatar(email, url, options) {
			if(options && (options.s >= 50) ) {
				big_avatars[email] = url;
			} else {
				avatars[email] = url;
			}
			if(big_avatars[email] && avatars[email]) {
				fn(avatars[email], big_avatars[email]);
			} else {
				socket.once('set-gravatar', do_set_gravatar);
				socket.emit('get-gravatar', email, {s: '200', d:'identicon', r: 'pg'}, false);
			}
		}
		socket.once('set-gravatar', do_set_gravatar);
		socket.emit('get-gravatar', email, {s: '32', d:'identicon', r: 'pg'}, false);
	}

	// set cookie if/when receiving api key
	socket.once('joined', function (apikey) {
		$.cookie('the_magic_oulu_cookie', apikey, { expires: 365, path: '/' });
		console.log('Client joined, magic cookie set with apikey '+ apikey);
		$('#apikey').val(apikey);
	});

	socket.on('rejected-apikey', function () {
		console.log('api key rejected, requesting new api key from server');
		socket.emit('create');
	});

	// request api key if cookie not found
	if (! $.cookie('the_magic_oulu_cookie')) {
		console.log('Requesting api key from server');
		socket.emit('create');
	} else {
		console.log('Existing cookie found, sending apikey to server');
		socket.emit('join',  $.cookie('the_magic_oulu_cookie'));
	};

        function handle_msg(data) {
	    console.log("Handling new MSG.");
	    get_avatar(data['address'], function(url, bigurl) {
		function img() {
		    if(url) return '';
		    return '';
		}

		update_me(data);

		$('#ircrows').prepend('
<div style="float: left; margin-right: 8px;"'+img()+'

'+ data.channel +'
'+
				      escape(HHmm(data.time))+
				      ' <'+
				      escape(data.presence)+
				      '> '+
				      make_urls(escape(data.msg))+
				      '

');
		$('.ircrow').fadeIn('slow');
		if(url) $('.imgurl').imgPreview({ imgCSS: { width: 200 } });
		if (data.msg.match(/(.*).(jpg|gif|jpeg|png)$/)) {
		    $('.imgurl').imgPreview({ imgCSS: { width: 200 } });
		};
	    });
	}

	// receive line from IRC
	socket.on('icecap-event', function (name, data) {
		console.log("icecap-event received: '" + name + "'");
		if(name == 'msg') {
		    handle_msg(data);
		};
		if(name == 'channel_presence_added') {
			function escape(str) { return $('').text(str).html(); }
			$('#ircrows').prepend('
'+
                    escape(HHmm(data.time))+ ' '+
                    escape(data.presence)+
                    ' joined'+
                    '

');
			$('.ircrow').fadeIn('slow');
		};
		if(name == 'channel_presence_removed') {
			function escape(str) { return $('').text(str).html(); }
			$('#ircrows').prepend('
'+
                    escape(HHmm(data.time))+ ' '+
                    escape(data.presence)+
                    ' left'+
                    '

');
			$('.ircrow').fadeIn('slow');
		};

	});

	// send line to IRC
	$('#sendmsgform').submit(function (event) {
		event.preventDefault();
	        handle_msg({ 'time': new Date().getTime(), 'presence': 'Me', 'network' : 'freenode', 'channel' : '#node.js', 'msg': $('#prompt').val() });
		socket.emit('icecap.command', 'msg', { 'network' : 'freenode', 'channel' : '#node.js', 'msg': $('#prompt').val() } );

		// clear the text field
		$('#prompt').val('');
	});

	// preferences menu
	$('#commit-button').click(function() {
		$('.modal').slideToggle('slow', function() {
			socket.emit('icecap.command', 'presence set', {'network' : 'freenode', 'mypresence' : 'dgfrtr', 'real_name' : 'derp' } );
			$.cookie('the_magic_oulu_cookie', $('#apikey').val(), { expires: 365, path: '/' });
 		});
	});

	$('#toggle-button').click(function() {
		$('.modal').slideToggle('slow', function() {
 		});
	});

	$('#timelinetab').click(function() {
		$('.tabcontent').hide();
		$('#ircrows').show();
		$('.tab').removeClass('active');
		$('#timelinetab').addClass('active');
	});

	$('#guidetab').click(function() {
		$('.tabcontent').hide();
		$('#guide').show();
		$('.tab').removeClass('active');
		$('#guidetab').addClass('active');
	});

}

// jquery
$(document).ready(function() {
	init();
});

/* EOF */
<|endoftext|>


<commit_before>import {
  voteCountsByGoal,
  getTeamSizesByGoal,
} from '../pool'

import PlayersGotTheirVoteAppraiser from './PlayersGotTheirVoteAppraiser'

export default class UnpopularGoalsNotConsideredAppraiser {
  constructor(pool, maxPopularGoals = 6) {
    this.pool = pool
    this.maxPopularGoals = maxPopularGoals
  }

  score(teamFormationPlan /* , {teamsAreIncomplete} = {} */) {
    const popularGoals = this.popularGoals()
    const teamsWithoutPopularGoals = teamFormationPlan.teams.filter(team => !popularGoals.has(team.goalDescriptor)).length
    return 1 - (teamsWithoutPopularGoals / this.maxPotentialTeamCount(teamFormationPlan))
  }

  popularGoals() {
    if (!this._popularGoals) {
      this._popularGoals = new Set(
        this.goalDescriptorsSortedByPopularity().slice(0, this.maxPopularGoals)
      )
    }
    return this._popularGoals
  }

  maxPotentialTeamCount(teamFormationPlan) {
    const seatsOnCurrentTeams = teamFormationPlan.teams.reduce((sum, team) => sum + team.teamSize, 0)
    const remainingSeats = teamFormationPlan.seatCount - seatsOnCurrentTeams
    const currentTeamCount = teamFormationPlan.teams.length
    return currentTeamCount + Math.floor(remainingSeats / this.smallestPossiblePopularGoalSize())
  }

  smallestPossiblePopularGoalSize() {
    if (!this._smallestPossiblePopularGoalSize) {
      const teamSizesByGoal = getTeamSizesByGoal(this.pool)
      const recommendeGoalSizes = [...this.popularGoals().values()].map(goal => teamSizesByGoal[goal])
      const smallestRecommendedSize = recommendeGoalSizes.sort()[0]
      this._smallestPossiblePopularGoalSize = smallestRecommendedSize - 1
    }
    return this._smallestPossiblePopularGoalSize
  }

  goalDescriptorsSortedByPopularity() {
    const voteCounts = voteCountsByGoal(this.pool)

    return [...voteCounts.entries()]
      .map(([goalDescriptor, [firstVoteCount, secondVoteCount]]) => {
        const popularity = firstVoteCount + secondVoteCount * PlayersGotTheirVoteAppraiser.SECOND_CHOICE_VALUE
        return {goalDescriptor, popularity}
      }).sort(
        (a, b) => b.popularity - a.popularity
      ).map(
       _ => _.goalDescriptor
      )
  }
}

<commit_msg>Allow more popular goals to be considered.<commit_after>import {
  voteCountsByGoal,
  getTeamSizesByGoal,
} from '../pool'

import PlayersGotTheirVoteAppraiser from './PlayersGotTheirVoteAppraiser'

export default class UnpopularGoalsNotConsideredAppraiser {
  constructor(pool, maxPopularGoals = 10) {
    this.pool = pool
    this.maxPopularGoals = maxPopularGoals
  }

  score(teamFormationPlan /* , {teamsAreIncomplete} = {} */) {
    const popularGoals = this.popularGoals()
    const teamsWithoutPopularGoals = teamFormationPlan.teams.filter(team => !popularGoals.has(team.goalDescriptor)).length
    return 1 - (teamsWithoutPopularGoals / this.maxPotentialTeamCount(teamFormationPlan))
  }

  popularGoals() {
    if (!this._popularGoals) {
      this._popularGoals = new Set(
        this.goalDescriptorsSortedByPopularity().slice(0, this.maxPopularGoals)
      )
    }
    return this._popularGoals
  }

  maxPotentialTeamCount(teamFormationPlan) {
    const seatsOnCurrentTeams = teamFormationPlan.teams.reduce((sum, team) => sum + team.teamSize, 0)
    const remainingSeats = teamFormationPlan.seatCount - seatsOnCurrentTeams
    const currentTeamCount = teamFormationPlan.teams.length
    return currentTeamCount + Math.floor(remainingSeats / this.smallestPossiblePopularGoalSize())
  }

  smallestPossiblePopularGoalSize() {
    if (!this._smallestPossiblePopularGoalSize) {
      const teamSizesByGoal = getTeamSizesByGoal(this.pool)
      const recommendeGoalSizes = [...this.popularGoals().values()].map(goal => teamSizesByGoal[goal])
      const smallestRecommendedSize = recommendeGoalSizes.sort()[0]
      this._smallestPossiblePopularGoalSize = smallestRecommendedSize - 1
    }
    return this._smallestPossiblePopularGoalSize
  }

  goalDescriptorsSortedByPopularity() {
    const voteCounts = voteCountsByGoal(this.pool)

    return [...voteCounts.entries()]
      .map(([goalDescriptor, [firstVoteCount, secondVoteCount]]) => {
        const popularity = firstVoteCount + secondVoteCount * PlayersGotTheirVoteAppraiser.SECOND_CHOICE_VALUE
        return {goalDescriptor, popularity}
      }).sort(
        (a, b) => b.popularity - a.popularity
      ).map(
       _ => _.goalDescriptor
      )
  }
}

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

var React = require('React');
var Site = require('Site');
var center = require('center');

var apps = [
  {
    name: 'Beetroot',
    icon: 'http://is1.mzstatic.com/image/pf/us/r30/Purple5/v4/66/fd/dd/66fddd70-f848-4fc5-43ee-4d52197ccab8/pr_source.png',
    link: 'https://itunes.apple.com/us/app/beetroot/id1016159001?ls=1&mt=8',
    author: 'Alex Duckmanton',
  },
  {
    name: 'Discovery VR',
    icon: 'http://a2.mzstatic.com/us/r30/Purple6/v4/d1/d5/f4/d1d5f437-9f6b-b5aa-5fe7-47bd19f934bf/icon175x175.png',
    link:  'https://itunes.apple.com/us/app/discovery-vr/id1030815031?mt=8',
    author: 'Discovery Communications',
  },
  {
    name: 'DropBot',
    icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/fb/df/73/fbdf73e0-22d2-c936-3115-1defa195acba/icon175x175.png',
    link:  'https://itunes.apple.com/us/app/dropbot-phone-replacement/id1000855694?mt=8',
    author: 'Peach Labs',
  },
  {
    name: 'Exponent',
    icon: 'http://a4.mzstatic.com/us/r30/Purple2/v4/3a/d3/c9/3ad3c96c-5e14-f988-4bdd-0fdc95efd140/icon175x175.png',
    link:  'https://itunes.apple.com/ca/app/exponent/id982107779?mt=8',
    author: 'Charlie Cheever & James Ide',
  },
  {
    name: 'F8',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple5/v4/bf/d9/50/bfd9504e-a1bd-67c5-b50b-24e97016dae9/pr_source.jpg',
    link: 'https://itunes.apple.com/us/app/f8/id853467066?mt=8',
    author: 'Facebook',
  },
  {
    name: 'Facebook Groups',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple69/v4/57/f8/4c/57f84c0c-793d-5f9a-95ee-c212d0369e37/mzl.ugjwfhzx.png',
    link: 'https://itunes.apple.com/us/app/facebook-groups/id931735837?mt=8',
    author: 'Facebook',
  },
  {
    name: 'Facebook Adverts Manager - Android',
    icon: 'https://lh3.googleusercontent.com/ODKlFYm7BaNiLMEEDO2b4DOCU-hmS1-Fg3_x_lLUaJZ0ssFsxciSoX1dYERaWDJuEs8=w300',
    link: 'https://play.google.com/store/apps/details?id=com.facebook.adsmanager',
    author: 'Facebook',
  },
  {
    name: 'Facebook Ads Manager - iOS',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple5/v4/9e/16/86/9e1686ef-cc55-805a-c977-538ddb5e6832/mzl.gqbhwitj.png',
    link: 'https://itunes.apple.com/us/app/facebook-ads-manager/id964397083?mt=8',
    author: 'Facebook',
  },
  {
    name: 'HSK Level 1 Chinese Flashcards',
    icon: 'http://is2.mzstatic.com/image/pf/us/r30/Purple1/v4/b2/4f/3a/b24f3ae3-2597-cc70-1040-731b425a5904/mzl.amxdcktl.jpg',
    link: 'https://itunes.apple.com/us/app/hsk-level-1-chinese-flashcards/id936639994',
    author: 'HS Schaaf',
  },
  {
    name: 'Lrn',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple1/v4/41/a9/e9/41a9e9b6-7801-aef7-2400-2eca14923321/mzl.adyswxad.png',
    link: 'https://itunes.apple.com/us/app/lrn-learn-to-code-at-your/id1019622677',
    author: 'Lrn Labs, Inc',
  },
  {
    name: 'Lumpen Radio',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/46/43/00/464300b1-fae3-9640-d4a2-0eb050ea3ff2/mzl.xjjawige.png',
    link: 'https://itunes.apple.com/us/app/lumpen-radio/id1002193127?mt=8',
    author: 'Joshua Habdas',
  },
  {
    name: 'MinTrain',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple5/v4/51/51/68/51516875-1323-3100-31a8-cd1853d9a2c0/mzl.gozwmstp.png',
    link: 'https://itunes.apple.com/us/app/mintrain/id1015739031?mt=8',
    author: 'Peter Cottle',
  },
  {
    name: 'Mr. Dapper',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple4/v4/e8/3f/7c/e83f7cb3-2602-f8e8-de9a-ce0a775a4a14/mzl.hmdjhfai.png',
    link: 'https://itunes.apple.com/us/app/mr.-dapper-men-fashion-app/id989735184?ls=1&mt=8',
    author: 'wei ping woon',
  },
  {
    name: 'Ncredible',
    icon: 'http://a3.mzstatic.com/us/r30/Purple2/v4/a9/00/74/a9007400-7ccf-df10-553b-3b6cb67f3f5f/icon350x350.png',
    link: 'https://itunes.apple.com/ca/app/ncredible/id1019662810?mt=8',
    author: 'NBC News Digital, LLC',
  },
  {
    name: 'Night Light',
    icon: 'http://is3.mzstatic.com/image/pf/us/r30/Purple7/v4/5f/50/5f/5f505fe5-0a30-6bbf-6ed9-81ef09351aba/mzl.lkeqxyeo.png',
    link: 'https://itunes.apple.com/gb/app/night-light-feeding-light/id1016843582?mt=8',
    author: 'Tian Yuan',
  },
  {
    name: 'ReactTo36',
    icon: 'http://is2.mzstatic.com/image/pf/us/r30/Purple5/v4/e3/c8/79/e3c87934-70c6-4974-f20d-4adcfc68d71d/mzl.wevtbbkq.png',
    link: 'https://itunes.apple.com/us/app/reactto36/id989009293?mt=8',
    author: 'Jonathan Solichin',
  },
  {
    name: 'RN Playground',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/20/ec/8e/20ec8eb8-9e12-6686-cd16-7ac9e3ef1d52/mzl.ngvuoybx.png',
    link: 'https://itunes.apple.com/us/app/react-native-playground/id1002032944?mt=8',
    author: 'Joshua Sierles',
  },
  {
    name: 'Start - medication manager for depression',
    icon: 'http://a1.mzstatic.com/us/r30/Purple49/v4/de/9b/6f/de9b6fe8-84ea-7a12-ba2c-0a6d6c7b10b0/icon175x175.png',
    link: 'https://itunes.apple.com/us/app/start-medication-manager-for/id1012099928?mt=8',
    author: 'Iodine Inc.',
  },
  {
    name: 'Tong Xing Wang',
    icon: 'http://a3.mzstatic.com/us/r30/Purple1/v4/7d/52/a7/7d52a71f-9532-82a5-b92f-87076624fdb2/icon175x175.jpeg',
    link: 'https://itunes.apple.com/cn/app/tong-xing-wang/id914254459?mt=8',
    author: 'Ho Yin Tsun Eugene',
  },
  {
    name: 'youmeyou',
    icon: 'http://is1.mzstatic.com/image/pf/us/r30/Purple7/v4/7c/42/30/7c423042-8945-7733-8af3-1523468706a8/mzl.qlecxphf.png',
    link: 'https://itunes.apple.com/us/app/youmeyou/id949540333?mt=8',
    author: 'youmeyou, LLC',
  },
];

var showcase = React.createClass({
  render: function() {
    return (
      <Site section="showcase" title="Showcase">

Apps using React Native

              Here is a list of apps using React Native. Submit a pull request on GitHub to list your app.

          {
            apps.map((app, i) => {
              return (

{app.name}

By {app.author}

              );
            })
          }

      </Site>
    );
  }
});

module.exports = showcase;
<commit_msg>Add leanpub to the list of showcase apps.<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

var React = require('React');
var Site = require('Site');
var center = require('center');

var apps = [
  {
    name: 'Beetroot',
    icon: 'http://is1.mzstatic.com/image/pf/us/r30/Purple5/v4/66/fd/dd/66fddd70-f848-4fc5-43ee-4d52197ccab8/pr_source.png',
    link: 'https://itunes.apple.com/us/app/beetroot/id1016159001?ls=1&mt=8',
    author: 'Alex Duckmanton',
  },
  {
    name: 'Discovery VR',
    icon: 'http://a2.mzstatic.com/us/r30/Purple6/v4/d1/d5/f4/d1d5f437-9f6b-b5aa-5fe7-47bd19f934bf/icon175x175.png',
    link:  'https://itunes.apple.com/us/app/discovery-vr/id1030815031?mt=8',
    author: 'Discovery Communications',
  },
  {
    name: 'DropBot',
    icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/fb/df/73/fbdf73e0-22d2-c936-3115-1defa195acba/icon175x175.png',
    link:  'https://itunes.apple.com/us/app/dropbot-phone-replacement/id1000855694?mt=8',
    author: 'Peach Labs',
  },
  {
    name: 'Exponent',
    icon: 'http://a4.mzstatic.com/us/r30/Purple2/v4/3a/d3/c9/3ad3c96c-5e14-f988-4bdd-0fdc95efd140/icon175x175.png',
    link:  'https://itunes.apple.com/ca/app/exponent/id982107779?mt=8',
    author: 'Charlie Cheever & James Ide',
  },
  {
    name: 'F8',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple5/v4/bf/d9/50/bfd9504e-a1bd-67c5-b50b-24e97016dae9/pr_source.jpg',
    link: 'https://itunes.apple.com/us/app/f8/id853467066?mt=8',
    author: 'Facebook',
  },
  {
    name: 'Facebook Groups',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple69/v4/57/f8/4c/57f84c0c-793d-5f9a-95ee-c212d0369e37/mzl.ugjwfhzx.png',
    link: 'https://itunes.apple.com/us/app/facebook-groups/id931735837?mt=8',
    author: 'Facebook',
  },
  {
    name: 'Facebook Adverts Manager - Android',
    icon: 'https://lh3.googleusercontent.com/ODKlFYm7BaNiLMEEDO2b4DOCU-hmS1-Fg3_x_lLUaJZ0ssFsxciSoX1dYERaWDJuEs8=w300',
    link: 'https://play.google.com/store/apps/details?id=com.facebook.adsmanager',
    author: 'Facebook',
  },
  {
    name: 'Facebook Ads Manager - iOS',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple5/v4/9e/16/86/9e1686ef-cc55-805a-c977-538ddb5e6832/mzl.gqbhwitj.png',
    link: 'https://itunes.apple.com/us/app/facebook-ads-manager/id964397083?mt=8',
    author: 'Facebook',
  },
  {
    name: 'HSK Level 1 Chinese Flashcards',
    icon: 'http://is2.mzstatic.com/image/pf/us/r30/Purple1/v4/b2/4f/3a/b24f3ae3-2597-cc70-1040-731b425a5904/mzl.amxdcktl.jpg',
    link: 'https://itunes.apple.com/us/app/hsk-level-1-chinese-flashcards/id936639994',
    author: 'HS Schaaf',
  },
  {
    name: 'Lrn',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple1/v4/41/a9/e9/41a9e9b6-7801-aef7-2400-2eca14923321/mzl.adyswxad.png',
    link: 'https://itunes.apple.com/us/app/lrn-learn-to-code-at-your/id1019622677',
    author: 'Lrn Labs, Inc',
  },
  {
    name: 'Lumpen Radio',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/46/43/00/464300b1-fae3-9640-d4a2-0eb050ea3ff2/mzl.xjjawige.png',
    link: 'https://itunes.apple.com/us/app/lumpen-radio/id1002193127?mt=8',
    author: 'Joshua Habdas',
  },
  {
    name: 'MinTrain',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple5/v4/51/51/68/51516875-1323-3100-31a8-cd1853d9a2c0/mzl.gozwmstp.png',
    link: 'https://itunes.apple.com/us/app/mintrain/id1015739031?mt=8',
    author: 'Peter Cottle',
  },
  {
    name: 'Mr. Dapper',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple4/v4/e8/3f/7c/e83f7cb3-2602-f8e8-de9a-ce0a775a4a14/mzl.hmdjhfai.png',
    link: 'https://itunes.apple.com/us/app/mr.-dapper-men-fashion-app/id989735184?ls=1&mt=8',
    author: 'wei ping woon',
  },
  {
    name: 'Ncredible',
    icon: 'http://a3.mzstatic.com/us/r30/Purple2/v4/a9/00/74/a9007400-7ccf-df10-553b-3b6cb67f3f5f/icon350x350.png',
    link: 'https://itunes.apple.com/ca/app/ncredible/id1019662810?mt=8',
    author: 'NBC News Digital, LLC',
  },
  {
    name: 'Night Light',
    icon: 'http://is3.mzstatic.com/image/pf/us/r30/Purple7/v4/5f/50/5f/5f505fe5-0a30-6bbf-6ed9-81ef09351aba/mzl.lkeqxyeo.png',
    link: 'https://itunes.apple.com/gb/app/night-light-feeding-light/id1016843582?mt=8',
    author: 'Tian Yuan',
  },
  {
    name: 'ReactTo36',
    icon: 'http://is2.mzstatic.com/image/pf/us/r30/Purple5/v4/e3/c8/79/e3c87934-70c6-4974-f20d-4adcfc68d71d/mzl.wevtbbkq.png',
    link: 'https://itunes.apple.com/us/app/reactto36/id989009293?mt=8',
    author: 'Jonathan Solichin',
  },
  {
    name: 'RN Playground',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/20/ec/8e/20ec8eb8-9e12-6686-cd16-7ac9e3ef1d52/mzl.ngvuoybx.png',
    link: 'https://itunes.apple.com/us/app/react-native-playground/id1002032944?mt=8',
    author: 'Joshua Sierles',
  },
  {
    name: 'Start - medication manager for depression',
    icon: 'http://a1.mzstatic.com/us/r30/Purple49/v4/de/9b/6f/de9b6fe8-84ea-7a12-ba2c-0a6d6c7b10b0/icon175x175.png',
    link: 'https://itunes.apple.com/us/app/start-medication-manager-for/id1012099928?mt=8',
    author: 'Iodine Inc.',
  },
  {
    name: 'Tong Xing Wang',
    icon: 'http://a3.mzstatic.com/us/r30/Purple1/v4/7d/52/a7/7d52a71f-9532-82a5-b92f-87076624fdb2/icon175x175.jpeg',
    link: 'https://itunes.apple.com/cn/app/tong-xing-wang/id914254459?mt=8',
    author: 'Ho Yin Tsun Eugene',
  },
  {
    name: 'youmeyou',
    icon: 'http://is1.mzstatic.com/image/pf/us/r30/Purple7/v4/7c/42/30/7c423042-8945-7733-8af3-1523468706a8/mzl.qlecxphf.png',
    link: 'https://itunes.apple.com/us/app/youmeyou/id949540333?mt=8',
    author: 'youmeyou, LLC',
  },
  {
    name: 'Leanpub',
    icon: 'http://a2.mzstatic.com/us/r30/Purple6/v4/9f/4a/6f/9f4a6f8c-8951-ed89-4083-74ace23df9ef/icon350x350.jpeg',
    link: 'https://itunes.apple.com/us/app/leanpub/id913517110?ls=1&mt=8',
    author: 'Leanpub'
  },
];

var showcase = React.createClass({
  render: function() {
    return (
      <Site section="showcase" title="Showcase">

Apps using React Native

              Here is a list of apps using React Native. Submit a pull request on GitHub to list your app.

          {
            apps.map((app, i) => {
              return (

{app.name}

By {app.author}

              );
            })
          }

      </Site>
    );
  }
});

module.exports = showcase;
<|endoftext|>


<commit_before>byteArrayToGame = function(bytes) {
    var headerSplit = bytes.indexOf(10);
    var header = String.fromCharCode.apply(null, bytes.slice(0, headerSplit))
    if (header != "HLT 9") {
		alert("Invalid header: " + header)
    }

    var detailSplit = bytes.indexOf(10, headerSplit + 1);
    var details = String.fromCharCode.apply(null, bytes.slice(headerSplit + 1, detailSplit))

    var game = {version: header};
    [game.width, game.height, game.numPlayers, game.numFrames] = details.split(" ");
    var cellCount = game.height * game.width;

    game.players = []
    var playerSplit = detailSplit;
    game.players.push({name: 'NULL', color: "0x888888"});
    for(i = 0; i < game.numPlayers; i++) {
		var nextPlayerSplit = bytes.indexOf(10, playerSplit + 1);
		var playerLine = String.fromCharCode.apply(null, bytes.slice(playerSplit + 1, nextPlayerSplit));
		var playerDetails = playerLine.split("\0");
		var playerColorString = playerDetails[1].split(' ');
		function compToHex(c) { var hex = c.toString(16); return hex.length == 1 ? "0" + hex : hex; };
		game.players.push({name: playerDetails[0], color: "0x" + compToHex(Math.round(parseFloat(playerColorString[0]) * 255)) + compToHex(Math.round(parseFloat(playerColorString[1]) * 255)) + compToHex(Math.round(parseFloat(playerColorString[2]) * 255)) });
		console.log(game.players[game.players.length - 1].color);
		playerSplit = nextPlayerSplit;
    }

    game.productions = []
    var offset = 0, maxProd = 0;
    for(var i = 0; i < cellCount; ++i) {
		game.productions.push(bytes[playerSplit + 1 + i]);
		if(bytes[playerSplit + 1 + i] > maxProd) maxProd = bytes[playerSplit + 1 + i];
    }

    game.productionNormals = []
    for(var i = 0; i < game.productions.length; i++) game.productionNormals.push(game.productions[i] / maxProd);

    game.frames = []
    game.moves = []
    var currIndex = playerSplit + 1 + cellCount + 1;
    for(var frameCount = 0; frameCount < game.numFrames; frameCount++) {
		var cellsRead = 0;
		var frame = [];
		while (cellsRead < cellCount) {
		    var counter = bytes[currIndex++]
		    var owner = bytes[currIndex++];
		    if (counter + cellsRead <= cellCount) {
				for(var i = 0; i < counter; i++) {
				    var strength = bytes[currIndex++]
				    frame.push({owner: owner, strength: strength});
				}
				cellsRead += counter;
		    } else {
				console.log("Gonna read: " + counter);
				cellsRead = cellCount
		    }
		}
		game.frames.push(frame);

		if (frameCount < game.numFrames - 1) {
		    var moves = [];
		    for(var i = 0; i < cellCount; i++) {
				moves.push(bytes[currIndex++])
		    }
		    game.moves.push(moves);
		}
    }
    return game
}<commit_msg>Made game\..* ints where they should be ints<commit_after>byteArrayToGame = function(bytes) {
    var headerSplit = bytes.indexOf(10);
    var header = String.fromCharCode.apply(null, bytes.slice(0, headerSplit))
    if (header != "HLT 9") {
		alert("Invalid header: " + header)
    }

    var detailSplit = bytes.indexOf(10, headerSplit + 1);
    var details = String.fromCharCode.apply(null, bytes.slice(headerSplit + 1, detailSplit))

    var game = {version: header};
    [game.width, game.height, game.numPlayers, game.numFrames] = details.split(" ");
    game.width = parseInt(game.width);
    game.height = parseInt(game.height);
    game.numPlayers = parseInt(game.numPlayers);
    game.numFrames = parseInt(game.numFrames);
    var cellCount = game.height * game.width;

    game.players = []
    var playerSplit = detailSplit;
    game.players.push({name: 'NULL', color: "0x888888"});
    for(i = 0; i < game.numPlayers; i++) {
		var nextPlayerSplit = bytes.indexOf(10, playerSplit + 1);
		var playerLine = String.fromCharCode.apply(null, bytes.slice(playerSplit + 1, nextPlayerSplit));
		var playerDetails = playerLine.split("\0");
		var playerColorString = playerDetails[1].split(' ');
		function compToHex(c) { var hex = c.toString(16); return hex.length == 1 ? "0" + hex : hex; };
		game.players.push({name: playerDetails[0], color: "0x" + compToHex(Math.round(parseFloat(playerColorString[0]) * 255)) + compToHex(Math.round(parseFloat(playerColorString[1]) * 255)) + compToHex(Math.round(parseFloat(playerColorString[2]) * 255)) });
		console.log(game.players[game.players.length - 1].color);
		playerSplit = nextPlayerSplit;
    }

    game.productions = []
    var offset = 0, maxProd = 0;
    for(var i = 0; i < cellCount; ++i) {
		game.productions.push(bytes[playerSplit + 1 + i]);
		if(bytes[playerSplit + 1 + i] > maxProd) maxProd = bytes[playerSplit + 1 + i];
    }

    game.productionNormals = []
    for(var i = 0; i < game.productions.length; i++) game.productionNormals.push(game.productions[i] / maxProd);

    game.frames = []
    game.moves = []
    var currIndex = playerSplit + 1 + cellCount + 1;
    for(var frameCount = 0; frameCount < game.numFrames; frameCount++) {
		var cellsRead = 0;
		var frame = [];
		while (cellsRead < cellCount) {
		    var counter = bytes[currIndex++]
		    var owner = bytes[currIndex++];
		    if (counter + cellsRead <= cellCount) {
				for(var i = 0; i < counter; i++) {
				    var strength = bytes[currIndex++]
				    frame.push({owner: owner, strength: strength});
				}
				cellsRead += counter;
		    } else {
				console.log("Gonna read: " + counter);
				cellsRead = cellCount
		    }
		}
		game.frames.push(frame);

		if (frameCount < game.numFrames - 1) {
		    var moves = [];
		    for(var i = 0; i < cellCount; i++) {
				moves.push(bytes[currIndex++])
		    }
		    game.moves.push(moves);
		}
    }
    return game
}<|endoftext|>


<commit_before>sap.ui.define([
	'sap/ui/test/Opa5',
	'sap/ui/test/matchers/AggregationLengthEquals',
	'sap/ui/test/matchers/PropertyStrictEquals',
	'sap/ui/test/matchers/BindingPath',
	'sap/ui/test/matchers/I18NText',
	'sap/ui/test/actions/Press',
	'sap/ui/test/actions/EnterText'
], function (Opa5, AggregationLengthEquals, PropertyStrictEquals, BindingPath, I18NText, Press, EnterText) {
	"use strict";

	var sViewName = "App",
		sTableId = "peopleList";

	function getListBinding(oTable) {
		return oTable.getBinding("items");
	}

	function getFirstTableEntry(oTable) {
		return getListBinding(oTable).getCurrentContexts()[0];
	}

	Opa5.createPageObjects({
		onTheTutorialPage : {
			actions : {
				iPressOnMoreData : function () {
					// Press action hits the "more" trigger on a table
					return this.waitFor({
						id : sTableId,
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Table not found or it does not have a 'See More' trigger"
					});
				},

				iPressOnSort : function () {
					return this.waitFor({
						id : "sortUsersButton",
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Could not find the 'Sort' button"
					});
				},

				iPressOnAdd : function () {
					return this.waitFor({
						id : "addUserButton",
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Could not find the 'Add' button"
					});
				},

				iPressOnDelete : function () {
					return this.waitFor({
						id : "deleteUserButton",
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Could not find the 'Delete' button"
					});
				},

				iPressOnSave : function () {
					return this.waitFor({
						id : "saveButton",
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Could not find the 'Save' button"
					});
				},

				iPressOnCancel : function () {
					return this.waitFor({
						id : "doneButton",
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Could not find the 'Cancel' button"
					});
				},

				iEnterSomeData : function (sValue) {
					return this.waitFor({
						controlType : "sap.m.Input",
						viewName : sViewName,
						matchers : [
							// Find the input fields for the new entry
							new BindingPath({
								path : "/People/-1"
							}),
							// Keep only empty input fields
							function (oItem) {
								return !oItem.getValue();
							}
						],
						actions : new EnterText({
							text : sValue
						}),
						errorMessage : "Could not find Input controls to enter data"
					});
				},

				iSearchFor : function (sSearchString) {
					return this.waitFor({
						id : "searchField",
						viewName : sViewName,
						actions : new EnterText({
							text : sSearchString
						}),
						errorMessage : "SearchField was not found"
					});
				},

				iSelectUser : function (sKey) {
					return this.waitFor({
						controlType : "sap.m.ColumnListItem",
						viewName : sViewName,
						matchers : new BindingPath({
							path : "/People('" + sKey + "')"
						}),
						actions : function (oItem) {
							oItem.setSelected(true);
						},
						errorMessage : "Could not find a user with the key '" + sKey + "'"
					});
				},

				iChangeAUserKey : function (sOldKey, sNewKey) {
					return this.waitFor({
						controlType : "sap.m.Input",
						viewName : sViewName,
						matchers : new PropertyStrictEquals({
							name : "value",
							value : sOldKey
						}),
						actions : new EnterText({
							text : sNewKey
						}),
						errorMessage : "Could not find a user with the key '" + sOldKey + "'"
					});
				},

				iCloseTheServiceError : function () {
					return this.waitFor({
						id : "serviceErrorMessageBox",
						success : function () {
							this.waitFor({
								controlType : "sap.m.Button",
								searchOpenDialogs : true,
								// The error MessageBox has only one button, which closes the box
								actions : new Press(),
								errorMessage : "Cannot find the 'Close' button"
							});
						},
						errorMessage : "Could not see the service error dialog"
					});
				}
			},
			assertions : {
				theTableShouldHavePagination : function () {
					return this.waitFor({
						id : sTableId,
						viewName : sViewName,
						matchers : new PropertyStrictEquals({
							name : "growing",
							value : true
						}),
						success : function () {
							Opa5.assert.ok(true, "The table is paginated");
						},
						errorMessage : "Table not found or it is not paginated"
					});
				},

				theTableShouldShowUsers : function (iNumber) {
					return this.waitFor({
						id : sTableId,
						viewName : sViewName,
						matchers : new AggregationLengthEquals({
							name : "items",
							length : iNumber
						}),
						success : function () {
							Opa5.assert.ok(true, "The table has "
								+ iNumber + " items");
						},
						errorMessage : "Table not found or it does not have "
						+ iNumber + " entries"
					});
				},

				theTableShouldShowTotalUsers : function (iNumber) {
					return this.waitFor({
						id : sTableId,
						viewName : sViewName,
						matchers : function (oTable) {
							var oListBinding = getListBinding(oTable);
							return oListBinding && oListBinding.getLength() === iNumber;
						},
						success : function () {
							Opa5.assert.ok(true, "The table shows a total of " + iNumber + " users");
						},
						errorMessage : "Table not found or it does not show " + iNumber + " total users"
					});
				},

				theTableShouldStartWith : function (sLastName) {
					return this.waitFor({
						id : sTableId,
						viewName : sViewName,
						matchers : function (oTable) {
							var oFirstItem = getFirstTableEntry(oTable);
							return oFirstItem && oFirstItem.getProperty("LastName") === sLastName;
						},
						success : function () {
							Opa5.assert.ok(true, "The table is sorted correctly");
						},
						errorMessage : "Table not found or it is not sorted correctl."
					});
				},

				thePageFooterShouldBeVisible : function (bVisible) {
					var sDesiredState = bVisible ? "visible" : "invisible";

					return this.waitFor({
						controlType : "sap.m.Toolbar",
						viewName : sViewName,
						visible : false,
						matchers : new PropertyStrictEquals({
							name : "visible",
							value : bVisible
						}),
						success : function () {
							Opa5.assert.ok(true, "The toolbar is " + sDesiredState);
						},
						errorMessage : "Toolbar not found or is not " + sDesiredState
					});
				},

				theTableToolbarItemsShouldBeEnabled : function (bEnabled) {
					var sDesiredState = bEnabled ? "enabled" : "disabled";

					return this.waitFor({
						id : /searchField$|addUserButton$|deleteUserButton$|refreshUsersButton$|sortUsersButton$/,
						viewName : sViewName,
						autoWait : false,	// Needed because we want to find disabled controls, too
						matchers : new PropertyStrictEquals({
							name : "enabled",
							value : bEnabled
						}),
						check : function (aControls) {
							// Validate that ALL controls have the right state
							return aControls.length === 5;
						},
						success : function () {
							Opa5.assert.ok(true, "All controls in the table toolbar are " + sDesiredState);
						},
						errorMessage : "Not all controls in the table toolbar could be found or not all are " + sDesiredState
					});
				},

				theMessageToastShouldShow : function (sTextId) {
					return this.waitFor({
						autoWait : false,
						id : sTableId,
						viewName : sViewName,
						check : function (oControl) {
							// Locate the message toast using its CSS class name and content
							var sText = oControl.getModel("i18n").getResourceBundle().getText(sTextId);
							var sSelector = ".sapMMessageToast:contains('" + sText + "')";
							return !!Opa5.getJQuery()(sSelector).length;
						},
						success : function () {
							Opa5.assert.ok(true, "Could see the MessageToast showing text with ID " + sTextId);
						},
						errorMessage : "Could not see a MessageToast showing text with ID " + sTextId
					});
				},

				iShouldSeeAServiceError : function () {
					return this.waitFor({
						id : "serviceErrorMessageBox",
						success : function () {
							Opa5.assert.ok(true, "Could see the service error dialog");
						},
						errorMessage : "Could not see the service error dialog"
					});
				}
			}
		}
	});
});
<commit_msg>[INTERNAL] fix OPA for OData V4 Tutorial<commit_after>sap.ui.define([
	'sap/ui/test/Opa5',
	'sap/ui/test/matchers/AggregationLengthEquals',
	'sap/ui/test/matchers/PropertyStrictEquals',
	'sap/ui/test/matchers/BindingPath',
	'sap/ui/test/matchers/I18NText',
	'sap/ui/test/actions/Press',
	'sap/ui/test/actions/EnterText'
], function (Opa5, AggregationLengthEquals, PropertyStrictEquals, BindingPath, I18NText, Press, EnterText) {
	"use strict";

	var sViewName = "App",
		sTableId = "peopleList";

	function getListBinding(oTable) {
		return oTable.getBinding("items");
	}

	function getFirstTableEntry(oTable) {
		return getListBinding(oTable).getCurrentContexts()[0];
	}

	Opa5.createPageObjects({
		onTheTutorialPage : {
			actions : {
				iPressOnMoreData : function () {
					// Press action hits the "more" trigger on a table
					return this.waitFor({
						id : sTableId,
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Table not found or it does not have a 'See More' trigger"
					});
				},

				iPressOnSort : function () {
					return this.waitFor({
						id : "sortUsersButton",
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Could not find the 'Sort' button"
					});
				},

				iPressOnAdd : function () {
					return this.waitFor({
						id : "addUserButton",
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Could not find the 'Add' button"
					});
				},

				iPressOnDelete : function () {
					return this.waitFor({
						id : "deleteUserButton",
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Could not find the 'Delete' button"
					});
				},

				iPressOnSave : function () {
					return this.waitFor({
						id : "saveButton",
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Could not find the 'Save' button"
					});
				},

				iPressOnCancel : function () {
					return this.waitFor({
						id : "doneButton",
						viewName : sViewName,
						actions : new Press(),
						errorMessage : "Could not find the 'Cancel' button"
					});
				},

				iEnterSomeData : function (sValue) {
					return this.waitFor({
						controlType : "sap.m.Input",
						viewName : sViewName,
						matchers : [
							// Find the input fields for the new entry
							function (oControl) {
								return oControl.getBindingContext().getIndex() === 0;
							},
							// Keep only empty input fields
							function (oItem) {
								return !oItem.getValue();
							}
						],
						actions : new EnterText({
							text : sValue
						}),
						errorMessage : "Could not find Input controls to enter data"
					});
				},

				iSearchFor : function (sSearchString) {
					return this.waitFor({
						id : "searchField",
						viewName : sViewName,
						actions : new EnterText({
							text : sSearchString
						}),
						errorMessage : "SearchField was not found"
					});
				},

				iSelectUser : function (sKey) {
					return this.waitFor({
						controlType : "sap.m.ColumnListItem",
						viewName : sViewName,
						matchers : new BindingPath({
							path : "/People('" + sKey + "')"
						}),
						actions : function (oItem) {
							oItem.setSelected(true);
						},
						errorMessage : "Could not find a user with the key '" + sKey + "'"
					});
				},

				iChangeAUserKey : function (sOldKey, sNewKey) {
					return this.waitFor({
						controlType : "sap.m.Input",
						viewName : sViewName,
						matchers : new PropertyStrictEquals({
							name : "value",
							value : sOldKey
						}),
						actions : new EnterText({
							text : sNewKey
						}),
						errorMessage : "Could not find a user with the key '" + sOldKey + "'"
					});
				},

				iCloseTheServiceError : function () {
					return this.waitFor({
						id : "serviceErrorMessageBox",
						success : function () {
							this.waitFor({
								controlType : "sap.m.Button",
								searchOpenDialogs : true,
								// The error MessageBox has only one button, which closes the box
								actions : new Press(),
								errorMessage : "Cannot find the 'Close' button"
							});
						},
						errorMessage : "Could not see the service error dialog"
					});
				}
			},
			assertions : {
				theTableShouldHavePagination : function () {
					return this.waitFor({
						id : sTableId,
						viewName : sViewName,
						matchers : new PropertyStrictEquals({
							name : "growing",
							value : true
						}),
						success : function () {
							Opa5.assert.ok(true, "The table is paginated");
						},
						errorMessage : "Table not found or it is not paginated"
					});
				},

				theTableShouldShowUsers : function (iNumber) {
					return this.waitFor({
						id : sTableId,
						viewName : sViewName,
						matchers : new AggregationLengthEquals({
							name : "items",
							length : iNumber
						}),
						success : function () {
							Opa5.assert.ok(true, "The table has "
								+ iNumber + " items");
						},
						errorMessage : "Table not found or it does not have "
						+ iNumber + " entries"
					});
				},

				theTableShouldShowTotalUsers : function (iNumber) {
					return this.waitFor({
						id : sTableId,
						viewName : sViewName,
						matchers : function (oTable) {
							var oListBinding = getListBinding(oTable);
							return oListBinding && oListBinding.getLength() === iNumber;
						},
						success : function () {
							Opa5.assert.ok(true, "The table shows a total of " + iNumber + " users");
						},
						errorMessage : "Table not found or it does not show " + iNumber + " total users"
					});
				},

				theTableShouldStartWith : function (sLastName) {
					return this.waitFor({
						id : sTableId,
						viewName : sViewName,
						matchers : function (oTable) {
							var oFirstItem = getFirstTableEntry(oTable);
							return oFirstItem && oFirstItem.getProperty("LastName") === sLastName;
						},
						success : function () {
							Opa5.assert.ok(true, "The table is sorted correctly");
						},
						errorMessage : "Table not found or it is not sorted correctl."
					});
				},

				thePageFooterShouldBeVisible : function (bVisible) {
					var sDesiredState = bVisible ? "visible" : "invisible";

					return this.waitFor({
						controlType : "sap.m.Toolbar",
						viewName : sViewName,
						visible : false,
						matchers : new PropertyStrictEquals({
							name : "visible",
							value : bVisible
						}),
						success : function () {
							Opa5.assert.ok(true, "The toolbar is " + sDesiredState);
						},
						errorMessage : "Toolbar not found or is not " + sDesiredState
					});
				},

				theTableToolbarItemsShouldBeEnabled : function (bEnabled) {
					var sDesiredState = bEnabled ? "enabled" : "disabled";

					return this.waitFor({
						id : /searchField$|addUserButton$|deleteUserButton$|refreshUsersButton$|sortUsersButton$/,
						viewName : sViewName,
						autoWait : false,	// Needed because we want to find disabled controls, too
						matchers : new PropertyStrictEquals({
							name : "enabled",
							value : bEnabled
						}),
						check : function (aControls) {
							// Validate that ALL controls have the right state
							return aControls.length === 5;
						},
						success : function () {
							Opa5.assert.ok(true, "All controls in the table toolbar are " + sDesiredState);
						},
						errorMessage : "Not all controls in the table toolbar could be found or not all are " + sDesiredState
					});
				},

				theMessageToastShouldShow : function (sTextId) {
					return this.waitFor({
						autoWait : false,
						id : sTableId,
						viewName : sViewName,
						check : function (oControl) {
							// Locate the message toast using its CSS class name and content
							var sText = oControl.getModel("i18n").getResourceBundle().getText(sTextId);
							var sSelector = ".sapMMessageToast:contains('" + sText + "')";
							return !!Opa5.getJQuery()(sSelector).length;
						},
						success : function () {
							Opa5.assert.ok(true, "Could see the MessageToast showing text with ID " + sTextId);
						},
						errorMessage : "Could not see a MessageToast showing text with ID " + sTextId
					});
				},

				iShouldSeeAServiceError : function () {
					return this.waitFor({
						id : "serviceErrorMessageBox",
						success : function () {
							Opa5.assert.ok(true, "Could see the service error dialog");
						},
						errorMessage : "Could not see the service error dialog"
					});
				}
			}
		}
	});
});
<|endoftext|>


<commit_before>// ==UserScript==
// @name          Datatableize
// @namespace     http://juan.one/userscripts
// @description   Datatableize Helvetas P2P
// @include       https://p2p.getunik.net/organisations/helvetas/*
// @grant         GM_getResourceText
// @resource      coffee https://raw.githubusercontent.com/romeroabelleira/datatableize/master/main.coffee
// @version       1.0.1
// ==/UserScript==
console.log("About to load coffee.");
eval(CoffeeScript.compile(GM_getResourceText(coffee)));
console.log("Did I just load coffee?");
<commit_msg>add necessary require<commit_after>// ==UserScript==
// @name          Datatableize
// @namespace     http://juan.one/userscripts
// @description   Datatableize Helvetas P2P
// @include       https://p2p.getunik.net/organisations/helvetas/*
// @grant         GM_getResourceText
// @require  http://coffeescript.org/extras/coffee-script.js
// @resource      coffee https://raw.githubusercontent.com/romeroabelleira/datatableize/master/main.coffee
// @version       1.0.1
// ==/UserScript==
console.log("About to load coffee.");
eval(CoffeeScript.compile(GM_getResourceText(coffee)));
console.log("Did I just load coffee?");
<|endoftext|>


<commit_before>require('dotenv').config();

const moment = require('moment');

const MongoDriver = require('../libs/MongoDriver');
const LogUtil = require('../libs/LogUtil');

const { getMedias } = require('../libs/InstagramDriver');

const isProd = process.env.NODE_ENV === 'production';

function insertMockData(db, callback) {
  const followerArray = [];
  const adminArray = [];
  let mediaArray = [];
  let followersCount = 500;

  // Function to random a number between min and max
  const getRandomNumber = (min, max) => Math.floor((Math.random() * (max - min)) + min);

  // Insert mock data for 14 days backward
  for (let i = 30; i >= 0; i -= 1) {
    const time = moment().utcOffset(7).hour(0).minute(0).second(0).subtract(i, 'days').unix();

    // Followers
    followerArray.push({ time: time.toString(), followers_count: followersCount });
    followersCount += getRandomNumber(1, 10);
  }

  getMedias(undefined, undefined, undefined, (response) => {
    const json = JSON.parse(response);
    mediaArray = json.data.map((media) => {
      const { id, created_time: createdTime } = media;

      return { id, created_time: parseInt(createdTime, 10) };
    });

    adminArray.push(
      {
        user_id: 'U1Y4059UM',
        // username: 'try.aji',
        is_admin: '1',
      },
      {
        user_id: 'U0L63DYL8',
        // username: 'abdymalikmulky',
        is_admin: '0',
      },
      {
        user_id: 'U3ZD2BT0D',
        // username: 'putrabangga',
        is_admin: '0',
      }
    );

    // Insert into postedmedias collection
    db.collection('postedmedias').insertMany(mediaArray, (err) => {
      if (err) {
        LogUtil.winston.log('error', 'Failed to mock "postedmedias" collection!');
      } else {
        LogUtil.winston.log('info', 'Successfully mocked "postedmedias" collection!');
      }

      // Insert into followers collection
      db.collection('followers').insertMany(followerArray, (err) => {
        if (err) {
          LogUtil.winston.log('error', 'Failed to mock "followers" collection!');
        } else {
          LogUtil.winston.log('info', 'Successfully mocked "followers" collection!');
        }

        // Insert into admins collection
        db.collection('admins').insertMany(adminArray, (err) => {
          if (err) {
            LogUtil.winston.log('error', 'Failed to mock "admins" collection!');
          } else {
            LogUtil.winston.log('info', 'Successfully mocked "admins" collection!');
          }

          // Callback function
          if (typeof callback === 'function') {
            callback(db);
          }
        });
      });
    });
  });
}

function clearCollection(db, callback) {
  // Clear collection
  db.collection('postedmedias').deleteMany({}, (err, r) => {
    if (err) {
      LogUtil.winston.log('error', 'Failed to truncate "postedmedias" collection!');
    } else {
      LogUtil.winston.log('info', 'Successfully truncated "postedmedias" collection!');
    }

    db.collection('followers').deleteMany({}, (err, r) => {
      if (err) {
        LogUtil.winston.log('error', 'Failed to truncate "followers" collection!');
      } else {
        LogUtil.winston.log('info', 'Successfully truncated "followers" collection!');
      }

      db.collection('admins').deleteMany({}, (err, r) => {
        if (err) {
          LogUtil.winston.log('error', 'Failed to truncate "admins" collection!');
        } else {
          LogUtil.winston.log('info', 'Successfully truncated "admins" collection!');
        }

        db.collection('channels').deleteMany({}, (err, r) => {
          if (err) {
            LogUtil.winston.log('error', 'Failed to truncate "channels" collection!');
          } else {
            LogUtil.winston.log('info', 'Successfully truncated "channels" collection!');
          }

          if (typeof callback === 'function') {
            callback(db);
          }
        });
      });
    });
  });
}

// Set callback function after database connection is established
function openConnectionCallback (db) {
  // Start database seeding process
  const clearCollectionCallback = (db) => {
    insertMockData(db, MongoDriver.closeDBConnection);
  };

  clearCollection(db, clearCollectionCallback);
};

// Open database connection, if environment is not production
// Just for safety reasons
if (isProd) {
  MongoDriver.openDBConnection(openConnectionCallback);
}
<commit_msg>fix(instagram queries): fixed database order, switched created_Time with id because mongodb apparently sorted inserted document based on first property of the doc<commit_after>require('dotenv').config();

const moment = require('moment');

const MongoDriver = require('../libs/MongoDriver');
const LogUtil = require('../libs/LogUtil');

const { getMedias } = require('../libs/InstagramDriver');

const isProd = process.env.NODE_ENV === 'production';

function insertMockData(db, callback) {
  const followerArray = [];
  const adminArray = [];
  let mediaArray = [];
  let followersCount = 500;

  // Function to random a number between min and max
  const getRandomNumber = (min, max) => Math.floor((Math.random() * (max - min)) + min);

  // Insert mock data for 14 days backward
  for (let i = 30; i >= 0; i -= 1) {
    const time = moment().utcOffset(7).hour(0).minute(0).second(0).subtract(i, 'days').unix();

    // Followers
    followerArray.push({ time: time.toString(), followers_count: followersCount });
    followersCount += getRandomNumber(1, 10);
  }

  getMedias(undefined, undefined, undefined, (response) => {
    const json = JSON.parse(response);
    mediaArray = json.data.map((media) => {
      const { id, created_time: createdTime } = media;

      return { created_time: parseInt(createdTime, 10), id };
    });

    adminArray.push(
      {
        user_id: 'U1Y4059UM',
        // username: 'try.aji',
        is_admin: '1',
      },
      {
        user_id: 'U0L63DYL8',
        // username: 'abdymalikmulky',
        is_admin: '0',
      },
      {
        user_id: 'U3ZD2BT0D',
        // username: 'putrabangga',
        is_admin: '0',
      }
    );

    // Insert into postedmedias collection
    db.collection('postedmedias').insertMany(mediaArray, (err) => {
      if (err) {
        LogUtil.winston.log('error', 'Failed to mock "postedmedias" collection!');
      } else {
        LogUtil.winston.log('info', 'Successfully mocked "postedmedias" collection!');
      }

      // Insert into followers collection
      db.collection('followers').insertMany(followerArray, (err) => {
        if (err) {
          LogUtil.winston.log('error', 'Failed to mock "followers" collection!');
        } else {
          LogUtil.winston.log('info', 'Successfully mocked "followers" collection!');
        }

        // Insert into admins collection
        db.collection('admins').insertMany(adminArray, (err) => {
          if (err) {
            LogUtil.winston.log('error', 'Failed to mock "admins" collection!');
          } else {
            LogUtil.winston.log('info', 'Successfully mocked "admins" collection!');
          }

          // Callback function
          if (typeof callback === 'function') {
            callback(db);
          }
        });
      });
    });
  });
}

function clearCollection(db, callback) {
  // Clear collection
  db.collection('postedmedias').deleteMany({}, (err, r) => {
    if (err) {
      LogUtil.winston.log('error', 'Failed to truncate "postedmedias" collection!');
    } else {
      LogUtil.winston.log('info', 'Successfully truncated "postedmedias" collection!');
    }

    db.collection('followers').deleteMany({}, (err, r) => {
      if (err) {
        LogUtil.winston.log('error', 'Failed to truncate "followers" collection!');
      } else {
        LogUtil.winston.log('info', 'Successfully truncated "followers" collection!');
      }

      db.collection('admins').deleteMany({}, (err, r) => {
        if (err) {
          LogUtil.winston.log('error', 'Failed to truncate "admins" collection!');
        } else {
          LogUtil.winston.log('info', 'Successfully truncated "admins" collection!');
        }

        db.collection('channels').deleteMany({}, (err, r) => {
          if (err) {
            LogUtil.winston.log('error', 'Failed to truncate "channels" collection!');
          } else {
            LogUtil.winston.log('info', 'Successfully truncated "channels" collection!');
          }

          if (typeof callback === 'function') {
            callback(db);
          }
        });
      });
    });
  });
}

// Set callback function after database connection is established
function openConnectionCallback (db) {
  // Start database seeding process
  const clearCollectionCallback = (db) => {
    insertMockData(db, MongoDriver.closeDBConnection);
  };

  clearCollection(db, clearCollectionCallback);
};

// Open database connection, if environment is not production
// Just for safety reasons
if (isProd) {
  MongoDriver.openDBConnection(openConnectionCallback);
}
<|endoftext|>