<commit_before>'use strict';

const child_process = require('mz/child_process');
const fs = require('mz/fs');
const mkdirp = require('mkdirp-then');
const path = require('path');
const co = require('co');

const debug = require('debug')('grm:git');

const config = require('../../../config.json');
const dataFolder = path.resolve(config.dir.git);

function Git(org, repo, OAuthToken) {
    this.org = org;
    this.repo = repo;
    this.orgDir = path.join(dataFolder, this.org);
    this.repoDir = path.join(this.orgDir, this.repo);

    this.gitUrl =
        `https://${OAuthToken}:@github.com/${this.org}/${this.repo}.git`;
    // the ':' is important to specify an empty password. Otherwise we risk to
    // trigger a prompt if the repository doesn't exist.
    this.execOptions = {
        cwd: this.repoDir
    };

    this.tasks = {};
}

function*initRepo() {
    let exist = yield fs.exists(path.join(this.repoDir, '.git'));
    if (!exist) {
        debug(`Repo ${this.org}/${this.repo} does not exist, cloning`);
        yield mkdirp(this.orgDir);
        yield child_process.execFile('git', ['clone', this.gitUrl], {cwd: this.orgDir});
        debug('clone successful');
    }
}
Git.prototype.init = makeTask('init', initRepo, true);

function*pullRepo() {
    yield this.init();
    debug('pulling from GitHub');
    yield child_process.execFile('git', ['pull'], this.execOptions);
}
Git.prototype.pull = makeTask('pull', pullRepo);

function*doBuild() {
    yield this.pull();
    debug('building project');
    yield child_process.execFile('npm', ['install'], this.execOptions);
    yield child_process.execFile('npm', ['run', 'build'], this.execOptions);
    debug('build finished, getting list of files');
    let buildDir = path.join(this.repoDir, 'dist');
    let buildFiles = yield fs.readdir(buildDir);
    return buildFiles.map(function (file) {
        return {
            name: file,
            path: path.join(buildDir, file)
        };
    });
}
Git.prototype.build = makeTask('build', doBuild);

function*doPublish(files, message) {
    yield this.pull();
    debug(`publishing : ${message}`);
    yield child_process.execFile('git', ['add'].concat(files), this.execOptions);
    yield child_process.execFile('git', ['commit', '-m', message], this.execOptions);
    yield child_process.execFile('git', ['push'], this.execOptions);
    debug('publish finished');
}
Git.prototype.publish = makeTask('publish', doPublish);

function*doNpmPublish() {
    yield this.pull();
    try {
        debug('getting npm authors');
        var authors = yield child_process.execFile('npm', ['author', 'ls'], this.execOptions);
        var isAdmin = authors[0].includes('cheminfo-bot');
        if (isAdmin) {
            debug(`publishing on NPM`);
            yield child_process.execFile('npm', ['publish'], this.execOptions);
        } else {
            debug('cheminfo-bot is not an admin')
        }
    } catch (e) {
        throw new Error('NPM publish failed');
    }
}
Git.prototype.npmPublish = makeTask('npmPublish', doNpmPublish);

function*doReadPkg() {
    yield this.pull();
    debug('reading package files');
    let result = {
        node: null,
        bower: null
    };
    let packageNode = path.join(this.repoDir, 'package.json');
    if (yield fs.exists(packageNode)) {
        result.node = JSON.parse(yield fs.readFile(packageNode, 'utf-8'));
        debug('found package.json');
    }
    let packageBower = path.join(this.repoDir, 'bower.json');
    if (yield fs.exists(packageBower)) {
        result.bower = JSON.parse(yield fs.readFile(packageBower, 'utf-8'));
        debug('found bower.json');
    }
    return result;
}
Git.prototype.readPkg = makeTask('readPkg', doReadPkg);

function*doWritePkg(pkg) {
    debug('writing package files');
    if (pkg.node) {
        yield fs.writeFile(path.join(this.repoDir, 'package.json'), JSON.stringify(pkg.node, null, '  '));
    }
    if (pkg.bower) {
        yield fs.writeFile(path.join(this.repoDir, 'bower.json'), JSON.stringify(pkg.bower, null, '  '));
    }
}
Git.prototype.writePkg = makeTask('writePkg', doWritePkg);

Git.prototype.task = function (name, executor, onlyOnce, args) {
    let task = this.tasks[name];
    if (task) {
        if (task === true) {
            return Promise.resolve();
        } else {
            return task;
        }
    } else {
        let self = this;
        this.tasks[name] = executor.apply(this, args).then(function (result) {
            self.tasks[name] = !!onlyOnce;
            return result;
        }, function (e) {
            self.tasks[name] = false;
            throw e;
        });
        return this.tasks[name];
    }
};

function makeTask(name, executor, onlyOnce) {
    executor = co.wrap(executor);
    return function () {
        return this.task(name, executor, onlyOnce, arguments);
    };
}

module.exports = Git;
<commit_msg>reset before pulling<commit_after>'use strict';

const child_process = require('mz/child_process');
const fs = require('mz/fs');
const mkdirp = require('mkdirp-then');
const path = require('path');
const co = require('co');

const debug = require('debug')('grm:git');

const config = require('../../../config.json');
const dataFolder = path.resolve(config.dir.git);

function Git(org, repo, OAuthToken) {
    this.org = org;
    this.repo = repo;
    this.orgDir = path.join(dataFolder, this.org);
    this.repoDir = path.join(this.orgDir, this.repo);

    this.gitUrl =
        `https://${OAuthToken}:@github.com/${this.org}/${this.repo}.git`;
    // the ':' is important to specify an empty password. Otherwise we risk to
    // trigger a prompt if the repository doesn't exist.
    this.execOptions = {
        cwd: this.repoDir
    };

    this.tasks = {};
}

function*initRepo() {
    let exist = yield fs.exists(path.join(this.repoDir, '.git'));
    if (!exist) {
        debug(`Repo ${this.org}/${this.repo} does not exist, cloning`);
        yield mkdirp(this.orgDir);
        yield child_process.execFile('git', ['clone', this.gitUrl], {cwd: this.orgDir});
        debug('clone successful');
    }
}
Git.prototype.init = makeTask('init', initRepo, true);

function*pullRepo(reset) {
    yield this.init();
    debug('pulling from GitHub');
    if (reset) {
        yield child_process.execFile('git', ['reset', '--hard', 'origin/master'], this.execOptions);
    }
    yield child_process.execFile('git', ['pull'], this.execOptions);
}
Git.prototype.pull = makeTask('pull', pullRepo);

function*doBuild() {
    yield this.pull(true);
    debug('building project');
    yield child_process.execFile('npm', ['install'], this.execOptions);
    yield child_process.execFile('npm', ['run', 'build'], this.execOptions);
    debug('build finished, getting list of files');
    let buildDir = path.join(this.repoDir, 'dist');
    let buildFiles = yield fs.readdir(buildDir);
    return buildFiles.map(function (file) {
        return {
            name: file,
            path: path.join(buildDir, file)
        };
    });
}
Git.prototype.build = makeTask('build', doBuild);

function*doPublish(files, message) {
    debug(`publishing : ${message}`);
    yield child_process.execFile('git', ['add'].concat(files), this.execOptions);
    yield child_process.execFile('git', ['commit', '-m', message], this.execOptions);
    yield child_process.execFile('git', ['push'], this.execOptions);
    debug('publish finished');
}
Git.prototype.publish = makeTask('publish', doPublish);

function*doNpmPublish() {
    try {
        debug('getting npm authors');
        var authors = yield child_process.execFile('npm', ['author', 'ls'], this.execOptions);
        var isAdmin = authors[0].includes('cheminfo-bot');
        if (isAdmin) {
            debug(`publishing on NPM`);
            yield child_process.execFile('npm', ['publish'], this.execOptions);
        } else {
            debug('cheminfo-bot is not an admin')
        }
    } catch (e) {
        throw new Error('NPM publish failed');
    }
}
Git.prototype.npmPublish = makeTask('npmPublish', doNpmPublish);

function*doReadPkg() {
    yield this.pull(true);
    debug('reading package files');
    let result = {
        node: null,
        bower: null
    };
    let packageNode = path.join(this.repoDir, 'package.json');
    if (yield fs.exists(packageNode)) {
        result.node = JSON.parse(yield fs.readFile(packageNode, 'utf-8'));
        debug('found package.json');
    }
    let packageBower = path.join(this.repoDir, 'bower.json');
    if (yield fs.exists(packageBower)) {
        result.bower = JSON.parse(yield fs.readFile(packageBower, 'utf-8'));
        debug('found bower.json');
    }
    return result;
}
Git.prototype.readPkg = makeTask('readPkg', doReadPkg);

function*doWritePkg(pkg) {
    debug('writing package files');
    if (pkg.node) {
        yield fs.writeFile(path.join(this.repoDir, 'package.json'), JSON.stringify(pkg.node, null, '  '));
    }
    if (pkg.bower) {
        yield fs.writeFile(path.join(this.repoDir, 'bower.json'), JSON.stringify(pkg.bower, null, '  '));
    }
}
Git.prototype.writePkg = makeTask('writePkg', doWritePkg);

Git.prototype.task = function (name, executor, onlyOnce, args) {
    let task = this.tasks[name];
    if (task) {
        if (task === true) {
            return Promise.resolve();
        } else {
            return task;
        }
    } else {
        let self = this;
        this.tasks[name] = executor.apply(this, args).then(function (result) {
            self.tasks[name] = !!onlyOnce;
            return result;
        }, function (e) {
            self.tasks[name] = false;
            throw e;
        });
        return this.tasks[name];
    }
};

function makeTask(name, executor, onlyOnce) {
    executor = co.wrap(executor);
    return function () {
        return this.task(name, executor, onlyOnce, arguments);
    };
}

module.exports = Git;
<|endoftext|>


<commit_before>import GeoJSON from '../src/ol/format/GeoJSON.js';
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';

const map = new Map({
  layers: [
    new TileLayer({
      source: new OSM(),
    }),
    new VectorLayer({
      source: new VectorSource({
        url: 'data/geojson/countries.geojson',
        format: new GeoJSON(),
      }),
      opacity: 0.5,
    }),
  ],
  target: 'map',
  view: new View({
    center: [0, 0],
    zoom: 2,
  }),
});

document.getElementById('export-png').addEventListener('click', function () {
  map.once('rendercomplete', function () {
    const mapCanvas = document.createElement('canvas');
    const size = map.getSize();
    mapCanvas.width = size[0];
    mapCanvas.height = size[1];
    const mapContext = mapCanvas.getContext('2d');
    Array.prototype.forEach.call(
      document.querySelectorAll('.ol-layer canvas'),
      function (canvas) {
        if (canvas.width > 0) {
          const opacity = canvas.parentNode.style.opacity;
          mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
          const transform = canvas.style.transform;
          // Get the transform parameters from the style's transform matrix
          const matrix = transform
            .match(/^matrix\(([^\(]*)\)$/)[1]
            .split(',')
            .map(Number);
          // Apply the transform to the export map context
          CanvasRenderingContext2D.prototype.setTransform.apply(
            mapContext,
            matrix
          );
          mapContext.drawImage(canvas, 0, 0);
        }
      }
    );
    if (navigator.msSaveBlob) {
      // link download attribute does not work on MS browsers
      navigator.msSaveBlob(mapCanvas.msToBlob(), 'map.png');
    } else {
      const link = document.getElementById('image-download');
      link.href = mapCanvas.toDataURL();
      link.click();
    }
  });
  map.renderSync();
});
<commit_msg>Add Heatmap layer to example<commit_after>import GeoJSON from '../src/ol/format/GeoJSON.js';
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {
  Heatmap as HeatmapLayer,
  Tile as TileLayer,
  Vector as VectorLayer,
} from '../src/ol/layer.js';
import {OSM, Vector as VectorSource} from '../src/ol/source.js';

const map = new Map({
  layers: [
    new TileLayer({
      source: new OSM(),
    }),
    new VectorLayer({
      source: new VectorSource({
        url: 'data/geojson/countries.geojson',
        format: new GeoJSON(),
      }),
      opacity: 0.5,
    }),
    new HeatmapLayer({
      source: new VectorSource({
        url: 'data/geojson/world-cities.geojson',
        format: new GeoJSON(),
      }),
      weight: function (feature) {
        return feature.get('population') / 1e7;
      },
      radius: 15,
      blur: 15,
      opacity: 0.5,
    }),
  ],
  target: 'map',
  view: new View({
    center: [0, 0],
    zoom: 2,
  }),
});

document.getElementById('export-png').addEventListener('click', function () {
  map.once('rendercomplete', function () {
    const mapCanvas = document.createElement('canvas');
    const size = map.getSize();
    mapCanvas.width = size[0];
    mapCanvas.height = size[1];
    const mapContext = mapCanvas.getContext('2d');
    Array.prototype.forEach.call(
      map.getViewport().querySelectorAll('.ol-layer canvas, canvas.ol-layer'),
      function (canvas) {
        if (canvas.width > 0) {
          const opacity =
            canvas.parentNode.style.opacity || canvas.style.opacity;
          mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
          let matrix;
          const transform = canvas.style.transform;
          if (transform) {
            // Get the transform parameters from the style's transform matrix
            matrix = transform
              .match(/^matrix\(([^\(]*)\)$/)[1]
              .split(',')
              .map(Number);
          } else {
            matrix = [
              parseFloat(canvas.style.width) / canvas.width,
              0,
              0,
              parseFloat(canvas.style.height) / canvas.height,
              0,
              0,
            ];
          }
          // Apply the transform to the export map context
          CanvasRenderingContext2D.prototype.setTransform.apply(
            mapContext,
            matrix
          );
          mapContext.drawImage(canvas, 0, 0);
        }
      }
    );
    if (navigator.msSaveBlob) {
      // link download attribute does not work on MS browsers
      navigator.msSaveBlob(mapCanvas.msToBlob(), 'map.png');
    } else {
      const link = document.getElementById('image-download');
      link.href = mapCanvas.toDataURL();
      link.click();
    }
  });
  map.renderSync();
});
<|endoftext|>


<commit_before>import {Button} from 'widget/button'
import {IconButton} from 'widget/legacyButton'
import {Msg, msg} from 'translate'
import {Progress} from 'widget/progress'
import {connect} from 'store'
import React from 'react'
import Tooltip from 'widget/tooltip'
import api from 'api'
import styles from './tasks.module.css'

const mapStateToProps = (state) => ({
    tasks: state.tasks,
})

class Tasks extends React.Component {
    constructor(props) {
        super(props)
        this.state = {tasks: props.tasks || []}
    }

    renderOverlay(task) {
        return (

                {['FAILED', 'COMPLETED', 'CANCELED'].includes(task.status) ? (
                    <React.Fragment>
                        <Button
                            className={styles.restart}
                            icon='undo'
                            label={msg('button.restart')}
                            onClick={() => this.restartTask(task)}/>
                        <Button
                            className={styles.remove}
                            icon='times'
                            label={msg('button.remove')}
                            onClick={() => this.removeTask(task)}/>
                    </React.Fragment>
                ) : task.status === 'ACTIVE' ?
                    <Button
                        className={styles.stop}
                        icon='stop'
                        label={msg('button.stop')}
                        onClick={() => this.stopTask(task)}/>
                    : null}

        )
    }

    renderTask(task) {
        return (

{task.name}

                <Progress className={styles.progress} status={task.status}/>

{task.statusDescription}

                {this.renderOverlay(task)}

        )
    }

    renderTasks() {
        const {tasks} = this.state
        return tasks.length
            ? (

                    {tasks.map(task => this.renderTask(task))}

            )
            : (

                    <Msg id='tasks.none'/>

            )
    }

    renderToolbar() {
        const {tasks} = this.state
        return (

                <Button
                    chromeless
                    size='large'
                    shape='circle'
                    icon='times'
                    tooltip={msg('tasks.removeAll.tooltip')}
                    tooltipPlacement='bottom'
                    onClick={() => this.removeAllTasks()}
                    disabled={!tasks.length}/>

        )
    }

    render() {
        return (

                {this.renderToolbar()}
                {this.renderTasks()}

        )
    }

    componentDidUpdate(prevProps) {
        if (prevProps.tasks !== this.props.tasks)
            this.setState(prevState => ({...prevState, tasks: this.props.tasks}))
    }

    restartTask(task) {
        const {asyncActionBuilder} = this.props
        this.updateTaskInState(task, () => ({
            ...task,
            status: 'PENDING',
            statusDescription: 'Restarting...'
        }))
        asyncActionBuilder('RESTART_TASK',
            api.tasks.restart$(task.id)
        ).dispatch()
    }

    removeTask(task) {
        const {asyncActionBuilder} = this.props
        const {tasks} = this.state
        this.setState(prevState => ({
            ...prevState,
            tasks: tasks.filter(t => t.id !== task.id)
        }))
        asyncActionBuilder('REMOVE_TASK',
            api.tasks.remove$(task.id)
        ).dispatch()
    }

    removeAllTasks() {
        const {asyncActionBuilder} = this.props
        const {tasks} = this.state
        this.setState(prevState => ({
            ...prevState,
            tasks: tasks.filter(t => !['FAILED', 'COMPLETED', 'CANCELED'].includes(t.status))
        }))
        asyncActionBuilder('REMOVE_ALL_TASK',
            api.tasks.removeAll$()
        ).dispatch()
    }

    stopTask(task) {
        const {asyncActionBuilder} = this.props
        this.updateTaskInState(task, () => ({
            ...task,
            status: 'CANCELED',
            statusDescription: 'Stopping...'
        }))
        asyncActionBuilder('STOP_TASK',
            api.tasks.cancel$(task.id)
        ).dispatch()
    }

    updateTaskInState(task, onUpdate) {
        const {tasks} = this.state
        this.setState(prevState => ({
            ...prevState,
            tasks: tasks.map(t =>
                t.id === task.id ? onUpdate() : t)
        }))
    }
}

export default connect(mapStateToProps)(Tasks)
<commit_msg>Cleanup.<commit_after>import {Button} from 'widget/button'
import {Msg, msg} from 'translate'
import {Progress} from 'widget/progress'
import {connect} from 'store'
import React from 'react'
import api from 'api'
import styles from './tasks.module.css'

const mapStateToProps = (state) => ({
    tasks: state.tasks,
})

class Tasks extends React.Component {
    constructor(props) {
        super(props)
        this.state = {tasks: props.tasks || []}
    }

    renderOverlay(task) {
        return (

                {['FAILED', 'COMPLETED', 'CANCELED'].includes(task.status) ? (
                    <React.Fragment>
                        <Button
                            className={styles.restart}
                            icon='undo'
                            label={msg('button.restart')}
                            onClick={() => this.restartTask(task)}/>
                        <Button
                            className={styles.remove}
                            icon='times'
                            label={msg('button.remove')}
                            onClick={() => this.removeTask(task)}/>
                    </React.Fragment>
                ) : task.status === 'ACTIVE' ?
                    <Button
                        className={styles.stop}
                        icon='stop'
                        label={msg('button.stop')}
                        onClick={() => this.stopTask(task)}/>
                    : null}

        )
    }

    renderTask(task) {
        return (

{task.name}

                <Progress className={styles.progress} status={task.status}/>

{task.statusDescription}

                {this.renderOverlay(task)}

        )
    }

    renderTasks() {
        const {tasks} = this.state
        return tasks.length
            ? (

                    {tasks.map(task => this.renderTask(task))}

            )
            : (

                    <Msg id='tasks.none'/>

            )
    }

    renderToolbar() {
        const {tasks} = this.state
        return (

                <Button
                    chromeless
                    size='large'
                    shape='circle'
                    icon='times'
                    tooltip={msg('tasks.removeAll.tooltip')}
                    tooltipPlacement='bottom'
                    onClick={() => this.removeAllTasks()}
                    disabled={!tasks.length}/>

        )
    }

    render() {
        return (

                {this.renderToolbar()}
                {this.renderTasks()}

        )
    }

    componentDidUpdate(prevProps) {
        if (prevProps.tasks !== this.props.tasks)
            this.setState(prevState => ({...prevState, tasks: this.props.tasks}))
    }

    restartTask(task) {
        const {asyncActionBuilder} = this.props
        this.updateTaskInState(task, () => ({
            ...task,
            status: 'PENDING',
            statusDescription: 'Restarting...'
        }))
        asyncActionBuilder('RESTART_TASK',
            api.tasks.restart$(task.id)
        ).dispatch()
    }

    removeTask(task) {
        const {asyncActionBuilder} = this.props
        const {tasks} = this.state
        this.setState(prevState => ({
            ...prevState,
            tasks: tasks.filter(t => t.id !== task.id)
        }))
        asyncActionBuilder('REMOVE_TASK',
            api.tasks.remove$(task.id)
        ).dispatch()
    }

    removeAllTasks() {
        const {asyncActionBuilder} = this.props
        const {tasks} = this.state
        this.setState(prevState => ({
            ...prevState,
            tasks: tasks.filter(t => !['FAILED', 'COMPLETED', 'CANCELED'].includes(t.status))
        }))
        asyncActionBuilder('REMOVE_ALL_TASK',
            api.tasks.removeAll$()
        ).dispatch()
    }

    stopTask(task) {
        const {asyncActionBuilder} = this.props
        this.updateTaskInState(task, () => ({
            ...task,
            status: 'CANCELED',
            statusDescription: 'Stopping...'
        }))
        asyncActionBuilder('STOP_TASK',
            api.tasks.cancel$(task.id)
        ).dispatch()
    }

    updateTaskInState(task, onUpdate) {
        const {tasks} = this.state
        this.setState(prevState => ({
            ...prevState,
            tasks: tasks.map(t =>
                t.id === task.id ? onUpdate() : t)
        }))
    }
}

export default connect(mapStateToProps)(Tasks)
<|endoftext|>


<commit_before>// @flow
// The filtered inbox rows. No dividers or headers, just smallbig row items
import {createSelector, type TypedState} from '../../../util/container'

const score = (lcFilter: string, lcYou: string, names: Array<string>): number => {
  // special case, looking for yourself
  if (names.length === 1 && names[0] === lcYou) {
    return lcYou.indexOf(lcFilter) !== -1 ? 1 : 0
  }

  const namesMinusYou = names.filter(n => n !== lcYou)
  // special case, comma search
  const filters = lcFilter.split(',').filter(Boolean)
  let filter
  if (filters.length > 1) {
    const mustExist = filters.slice(0, -1)
    const partial = filters.slice(-1)
    // In comma sep. inputs all but the last name must be exact matches
    if (!mustExist.every(m => namesMinusYou.includes(m))) {
      return 0
    }
    filter = partial[0]
  } else {
    filter = filters[0]
  }

  const {foundExact, foundPrefix, foundSub} = namesMinusYou.reduce(
    (data, p) => {
      if (p === filter) {
        data.foundExact += 1
        return data
      } else {
        const idx = p.indexOf(filter)
        if (idx === 0) {
          data.foundPrefix += 1
          return data
        } else if (idx !== -1) {
          data.foundSub += 1
          return data
        } else {
          return data
        }
      }
    },
    {foundExact: 0, foundPrefix: 0, foundSub: 0}
  )
  return (
    (foundExact ? 1000 : 0) + (foundPrefix ? 100 : 0) + (foundSub ? 10 : 0) - namesMinusYou.join('').length
  )
}

let _metaMap
// Note: This is NOT a real selector. Instead this fires and stashes into _metaMap a cached copy.
// If the other things change (inboxFilter, username, etc) then they'll just grab the cached value.
// This serves 2 purposes. 1. No thrashing as people are chatting (since we don't show snippets / use the ordering of timestamps)
// and 2. We don't want the results to move around
const fakeGetMetaMap = createSelector([(state: TypedState) => state.chat2.metaMap], metaMap => {
  _metaMap = metaMap
  return null
})

// Ignore headers, score based on matches of participants, ignore total non matches
const getFilteredRowsAndMetadata = createSelector(
  [
    fakeGetMetaMap,
    (state: TypedState) => state.chat2.inboxFilter,
    (state: TypedState) => state.config.username || '',
  ],
  (_, filter, username) => {
    const metas = _metaMap.valueSeq().toArray()
    const lcFilter = filter.toLowerCase()
    const lcYou = username.toLowerCase()
    const smallRows = metas
      .map(meta => {
        if (meta.teamType !== 'big') {
          const s = score(lcFilter, lcYou, meta.teamname ? [meta.teamname] : meta.participants.toArray())
          return s > 0
            ? {
                conversationIDKey: meta.conversationIDKey,
                score: s,
                timestamp: meta.timestamp,
              }
            : null
        } else {
          return null
        }
      })
      .filter(Boolean)
      .sort((a, b) => (a.score === b.score ? b.timestamp - a.timestamp : b.score - a.score))
      .map(({conversationIDKey}) => ({conversationIDKey, type: 'small'}))

    const bigRows = metas
      .map(meta => {
        if (meta.teamType === 'big') {
          const s = score(lcFilter, '', [meta.teamname, meta.channelname].filter(Boolean))
          return s > 0
            ? {
                channelname: meta.channelname,
                conversationIDKey: meta.conversationIDKey,
                score: s,
                teamname: meta.teamname,
              }
            : null
        } else {
          return null
        }
      })
      .filter(Boolean)
      .sort((a, b) => b.score - a.score)
      .map(({conversationIDKey, channelname, teamname}) => ({
        channelname,
        conversationIDKey,
        teamname,
        type: 'big',
      }))

    return {
      rows: [...smallRows, ...bigRows],
      showBuildATeam: false,
      showSmallTeamsExpandDivider: false,
      smallIDsHidden: [],
      smallTeamsExpanded: true,
    }
  }
)

export default getFilteredRowsAndMetadata

export const _testing = {
  score,
}
<commit_msg>fix jump to convo disappearing sometimes (#11691)<commit_after>// @flow
// The filtered inbox rows. No dividers or headers, just smallbig row items
import {createSelector, type TypedState} from '../../../util/container'

const score = (lcFilter: string, lcYou: string, names: Array<string>): number => {
  // special case, looking for yourself
  if (names.length === 1 && names[0] === lcYou) {
    return lcYou.indexOf(lcFilter) !== -1 ? 1 : 0
  }

  const namesMinusYou = names.filter(n => n !== lcYou)
  // special case, comma search
  const filters = lcFilter.split(',').filter(Boolean)
  let filter
  if (filters.length > 1) {
    const mustExist = filters.slice(0, -1)
    const partial = filters.slice(-1)
    // In comma sep. inputs all but the last name must be exact matches
    if (!mustExist.every(m => namesMinusYou.includes(m))) {
      return 0
    }
    filter = partial[0]
  } else {
    filter = filters[0]
  }

  const {foundExact, foundPrefix, foundSub} = namesMinusYou.reduce(
    (data, p) => {
      if (p === filter) {
        data.foundExact += 1
        return data
      } else {
        const idx = p.indexOf(filter)
        if (idx === 0) {
          data.foundPrefix += 1
          return data
        } else if (idx !== -1) {
          data.foundSub += 1
          return data
        } else {
          return data
        }
      }
    },
    {foundExact: 0, foundPrefix: 0, foundSub: 0}
  )
  const rawScore = (foundExact ? 1000 : 0) + (foundPrefix ? 100 : 0) + (foundSub ? 10 : 0)
  // We subtract inputLength to give a bonus to shorter groups, but we never want that to make a matching score go to zero
  const inputLength = namesMinusYou.join('').length

  return rawScore > 0 ? Math.max(1, rawScore - inputLength) : 0
}

let _metaMap
// Note: This is NOT a real selector. Instead this fires and stashes into _metaMap a cached copy.
// If the other things change (inboxFilter, username, etc) then they'll just grab the cached value.
// This serves 2 purposes. 1. No thrashing as people are chatting (since we don't show snippets / use the ordering of timestamps)
// and 2. We don't want the results to move around
const fakeGetMetaMap = createSelector([(state: TypedState) => state.chat2.metaMap], metaMap => {
  _metaMap = metaMap
  return null
})

// Ignore headers, score based on matches of participants, ignore total non matches
const getFilteredRowsAndMetadata = createSelector(
  [
    fakeGetMetaMap,
    (state: TypedState) => state.chat2.inboxFilter,
    (state: TypedState) => state.config.username || '',
  ],
  (_, filter, username) => {
    const metas = _metaMap.valueSeq().toArray()
    const lcFilter = filter.toLowerCase()
    const lcYou = username.toLowerCase()
    const smallRows = metas
      .map(meta => {
        if (meta.teamType !== 'big') {
          const s = score(lcFilter, lcYou, meta.teamname ? [meta.teamname] : meta.participants.toArray())
          return s > 0
            ? {
                conversationIDKey: meta.conversationIDKey,
                score: s,
                timestamp: meta.timestamp,
              }
            : null
        } else {
          return null
        }
      })
      .filter(Boolean)
      .sort((a, b) => (a.score === b.score ? b.timestamp - a.timestamp : b.score - a.score))
      .map(({conversationIDKey}) => ({conversationIDKey, type: 'small'}))

    const bigRows = metas
      .map(meta => {
        if (meta.teamType === 'big') {
          const s = score(lcFilter, '', [meta.teamname, meta.channelname].filter(Boolean))
          return s > 0
            ? {
                channelname: meta.channelname,
                conversationIDKey: meta.conversationIDKey,
                score: s,
                teamname: meta.teamname,
              }
            : null
        } else {
          return null
        }
      })
      .filter(Boolean)
      .sort((a, b) => b.score - a.score)
      .map(({conversationIDKey, channelname, teamname}) => ({
        channelname,
        conversationIDKey,
        teamname,
        type: 'big',
      }))

    return {
      rows: [...smallRows, ...bigRows],
      showBuildATeam: false,
      showSmallTeamsExpandDivider: false,
      smallIDsHidden: [],
      smallTeamsExpanded: true,
    }
  }
)

export default getFilteredRowsAndMetadata

export const _testing = {
  score,
}
<|endoftext|>


<commit_before>/*global beforeEach, afterEach, describe, it, inject, expect, module, spyOn, moment, angular, $*/
describe('$moment', function () {
    'use strict';

    // So we don't have to worry about timezones for test runner's machine
    moment.defaultFormat = 'X';

    var $moment, $scope, $compile, $timeout, compile, controller, consoleLog;

    var momentInput                = '<input type="moment" ng-model="date">',
        momentInputFormat          = '<input type="moment" ng-model="date" format="dateFormat">',
        momentInputViewModelFormat = '<input type="moment" ng-model="date" view-format="dateViewFormat" model-format="dateModelFormat">',
        momentInputMinMax          = '<input type="moment" ng-model="date" min="dateMin" max="dateMax">';

    var dateFormat1 = 'MM-DD-YYYY',
        dateFormat2 = 'YYYY-MM-DD',
        dateFormat3 = 'MM-YYYY-DD',
        monthFormat = 'MM-YYYY';

    var viewDate  = '01/31/1986',
        modelDate = '507542400';

    var modelDateLowest  = '307542400',
        modelDateLower   = '407542400',
        modelDateHigher  = '607542400',
        modelDateHighest = '707542400',

        viewDateLowest   = '09/30/1979',
        viewDateLower    = '11/30/1982',
        viewDateHigher   = '04/02/1989',
        viewDateHighest  = '06/02/1992';

    var wheelUpEvent   = ['mousewheel', { type:'wheel', wheelDelta:120, which:1 }],
        wheelDownEvent = ['mousewheel', { type:'wheel', wheelDelta:-120, which:1 }],
        upKeyEvent     = ['keydown', { type:'keydown', which:38 }],
        downKeyEvent   = ['keydown', { type:'keydown', which:40 }],
        plusKeyEvent   = ['keydown', { type:'keydown', which:107 }],
        minusKeyEvent  = ['keydown', { type:'keydown', which:109 }];

    beforeEach(angular.mock.module('angular-momentjs'));
    beforeEach(inject(function (_$moment_, _$rootScope_, _$compile_, _$timeout_) {
      $moment  = _$moment_;
      $scope   = _$rootScope_.$new();
      $compile = _$compile_;
      $timeout = _$timeout_;
      compile  = function(markup) { return $compile(markup)($scope); };

      consoleLog = console.log || angular.noop;
    }));

    describe('input directive', function() {

      it('should initialize only on type "date" and "moment" inputs', function() {
        var textInput   = compile('<input type="text" ng-model="date">');
        var dateInput   = compile('<input type="date" ng-model="date">');
        var momentInput = compile('<input type="moment" ng-model="date">');
        $scope.$apply("dateFormat = '"+ modelDate +"'");
        expect(textInput.attr('class').split(' ')).not.toContain('ng-valid-date');
        expect(dateInput.attr('class').split(' ')).toContain('ng-valid-date');
        expect(momentInput.attr('class').split(' ')).toContain('ng-valid-date');
      });

      it('should initialize only on inputs with an ngModelController', function() {
        var plainInput  = compile('<input type="moment">');
        var momentInput = compile('<input type="moment" ng-model="date">');
        $scope.$apply("dateFormat = '"+ modelDate +"'");
        expect(plainInput.attr('class').split(' ')).not.toContain('ng-valid-date');
        expect(momentInput.attr('class').split(' ')).toContain('ng-valid-date');
      });

      it('should set the placeholder value to match the view\'s format', function() {
        var input = compile(momentInput);
        expect(input.attr('placeholder')).toBe('MM/DD/YYYY');
      });

      it('should change the placeholder value to match a dynamic format', function() {
        var input = compile(momentInputFormat);
        $scope.$apply("dateFormat = '"+ dateFormat1 +"'");
        expect(input.attr('placeholder')).toBe(dateFormat1);
        $scope.$apply("dateFormat = '"+ dateFormat2 +"'");
        expect(input.attr('placeholder')).toBe(dateFormat2);
      });

      it('should format a model date for the view', function() {
        var input = compile(momentInput);
        $scope.$apply("date = '"+ modelDate +"'");
        expect(input.val()).toBe(viewDate);
      });

      it('should format a view date for the model', function() {
        var input = compile(momentInput),
            ctrl  = input.controller('ngModel');
        ctrl.$setViewValue(viewDate);
        expect($scope.date).toBe(modelDate);
      });

      it('should invalidate an invalid view date', function() {
        var input = compile(momentInput),
            ctrl  = input.controller('ngModel');

        ctrl.$setViewValue('Purple monkey dishwasher');
        expect(ctrl.$error.date).toBe(true);
        expect($scope.date).toBeUndefined();

        ctrl.$setViewValue('01/32/1986');
        expect(ctrl.$error.date).toBe(true);
        expect($scope.date).toBeUndefined();
      });

      it('should reformat view/model based on view- and model-format attrs', function() {
        var input = compile(momentInputViewModelFormat),
            ctrl  = input.controller('ngModel');
        $scope.$apply("date = '"+ viewDate +"'");

        // Flip default view and model formats so model becomes valid
        $scope.$apply("dateModelFormat = 'L'");
        $scope.$apply("dateViewFormat  = 'X'");
        $timeout.flush();
        expect($scope.date).toBe(viewDate);
        expect(input.val()).toBe(modelDate);

        // Reset view format to default
        $scope.$apply("dateViewFormat = 'L'");
        $timeout.flush();
        expect(input.val()).toBe(viewDate);

        // Reset model format to default
        $scope.$apply("dateModelFormat = 'X'");
        expect($scope.date).toBe(modelDate);
      });

      // Model-side min/max tests

      it('should validate the model against min and max string values', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("date    = '"+ modelDate +"'");
        $scope.$apply("dateMin = '"+ modelDateLower +"'");
        $scope.$apply("dateMax = '"+ modelDateHigher +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe(viewDate);

        $scope.$apply("date = '"+ modelDateLowest +"'");
        expect(ctrl.$error.min).toBe(true);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe('');

        $scope.$apply("date = '"+ modelDateHighest +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(true);
        expect(input.val()).toBe('');

        $scope.$apply("date = '"+ modelDate +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe(viewDate);
      });

      it('should validate the model against min and max array values', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("date    = '"+ modelDate +"'");
        $scope.$apply("dateMin = ['"+ viewDateLower +"', 'MM-DD-YYYY'] ");
        $scope.$apply("dateMax = ['"+ viewDateHigher +"', 'MM-DD-YYYY'] ");

        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe(viewDate);

        $scope.$apply("date = '"+ modelDateLowest +"'");
        expect(ctrl.$error.min).toBe(true);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe('');

        $scope.$apply("date = '"+ modelDateHighest +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(true);
        expect(input.val()).toBe('');

        $scope.$apply("date = '"+ modelDate +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe(viewDate);
      });

      // View-side min/max tests

      it('should validate the view against min and max string values', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("dateMin = '"+ modelDateLower +"'");
        $scope.$apply("dateMax = '"+ modelDateHigher +"'");

        ctrl.$setViewValue(viewDateLowest);
        expect(ctrl.$error.min).toBe(true);
        expect(ctrl.$error.max).toBe(false);
        expect($scope.date).toBeUndefined();

        ctrl.$setViewValue(viewDateHighest);
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(true);
        expect($scope.date).toBeUndefined();
      });

      it('should validate the view against min and max array values', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("dateMin = ['"+ viewDateLower +"', 'MM-DD-YYYY'] ");
        $scope.$apply("dateMax = ['"+ viewDateHigher +"', 'MM-DD-YYYY'] ");

        ctrl.$setViewValue(viewDateLowest);
        expect(ctrl.$error.min).toBe(true);
        expect(ctrl.$error.max).toBe(false);
        expect($scope.date).toBeUndefined();

        ctrl.$setViewValue(viewDateHighest);
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(true);
        expect($scope.date).toBeUndefined();
      });

      // End view-size min/max tests

      it('should revalidate when min/max values change', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("date    = '"+ modelDate +"'");
        $scope.$apply("dateMin = '"+ modelDateLower +"'");
        $scope.$apply("dateMax = '"+ modelDateHigher +"'");

        $scope.$apply("dateMin = '"+ modelDateLowest +"'");
        $scope.$apply("dateMax = '"+ modelDateLower +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(true);
        expect($scope.date).toBeUndefined();

        $scope.$apply("dateMin = '"+ modelDateHigher +"'");
        $scope.$apply("dateMax = '"+ modelDateHighest +"'");
        expect(ctrl.$error.min).toBe(true);
        expect(ctrl.$error.max).toBe(false);
        expect($scope.date).toBeUndefined();

        $scope.$apply("dateMin = '"+ modelDateLower +"'");
        $scope.$apply("dateMax = '"+ modelDateHigher +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(false);
        expect($scope.date).toBe(modelDate);
      });

      // Stepping

      it('should set value to today\'s date on up, down, plus, or minus keys, or mousewheel', function() {
        var input = compile(momentInput),
            today = $moment().format('L');

        input.triggerHandler.apply(input, wheelUpEvent);
        expect(input.val()).toBe(today);

        $scope.$apply("date = undefined");
        input.triggerHandler.apply(input, wheelDownEvent);
        expect(input.val()).toBe(today);

        $scope.$apply("date = undefined");
        input.triggerHandler.apply(input, upKeyEvent);
        expect(input.val()).toBe(today);

        $scope.$apply("date = undefined");
        input.triggerHandler.apply(input, downKeyEvent);
        expect(input.val()).toBe(today);

        $scope.$apply("date = undefined");
        input.triggerHandler.apply(input, plusKeyEvent);
        expect(input.val()).toBe(today);

        $scope.$apply("date = undefined");
        input.triggerHandler.apply(input, minusKeyEvent);
        expect(input.val()).toBe(today);

      });

      it('should step by one day with a value', function() {
        var input     = compile(momentInput),
            ctrl      = input.controller('ngModel'),
            today     = $moment().format('L'),
            tomorrow  = $moment().add(1, 'day').format('L'),
            yesterday = $moment().subtract(1, 'day').format('L');

        ctrl.$setViewValue(today);
        input.triggerHandler.apply(input, wheelUpEvent);
        expect(ctrl.$viewValue).toBe(tomorrow);

        input.triggerHandler.apply(input, downKeyEvent);
        input.triggerHandler.apply(input, minusKeyEvent);
        expect(ctrl.$viewValue).toBe(yesterday);
      });

      it('should step by one month if shift key is pressed', function() {
        var input     = compile(momentInput),
            ctrl                = input.controller('ngModel'),
            today               = $moment().format('L'),
            nextMonth           = $moment().add(1, 'month').format('L'),
            wheelUpShiftEvent   = angular.copy(wheelUpEvent),
            wheelDownShiftEvent = angular.copy(wheelDownEvent);

        wheelUpShiftEvent[1].shiftKey   = true;
        wheelDownShiftEvent[1].shiftKey = true;

        ctrl.$setViewValue(today);
        input.triggerHandler.apply(input, wheelUpShiftEvent);
        expect(ctrl.$viewValue).toBe(nextMonth);

        input.triggerHandler.apply(input, wheelDownShiftEvent);
        expect(ctrl.$viewValue).toBe(today);
      });

      it('should not step if input view value is invalid', function() {
        var input = compile(momentInput),
            ctrl  = input.controller('ngModel');

        ctrl.$setViewValue('Purple monkey dishwasher');
        input.triggerHandler.apply(input, wheelUpEvent);
        expect(ctrl.$viewValue).toBe('Purple monkey dishwasher');
        expect($scope.date).toBeUndefined();
      });

      it('should not step if keydown event key isn\'t up, down, plus, or minus', function() {
        var input = compile(momentInput),
            ctrl  = input.controller('ngModel'),
            badKeyEvent = angular.copy(upKeyEvent);
        badKeyEvent[1].which = 39;

        input.triggerHandler.apply(input, badKeyEvent);
        expect(ctrl.$viewValue).toBeFalsy();
        expect($scope.date).toBeUndefined();
      });

    });

});<commit_msg>Complete suite of tests on stepping<commit_after>/*global beforeEach, afterEach, describe, it, inject, expect, module, spyOn, moment, angular, $*/
describe('$moment', function () {
    'use strict';

    // So we don't have to worry about timezones for test runner's machine
    moment.defaultFormat = 'X';

    var $moment, $scope, $compile, $timeout, compile, controller, consoleLog;

    var momentInput                = '<input type="moment" ng-model="date">',
        momentInputFormat          = '<input type="moment" ng-model="date" format="dateFormat">',
        momentInputViewModelFormat = '<input type="moment" ng-model="date" view-format="dateViewFormat" model-format="dateModelFormat">',
        momentInputMinMax          = '<input type="moment" ng-model="date" min="dateMin" max="dateMax">',
        momentInputStep            = '<input type="moment" ng-model="date" step="dateStep">';

    var dateFormat1 = 'MM-DD-YYYY',
        dateFormat2 = 'YYYY-MM-DD',
        dateFormat3 = 'MM-YYYY-DD',
        monthFormat = 'MM-YYYY';

    var viewDate  = '01/31/1986',
        modelDate = '507542400';

    var modelDateLowest  = '307542400',
        modelDateLower   = '407542400',
        modelDateHigher  = '607542400',
        modelDateHighest = '707542400',

        viewDateLowest   = '09/30/1979',
        viewDateLower    = '11/30/1982',
        viewDateHigher   = '04/02/1989',
        viewDateHighest  = '06/02/1992';

    var wheelUpEvent   = ['mousewheel', { type:'wheel', wheelDelta:120, which:1 }],
        wheelDownEvent = ['mousewheel', { type:'wheel', wheelDelta:-120, which:1 }],
        upKeyEvent     = ['keydown', { type:'keydown', which:38 }],
        downKeyEvent   = ['keydown', { type:'keydown', which:40 }],
        plusKeyEvent   = ['keydown', { type:'keydown', which:107 }],
        minusKeyEvent  = ['keydown', { type:'keydown', which:109 }];

    beforeEach(angular.mock.module('angular-momentjs'));
    beforeEach(inject(function (_$moment_, _$rootScope_, _$compile_, _$timeout_) {
      $moment  = _$moment_;
      $scope   = _$rootScope_.$new();
      $compile = _$compile_;
      $timeout = _$timeout_;
      compile  = function(markup) { return $compile(markup)($scope); };

      consoleLog = console.log || angular.noop;
    }));

    describe('input directive', function() {

      it('should initialize only on type "date" and "moment" inputs', function() {
        var textInput   = compile('<input type="text" ng-model="date">');
        var dateInput   = compile('<input type="date" ng-model="date">');
        var momentInput = compile('<input type="moment" ng-model="date">');
        $scope.$apply("dateFormat = '"+ modelDate +"'");
        expect(textInput.attr('class').split(' ')).not.toContain('ng-valid-date');
        expect(dateInput.attr('class').split(' ')).toContain('ng-valid-date');
        expect(momentInput.attr('class').split(' ')).toContain('ng-valid-date');
      });

      it('should initialize only on inputs with an ngModelController', function() {
        var plainInput  = compile('<input type="moment">');
        var momentInput = compile('<input type="moment" ng-model="date">');
        $scope.$apply("dateFormat = '"+ modelDate +"'");
        expect(plainInput.attr('class').split(' ')).not.toContain('ng-valid-date');
        expect(momentInput.attr('class').split(' ')).toContain('ng-valid-date');
      });

      it('should set the placeholder value to match the view\'s format', function() {
        var input = compile(momentInput);
        expect(input.attr('placeholder')).toBe('MM/DD/YYYY');
      });

      it('should change the placeholder value to match a dynamic format', function() {
        var input = compile(momentInputFormat);
        $scope.$apply("dateFormat = '"+ dateFormat1 +"'");
        expect(input.attr('placeholder')).toBe(dateFormat1);
        $scope.$apply("dateFormat = '"+ dateFormat2 +"'");
        expect(input.attr('placeholder')).toBe(dateFormat2);
      });

      it('should format a model date for the view', function() {
        var input = compile(momentInput);
        $scope.$apply("date = '"+ modelDate +"'");
        expect(input.val()).toBe(viewDate);
      });

      it('should format a view date for the model', function() {
        var input = compile(momentInput),
            ctrl  = input.controller('ngModel');
        ctrl.$setViewValue(viewDate);
        expect($scope.date).toBe(modelDate);
      });

      it('should invalidate an invalid view date', function() {
        var input = compile(momentInput),
            ctrl  = input.controller('ngModel');

        ctrl.$setViewValue('Purple monkey dishwasher');
        expect(ctrl.$error.date).toBe(true);
        expect($scope.date).toBeUndefined();

        ctrl.$setViewValue('01/32/1986');
        expect(ctrl.$error.date).toBe(true);
        expect($scope.date).toBeUndefined();
      });

      it('should reformat view/model based on view- and model-format attrs', function() {
        var input = compile(momentInputViewModelFormat),
            ctrl  = input.controller('ngModel');
        $scope.$apply("date = '"+ viewDate +"'");

        // Flip default view and model formats so model becomes valid
        $scope.$apply("dateModelFormat = 'L'");
        $scope.$apply("dateViewFormat  = 'X'");
        $timeout.flush();
        expect($scope.date).toBe(viewDate);
        expect(input.val()).toBe(modelDate);

        // Reset view format to default
        $scope.$apply("dateViewFormat = 'L'");
        $timeout.flush();
        expect(input.val()).toBe(viewDate);

        // Reset model format to default
        $scope.$apply("dateModelFormat = 'X'");
        expect($scope.date).toBe(modelDate);
      });

      // Model-side min/max tests

      it('should validate the model against min and max string values', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("date    = '"+ modelDate +"'");
        $scope.$apply("dateMin = '"+ modelDateLower +"'");
        $scope.$apply("dateMax = '"+ modelDateHigher +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe(viewDate);

        $scope.$apply("date = '"+ modelDateLowest +"'");
        expect(ctrl.$error.min).toBe(true);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe('');

        $scope.$apply("date = '"+ modelDateHighest +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(true);
        expect(input.val()).toBe('');

        $scope.$apply("date = '"+ modelDate +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe(viewDate);
      });

      it('should validate the model against min and max array values', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("date    = '"+ modelDate +"'");
        $scope.$apply("dateMin = ['"+ viewDateLower +"', 'MM-DD-YYYY'] ");
        $scope.$apply("dateMax = ['"+ viewDateHigher +"', 'MM-DD-YYYY'] ");

        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe(viewDate);

        $scope.$apply("date = '"+ modelDateLowest +"'");
        expect(ctrl.$error.min).toBe(true);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe('');

        $scope.$apply("date = '"+ modelDateHighest +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(true);
        expect(input.val()).toBe('');

        $scope.$apply("date = '"+ modelDate +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(false);
        expect(input.val()).toBe(viewDate);
      });

      // View-side min/max tests

      it('should validate the view against min and max string values', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("dateMin = '"+ modelDateLower +"'");
        $scope.$apply("dateMax = '"+ modelDateHigher +"'");

        ctrl.$setViewValue(viewDateLowest);
        expect(ctrl.$error.min).toBe(true);
        expect(ctrl.$error.max).toBe(false);
        expect($scope.date).toBeUndefined();

        ctrl.$setViewValue(viewDateHighest);
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(true);
        expect($scope.date).toBeUndefined();
      });

      it('should validate the view against min and max array values', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("dateMin = ['"+ viewDateLower +"', 'MM-DD-YYYY'] ");
        $scope.$apply("dateMax = ['"+ viewDateHigher +"', 'MM-DD-YYYY'] ");

        ctrl.$setViewValue(viewDateLowest);
        expect(ctrl.$error.min).toBe(true);
        expect(ctrl.$error.max).toBe(false);
        expect($scope.date).toBeUndefined();

        ctrl.$setViewValue(viewDateHighest);
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(true);
        expect($scope.date).toBeUndefined();
      });

      // End view-size min/max tests

      it('should revalidate when min/max values change', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("date    = '"+ modelDate +"'");
        $scope.$apply("dateMin = '"+ modelDateLower +"'");
        $scope.$apply("dateMax = '"+ modelDateHigher +"'");

        $scope.$apply("dateMin = '"+ modelDateLowest +"'");
        $scope.$apply("dateMax = '"+ modelDateLower +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(true);
        expect($scope.date).toBeUndefined();

        $scope.$apply("dateMin = '"+ modelDateHigher +"'");
        $scope.$apply("dateMax = '"+ modelDateHighest +"'");
        expect(ctrl.$error.min).toBe(true);
        expect(ctrl.$error.max).toBe(false);
        expect($scope.date).toBeUndefined();

        $scope.$apply("dateMin = '"+ modelDateLower +"'");
        $scope.$apply("dateMax = '"+ modelDateHigher +"'");
        expect(ctrl.$error.min).toBe(false);
        expect(ctrl.$error.max).toBe(false);
        expect($scope.date).toBe(modelDate);
      });

      // Stepping

      it('should set value to today\'s date on up, down, plus, or minus keys, or mousewheel', function() {
        var input = compile(momentInput),
            today = $moment().format('L');

        input.triggerHandler.apply(input, wheelUpEvent);
        expect(input.val()).toBe(today);

        $scope.$apply("date = undefined");
        input.triggerHandler.apply(input, wheelDownEvent);
        expect(input.val()).toBe(today);

        $scope.$apply("date = undefined");
        input.triggerHandler.apply(input, upKeyEvent);
        expect(input.val()).toBe(today);

        $scope.$apply("date = undefined");
        input.triggerHandler.apply(input, downKeyEvent);
        expect(input.val()).toBe(today);

        $scope.$apply("date = undefined");
        input.triggerHandler.apply(input, plusKeyEvent);
        expect(input.val()).toBe(today);

        $scope.$apply("date = undefined");
        input.triggerHandler.apply(input, minusKeyEvent);
        expect(input.val()).toBe(today);

      });

      it('should step by one day with a value', function() {
        var input     = compile(momentInput),
            ctrl      = input.controller('ngModel'),
            today     = $moment().format('L'),
            tomorrow  = $moment().add(1, 'day').format('L'),
            yesterday = $moment().subtract(1, 'day').format('L');

        ctrl.$setViewValue(today);
        input.triggerHandler.apply(input, wheelUpEvent);
        expect(ctrl.$viewValue).toBe(tomorrow);

        input.triggerHandler.apply(input, downKeyEvent);
        input.triggerHandler.apply(input, minusKeyEvent);
        expect(ctrl.$viewValue).toBe(yesterday);
      });

      it('should step by one month if shift key is pressed', function() {
        var input     = compile(momentInput),
            ctrl                = input.controller('ngModel'),
            today               = $moment().format('L'),
            nextMonth           = $moment().add(1, 'month').format('L'),
            wheelUpShiftEvent   = angular.copy(wheelUpEvent),
            wheelDownShiftEvent = angular.copy(wheelDownEvent);

        wheelUpShiftEvent[1].shiftKey   = true;
        wheelDownShiftEvent[1].shiftKey = true;

        ctrl.$setViewValue(today);
        input.triggerHandler.apply(input, wheelUpShiftEvent);
        expect(ctrl.$viewValue).toBe(nextMonth);

        input.triggerHandler.apply(input, wheelDownShiftEvent);
        expect(ctrl.$viewValue).toBe(today);
      });

      it('should not step if input view value is invalid', function() {
        var input = compile(momentInput),
            ctrl  = input.controller('ngModel');

        ctrl.$setViewValue('Purple monkey dishwasher');
        input.triggerHandler.apply(input, wheelUpEvent);
        expect(ctrl.$viewValue).toBe('Purple monkey dishwasher');
        expect($scope.date).toBeUndefined();
      });

      it('should not step if keydown event key isn\'t up, down, plus, or minus', function() {
        var input = compile(momentInput),
            ctrl  = input.controller('ngModel'),
            badKeyEvent = angular.copy(upKeyEvent);
        badKeyEvent[1].which = 39;

        input.triggerHandler.apply(input, badKeyEvent);
        expect(ctrl.$viewValue).toBeFalsy();
        expect($scope.date).toBeUndefined();
      });

      it('should begin stepping at min when specified', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("dateMin = '"+ modelDateLower +"'");
        $scope.$apply("dateMax = '"+ modelDateHigher +"'");

        input.triggerHandler.apply(input, minusKeyEvent);
        expect(ctrl.$viewValue).toBe(viewDateLower);

        $scope.$apply("date = undefined");
        input.triggerHandler.apply(input, plusKeyEvent);
        expect(ctrl.$viewValue).toBe(viewDateLower);
      });

      it('should not allow stepping out of min/max bounds', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("date    = '"+ modelDateLower +"'");
        $scope.$apply("dateMin = '"+ modelDateLower +"'");
        $scope.$apply("dateMax = '"+ modelDateHigher +"'");

        input.triggerHandler.apply(input, downKeyEvent);
        expect(ctrl.$viewValue).toBe(viewDateLower);

        $scope.$apply("date = '"+ modelDateHigher +"'");
        input.triggerHandler.apply(input, upKeyEvent);
        expect(ctrl.$viewValue).toBe(viewDateHigher);
      });

      it('should step out-of-bounds date to within min and max bounds when inc. and dec., respectively', function() {
        var input = compile(momentInputMinMax),
            ctrl  = input.controller('ngModel');

        $scope.$apply("dateMin = '"+ modelDateLower +"'");
        $scope.$apply("dateMax = '"+ modelDateHigher +"'");

        ctrl.$setViewValue(viewDateLowest);
        input.triggerHandler.apply(input, upKeyEvent);
        expect(ctrl.$viewValue).toBe(viewDateLower);

        ctrl.$setViewValue(viewDateHighest);
        input.triggerHandler.apply(input, downKeyEvent);
        expect(ctrl.$viewValue).toBe(viewDateHigher);
      });

      it('should respect the step attribute and ignore pluralization of unit', function() {
        var input = compile(momentInputStep),
            ctrl                = input.controller('ngModel'),
            today               = $moment().format('L'),
            nextMonth           = $moment().add(1, 'month').format('L');

        $scope.$apply("dateStep = '1 month'");

        input.triggerHandler.apply(input, upKeyEvent);
        expect(ctrl.$viewValue).toBe(today);

        $scope.$apply("dateStep = '1 months'");

        input.triggerHandler.apply(input, upKeyEvent);
        expect(ctrl.$viewValue).toBe(nextMonth);

        input.triggerHandler.apply(input, downKeyEvent);
        expect(ctrl.$viewValue).toBe(today);
      });

      it('should fall back to default stepping if step attribute is invalid', function() {
        var input = compile(momentInputStep),
            ctrl     = input.controller('ngModel'),
            today    = $moment().format('L'),
            tomorrow = $moment().add(1, 'day').format('L');

        input.triggerHandler.apply(input, upKeyEvent);
        $scope.$apply("dateStep = 'month 1'");

        input.triggerHandler.apply(input, upKeyEvent);
        expect(ctrl.$viewValue).toBe(tomorrow);

        $scope.$apply("dateStep = 'Purple monkey dishwasher'");
        input.triggerHandler.apply(input, downKeyEvent);
        expect(ctrl.$viewValue).toBe(today);
      });

    });

});<|endoftext|>


<commit_before>

$("#create_boton").click(function (e) {
    e.preventDefault();
    if ($("#name").val() == "" || $("#description").val() == "" || $("#avgprice").val() == "" || $("#address").val() == "" || $("#phone").val() == "" || $("#lat").val() == "" || $("#lng").val() == "") {
        if ($("#name").val() == "") {
            document.getElementById('name').style.background = '#F6B5B5';
            $('#name').attr('placeholder', 'Fill it!');
        }
        if ($("#description").val() == "") {
            document.getElementById('description').style.background = '#F6B5B5';
            $('#description').attr('placeholder', 'Fill it!');
        }
        if ($("#avgprice").val() == "") {
            document.getElementById('avgprice').style.background = '#F6B5B5';
            $('#avgprice').attr('placeholder', 'Fill it!');
        }
        if ($("#address").val() == "") {
            document.getElementById('address').style.background = '#F6B5B5';
            $('#address').attr('placeholder', 'Fill it!');
        }
        if ($("#phone").val() == "") {
            document.getElementById('phone').style.background = '#F6B5B5';
            $('#phone').attr('placeholder', 'Fill it!');
        }
        if ($("#lat").val() == "") {
            document.getElementById('lat').style.background = '#F6B5B5';
            $('#lat').attr('placeholder', 'Fill it!');
        }
        if ($("#lng").val() == "") {
            document.getElementById('lng').style.background = '#F6B5B5';
            $('#lng').attr('placeholder', 'Fill it!');
        }
    }else {
        var create = new Object();
        create.name = $("#name").val();
        create.description = $("#description").val();
        create.avgprice = $("#avgprice").val();
        create.address = $("#address").val();
        create.phone = $("#phone").val();
        create.lat = $("#lat").val();
        create.lng = $("#lng").val();
        CreateRes(create);
    }
});

function getLocation() {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(showPosition);
    } else {
        alert("Geolocation is not supported by this browser.");
    }
}

function showPosition(position) {
    $("#lat").val(position.coords.latitude);
    $("#lng").val(position.coords.longitude);
}<commit_msg>errors handling geolocation<commit_after>

$("#create_boton").click(function (e) {
    e.preventDefault();
    if ($("#name").val() == "" || $("#description").val() == "" || $("#avgprice").val() == "" || $("#address").val() == "" || $("#phone").val() == "" || $("#lat").val() == "" || $("#lng").val() == "") {
        if ($("#name").val() == "") {
            document.getElementById('name').style.background = '#F6B5B5';
            $('#name').attr('placeholder', 'Fill it!');
        }
        if ($("#description").val() == "") {
            document.getElementById('description').style.background = '#F6B5B5';
            $('#description').attr('placeholder', 'Fill it!');
        }
        if ($("#avgprice").val() == "") {
            document.getElementById('avgprice').style.background = '#F6B5B5';
            $('#avgprice').attr('placeholder', 'Fill it!');
        }
        if ($("#address").val() == "") {
            document.getElementById('address').style.background = '#F6B5B5';
            $('#address').attr('placeholder', 'Fill it!');
        }
        if ($("#phone").val() == "") {
            document.getElementById('phone').style.background = '#F6B5B5';
            $('#phone').attr('placeholder', 'Fill it!');
        }
        if ($("#lat").val() == "") {
            document.getElementById('lat').style.background = '#F6B5B5';
            $('#lat').attr('placeholder', 'Fill it!');
        }
        if ($("#lng").val() == "") {
            document.getElementById('lng').style.background = '#F6B5B5';
            $('#lng').attr('placeholder', 'Fill it!');
        }
    }else {
        var create = new Object();
        create.name = $("#name").val();
        create.description = $("#description").val();
        create.avgprice = $("#avgprice").val();
        create.address = $("#address").val();
        create.phone = $("#phone").val();
        create.lat = $("#lat").val();
        create.lng = $("#lng").val();
        CreateRes(create);
    }
});

function getLocation() {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(showPosition, showError);
    } else {
        alert("Geolocation is not supported by this browser.");
    }
}

function showPosition(position) {
    $("#lat").val(position.coords.latitude);
    $("#lng").val(position.coords.longitude);
}

function showError(error) {
    switch(error.code) {
        case error.PERMISSION_DENIED:
            alert("User denied the request for Geolocation.");
            break;
        case error.POSITION_UNAVAILABLE:
            alert("Location information is unavailable.");
            break;
        case error.TIMEOUT:
            alert("The request to get user location timed out.");
            break;
        case error.UNKNOWN_ERROR:
           alert("An unknown error occurred.");
            break;
    }
}<|endoftext|>


<commit_before>
Services = new Mongo.Collection("services");

FlowRouter.route('/gig/:id', {
	action: function(params) {
		var service = Services.findOne({_id: params.id});
        console.log("Flowrouter.route");

		console.log(service);
        //Will either bring in the service or have an empty one so there are no errors when bringing up service.employer
        service = service || {}
        //used for displaying the apply button for employees (see servicelistingpage.html)
        service.isUserEmployer = service.employer === Meteor.userId();

        //debug logs
        console.log(this);
        console.log(Meteor.userId());

        // get employer user object
        var user = Meteor.users.findOne({_id: service.employer});
        console.log(user);
        console.log(service.employer);

		BlazeLayout.render("layout", {
			area: "serviceListingPage",
			params: params,
			service: service,
			employer: user,
			employerName: user.emails[0].address
		});
	}
});

FlowRouter.route('/postgig', {
	action: function(params) {
		BlazeLayout.render("layout", {area: "servicePostForm"});
	}
});
FlowRouter.route('/edit/:id', {
	action: function(params) {
		var service = Services.findOne({_id: params.id});
        console.log("Flowrouter.route");

		console.log(service);
        //Will either bring in the service or have an empty one so there are no errors when bringing up service.employer
        service = service || {}
        //used for displaying the apply button for employees (see servicelistingpage.html)
        service.isUserEmployer = service.employer === Meteor.userId();

        //debug logs
        console.log(this);
        console.log(Meteor.userId());

        // get employer user object
        var user = Meteor.users.findOne({_id: service.employer});
        console.log(user);
        console.log(service.employer);

		BlazeLayout.render("layout", {
			area: "serviceListingPage",
			params: params,
			service: service,
			employer: user,
			employerName: user.emails[0].address
		});
	}
});
FlowRouter.route('/editjobpost', {
	action: function(params) {
		BlazeLayout.render("layout", {area: "editpost"});
	}
});

if (Meteor.isServer) {

	Meteor.publish("services", function () {
		return Services.find({});
	});

	Meteor.methods({
		"createService": function(serviceObj) {

            if (!this.userId) {
				console.log("not logged in");
				return false;
			}

			if (!serviceObj) {
				console.log("no service obj");
				return false;
			}

			if (typeof(serviceObj.title) != "string" || serviceObj.title.length == 0) {
				console.log("no title");
				return false;
			}

			if (typeof(serviceObj.description) != "string" || serviceObj.description.length == 0) {
				console.log("no descript");
				return false;
			}

			if ( Number.isNaN(parseInt(serviceObj.wage, 10)) ) {
				console.log("no wage");
				return false;
			}

			var newService = Services.insert({
				employer: this.userId,
				title: serviceObj.title,
				description: serviceObj.description,
				wage: serviceObj.wage,
			});

			return newService;
		}
	});

}

if (Meteor.isClient) {

	Meteor.subscribe("services");
    Template.serviceListingPage.helpers({
       isLoggedIn: function() {
        return Meteor.userId() !== null;
       }
    });
    Template.serviceListingPage.events({
        "click #apply": function(event) {
            event.target.innerHTML = "Thank you for applying";
        }
    });

	Template.servicePostForm.events({
		"input #serviceWage": function(event) {
			event.target.value = event.target.value.replace(/\D/g, "");
		},

		"submit .servicePostForm": function() {
			event.preventDefault();

			Meteor.call("createService", {
				title: event.target.serviceTitle.value,
				description: event.target.serviceDescription.value,
				wage: parseFloat(event.target.serviceWage.value)
			}, function(err, id) {
				if (id) {
					FlowRouter.go("/gig/" + id);
				} else {
					console.log("Failure! Handle this!");
				}
			});

		}
	});
	Template.editpost.events({
		"input #serviceWage": function(event) {
			event.target.value = event.target.value.replace(/\D/g, "");
		},

		"submit .editpost": function() {
			event.preventDefault();

			Meteor.call("createService", {
				title: event.target.serviceTitle.value,
				description: event.target.serviceDescription.value,
				wage: parseFloat(event.target.serviceWage.value)
			}, function(err, id) {
				if (id) {
					FlowRouter.go("/edit/" + id);
				} else {
					console.log("Failure! Handle this!");
				}
			});

		}
	});

}
/*
Services = new Mongo.Collection("services");

FlowRouter.route('/gig/:id', {
	action: function(params) {
		var service = Services.findOne({_id: params.id});

		console.log(service);

		BlazeLayout.render("layout", {
			area: "serviceListingPage",
			params: params,
			service: service
		});
	}
});

FlowRouter.route('/postgig', {
	action: function(params) {
		BlazeLayout.render("layout", {area: "servicePostForm"});
	}
});

if (Meteor.isServer) {

	Meteor.publish("services", function () {
		return Services.find({});
	});

	Meteor.methods({
		"createService": function(serviceObj) {
			if (!this.userId) {
				console.log("not logged in");
				return false;
			}

			if (!serviceObj) {
				console.log("no service obj");
				return false;
			}

			if (typeof(serviceObj.title) != "string" || serviceObj.title.length == 0) {
				console.log("no title");
				return false;
			}

			if (typeof(serviceObj.description) != "string" || serviceObj.description.length == 0) {
				console.log("no descript");
				return false;
			}

			if (typeof(serviceObj.wage) != "number" || (new String(serviceObj.wage)).length == 0) {
				console.log("no wage");
				return false;
			}

			var newService = Services.insert({
				employer: this.userId,
				title: serviceObj.title,
				description: serviceObj.description,
				wage: serviceObj.wage,
			});

			return newService;
		}
	});

}

if (Meteor.isClient) {

	Meteor.subscribe("services");

	Template.servicePostForm.events({
		"input #serviceWage": function(event) {
			event.target.value = event.target.value.replace(/[^0-9.]+/g, "");
		},

		"submit .servicePostForm": function() {
			event.preventDefault();

			Meteor.call("createService", {
				title: event.target.serviceTitle.value,
				description: event.target.serviceDescription.value,
				wage: parseFloat(event.target.serviceWage.value)
			}, function(err, id) {
				if (id) {
					FlowRouter.go("/gig/" + id);
				} else {
					console.log("Failure! Handle this!");
				}
			});

		}
	});

}
*/
<commit_msg>Update service.js<commit_after>
Services = new Mongo.Collection("services");

FlowRouter.route('/gig/:id', {
	action: function(params) {
		var service = Services.findOne({_id: params.id});
        console.log("Flowrouter.route");

		console.log(service);
        //Will either bring in the service or have an empty one so there are no errors when bringing up service.employer
        service = service || {}
        //used for displaying the apply button for employees (see servicelistingpage.html)
        service.isUserEmployer = service.employer === Meteor.userId();

        //debug logs
        console.log(this);
        console.log(Meteor.userId());

        // get employer user object
        var user = Meteor.users.findOne({_id: service.employer});
        console.log(user);
        console.log(service.employer);

		BlazeLayout.render("layout", {
			area: "serviceListingPage",
			params: params,
			service: service,
			employer: user,
			employerName: user.emails[0].address
		});
	}
});

FlowRouter.route('/postgig', {
	action: function(params) {
		BlazeLayout.render("layout", {area: "servicePostForm"});
	}
});
FlowRouter.route('/edit/:id', {
	action: function(params) {
		var service = Services.findOne({_id: params.id});
        console.log("Flowrouter.route");

		console.log(service);
        //Will either bring in the service or have an empty one so there are no errors when bringing up service.employer
        service = service || {}
        //used for displaying the apply button for employees (see servicelistingpage.html)
        service.isUserEmployer = service.employer === Meteor.userId();

        //debug logs
        console.log(this);
        console.log(Meteor.userId());

        // get employer user object
        var user = Meteor.users.findOne({_id: service.employer});
        console.log(user);
       	console.log(service.employer);

		BlazeLayout.render("editpost", {
			area: "serviceListingPage",
			params: params,
			service: service,
			employer: user,
			employerName: user.emails[0].address
		});
	}
});
FlowRouter.route('/editpost', {
	action: function(params) {
		BlazeLayout.render("layout", {area: "editpost"});
	}
});

if (Meteor.isServer) {

	Meteor.publish("services", function () {
		return Services.find({});
	});

	Meteor.methods({
		"createService": function(serviceObj) {

            if (!this.userId) {
				console.log("not logged in");
				return false;
			}

			if (!serviceObj) {
				console.log("no service obj");
				return false;
			}

			if (typeof(serviceObj.title) != "string" || serviceObj.title.length == 0) {
				console.log("no title");
				return false;
			}

			if (typeof(serviceObj.description) != "string" || serviceObj.description.length == 0) {
				console.log("no descript");
				return false;
			}

			if ( Number.isNaN(parseInt(serviceObj.wage, 10)) ) {
				console.log("no wage");
				return false;
			}

			var newService = Services.insert({
				employer: this.userId,
				title: serviceObj.title,
				description: serviceObj.description,
				wage: serviceObj.wage,
			});

			return newService;
		}
	});

}

if (Meteor.isClient) {

	Meteor.subscribe("services");
    Template.serviceListingPage.helpers({
       isLoggedIn: function() {
        return Meteor.userId() !== null;
       }
    });
    Template.serviceListingPage.events({
        "click #apply": function(event) {
            event.target.innerHTML = "Thank you for applying";
        }
    });

	Template.servicePostForm.events({
		"input #serviceWage": function(event) {
			event.target.value = event.target.value.replace(/\D/g, "");
		},

		"submit .servicePostForm": function() {
			event.preventDefault();

			Meteor.call("createService", {
				title: event.target.serviceTitle.value,
				description: event.target.serviceDescription.value,
				wage: parseFloat(event.target.serviceWage.value)
			}, function(err, id) {
				if (id) {
					FlowRouter.go("/gig/" + id);
				} else {
					console.log("Failure! Handle this!");
				}
			});

		}
	});
	Template.editpost.events({
		"input #serviceWage": function(event) {
			event.target.value = event.target.value.replace(/\D/g, "");
		},

		"submit .editpost": function() {
			event.preventDefault();

			Meteor.call("createService", {
				title: event.target.serviceTitle.value,
				description: event.target.serviceDescription.value,
				wage: parseFloat(event.target.serviceWage.value)
			}, function(err, id) {
				if (id) {
					FlowRouter.go("/edit/" + id);
				} else {
					console.log("Failure! Handle this!");
				}
			});

		}
	});

}
/*
Services = new Mongo.Collection("services");

FlowRouter.route('/gig/:id', {
	action: function(params) {
		var service = Services.findOne({_id: params.id});

		console.log(service);

		BlazeLayout.render("layout", {
			area: "serviceListingPage",
			params: params,
			service: service
		});
	}
});

FlowRouter.route('/postgig', {
	action: function(params) {
		BlazeLayout.render("layout", {area: "servicePostForm"});
	}
});

if (Meteor.isServer) {

	Meteor.publish("services", function () {
		return Services.find({});
	});

	Meteor.methods({
		"createService": function(serviceObj) {
			if (!this.userId) {
				console.log("not logged in");
				return false;
			}

			if (!serviceObj) {
				console.log("no service obj");
				return false;
			}

			if (typeof(serviceObj.title) != "string" || serviceObj.title.length == 0) {
				console.log("no title");
				return false;
			}

			if (typeof(serviceObj.description) != "string" || serviceObj.description.length == 0) {
				console.log("no descript");
				return false;
			}

			if (typeof(serviceObj.wage) != "number" || (new String(serviceObj.wage)).length == 0) {
				console.log("no wage");
				return false;
			}

			var newService = Services.insert({
				employer: this.userId,
				title: serviceObj.title,
				description: serviceObj.description,
				wage: serviceObj.wage,
			});

			return newService;
		}
	});

}

if (Meteor.isClient) {

	Meteor.subscribe("services");

	Template.servicePostForm.events({
		"input #serviceWage": function(event) {
			event.target.value = event.target.value.replace(/[^0-9.]+/g, "");
		},

		"submit .servicePostForm": function() {
			event.preventDefault();

			Meteor.call("createService", {
				title: event.target.serviceTitle.value,
				description: event.target.serviceDescription.value,
				wage: parseFloat(event.target.serviceWage.value)
			}, function(err, id) {
				if (id) {
					FlowRouter.go("/gig/" + id);
				} else {
					console.log("Failure! Handle this!");
				}
			});

		}
	});

}
*/
<|endoftext|>


<commit_before>/* eslint-disable no-undef */

import gulp from 'gulp';
import gutil from 'gulp-util';
import mocha from 'gulp-mocha';

function reportError(errorReporter) {
  return errorReporter === 'process' ? process.exit.bind(process, 1) : gutil.log;
}

export default function mochaRunCreator(errorReporter = 'process') {
  return (file) => {
    let source = 'src/**/__test__/**/*.js';

    if (file) {
      // Do not run tests when changed something not JS
      if (!/\.(js|jsx)?$/.test(file.path)) {
        console.log(`Change happend on '${file.path}' but it is not valid JS file`); // eslint-disable-line no-console
        return null;
      }

      if (file.path.indexOf('__test__') !== -1)
        source = file.path;
      else {
        const parts = file.path.split('/');
        const filename = parts.pop(1);
        const dir = parts.join('/');
        source = `${dir}/__test__/${filename.split('.')[0]}*.js`;
      }
    }

    console.log(`Running ${source}`); // eslint-disable-line no-console
    gulp.src(source, {read: false})
      .pipe(mocha({
        require: ['./test/mochaSetup.js'],
        reporter: 'spec'
      }))
      .on('error', reportError(errorReporter));
  };
}
<commit_msg>fix mochaRunCreator for windows<commit_after>/* eslint-disable no-undef */

import gulp from 'gulp';
import gutil from 'gulp-util';
import mocha from 'gulp-mocha';
import path from 'path';

function reportError(errorReporter) {
  return errorReporter === 'process' ? process.exit.bind(process, 1) : gutil.log;
}

export default function mochaRunCreator(errorReporter = 'process') {
  return (file) => {
    let source = 'src/**/__test__/**/*.js';

    if (file) {
      // Do not run tests when changed something not JS
      if (!/\.(js|jsx)?$/.test(file.path)) {
        console.log(`Change happend on '${file.path}' but it is not valid JS file`); // eslint-disable-line no-console
        return null;
      }

      if (file.path.indexOf('__test__') !== -1)
        source = file.path;
      else {
        const parts = file.path.split(path.sep);
        const filename = parts.pop(1);
        const dir = parts.join(path.sep);
        source = `${dir}/__test__/${filename.split('.')[0]}*.js`;
      }
    }

    console.log(`Running ${source}`); // eslint-disable-line no-console
    gulp.src(source, {read: false})
      .pipe(mocha({
        require: ['./test/mochaSetup.js'],
        reporter: 'spec'
      }))
      .on('error', reportError(errorReporter));
  };
}
<|endoftext|>


<commit_before>#!/usr/bin/gjs
//
// Copyright (c) 2016, Jens Georg <mail@jensge.org>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//         SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.

imports.gi.versions.GUPnP = "1.2"

const Mainloop = imports.mainloop;
const GObject = imports.gi.GObject;
const GUPnP = imports.gi.GUPnP;

const CONTENT_DIR = "urn:schemas-upnp-org:service:RenderingControl:1";

function _on_ready () {
}

function _on_sp_available (cp, proxy) {
    print ("Got Proxy ", proxy.get_location());
    for (let i = 0; i < 1000; ++i) {
	let action = GUPnP.ServiceProxyAction.new_from_list("GetVolume", ["InstanceId", "Channel"], [0, 0]);
	proxy.call_action(action, null);
	let [success, result] = action.get_result_list(["CurrentVolume"], [GObject.TYPE_FLOAT]);
	print(result);
    }
}

var context = new GUPnP.Context ( {'interface': "wlp3s0"});
context.init(null);
var cp = new GUPnP.ControlPoint ( {'client': context, 'target' : CONTENT_DIR});
cp.connect ("service-proxy-available", _on_sp_available);
cp.active = true;
Mainloop.run ("");
<commit_msg>examples: Fix JavaScript example<commit_after>#!/usr/bin/gjs
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//         SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.

imports.gi.versions.GUPnP = "1.2"

const Mainloop = imports.mainloop;
const GObject = imports.gi.GObject;
const GUPnP = imports.gi.GUPnP;
const GLib = imports.gi.GLib;

const CONTENT_DIR = "urn:schemas-upnp-org:service:RenderingControl:1";

function on_action(proxy, res) {
    let action = proxy.call_action_finish (res);
    let [success, volume] = action.get_result_list(["CurrentVolume"], [GObject.TYPE_FLOAT]);
    print(volume);
}

function on_service_introspection(proxy, res) {
    var result = proxy.introspect_finish(res);
    var action_info = result.get_action("GetVolume")
    var state_variable_name = action_info.arguments[1].related_state_variable;

    var channel = result.get_state_variable (state_variable_name);

    print ("Calling GetVolume for channel ", channel.allowed_values[0]);
    var action = GUPnP.ServiceProxyAction.new_from_list("GetVolume", ["InstanceID", "Channel"], [0, channel.allowed_values[0]]);
    proxy.call_action_async (action, null, on_action);
}

function _on_sp_available (cp, proxy) {
    print ("Got ServiceProxy ", proxy.get_id(), proxy.get_location());
    print ("Introspecting service...");
    proxy.introspect_async(null, on_service_introspection)
}

var context = new GUPnP.Context ( {'interface': "wlp3s0"});
context.init(null);
var cp = new GUPnP.ControlPoint ( {'client': context, 'target' : CONTENT_DIR});
cp.connect ("service-proxy-available", _on_sp_available);
cp.active = true;
GLib.timeout_add_seconds (GLib.PRIORITY_LOW, 10, () => { Mainloop.quit(); return false; })
Mainloop.run ();
<|endoftext|>


<commit_before>/******************************************
 * Form Handlers and page                 *
 * generators for TSSAA WebApp Fat Client *
 *****************************************/

$(document).on("pageinit", function(e, obj) {
    /**
     * Login form handler
     */
    $("#login_page").on("submit", function(e, obj) {

        var formData = $("#login_form").serialize();

        $.ajax( "app_dev.php/login", {
            type: "POST",
            data: formData,
            contentType: 'application/x-www-form-urlencoded',
            success: loginSuccess
        });
        return false;
    });

    /**
     * Get school list ajax handler
     */
    $("#school_list_page_a").on("click", function(e, obj) {
        $.ajax("app_dev.php/get_school_list", {
            type: "GET",
            cache: "true",
            success: generateSchoolList
        });
    });

    /**
     * Add school form ajax handler
     */
    $('#add_school_submit').on('click', function(e, obj) {

        var  formData = $('#add_school_form').serialize();

        $.ajax("app_dev.php/add_school", {
            type: "POST",
            cache: false,
            data: formData,
            success: popDBDialog
        });
        return false;
    });

});

/**
 * Login form ajax callback
 * TODO session management handled here?
 */
function loginSuccess(response) {
    alert("loginSuccess:\n" + response);
    $.mobile.changePage($("#options_page"), {
            transition: "slideup",
            reverse: true,
        });
}

/**
 * DB Dialog ajax success callback
 */
function popDBDialog(response) {
    try {
        var data = $.parseJSON(response);
    } catch(err) {
        alert(err);
    }

    var response_items = [];

    $.each(data, function(key, val) {
            response_items.push('
'+key+':	'+val+'
');
    });

    $('
',{
			'class': 'response_table',
			html: response_items.join('')
		}).replaceAll("#response");

    $.mobile.changePage("#db_confirm_dialog");
}

/**
 * School List response handler
 * generates ul of schools returned from DB
 */
function generateSchoolList(response) {
    alert("mobile.pageContainer is: " +
            for (name in $.mobile.pageContainer) {
                this[name]});
    try {
        var school_data = $.parseJSON(response);
    } catch(err) {
        alert(err);
    }

    var schools = [];

    $.each(school_data, function() {
                var name = this.name;
                var phone = this.phone;
                var address = this.address;

                var block = '

' +
                    this.name + '

Phone: ' +
                    this.phone + '

Address: ' +
                    this.address + '

'

                schools.push(block);
            });

    $('div#school_list').html(schools.join(''));
};
<commit_msg>removed call to listview refresh<commit_after>/******************************************
 * Form Handlers and page                 *
 * generators for TSSAA WebApp Fat Client *
 *****************************************/

$(document).on("pageinit", function(e, obj) {
    /**
     * Login form handler
     */
    $("#login_page").on("submit", function(e, obj) {

        var formData = $("#login_form").serialize();

        $.ajax( "app_dev.php/login", {
            type: "POST",
            data: formData,
            contentType: 'application/x-www-form-urlencoded',
            success: loginSuccess
        });
        return false;
    });

    /**
     * Get school list ajax handler
     */
    $("#school_list_page_a").on("click", function(e, obj) {
        $.ajax("app_dev.php/get_school_list", {
            type: "GET",
            cache: "true",
            success: generateSchoolList
        });
    });

    /**
     * Add school form ajax handler
     */
    $('#add_school_submit').on('click', function(e, obj) {

        var  formData = $('#add_school_form').serialize();

        $.ajax("app_dev.php/add_school", {
            type: "POST",
            cache: false,
            data: formData,
            success: popDBDialog
        });
        return false;
    });

});

/**
 * Login form ajax callback
 * TODO session management handled here?
 */
function loginSuccess(response) {
    alert("loginSuccess:\n" + response);
    $.mobile.changePage($("#options_page"), {
            transition: "slideup",
            reverse: true,
        });
}

/**
 * DB Dialog ajax success callback
 */
function popDBDialog(response) {
    try {
        var data = $.parseJSON(response);
    } catch(err) {
        alert(err);
    }

    var response_items = [];

    $.each(data, function(key, val) {
            response_items.push('
'+key+':	'+val+'
');
    });

    $('
',{
			'class': 'response_table',
			html: response_items.join('')
		}).replaceAll("#response");

    $.mobile.changePage("#db_confirm_dialog");
}

/**
 * School List response handler
 * generates ul of schools returned from DB
 */
function generateSchoolList(response) {
    alert("mobile.pageContainer is: " +
            (for (name in $.mobile.pageContainer) {
                this[name]}));
    try {
        var school_data = $.parseJSON(response);
    } catch(err) {
        alert(err);
    }

    var schools = [];

    $.each(school_data, function() {
                var name = this.name;
                var phone = this.phone;
                var address = this.address;

                var block = '

' +
                    this.name + '

Phone: ' +
                    this.phone + '

Address: ' +
                    this.address + '

'

                schools.push(block);
            });

    $('div#school_list').html(schools.join(''));
};
<|endoftext|>