<commit_before>/**
 * Created by ksiabani on 12/3/2015.
 */
'use strict';

/**
 * Module dependencies.
 */
var fs = require('fs'),
    path = require('path'),
    readdirp = require('readdirp'),
    config = require('../config/config'),
    ID3 = require('id3v2-parser'),
    mongoose = require('mongoose'),
    Track = mongoose.model('Track'),
    logger = require('../config/logger'),
    md5 = require('MD5'),
    //es = require('event-stream'),
    async = require('async'),
    S = require('string');

/**
 * Module init function.
 */
module.exports = function () {
    console.log('start of response');
    readdirp({ root: config.walkPath, fileFilter: '*.mp3' }, function (errors, res) {
        if (errors) {
            errors.forEach(function (err) {
                console.error('Error: ', err);
            });
        }
        var myFiles = [];

        res.files.forEach(function(file){
            myFiles.push(file.fullPath);
        });
        console.log(myFiles);
        console.log('end of response');

        async.eachSeries(myFiles, function(file, callback) {

            // Perform operation on file here.
            console.log('Processing file ' + file);
            var meta = { cover:{} };
            //id3v1/v2
            fs.createReadStream(file)
                .pipe(new ID3())
                .on('data', function(tag){
                    //console.log(tag);
                    if(tag.type === 'TPE1'){ meta.artist = tag.value; }
                    if(tag.type === 'TALB'){ meta.album = tag.value; }
                    if(tag.type === 'TIT2'){ meta.title = tag.value; }
                    if(tag.type === 'TYER'){ meta.year = tag.value; }
                    if(tag.type === 'TCON'){ meta.genre = tag.value; }
                    if(tag.type === 'TPUB'){ meta.publisher = tag.value; }
                    if(tag.type === 'APIC'){
                        meta.cover.mime = S(tag.value.mime).chompLeft('image/').s;
                    }
                    if(tag.type === 'APIC'){ meta.cover.type = tag.value.type; }
                    if(tag.type === 'APIC'){ meta.cover.data = tag.value.data; }
                    if(meta.cover.mime){ meta.cover.name = md5(meta.artist + meta.album + meta.publisher) + '.' + meta.cover.mime;}
                    if(tag.type === 'TXXX' && S(tag.value).left(9).s === 'Rip date/' ){
                        meta.released = S(tag.value).chompLeft('Rip date/').s;
                    }
                })
                .on('end', function(){
                    console.log(meta);
                    console.log( 'the end' );
                    //if(!meta.cover) {
                    //    var cover = md5(meta.artist + meta.album + meta.publisher) + '.' + meta.cover.type;
                    //}
                    Track.findOneAndUpdate(
                        {
                            source: file
                        },
                        {
                            $setOnInsert: {
                                artist: meta.artist,
                                title: meta.title,
                                album: meta.album,
                                publisher: meta.publisher,
                                genre: meta.genre || null,
                                year: meta.year || null,
                                released: new Date(meta.released) || null,
                                cover: meta.cover.name || null,
                                source: file,
                                created: Date.now(),
                                copied: false
                            }
                        },
                        {
                            upsert: true
                        }
                    ).exec(function (err) {
                            if (err) logger.error(err);
                        });
                    callback();
                });

        }, function(err){
            // if any of the file processing produced an error, err would equal that error
            if( err ) {
                // One of the iterations produced an error.
                // All processing will now stop.
                console.log('A file failed to process');
            } else {
                console.log('All files have been processed successfully');
            }
        });

    });

    //var stream = readdirp({ root: config.walkPath, fileFilter: '*.mp3' });
    //stream
    //    .on('warn', function (err) {
    //        console.error('non-fatal error', err);
    //        // optionally call stream.destroy() here in order to abort and cause 'close' to be emitted
    //    })
    //    .on('error', function (err) { console.error('fatal error', err); })
    //    //.on('end' , function (err) { });
    //    //.pipe(es.stringify())
    //    //.pipe(fs.createWriteStream('out.txt'));
    //    .pipe(es.mapSync(function (entry) {
    //        //return { path: entry.fullPath }; //, size: entry.stat.size };
    //        //fs.createReadStream(config.walkPath+'/'+entry.path)
    //        //    .pipe(new ID3())
    //        //    .on('data', function(tag){
    //        //        console.log( tag.type, tag.value );
    //        //    });
    //        fs.appendFile('out.txt', entry.fullPath + '\n', function (err) {
    //            if(err) console.error(err);
    //        });
    //    }))
    //    //.pipe(es.stringify())
    //    //.pipe(process.stdout);
    //    .on('end', function(){
    //        console.log('Writing to file finished');
    //        var myFiles = fs.readFileSync('out.txt').toString().split('\n');
    //        async.forEachSeries(myFiles, function(fullPath, callback) {
    //            var parser = mm(fs.createReadStream(fullPath), function (err, metadata) {
    //                if (err) throw err;
    //                console.log(metadata);
    //            });
    //            callback();
    //        }, function(err) {
    //            if (err) console.error('Error: ', err);
    //        });
    //    });

    //var array = fs.readFileSync('file.txt').toString().split("\n");

    //readdirp(
    //    { root: config.walkPath, fileFilter: '*.mp3' },
    //    function(fileInfo) {
    //        // do something with file entry here
    //    },
    //    function (err, res) {
    //        // all done, move on or do final step for all file entries here
    //    }
    //);

};

//TODO: Review the fields that are being updated
<commit_msg>Fixed reader so that stream is destroyed after read by id3 parser<commit_after>/**
 * Created by ksiabani on 12/3/2015.
 */
'use strict';

/**
 * Module dependencies.
 */
var fs = require('fs'),
    path = require('path'),
    readdirp = require('readdirp'),
    config = require('../config/config'),
    ID3 = require('id3v2-parser'),
    mongoose = require('mongoose'),
    Track = mongoose.model('Track'),
    logger = require('../config/logger'),
    md5 = require('MD5'),
    //es = require('event-stream'),
    async = require('async'),
    S = require('string');

/**
 * Module init function.
 */
module.exports = function () {
    console.log('start of response');
    readdirp({ root: config.walkPath, fileFilter: '*.mp3' }, function (errors, res) {
        if (errors) {
            errors.forEach(function (err) {
                console.error('Error: ', err);
            });
        }
        var myFiles = [];

        res.files.forEach(function(file){
            myFiles.push(file.fullPath);
        });
        console.log(myFiles);
        console.log('end of response');

        async.eachSeries(myFiles, function(file, callback) {

            // Perform operation on file here.
            console.log('Processing file ' + file);
            var meta = { cover:{} };
            //id3v1/v2
            var stream = fs.createReadStream(file);

            stream
                .pipe(new ID3())
                .on('data', function(tag){
                    //console.log(tag);
                    if(tag.type === 'TPE1'){ meta.artist = tag.value; }
                    if(tag.type === 'TALB'){ meta.album = tag.value; }
                    if(tag.type === 'TIT2'){ meta.title = tag.value; }
                    if(tag.type === 'TYER'){ meta.year = tag.value; }
                    if(tag.type === 'TCON'){ meta.genre = tag.value; }
                    if(tag.type === 'TPUB'){ meta.publisher = tag.value; }
                    if(tag.type === 'APIC'){
                        meta.cover.mime = S(tag.value.mime).chompLeft('image/').s;
                    }
                    if(tag.type === 'APIC'){ meta.cover.type = tag.value.type; }
                    if(tag.type === 'APIC'){ meta.cover.data = tag.value.data; }
                    if(meta.cover.mime){ meta.cover.name = md5(meta.artist + meta.album + meta.publisher) + '.' + meta.cover.mime;}
                    if(tag.type === 'TXXX' && S(tag.value).left(9).s === 'Rip date/' ){
                        meta.released = S(tag.value).chompLeft('Rip date/').s;
                    }
                })
                .on('end', function(){
                    console.log(meta);
                    console.log( 'the end' );
                    stream.destroy();
                    //if(!meta.cover) {
                    //    var cover = md5(meta.artist + meta.album + meta.publisher) + '.' + meta.cover.type;
                    //}
                    Track.findOneAndUpdate(
                        {
                            source: file
                        },
                        {
                            $setOnInsert: {
                                artist: meta.artist,
                                title: meta.title,
                                album: meta.album,
                                publisher: meta.publisher,
                                genre: meta.genre || null,
                                year: meta.year || null,
                                released: new Date(meta.released) || null,
                                cover: meta.cover.name || null,
                                source: file,
                                created: Date.now(),
                                copied: false
                            }
                        },
                        {
                            upsert: true
                        }
                    ).exec(function (err) {
                            if (err) logger.error(err);
                        });
                    callback();
                });

        }, function(err){
            // if any of the file processing produced an error, err would equal that error
            if( err ) {
                // One of the iterations produced an error.
                // All processing will now stop.
                console.log('A file failed to process');
            } else {
                console.log('All files have been processed successfully');
            }
        });

    });

    //var stream = readdirp({ root: config.walkPath, fileFilter: '*.mp3' });
    //stream
    //    .on('warn', function (err) {
    //        console.error('non-fatal error', err);
    //        // optionally call stream.destroy() here in order to abort and cause 'close' to be emitted
    //    })
    //    .on('error', function (err) { console.error('fatal error', err); })
    //    //.on('end' , function (err) { });
    //    //.pipe(es.stringify())
    //    //.pipe(fs.createWriteStream('out.txt'));
    //    .pipe(es.mapSync(function (entry) {
    //        //return { path: entry.fullPath }; //, size: entry.stat.size };
    //        //fs.createReadStream(config.walkPath+'/'+entry.path)
    //        //    .pipe(new ID3())
    //        //    .on('data', function(tag){
    //        //        console.log( tag.type, tag.value );
    //        //    });
    //        fs.appendFile('out.txt', entry.fullPath + '\n', function (err) {
    //            if(err) console.error(err);
    //        });
    //    }))
    //    //.pipe(es.stringify())
    //    //.pipe(process.stdout);
    //    .on('end', function(){
    //        console.log('Writing to file finished');
    //        var myFiles = fs.readFileSync('out.txt').toString().split('\n');
    //        async.forEachSeries(myFiles, function(fullPath, callback) {
    //            var parser = mm(fs.createReadStream(fullPath), function (err, metadata) {
    //                if (err) throw err;
    //                console.log(metadata);
    //            });
    //            callback();
    //        }, function(err) {
    //            if (err) console.error('Error: ', err);
    //        });
    //    });

    //var array = fs.readFileSync('file.txt').toString().split("\n");

    //readdirp(
    //    { root: config.walkPath, fileFilter: '*.mp3' },
    //    function(fileInfo) {
    //        // do something with file entry here
    //    },
    //    function (err, res) {
    //        // all done, move on or do final step for all file entries here
    //    }
    //);

};

//TODO: Review the fields that are being updated
<|endoftext|>


<commit_before>'use strict';

describe('tmdb Factory', function() {
  var TmdbFactory, httpBackend;
  var baseUrl = 'http://localhost:3000/';
  var configUrl = baseUrl + 'configs';
  var configResults = {
    configs: [{
      images: {
        base_url: 'http://image.tmdb.org/t/p/', // jshint ignore:line
        secure_base_url: 'https://image.tmdb.org/t/p/', // jshint ignore:line
        backdrop_sizes: ['w300', 'w780', 'w1280', 'original'], // jshint ignore:line
        logo_sizes: ['w45', 'w92', 'w154', 'w185', 'w300', 'w500', 'original'], // jshint ignore:line
        poster_sizes: ['w92', 'w154', 'w185', 'w342', 'w500', 'w780', 'original'], // jshint ignore:line
        profile_sizes: ['w45', 'w185', 'h632', 'original'], // jshint ignore:line
        still_sizes: ['w92', 'w185', 'w300', 'original'] // jshint ignore:line
      }
    }]
  };
  var allMoviesUrl = baseUrl + 'movies';
  var allMoviesResults = {
    movies: [{
      title: 'Fight Club',
      themoviedbid: 550,
      id: 1,
      createdAt: '2015-02-13T05:44:34.000Z',
      updatedAt: '2015-02-13T05:44:34.000Z'
    }, {
      title: 'Guardians of the Galaxy',
      themoviedbid: 118340,
      id: 2,
      createdAt: '2015-02-13T06:19:29.000Z',
      updatedAt: '2015-02-13T06:19:29.000Z'
    }]
  };
  var createMovieUrl = baseUrl + 'movies';
  var createMovieResults = {
    movie: {
      title: 'The Matrix',
      themoviedbid: 603,
      id: 3,
      createdAt: '2015-02-13T05:44:34.000Z',
      updatedAt: '2015-02-13T05:44:34.000Z'
    }
  };
  var searchUrl = baseUrl + 'movies/search/SDF';
  var searchResults = {
    page: 1,
    results: [{
      adult: false,
      backdrop_path: '/qLxJlnfZ9b2BMzvhzvnJMBi7EGH.jpg', // jshint ignore:line
      id: 14114,
      original_title: 'You Got Served', // jshint ignore:line
      release_date: '2004-01-30', // jshint ignore:line
      poster_path: '/3ESy6TiBPSYIbEES1zNspdYtMtw.jpg', // jshint ignore:line
      popularity: 0.33499858390984,
      title: 'You Got Served',
      video: false,
      vote_average: 6.3, // jshint ignore:line
      vote_count: 9 // jshint ignore:line
    }],
    total_pages: 1, // jshint ignore:line
    total_results: 1 // jshint ignore:line
  };
  var infoUrl = baseUrl + 'movies/info/550';
  var infoResults = {
    adult: false,
    backdrop_path: '/8uO0gUM8aNqYLs1OsTBQiXu0fEv.jpg', // jshint ignore:line
    belongs_to_collection: null, // jshint ignore:line
    budget: 63000000,
    genres: [{
      id: 18,
      name: 'Drama'
    }],
    homepage: '',
    id: 550,
    imdb_id: 'tt0137523', // jshint ignore:line
    original_language: 'en', // jshint ignore:line
    original_title: 'Fight Club', // jshint ignore:line
    overview: 'A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground " fight clubs " forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion.',
    popularity: 3.16634464772838,
    poster_path: '/2lECpi35Hnbpa4y46JX0aY3AWTy.jpg', // jshint ignore:line
    production_companies: [{ // jshint ignore:line
      name: '20th Century Fox',
      id: 25
    }, {
      name: 'Fox 2000 Pictures',
      id: 711
    }, {
      name: 'Regency Enterprises',
      id: 508
    }],
    production_countries: [{ // jshint ignore:line
      iso_3166_1: 'DE', // jshint ignore:line
      name: 'Germany'
    }, {
      iso_3166_1: 'US', // jshint ignore:line
      name: 'United States of America'
    }],
    release_date: '1999-10-14', // jshint ignore:line
    revenue: 100853753,
    runtime: 139,
    spoken_languages: [{ // jshint ignore:line
      iso_639_1: 'en', // jshint ignore:line
      name: 'English'
    }],
    status: 'Released',
    tagline: 'How much can you know about yourself if you\'ve never been in a fight?',
    title: 'Fight Club',
    video: false,
    vote_average: 7.8, // jshint ignore:line
    vote_count: 3286 // jshint ignore:line
  };

  beforeEach(module('polyflix'));

  beforeEach(inject(function($injector) {
    httpBackend = $injector.get('$httpBackend');
    httpBackend.whenGET(configUrl).respond(
      JSON.stringify(configResults)
    );
    httpBackend.whenGET(allMoviesUrl).respond(
      JSON.stringify(allMoviesResults)
    );
    httpBackend.whenPOST(createMovieUrl).respond(
      JSON.stringify(createMovieResults)
    );
    httpBackend.whenGET(searchUrl).respond(
      JSON.stringify(searchResults)
    );
    httpBackend.whenGET(infoUrl).respond(
      JSON.stringify(infoResults)
    );
  }));

  beforeEach(inject(function(_TmdbFactory_) {
    TmdbFactory = _TmdbFactory_;
  }));

  afterEach(function() {
    httpBackend.verifyNoOutstandingExpectation();
    httpBackend.verifyNoOutstandingRequest();
  });

  describe('call config', function() {
    it('config should exist', function() {
      expect(TmdbFactory.configuration).toEqual(undefined);
      httpBackend.expectGET(configUrl);
      TmdbFactory.config();
      httpBackend.flush();
      var actualConfigImages = TmdbFactory.configuration.$object[0].images;
      var expectedConfigImages = configResults.configs[0].images;
      expect(actualConfigImages).toEqual(expectedConfigImages);
    });
  });

  describe('call all movies', function() {
    it('movies should exist', function() {
      httpBackend.expectGET(allMoviesUrl);
      var movies = TmdbFactory.all('movies');
      httpBackend.flush();
      var actualMovies = movies.$object;
      var expectedMovies = allMoviesResults.movies;
      var config = TmdbFactory.configuration.$object[0];
      expect(config).toBeDefined();
      expect(actualMovies[0].title).toEqual(expectedMovies[0].title);
      expect(actualMovies[0].themoviedbid).toEqual(expectedMovies[0].themoviedbid);
      expect(actualMovies[0].id).toEqual(expectedMovies[0].id);
      expect(actualMovies[0].createdAt).toEqual(expectedMovies[0].createdAt);
      expect(actualMovies[0].updatedAt).toEqual(expectedMovies[0].updatedAt);
      expect(actualMovies[1].title).toEqual(expectedMovies[1].title);
      expect(actualMovies[1].themoviedbid).toEqual(expectedMovies[1].themoviedbid);
      expect(actualMovies[1].id).toEqual(expectedMovies[1].id);
      expect(actualMovies[1].createdAt).toEqual(expectedMovies[1].createdAt);
      expect(actualMovies[1].updatedAt).toEqual(expectedMovies[1].updatedAt);
    });
  });

  describe('call add movies', function() {
    it('movies should exist', function() {
      httpBackend.expectPOST(createMovieUrl);
      var newMovie = {
        movie: {
          title: 'The Matrix',
          themoviedbid: 603
        }
      };
      var movie = TmdbFactory.create('movies', newMovie);
      httpBackend.flush();
      var actualMovies = movie.$object.movie;
      var expectedMovies = createMovieResults.movie;
      var config = TmdbFactory.configuration.$object[0];
      expect(config).toBeDefined();
      expect(actualMovies.title).toEqual(expectedMovies.title);
      expect(actualMovies.themoviedbid).toEqual(expectedMovies.themoviedbid);
      expect(actualMovies.id).toEqual(expectedMovies.id);
      expect(actualMovies.createdAt).toEqual(expectedMovies.createdAt);
      expect(actualMovies.updatedAt).toEqual(expectedMovies.updatedAt);
    });
  });

  describe('call search movies', function() {
    it('results should exist', function() {
      httpBackend.expectGET(searchUrl);
      var results = TmdbFactory.movieSearch('SDF');
      httpBackend.flush();
      var actualResults = results.$object.results;
      var expectedResults = searchResults.results;
      var config = TmdbFactory.configuration.$object[0];
      expect(config).toBeDefined();
      expect(actualResults).toEqual(expectedResults);
      expect(actualResults.length).toEqual(expectedResults.length);
      expect(actualResults[0].title).toEqual(expectedResults[0].title);
      expect(actualResults[0].id).toEqual(expectedResults[0].id);
      expect(actualResults[0].release_date).toEqual(expectedResults[0].release_date); // jshint ignore:line
      expect(actualResults[0].original_title).toEqual(expectedResults[0].original_title); // jshint ignore:line
    });
  });

  describe('call info Fight Club', function() {
    it('results should exist', function() {
      httpBackend.expectGET(infoUrl);
      var results = TmdbFactory.movieInfo(550);
      httpBackend.flush();
      var actualResults = results.$object;
      var expectedResults = infoResults;
      var config = TmdbFactory.configuration.$object[0];
      expect(config).toBeDefined();
      expect(actualResults.title).toEqual(expectedResults.title);
      expect(actualResults.id).toEqual(expectedResults.id);
      expect(actualResults.overview).toEqual(expectedResults.overview);
      expect(actualResults.tagline).toEqual(expectedResults.tagline);
      expect(actualResults.release_date).toEqual(expectedResults.release_date); // jshint ignore:line
      expect(actualResults.original_title).toEqual(expectedResults.original_title); // jshint ignore:line
    });
  });
});<commit_msg>Remove unnecessary httpBackend lines<commit_after>'use strict';

describe('tmdb Factory', function() {
  var TmdbFactory, httpBackend;
  var baseUrl = 'http://localhost:3000/';
  var configUrl = baseUrl + 'configs';
  var configResults = {
    configs: [{
      images: {
        base_url: 'http://image.tmdb.org/t/p/', // jshint ignore:line
        secure_base_url: 'https://image.tmdb.org/t/p/', // jshint ignore:line
        backdrop_sizes: ['w300', 'w780', 'w1280', 'original'], // jshint ignore:line
        logo_sizes: ['w45', 'w92', 'w154', 'w185', 'w300', 'w500', 'original'], // jshint ignore:line
        poster_sizes: ['w92', 'w154', 'w185', 'w342', 'w500', 'w780', 'original'], // jshint ignore:line
        profile_sizes: ['w45', 'w185', 'h632', 'original'], // jshint ignore:line
        still_sizes: ['w92', 'w185', 'w300', 'original'] // jshint ignore:line
      }
    }]
  };
  var allMoviesUrl = baseUrl + 'movies';
  var allMoviesResults = {
    movies: [{
      title: 'Fight Club',
      themoviedbid: 550,
      id: 1,
      createdAt: '2015-02-13T05:44:34.000Z',
      updatedAt: '2015-02-13T05:44:34.000Z'
    }, {
      title: 'Guardians of the Galaxy',
      themoviedbid: 118340,
      id: 2,
      createdAt: '2015-02-13T06:19:29.000Z',
      updatedAt: '2015-02-13T06:19:29.000Z'
    }]
  };
  var createMovieUrl = baseUrl + 'movies';
  var createMovieResults = {
    movie: {
      title: 'The Matrix',
      themoviedbid: 603,
      id: 3,
      createdAt: '2015-02-13T05:44:34.000Z',
      updatedAt: '2015-02-13T05:44:34.000Z'
    }
  };
  var searchUrl = baseUrl + 'movies/search/SDF';
  var searchResults = {
    page: 1,
    results: [{
      adult: false,
      backdrop_path: '/qLxJlnfZ9b2BMzvhzvnJMBi7EGH.jpg', // jshint ignore:line
      id: 14114,
      original_title: 'You Got Served', // jshint ignore:line
      release_date: '2004-01-30', // jshint ignore:line
      poster_path: '/3ESy6TiBPSYIbEES1zNspdYtMtw.jpg', // jshint ignore:line
      popularity: 0.33499858390984,
      title: 'You Got Served',
      video: false,
      vote_average: 6.3, // jshint ignore:line
      vote_count: 9 // jshint ignore:line
    }],
    total_pages: 1, // jshint ignore:line
    total_results: 1 // jshint ignore:line
  };
  var infoUrl = baseUrl + 'movies/info/550';
  var infoResults = {
    adult: false,
    backdrop_path: '/8uO0gUM8aNqYLs1OsTBQiXu0fEv.jpg', // jshint ignore:line
    belongs_to_collection: null, // jshint ignore:line
    budget: 63000000,
    genres: [{
      id: 18,
      name: 'Drama'
    }],
    homepage: '',
    id: 550,
    imdb_id: 'tt0137523', // jshint ignore:line
    original_language: 'en', // jshint ignore:line
    original_title: 'Fight Club', // jshint ignore:line
    overview: 'A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground " fight clubs " forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion.',
    popularity: 3.16634464772838,
    poster_path: '/2lECpi35Hnbpa4y46JX0aY3AWTy.jpg', // jshint ignore:line
    production_companies: [{ // jshint ignore:line
      name: '20th Century Fox',
      id: 25
    }, {
      name: 'Fox 2000 Pictures',
      id: 711
    }, {
      name: 'Regency Enterprises',
      id: 508
    }],
    production_countries: [{ // jshint ignore:line
      iso_3166_1: 'DE', // jshint ignore:line
      name: 'Germany'
    }, {
      iso_3166_1: 'US', // jshint ignore:line
      name: 'United States of America'
    }],
    release_date: '1999-10-14', // jshint ignore:line
    revenue: 100853753,
    runtime: 139,
    spoken_languages: [{ // jshint ignore:line
      iso_639_1: 'en', // jshint ignore:line
      name: 'English'
    }],
    status: 'Released',
    tagline: 'How much can you know about yourself if you\'ve never been in a fight?',
    title: 'Fight Club',
    video: false,
    vote_average: 7.8, // jshint ignore:line
    vote_count: 3286 // jshint ignore:line
  };

  beforeEach(module('polyflix'));

  beforeEach(inject(function($injector) {
    httpBackend = $injector.get('$httpBackend');
    httpBackend.whenGET(configUrl).respond(
      JSON.stringify(configResults)
    );
    httpBackend.whenGET(allMoviesUrl).respond(
      JSON.stringify(allMoviesResults)
    );
    httpBackend.whenPOST(createMovieUrl).respond(
      JSON.stringify(createMovieResults)
    );
    httpBackend.whenGET(searchUrl).respond(
      JSON.stringify(searchResults)
    );
    httpBackend.whenGET(infoUrl).respond(
      JSON.stringify(infoResults)
    );
  }));

  beforeEach(inject(function(_TmdbFactory_) {
    TmdbFactory = _TmdbFactory_;
  }));

  afterEach(function() {
    httpBackend.verifyNoOutstandingExpectation();
    httpBackend.verifyNoOutstandingRequest();
  });

  describe('call config', function() {
    it('config should exist', function() {
      expect(TmdbFactory.configuration).toEqual(undefined);
      httpBackend.expectGET(configUrl);
      TmdbFactory.config();
      httpBackend.flush();
      var actualConfigImages = TmdbFactory.configuration.$object[0].images;
      var expectedConfigImages = configResults.configs[0].images;
      expect(actualConfigImages).toEqual(expectedConfigImages);
    });
  });

  describe('call all movies', function() {
    it('movies should exist', function() {
      var movies = TmdbFactory.all('movies');
      httpBackend.flush();
      var actualMovies = movies.$object;
      var expectedMovies = allMoviesResults.movies;
      var config = TmdbFactory.configuration.$object[0];
      expect(config).toBeDefined();
      expect(actualMovies[0].title).toEqual(expectedMovies[0].title);
      expect(actualMovies[0].themoviedbid).toEqual(expectedMovies[0].themoviedbid);
      expect(actualMovies[0].id).toEqual(expectedMovies[0].id);
      expect(actualMovies[0].createdAt).toEqual(expectedMovies[0].createdAt);
      expect(actualMovies[0].updatedAt).toEqual(expectedMovies[0].updatedAt);
      expect(actualMovies[1].title).toEqual(expectedMovies[1].title);
      expect(actualMovies[1].themoviedbid).toEqual(expectedMovies[1].themoviedbid);
      expect(actualMovies[1].id).toEqual(expectedMovies[1].id);
      expect(actualMovies[1].createdAt).toEqual(expectedMovies[1].createdAt);
      expect(actualMovies[1].updatedAt).toEqual(expectedMovies[1].updatedAt);
    });
  });

  describe('call add movies', function() {
    it('movies should exist', function() {
      var newMovie = {
        movie: {
          title: 'The Matrix',
          themoviedbid: 603
        }
      };
      var movie = TmdbFactory.create('movies', newMovie);
      httpBackend.flush();
      var actualMovies = movie.$object.movie;
      var expectedMovies = createMovieResults.movie;
      var config = TmdbFactory.configuration.$object[0];
      expect(config).toBeDefined();
      expect(actualMovies.title).toEqual(expectedMovies.title);
      expect(actualMovies.themoviedbid).toEqual(expectedMovies.themoviedbid);
      expect(actualMovies.id).toEqual(expectedMovies.id);
      expect(actualMovies.createdAt).toEqual(expectedMovies.createdAt);
      expect(actualMovies.updatedAt).toEqual(expectedMovies.updatedAt);
    });
  });

  describe('call search movies', function() {
    it('results should exist', function() {
      var results = TmdbFactory.movieSearch('SDF');
      httpBackend.flush();
      var actualResults = results.$object.results;
      var expectedResults = searchResults.results;
      var config = TmdbFactory.configuration.$object[0];
      expect(config).toBeDefined();
      expect(actualResults).toEqual(expectedResults);
      expect(actualResults.length).toEqual(expectedResults.length);
      expect(actualResults[0].title).toEqual(expectedResults[0].title);
      expect(actualResults[0].id).toEqual(expectedResults[0].id);
      expect(actualResults[0].release_date).toEqual(expectedResults[0].release_date); // jshint ignore:line
      expect(actualResults[0].original_title).toEqual(expectedResults[0].original_title); // jshint ignore:line
    });
  });

  describe('call info Fight Club', function() {
    it('results should exist', function() {
      var results = TmdbFactory.movieInfo(550);
      httpBackend.flush();
      var actualResults = results.$object;
      var expectedResults = infoResults;
      var config = TmdbFactory.configuration.$object[0];
      expect(config).toBeDefined();
      expect(actualResults.title).toEqual(expectedResults.title);
      expect(actualResults.id).toEqual(expectedResults.id);
      expect(actualResults.overview).toEqual(expectedResults.overview);
      expect(actualResults.tagline).toEqual(expectedResults.tagline);
      expect(actualResults.release_date).toEqual(expectedResults.release_date); // jshint ignore:line
      expect(actualResults.original_title).toEqual(expectedResults.original_title); // jshint ignore:line
    });
  });
});<|endoftext|>


<commit_before>(function ( $ ) {
    $.fn.add_calculation = function( options ) {
        var settings = $.extend({
            // These are the defaults.
            calculation: function (context) { context.result = "???"; },
            subjects: '', // E.g. "CDE01,CDE02" comma separated list of inputs to the calculation
            prefix: '',//  formcode^^sectioncode^^
            target: "value",
            observer: ''  // the cde code of the output e,g, CDE03
        }, options );

        var subject_codes_string  = _.map(settings.subjects.split(","), function(code){return "#id_" + settings.prefix + code;}).join()

        $(subject_codes_string).on("input, change",function () {
            var context = {};
            var subject_codes = settings.subjects.split(",");

            for(var i=0;i<subject_codes.length;i++) {
                // Note how we use the prefix to map from the page to the context variable names
                // and reverse map to update the output
                context[subject_codes[i]] = $("#id_" + settings.prefix + subject_codes[i]).val();
            }

            try {
                settings.calculation(context);
            }
            catch(err) {
                context.result = "#ERROR";
            }

            $("#id_" + settings.prefix + settings.observer).val(context.result);
        });
    };

}( jQuery ));<commit_msg>RDR-318 Made context.CDECode find CDECode on page , even in different sections ( this entails that the input cdes to a calculated field be unique on the page.)<commit_after>(function ( $ ) {
    $.fn.add_calculation = function( options ) {
        var settings = $.extend({
            // These are the defaults.
            calculation: function (context) { context.result = "???"; },
            subjects: '', // E.g. "CDE01,CDE02" comma separated list of inputs to the calculation
            prefix: '',//  formcode^^sectioncode^^
            target: "value",
            observer: ''  // the cde code of the output e,g, CDE03
        }, options );

        //var subject_codes_string  = _.map(settings.subjects.split(","), function(code){return "#id_" + settings.prefix + code;}).join()

        // locate the codes anywhere on the page ( we assume only one occurance of given cde for now
        function locate_code(code) {
            var id = $('[id*=' + code + ']').attr("id");
            return "#" + id;
        }
        var subject_codes_string = _.map(settings.subjects.split(","), function(code) { return locate_code(code);}).join();
        $(subject_codes_string).on("input, change",function () {
            var context = {};
            var subject_codes = settings.subjects.split(",");

            for(var i=0;i<subject_codes.length;i++) {
                // Note how we use the prefix to map from the page to the context variable names
                // and reverse map to update the output
                var subject_code_id_on_page = locate_code(subject_codes[i]);
                context[subject_codes[i]] = $(subject_code_id_on_page).val();
            }

            try {
                settings.calculation(context);
            }
            catch(err) {
                context.result = "ERROR";
            }

            $("#id_" + settings.prefix + settings.observer).val(context.result);
        });
    };

}( jQuery ));<|endoftext|>


<commit_before>import * as utils from './utils.js';
import secret from './secret.js';

const lock = {};

function basicNode(name) {
  let self;
  // this is faster than a Map as long as you keep your link count down.
  // it's also absolutely appalling... but let's not worry about that.
  const nodes = [], values = [];

  const set = (node, value) => {
    const index = utils.indexOf(nodes, node);
    if(index === -1 || values[index] !== value) {
      if(index === -1) {
        nodes.push(node);
        values.push(value);
      } else {
        values[index] = value;
      }
      node.set(self, value);
      return true;
    }
    return false;
  };
  const remove = node => {
    const index = utils.remove(nodes, node);
    if(index !== -1) {
      utils.removeIndex(values, index);
      node.remove(self);
      return true;
    }
    return false;
  };
  const has = node => {
    return node.nodes.length < nodes.length ?
             !utils.excludes(node.nodes, self) :
             !utils.excludes(nodes, node);
  };
  const get = (node, unvalue) => {
    if(node.nodes.length < nodes.length) {
      const index = utils.indexOf(node.nodes, self);
      if(index !== -1) {
        return node.values[index];
      }
    } else {
      const index = utils.indexOf(nodes, node);
      if(index !== -1) {
        return values[index];
      }
    }
    return unvalue;
  };
  const getNodes = copy => copy === undefined || copy ? utils.copy(nodes) : nodes;

  self = {
    name, set, remove, has, get, getNodes, nodes, values
  };
  return self;
}

export function node(name) {
  return Object.freeze(basicNode(name));
}

export function supernode(name) {
  const self = basicNode(name);
  const adders = [], updaters = [], removers = [];
  const pAdders = [], pRemovers = [];

  const nhas = self.has, nset = self.set, nremove = self.remove, nnodes = self.nodes, nvalues = self.values;

  secret.set(self, { adders: pAdders, removers: pRemovers, lazyHas: nhas });

  self.set = (node, value) => {
    const length = nnodes.length;
    if(nset(node, value)) {
      let alerts = updaters;
      if(nnodes.length > length) {
        alerts = adders;
        utils.executeAll(pAdders, node);
      }
      for(let i = 0, len = alerts.length; i < len; ++i) {
        alerts[i](node, value);
      }
      return true;
    }
    return false;
  };
  self.remove = node => {
    const index = utils.remove(nnodes, node);
    if(index !== -1) {
      const value = nvalues[index];
      utils.removeIndex(nvalues, index);
      utils.executeAll(pRemovers, node);
      node.remove(self);
      for(let i = 0, len = removers.length; i < len; ++i) {
        removers[i](node, value);
      }
      return true;
    }
    return false;
  };

  const alerts = { 'add': adders, 'update': updaters, 'remove': removers };
  self.on = utils.onFunc(alerts);
  self.off = utils.offFunc(alerts);

  return Object.freeze(self);
}
<commit_msg>Made sure adders will never run before pAdders<commit_after>import * as utils from './utils.js';
import secret from './secret.js';

const lock = {};

function basicNode(name) {
  let self;
  // this is faster than a Map as long as you keep your link count down.
  // it's also absolutely appalling... but let's not worry about that.
  const nodes = [], values = [];

  const set = (node, value) => {
    const index = utils.indexOf(nodes, node);
    if(index === -1 || values[index] !== value) {
      if(index === -1) {
        nodes.push(node);
        values.push(value);
      } else {
        values[index] = value;
      }
      node.set(self, value);
      return true;
    }
    return false;
  };
  const remove = node => {
    const index = utils.remove(nodes, node);
    if(index !== -1) {
      utils.removeIndex(values, index);
      node.remove(self);
      return true;
    }
    return false;
  };
  const has = node => {
    return node.nodes.length < nodes.length ?
             !utils.excludes(node.nodes, self) :
             !utils.excludes(nodes, node);
  };
  const get = (node, unvalue) => {
    if(node.nodes.length < nodes.length) {
      const index = utils.indexOf(node.nodes, self);
      if(index !== -1) {
        return node.values[index];
      }
    } else {
      const index = utils.indexOf(nodes, node);
      if(index !== -1) {
        return values[index];
      }
    }
    return unvalue;
  };
  const getNodes = copy => copy === undefined || copy ? utils.copy(nodes) : nodes;

  self = {
    name, set, remove, has, get, getNodes, nodes, values
  };
  return self;
}

export function node(name) {
  return Object.freeze(basicNode(name));
}

export function supernode(name) {
  const self = basicNode(name);
  const adders = [], updaters = [], removers = [];
  const pAdders = [], pRemovers = [];

  const nhas = self.has, nnodes = self.nodes, nvalues = self.values;

  secret.set(self, { adders: pAdders, removers: pRemovers, lazyHas: nhas });

  self.set = (node, value) => {
    const index = utils.indexOf(nnodes, node);
    if(index === -1 || nvalues[index] !== value) {
      let alerts = updaters;
      if(index === -1) {
        nnodes.push(node);
        nvalues.push(value);
        alerts = adders;
        utils.executeAll(pAdders, node);
      } else {
        nvalues[index] = value;
      }
      node.set(self, value);
      for(let i = 0, len = alerts.length; i < len; ++i) {
        alerts[i](node, value);
      }
      return true;
    }
    return false;
  };
  self.remove = node => {
    const index = utils.remove(nnodes, node);
    if(index !== -1) {
      const value = nvalues[index];
      utils.removeIndex(nvalues, index);
      utils.executeAll(pRemovers, node);
      node.remove(self);
      for(let i = 0, len = removers.length; i < len; ++i) {
        removers[i](node, value);
      }
      return true;
    }
    return false;
  };

  const alerts = { 'add': adders, 'update': updaters, 'remove': removers };
  self.on = utils.onFunc(alerts);
  self.off = utils.offFunc(alerts);

  return Object.freeze(self);
}
<|endoftext|>


<commit_before>/***********************
    Page specific event triggers
***********************/
    $('input.datepicker').datepicker();

    $('.btn#query-compile').click(function(){
        $this = $(this);
        $this.addClass('disabled');

        bzURL = $('input#bz-url').val();
        var bzURL = bzURL.split('?');
        if ( !bzURL[1] ) {
            alert('No bugzilla query found.');
            $this.removeClass('disabled');
            return;
        }

        var bzQueryURL = 'https://bugzilla.mozilla.org/query.cgi?' + bzURL[1];

        $.ajax({
            url: '/api/misc/exthtml',
            data: { source : bzQueryURL },
            type: 'POST',
            success: function( response ) {
                var start = '<birthday>';
                if ( $('input#query-start').val() ) {
                    start = $('input#query-start').val();
                }

                var end = '<timestamp>';
                if ( $('input#query-end').val() ) {
                    end = $('input#query-end').val();
                }

                var cluster = 'private_bugs';
                if ( $('input#public_cluster:checked').length == 1 ) {
                    cluster = 'public_bugs';
                }

                var qbQuery = bzSearchToQb( response, start, end, cluster );

                $this.removeClass('disabled');
                showResult(qbQuery);
            },
            error: function(response) {
                alert('Fail: Bugzilla could not be reached.');
                $this.removeClass('disabled');
                console.log(response);
            }
        });
    });

/*****************************
    Make life awesome - Helper functions
******************************/

    function showResult( text ){
        $('textarea.query-output').css( 'background', '#E5FFDD' );
        $('textarea.query-output').text( text );
        setTimeout(function() {
            $('textarea.query-output').css( 'background', '' );
        }, 1500);
    }

/******************
    Outputs a Qb query in JSON
    Based on BZ search HTML
    With pre-filled params
******************/

    /*****************
        High level function that is being called
        Handles all the coordination and simple work
    *****************/
        function bzSearchToQb( html, start, end, cluster ){
            var qbQuery = {};

            qbQuery.from    = cluster;

            qbQuery.select  = {
                    "name": "num",
                    "value": "bug_id",
                    "aggregate": "count"
                };

            // Replace password fields with text fields in the HTML
            // Prevents false security errors from appearing in console
            html = html.replace('type="password"', 'type="text"');
            $extract = $('form#queryform', html);
            qbQuery.esfilter = parseBzSearch( $extract );

            qbQuery.edges = [{
                    "range": {
                        "min": "modified_ts",
                        "max": "expires_on"
                    },
                    "domain": {
                        "type": "date",
                        "min": start,
                        "max": end,
                        "interval": "day"
                    }
                }];

            return JSON.stringify( qbQuery, null, '\t' ).replace(/"</g, '<').replace(/>"/g, ">");
        }

    /******************
        Applies jQuery to extract Bugzilla search params from HTML
    ******************/
        function parseBzSearch( $subject ){
            var esfilterObj = {};
            esfilterObj.and = [];
            var tempVal = '';

            /******************
                Parses top most summary input (needs regex filter)
            ******************/
                tempVal = $subject.find('div#summary_field input#short_desc').val() ;
                if ( tempVal ){
                    var tempOpr = $subject.find('div#summary_field select[name="short_desc_type"]').val();
                    var terms = fovQb( 'short_desc', tempOpr, tempVal );
                    esfilterObj.and.push( terms );
                }
            /******************
                End of parsing top most summary input (needs regex filter)
            ******************/

            /******************
                Parses the two rows of multi-select grids
            ******************/
                var search_field_grid = [
                    'classification',
                    'product',
                    'component',
                    'bug_status',
                    'resolution',
                    'version',
                    'target_milestone',
                    'bug_severity',
                    'priority',
                    'rep_platform',
                    'op_sys'
                ];
                $.each( search_field_grid, function( key, gridName ){
                    tempVal = $subject.find('div#container_'+ gridName +' select#'+ gridName +' option:selected').map(function(){return $(this).val();}).get() ;
                    if ( tempVal.length > 0 ){
                        var terms = {};
                        if ( gridName == 'bug_status' ) {
                            // bug_status works on lower case only
                            $.each( tempVal, function( key, value ){
                                tempVal[key] = value.toLowerCase();
                            });
                        }
                        terms[gridName] = tempVal;
                        esfilterObj.and.push( { "terms" : terms } );
                    }
                });
            /******************
                End of parsing the two rows of multi-select grids
            ******************/

            /******************
                Parses the six rows directly below "Detailed Bug Information"
            ******************/
                var search_field_row = [ 'longdesc', 'bug_file_loc', 'status_whiteboard', 'keywords', 'bug_id', 'votes' ];
                $.each( search_field_row, function( key, rowName ){
                    tempVal = $subject.find('div.search_field_row').find('input#'+rowName).val() ;
                    if ( tempVal.length > 0 ){
                        var tempOpr = '';
                        if ( rowName == 'votes' ){
                            tempOpr = $subject.find('div.search_field_row').find('input[name="votes_type"]').val();
                        } else {
                            tempOpr = $subject.find('div.search_field_row').find('select[name="'+rowName+'_type"] option:selected').val();
                        }

                        var terms = fovQb( rowName, tempOpr, tempVal );
                        esfilterObj.and.push( terms );
                    }
                });
            /******************
                End of parsing the six rows directly below "Detailed Bug Information"
            ******************/

            /*********************
                Parses the email search fields
            *********************/
                var search_email_fields = [ 1, 2, 3 ];
                var roles = [ 'assigned_to', 'reporter', 'qa_contact', 'cc', 'longdesc' ];
                $.each( search_email_fields, function( key, col ){
                    tempVal = $subject.find('div.search_email_fields').find('input#email'+col).val() ;
                    if ( tempVal.length > 0 ){
                        var subObj = {};
                        subObj.or = [];

                        var tempOpr = $subject.find('div.search_email_fields').find('select[name="email_type'+col+'"] option:selected').val();
                        $.each( roles, function( key, role ){
                            var isChecked = $subject.find('div.search_email_fields').find('input#email'+role+col+':checked').length;
                            if ( isChecked > 0 ){
                                subObj.or.push( fovQb(role, tempOpr, tempVal) );
                            }
                        });

                        esfilterObj.and.push( subObj );
                    }
                });
            /*********************
                End of parsing the email search fields
            *********************/

            /*********************
                Parses the change history fields
            *********************/
                chFlds = $subject.find('select[name="chfield"] option:selected').map(function(){return $(this).val();}).get() ;
                if ( chFlds.length > 0 ) {
                    var chObj = {};
                    chObj.and = [];

                    var start = $subject.find('input[name="chfieldfrom"]').val();
                    start = makeESDates( start );
                    startObj = {};
                    startObj["range"] = { "expires_on" : {"gte":start} };
                    chObj.and.push( startObj );

                    var end   = $subject.find('input[name="chfieldto"]').val();
                    end   = makeESDates( end );
                    endObj = {};
                    endObj["range"] = { "modified_ts" : {"lte":end} }
                    chObj.and.push( endObj );

                    tempVal   = $subject.find('input[name="chfieldvalue"]').val();
                    var nestedObj = {
                                        "nested": {
                                             "path": "changes",
                                             "query": {
                                                "filtered":{
                                                    "query":{ "match_all":{} },
                                                    "filter":{
                                                        "and":[
                                                            {"terms": {"changes.field_name" : chFlds  } },
                                                            {"term" : {"changes.new_value"  : tempVal } }
                                                        ]
                                                    }
                                                }
                                            }
                                        }
                                    };
                    chObj.and.push( nestedObj );
                    esfilterObj.and.push( chObj );
                }
            /*********************
                End of parsing the change history fields
            *********************/

            /*********************
                Parses the custom search section
            *********************/
                var customParams = '';
                var $customSearch = $subject.find('div#custom_search_filter_section');
                var clause = getCustomClause( $customSearch, 'j_top' );
                customParams += '{"'+clause+'":[';

                var hasNegatives = [];
                var openedBrackets = 1;
                $customSearch.find('div.custom_search_condition').each(function( key ){
                    var isOpened = $(this).find('input[type="hidden"][value="OP"]').length;
                    var isClosed = $(this).find('input[type="hidden"][value="CP"]').length;

                    if ( isOpened > 0 ) {
                        if ( customParams.trim().charAt(customParams.length - 1) != '[' ) {
                            customParams += ',';
                        }

                        var isNot = $(this).find('input.custom_search_form_field[type="checkbox"]:checked').length;
                        if ( isNot > 0 ) {
                            customParams += '{"not":' ;
                            hasNegatives.push( true );
                        } else {
                            hasNegatives.push( false );
                        }

                        openedBrackets++;

                    } else if ( isClosed > 0 ) {
                        customParams += ']}';

                        var hasNegative = hasNegatives.pop();
                        if ( hasNegative ) {
                            customParams += '}';
                        }

                        openedBrackets--;

                    } else {
                        hasClause = $(this).find('div.any_all_select select[name^="j"]').length ;
                        if ( hasClause > 0 ) {
                            var clauseName = $(this).find('select[name^="j"]').attr('name');
                            clause = getCustomClause( $(this), clauseName ) ;
                            customParams += '{"'+clause+'":[';
                        }

                        var tempFld = $(this).find('select[name^="f"] option:selected').val();
                        if ( typeof tempFld != 'undefined' && tempFld != 'noop' ) {
                            var tempOpr = $(this).find('select[name^="o"] option:selected').val();
                            var tempVal = $(this).find('input[name^="v"]').val();

                            var isNot = $(this).find('input[name^="n"]:checked').length;
                            var subObj = fovQb(tempFld, tempOpr, tempVal) ;
                            if ( isNot > 0 ) {
                                var subObj = { "not" : subObj } ;
                            }

                            if ( customParams.trim().charAt(customParams.length - 1) != '[' ) {
                                customParams += ',';
                            }
                            customParams += JSON.stringify( subObj );
                        }
                    }
                });

                while ( openedBrackets > 0 ){
                    customParams += "]}";

                    if ( hasNegatives.length > 0 ) {
                        hasNegative = hasNegatives.pop();
                        if ( hasNegative ) {
                            customParams += '}';
                        }
                    }
                    openedBrackets--;
                }

                try {
                    esfilterObj.and.push( $.parseJSON(customParams) );
                } catch (e) {
                    alert( "Failed: Could not parse custom fields" );
                    console.log(customParams);
                    console.log(e);
                }
            /*********************
                End of parsing the custom search section
            *********************/

            return esfilterObj;
        }

    /*****************
        Takes in a field, operator and value as strings
        Converts them to an appropriate ES compatible filter object
        Reference: http://www.elasticsearch.org/guide/en/elasticsearch/reference/0.90/query-dsl-filters.html
    *****************/
        function fovQb( field, operator, value ){
            var outer = {};
            var inner = {};

            inner[field] = value;
            outer[operator] = inner;

            return outer;
        }

    /*****************
        Receives a date input extracted from Bugzilla
        Parses and converts to ES compatible
        I.e. Milliseconds since epoch.
    *****************/
        function makeESDates( date ) {
            var dateValue = 0;
            var dateObj = new Date();

            if ( date == 'Now' ) {
                dateValue = dateObj.now();
            } else {
                date = date.split('-');
                var year    = parseInt( date[0] ) - 1900;
                var month   = parseInt( date[1] );
                var day     = parseInt( date[2] );
                dateValue = dateObj.UTC( year, month, day, 0, 0, 0 );
            }

            return parseInt( dateValue );
        }

    /*****************
        Extract selections from dropdown fields
        Where users are asked to choose whether to apply all or any (and / or)
    *****************/
        function getCustomClause( $subject, identifier ){
            var $clause = $subject.find('div.any_all_select select#'+identifier+' option:selected');
            var clauseValue = '';

            if ( $clause.length == 0 ) {
                clauseValue = 'and';
            } else {
                if ( $clause.val().toLowerCase() != 'or' ){ // Watch out for "and_g"
                    clauseValue = 'and';
                } else {
                    clauseValue = 'or';
                }
            }

            return clauseValue;
        }
<commit_msg>Almost complete<commit_after>/***********************
    Page specific event triggers
***********************/
    $('input.datepicker').datepicker();

    $('.btn#query-compile').click(function(){
        $this = $(this);
        $this.addClass('disabled');

        bzURL = $('input#bz-url').val();
        var bzURL = bzURL.split('?');
        if ( !bzURL[1] ) {
            alert('No bugzilla query found.');
            $this.removeClass('disabled');
            return;
        }

        var bzQueryURL = 'https://bugzilla.mozilla.org/query.cgi?' + bzURL[1];

        $.ajax({
            url: '/api/misc/exthtml',
            data: { source : bzQueryURL },
            type: 'POST',
            success: function( response ) {
                var start = '<birthday>';
                if ( $('input#query-start').val() ) {
                    start = $('input#query-start').val();
                }

                var end = '<timestamp>';
                if ( $('input#query-end').val() ) {
                    end = $('input#query-end').val();
                }

                var cluster = 'private_bugs';
                if ( $('input#public_cluster:checked').length == 1 ) {
                    cluster = 'public_bugs';
                }

                var qbQuery = bzSearchToQb( response, start, end, cluster );

                $this.removeClass('disabled');
                showResult(qbQuery);
            },
            error: function(response) {
                alert('Fail: Bugzilla could not be reached.');
                $this.removeClass('disabled');
                console.log(response);
            }
        });
    });

/*****************************
    Make life awesome - Helper functions
******************************/

    function showResult( text ){
        $('textarea.query-output').css( 'background', '#E5FFDD' );
        $('textarea.query-output').text( text );
        setTimeout(function() {
            $('textarea.query-output').css( 'background', '' );
        }, 1500);
    }

/******************
    Outputs a Qb query in JSON
    Based on BZ search HTML
    With pre-filled params
******************/

    /*****************
        High level function that is being called
        Handles all the coordination and simple work
    *****************/
        function bzSearchToQb( html, start, end, cluster ){
            var qbQuery = {};

            qbQuery.from    = cluster;

            qbQuery.select  = {
                    "name": "num",
                    "value": "bug_id",
                    "aggregate": "count"
                };

            // Replace password fields with text fields in the HTML
            // Prevents false security errors from appearing in console
            html = html.replace('type="password"', 'type="text"');
            $extract = $('form#queryform', html);
            qbQuery.esfilter = parseBzSearch( $extract );

            qbQuery.edges = [{
                    "range": {
                        "min": "modified_ts",
                        "max": "expires_on"
                    },
                    "domain": {
                        "type": "date",
                        "min": start,
                        "max": end,
                        "interval": "day"
                    }
                }];

            return JSON.stringify( qbQuery, null, '\t' ).replace(/"</g, '<').replace(/>"/g, ">");
        }

    /******************
        Applies jQuery to extract Bugzilla search params from HTML
    ******************/
        function parseBzSearch( $subject ){
            var esfilterObj = {};
            esfilterObj.and = [];
            var tempVal = '';

            /******************
                Parses top most summary input (needs regex filter)
            ******************/
                tempVal = $subject.find('div#summary_field input#short_desc').val() ;
                if ( tempVal ){
                    var tempOpr = $subject.find('div#summary_field select[name="short_desc_type"]').val();
                    var terms = fovQb( 'short_desc', tempOpr, tempVal );
                    esfilterObj.and.push( terms );
                }
            /******************
                End of parsing top most summary input (needs regex filter)
            ******************/

            /******************
                Parses the two rows of multi-select grids
            ******************/
                var search_field_grid = [
                    'classification',
                    'product',
                    'component',
                    'bug_status',
                    'resolution',
                    'version',
                    'target_milestone',
                    'bug_severity',
                    'priority',
                    'rep_platform',
                    'op_sys'
                ];
                $.each( search_field_grid, function( key, gridName ){
                    tempVal = $subject.find('div#container_'+ gridName +' select#'+ gridName +' option:selected').map(function(){return $(this).val();}).get() ;
                    if ( tempVal.length > 0 ){
                        var terms = {};
                        if ( gridName == 'bug_status' ) {
                            // bug_status works on lower case only
                            $.each( tempVal, function( key, value ){
                                tempVal[key] = value.toLowerCase();
                            });
                        }
                        terms[gridName] = tempVal;
                        esfilterObj.and.push( { "terms" : terms } );
                    }
                });
            /******************
                End of parsing the two rows of multi-select grids
            ******************/

            /******************
                Parses the six rows directly below "Detailed Bug Information"
            ******************/
                var search_field_row = [ 'longdesc', 'bug_file_loc', 'status_whiteboard', 'keywords', 'bug_id', 'votes' ];
                $.each( search_field_row, function( key, rowName ){
                    tempVal = $subject.find('div.search_field_row').find('input#'+rowName).val() ;
                    if ( tempVal.length > 0 ){
                        var tempOpr = '';
                        if ( rowName == 'votes' ){
                            tempOpr = $subject.find('div.search_field_row').find('input[name="votes_type"]').val();
                        } else {
                            tempOpr = $subject.find('div.search_field_row').find('select[name="'+rowName+'_type"] option:selected').val();
                        }

                        var terms = fovQb( rowName, tempOpr, tempVal );
                        esfilterObj.and.push( terms );
                    }
                });
            /******************
                End of parsing the six rows directly below "Detailed Bug Information"
            ******************/

            /*********************
                Parses the email search fields
            *********************/
                var search_email_fields = [ 1, 2, 3 ];
                var roles = [ 'assigned_to', 'reporter', 'qa_contact', 'cc', 'longdesc' ];
                $.each( search_email_fields, function( key, col ){
                    tempVal = $subject.find('div.search_email_fields').find('input#email'+col).val() ;
                    if ( tempVal.length > 0 ){
                        var subObj = {};
                        subObj.or = [];

                        var tempOpr = $subject.find('div.search_email_fields').find('select[name="emailtype'+col+'"] option:selected').val();
                        $.each( roles, function( key, role ){
                            var isChecked = $subject.find('div.search_email_fields').find('input#email'+role+col+':checked').length;
                            if ( isChecked > 0 ){
                                subObj.or.push( fovQb(role, tempOpr, tempVal) );
                            }
                        });

                        esfilterObj.and.push( subObj );
                    }
                });
            /*********************
                End of parsing the email search fields
            *********************/

            /*********************
                Parses the change history fields
            *********************/
                chFlds = $subject.find('select[name="chfield"] option:selected').map(function(){return $(this).val();}).get() ;
                if ( chFlds.length > 0 ) {
                    var chObj = {};
                    chObj.and = [];

                    var start = $subject.find('input[name="chfieldfrom"]').val();
                    start = makeESDates( start );
                    startObj = {};
                    startObj["range"] = { "expires_on" : {"gte":start} };
                    chObj.and.push( startObj );

                    var end   = $subject.find('input[name="chfieldto"]').val();
                    end   = makeESDates( end );
                    endObj = {};
                    endObj["range"] = { "modified_ts" : {"lte":end} }
                    chObj.and.push( endObj );

                    tempVal   = $subject.find('input[name="chfieldvalue"]').val();
                    var nestedObj = {
                                        "nested": {
                                             "path": "changes",
                                             "query": {
                                                "filtered":{
                                                    "query":{ "match_all":{} },
                                                    "filter":{
                                                        "and":[
                                                            {"terms": {"changes.field_name" : chFlds  } },
                                                            {"term" : {"changes.new_value"  : tempVal } }
                                                        ]
                                                    }
                                                }
                                            }
                                        }
                                    };
                    chObj.and.push( nestedObj );
                    esfilterObj.and.push( chObj );
                }
            /*********************
                End of parsing the change history fields
            *********************/

            /*********************
                Parses the custom search section
            *********************/
                var customParams = '';
                var $customSearch = $subject.find('div#custom_search_filter_section');
                var clause = getCustomClause( $customSearch, 'j_top' );
                customParams += '{"'+clause+'":[';

                var hasNegatives = [];
                var openedBrackets = 1;
                $customSearch.find('div.custom_search_condition').each(function( key ){
                    var isOpened = $(this).find('input[type="hidden"][value="OP"]').length;
                    var isClosed = $(this).find('input[type="hidden"][value="CP"]').length;

                    if ( isOpened > 0 ) {
                        if ( customParams.trim().charAt(customParams.length - 1) != '[' ) {
                            customParams += ',';
                        }

                        var isNot = $(this).find('input.custom_search_form_field[type="checkbox"]:checked').length;
                        if ( isNot > 0 ) {
                            customParams += '{"not":' ;
                            hasNegatives.push( true );
                        } else {
                            hasNegatives.push( false );
                        }

                        openedBrackets++;

                    } else if ( isClosed > 0 ) {
                        customParams += ']}';

                        var hasNegative = hasNegatives.pop();
                        if ( hasNegative ) {
                            customParams += '}';
                        }

                        openedBrackets--;

                    } else {
                        hasClause = $(this).find('div.any_all_select select[name^="j"]').length ;
                        if ( hasClause > 0 ) {
                            var clauseName = $(this).find('select[name^="j"]').attr('name');
                            clause = getCustomClause( $(this), clauseName ) ;
                            customParams += '{"'+clause+'":[';
                        }

                        var tempFld = $(this).find('select[name^="f"] option:selected').val();
                        if ( typeof tempFld != 'undefined' && tempFld != 'noop' ) {
                            var tempOpr = $(this).find('select[name^="o"] option:selected').val();
                            var tempVal = $(this).find('input[name^="v"]').val();

                            var isNot = $(this).find('input[name^="n"]:checked').length;
                            var subObj = fovQb(tempFld, tempOpr, tempVal) ;
                            if ( isNot > 0 ) {
                                var subObj = { "not" : subObj } ;
                            }

                            if ( customParams.trim().charAt(customParams.length - 1) != '[' ) {
                                customParams += ',';
                            }
                            customParams += JSON.stringify( subObj );
                        }
                    }
                });

                while ( openedBrackets > 0 ){
                    customParams += "]}";

                    if ( hasNegatives.length > 0 ) {
                        hasNegative = hasNegatives.pop();
                        if ( hasNegative ) {
                            customParams += '}';
                        }
                    }
                    openedBrackets--;
                }

                try {
                    esfilterObj.and.push( $.parseJSON(customParams) );
                } catch (e) {
                    alert( "Failed: Could not parse custom fields" );
                    console.log(customParams);
                    console.log(e);
                }
            /*********************
                End of parsing the custom search section
            *********************/

            return esfilterObj;
        }

    /*****************
        Takes in a field, operator and value as strings
        Converts them to an appropriate ES compatible filter object
        Reference: http://www.elasticsearch.org/guide/en/elasticsearch/reference/0.90/query-dsl-filters.html
    *****************/
        function fovQb( field, operator, value ){
            /*********************
            // Possible values for operator
                x "equals"            => is equal to
                x "notequals"         => is not equal to
                x "anyexact"          => is equal to any of the strings
                x "substring"         => contains the string
                x "casesubstring"     => contains the string (exact case)
                x "notsubstring"      => does not contain the string
                x "anywordssubstr"    => contains any of the strings
                x "allwordssubstr"    => contains all of the strings
                x "nowordssubstr"     => contains none of the strings
                x "regexp"            => matches regular expression
                x "notregexp"         => does not match regular expression
                  "lessthan"          => is less than
                  "lessthaneq"        => is less than or equal to
                  "greaterthan"       => is greater than
                  "greaterthaneq"     => is greater than or equal to
                x "anywords"          => contains any of the words
                x "allwords"          => contains all of the words
                x "nowords"           => contains none of the words
                 "changedbefore"     => changed before
                 "changedafter"      => changed after
                 "changedfrom"       => changed from
                 "changedto"         => changed to
                 "changedby"         => changed by
                x "matches"           => matches
                x "notmatches"        => does not match
                x "isempty"           => is empty
                x "isnotempty"        => is not empty
            // End of possible values for operator
            *********************/
            var outer = {};
            var inner = {};

            if ( operator == 'equals' || operator == 'notequals' ) {
                inner[field] = value;
                outer["term"] = inner;
                if ( operator == 'notequals' ) {
                    outer = { "not" : outer };
                }

            } else if ( operator == 'anyexact' ) {
                value = value.replace(/ /g, '');
                value = value.split(',');

                inner[field] = value;
                outer["terms"] = inner;
                outer = { "not" : outer };

            } else if ( operator == 'substring' || operator == 'casesubstring' || operator == 'notsubstring' ) {
                if ( operator == 'casesubstring' ) {
                    inner[field] = '(' + value + ')+';
                } else {
                    inner[field] = '/(' + value + ')+/i';
                }

                outer['regexp'] = inner;
                if ( operator == 'notsubstring' ) {
                    outer = { "not" : outer };
                }

            } else if ( operator == 'anywordssubstr' || operator == 'allwordssubstr' || operator == 'nowordssubstr' || operator == 'anywords' || operator == 'allwords' || operator == 'nowords' ) {
                value = value.replace(/ /g, '');
                value = value.split(',');

                var clause = 'and';
                if ( operator == 'anywordssubstr' || operator == 'anywords' ) {
                    clause = 'or';
                }
                outer[clause] = [];

                $.each( value, function(key, arrayValue){
                    inner[field] = '/(' + arrayValue + ')+/i';
                    outer[clause].push( {"regex" : inner} );
                });

                if ( operator == 'nowordssubstr' || operator == 'nowords' ) {
                    outer = { "not" : outer };
                }

            } else if ( operator == 'regexp' || operator == 'matches' || operator == 'notregexp' || operator == 'notmatches' ) {
                inner[field] = value;
                outer["regexp"] = inner;
                if ( operator == 'notregexp' || operator == 'notmatches' ) {
                    outer = { "not" : outer };
                }

            } else if ( operator == 'isempty' || operator == 'isnotempty' ) {
                inner["field"] = field ;
                outer["missing"] = inner;
                if ( operator == 'isnotempty' ) {
                    outer = { "not" : outer };
                }
            } else {
                // This should never happen
                inner[field] = value;
                outer[operator] = inner;
            }

            return outer;
        }

    /*****************
        Receives a date input extracted from Bugzilla
        Parses and converts to ES compatible
        I.e. Milliseconds since epoch
        Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
    *****************/
        function makeESDates( date ) {
            var dateValue = 0;

            if ( date == 'Now' ) {
                dateValue = Date.now();
            } else {
                date = date.split('-');
                var year    = parseInt( date[0] );
                var month   = parseInt( date[1] ) - 1;
                var day     = parseInt( date[2] );
                dateValue = Date.UTC( year, month, day, 0, 0, 0 );
            }

            return parseInt( dateValue );
        }

    /*****************
        Extract selections from dropdown fields
        Where users are asked to choose whether to apply all or any (and / or)
    *****************/
        function getCustomClause( $subject, identifier ){
            var $clause = $subject.find('div.any_all_select select#'+identifier+' option:selected');
            var clauseValue = '';

            if ( $clause.length == 0 ) {
                clauseValue = 'and';
            } else {
                if ( $clause.val().toLowerCase() != 'or' ){ // Watch out for "and_g"
                    clauseValue = 'and';
                } else {
                    clauseValue = 'or';
                }
            }

            return clauseValue;
        }
<|endoftext|>


<commit_before>/**
 * Insert List.V2 View Class
 *
 * @class View.List.V2.Insert
 * @author Bruno Santos, Jerome Vial
 */
define(function(require, exports, module) {

	var _log = __debug('view-core-listV2-insert').defineLevel();

	var Insert = new Class({

		/**
		 * new info
		 * @return {void}
		 */
		_newInfo: function() {

			_log.debug('_newInfo', this.data);

			var newInfo = {
				_id: 'new',
				type: this.data.type,
				nodes: []
			};

			if (this.data && this.data._id) {
				newInfo.nodes.push(this.data._id);
			}

			this.remove('new');
			this._setInfo(newInfo);

			this.select('new');
		},

		/**
		 * set info
		 * @param {Object} info
		 */
		_setInfo: function(info) {
			_log.debug('_setInfo', info);

			if (typeof info !== 'object' || this.virtualSize === undefined) {
				_log.warn('invalid info type', info);
				return;
			}

			//check if the id is in the list
			var exist = this._getInfoById(info._id);
			if (exist) {
				this.updateInfo(info);
				this.select(this.selectedId);
				return;
			}

			if (this.options.verifyBeforeInsert === true) {
				var data = this.data || {};

				/*check type*/
				if (data.type !== info.type) {
					return;
				}

				/*check if the info is a node*/
				if (!info.nodes) {
					return;
				}

				/*check if the info is inside the node*/
				if (data._id && info.nodes.indexOf(data._id) === -1) {
					return;
				}
			}

			this.remove('new');

			this.virtualSize ++;

			this.virtualList.unshift(info);

			this.renderInfo(info, 1, 'top');

			this.element.scrollTop = 0;
			this._scroll();
		},

		/**
		 * update info
		 * @param  {Object} info
		 * @return {void}
		 */
		updateInfo: function(info) {
			_log.debug('updateInfo', info);

			/*update element*/
			var oldEl = this._getElById(info._id);
			var newEl = this._createEl(info);
			newEl.replaces(oldEl);

			/*update virtualList*/
			for (var i = 0; i < this.virtualList.length; i++) {
				var oldInfo = this.virtualList[i];

				if (oldInfo && oldInfo._id === info._id) {
					this.virtualList[i] = info;
					break;
				}
			}
		},

	});

	module.exports = Insert;

});
<commit_msg>enhancements in insert module for list view<commit_after>/**
 * Insert List.V2 View Class
 *
 * @class View.List.V2.Insert
 * @author Bruno Santos, Jerome Vial
 */
define(function(require, exports, module) {

	var _log = __debug('view-core-listV2-insert').defineLevel();

	var Insert = new Class({

		/**
		 * new info
		 * @return {void}
		 */
		_newInfo: function() {

			_log.debug('_newInfo', this.data);

			var newInfo = {
				_id: 'new',
				type: this.data.type,
				nodes: []
			};

			if (this.data && this.data._id) {
				newInfo.nodes.push(this.data._id);
			}

			this.remove('new');
			this._setInfo(newInfo);

			this.select('new');
		},

		/**
		 * set info
		 * @param {Object} info
		 */
		_setInfo: function(info) {
			_log.debug('_setInfo', info);

			if (typeof info !== 'object' || this.virtualSize === undefined) {
				_log.warn('invalid info type', info);
				return;
			}

			//check if the id is in the list
			var exist = this._getInfoById(info._id);
			if (exist) {
				this.updateInfo(info);
				//this.processInfos();
				this.select(this.selectedId);
				return;
			}

			if (this.options.verifyBeforeInsert === true) {
				var data = this.data || {};

				/*check type*/
				if (data.type !== info.type) {
					return;
				}

				/*check if the info is a node*/
				if (!info.nodes) {
					return;
				}

				/*check if the info is inside the node*/
				if (data._id && info.nodes.indexOf(data._id) === -1) {
					return;
				}
			}

			this.remove('new');

			this.virtualSize++;

			this.virtualList.unshift(info);

			this.renderInfo(info, 1, 'top');

			this.element.scrollTop = 0;
			this._scroll();
		},

		/**
		 * update info
		 * @param  {Object} info
		 * @return {void}
		 */
		updateInfo: function(info) {
			_log.debug('updateInfo', info);

			//update element
			var oldEl = this._getElById(info._id);
			var newEl = this._createEl(info);
			newEl.replaces(oldEl);

			//update virtualList
			for (var i = 0; i < this.virtualList.length; i++) {
				var oldInfo = this.virtualList[i];

				if (oldInfo && oldInfo._id === info._id) {
					this.virtualList[i] = info;
					break;
				}
			}

			//update _tempCache
			if (this._tempCache.length) {
				for (var j = 0; j < this._tempCache.length; j++) {
					var oldInfo = this._tempCache[j];

					if (oldInfo && oldInfo._id === info._id) {
						this._tempCache[j] = info;
						break;
					}
				}
			}
		},

	});

	module.exports = Insert;

});
<|endoftext|>


<commit_before>import React from 'react'
import {
  Button,
  Keyboard,
  StyleSheet,
  Text,
  TextInput,
  ScrollView,
  View
} from 'react-native'
import { actionCreators } from './dataModel/SRSimpleDataModel'

const intensityOptions = {
  NORMAL: 'NORMAL',
  CUSTOM: 'CUSTOM', // allow user to choose by when something should be learned
}

// TODO: make tab bar open this modally like in Instagram app
export default class SRStudyTaskEditor extends React.Component {

  static navigationOptions = {
    tabBarLabel: 'Add',
    tabBarIcon: ({ tintColor }) => (
      <Text>➕</Text>
    ),
  }

  // TODO: for opening editor with UI pre-filled with data
  props: {
    taskName: ?string,
    notes: ?string,
    dates: ?string,
    intensity: ?intensityOptions,
    saveAction: (studyTask) => any,
  }

  render() {
    const { taskName, notes, dates, intensity } = this.props

    return (
      <ScrollView style={styles.scrollView}>
        <View style={styles.edgePadding}>
          <TextInput
            style={styles.dataInputItemPadding}
            placeholder="Study Task"
            onSubmitEditing={Keyboard.dismiss}
            onChangeText={(studyTaskName) => this.setState({studyTaskName})}
          />
          <TextInput
            style={styles.dataInputItemPadding}
            placeholder="Notes"
            onSubmitEditing={Keyboard.dismiss}
          />
          <Text style={styles.dataInputItemPadding}>Date</Text>
          <Text style={styles.dataInputItemPadding}>Intensity</Text>
          <Button
            style={styles.dataInputItemPadding}
            title='Save'
            onPress={this.saveButtonAction}
          />
        </View>
      </ScrollView>
    )
  }

  saveButtonAction = () => {
    const { studyTaskName } = this.state
    const { store } = this.props.screenProps
    store.dispatch(actionCreators.add(studyTaskName))
  }

}

const styles = StyleSheet.create({
  scrollView: {
    flex: 1,
    paddingTop: 44,
  },
  edgePadding: {
    padding: 15,
    flex:1,
  },
  dataInputItemPadding: {
    padding: 5,
  }
})
<commit_msg>Added: tasks can now be added using updated model.<commit_after>import React from 'react'
import {
  Button,
  Keyboard,
  StyleSheet,
  Text,
  TextInput,
  ScrollView,
  View
} from 'react-native'
import { actionCreators, SRStudyTask, SRSpacedRepetition, SRStudyTaskIntensity } from './dataModel/SRSimpleDataModel'
import expect, { createSpy, spyOn, isSpy } from 'expect'
import { uuid } from './utilities/UUID'

// TODO: make tab bar open this modally like in Instagram app
export default class SRStudyTaskEditor extends React.Component {

  static navigationOptions = {
    tabBarLabel: 'Add',
    tabBarIcon: ({ tintColor }) => (
      <Text>➕</Text>
    ),
  }

  constructor(props) {
    super(props)

    this.state = {
      id:             props.id == null            ? props.id            : uuid(),
      taskName:       props.taskName == null      ? props.taskName      : null,
      notes:          props.notes == null         ? props.notes         : null,
      dates:          props.dates == null         ? props.dates         : [new Date()],
      ratingHistory:  props.ratingHistory == null ? props.ratingHistory : [],
      srs:            props.srs == null           ? props.srs           : new SRSpacedRepetition(),
      intensity:      props.intensity == null     ? props.intensity     : SRStudyTaskIntensity.NORMAL
    }
  }

  props: {
    saveAction: (studyTask) => any,
  }

  render() {
    // const {  } = this.state

    return (
      <ScrollView style={styles.scrollView}>
        <View style={styles.edgePadding}>
          <TextInput
            style={styles.dataInputItemPadding}
            placeholder="Study Task"
            onSubmitEditing={Keyboard.dismiss}
            onChangeText={(taskName) => this.setState({taskName})}
          />
          <TextInput
            style={styles.dataInputItemPadding}
            placeholder="Notes"
            onSubmitEditing={Keyboard.dismiss}
          />
          <Text style={styles.dataInputItemPadding}>Date</Text>
          <Text style={styles.dataInputItemPadding}>Intensity</Text>
          <Button
            style={styles.dataInputItemPadding}
            title='Save'
            onPress={this.saveButtonAction}
          />
        </View>
      </ScrollView>
    )
  }

  saveButtonAction = () => {
    const { store } = this.props.screenProps

    const studyTask = new SRStudyTask(
      this.state.id,
      this.state.taskName,
      this.state.notes,
      this.state.dates,
      this.state.ratingHistory,
      this.state.srs,
      this.state.intensity
    )

    store.dispatch(actionCreators.add(studyTask))
  }

}

const styles = StyleSheet.create({
  scrollView: {
    flex: 1,
    paddingTop: 44,
  },
  edgePadding: {
    padding: 15,
    flex:1,
  },
  dataInputItemPadding: {
    padding: 5,
  }
})
<|endoftext|>


<commit_before>/*
* Example Node implementation.
* Every node routes a packet to a random neighbor until it reaches the final destination.
*/

function Node(mac, meta = null) {
/* Required fields */

  // Basic data
  this.mac = mac;
  this.meta = meta;
  this.incoming = [];
  this.outgoing = [];

/* Additional fields */

  // Record next hop neighbors
  this.neighbors = {};
}

/*
* The simple routing algorithm here learns of its neigbhors
* once and sends incoming packets to a random neighbor.
*/
Node.prototype.step = function () {
  // Send a broadcast to direct neighbors
  if (isEmpty(this.neighbors)) {
    this.outgoing.push(
      new Packet(this.mac, BROADCAST_MAC, this.mac, BROADCAST_MAC)
    );
  }

  for (var i = 0; i < this.incoming.length; i += 1) {
    var packet = this.incoming[i];

    // Packet arrived at the destination
    if (packet.destinationAddress === this.mac) {
      console.log('packet arrived at the destination');
      continue;
    }

    // Catch broadcast packets and record neighbor
    if (packet.receiverAddress === BROADCAST_MAC) {
      this.neighbors[packet.transmitterAddress] = true;
      continue;
    }

    // Select random destination
    var others = Object.keys(this.neighbors);
    if (others.length) {
      var nextHop = others[Math.floor(Math.random() * others.length)];

      packet.transmitterAddress = this.mac;
      packet.receiverAddress = nextHop;

      this.outgoing.push(packet);
    }
  }
}

// Name displayed under the node
Node.prototype.getNodeName = function () {
  // Find hostname in meta data, display MAC address as fallback
  return findValue(this.meta, 'hostname', this.mac);
}

// Label on top of the node body
Node.prototype.getNodeLabel = function () {
  function countUnicastPackets(packets) {
    return packets.reduce(function(acc, val) {
      return acc + (val.receiverAddress !== BROADCAST_MAC);
    }, 0);
  }
  var packetCount = countUnicastPackets(this.incoming) + countUnicastPackets(this.outgoing);
  return packetCount ? packetCount.toString() : '';
}

// Color of the ring around the node body
Node.prototype.getRingColor = function () {
  return isEmpty(this.neighbors) ? '' : '#008000';
}

// Color of the round node body
Node.prototype.getBodyColor = function () {
  return '#fff';
}

// Number of small red circles around the node
// body indicating the number of connected clients
Node.prototype.getClientCount = function () {
  return (this.meta && ('statistics' in this.meta)) ? this.meta.statistics.clients : 0;
}

Node.prototype.reset = function () {
  this.incoming = [];
  this.outgoing = [];
  this.neighbors = {};
}

// For the transition to new implementations
Node.prototype.copyFromOldImplementation = function (oldNode) {
  copyExistingFields(oldNode, this);
};
<commit_msg>simplify packet counting<commit_after>/*
* Example Node implementation.
* Every node routes a packet to a random neighbor until it reaches the final destination.
*/

function Node(mac, meta = null) {
/* Required fields */

  // Basic data
  this.mac = mac;
  this.meta = meta;
  this.incoming = [];
  this.outgoing = [];

/* Additional fields */

  // Record next hop neighbors
  this.neighbors = {};
}

/*
* The simple routing algorithm here learns of its neigbhors
* once and sends incoming packets to a random neighbor.
*/
Node.prototype.step = function () {
  // Send a broadcast to direct neighbors
  if (isEmpty(this.neighbors)) {
    this.outgoing.push(
      new Packet(this.mac, BROADCAST_MAC, this.mac, BROADCAST_MAC)
    );
  }

  for (var i = 0; i < this.incoming.length; i += 1) {
    var packet = this.incoming[i];

    // Packet arrived at the destination
    if (packet.destinationAddress === this.mac) {
      console.log('packet arrived at the destination');
      continue;
    }

    // Catch broadcast packets and record neighbor
    if (packet.receiverAddress === BROADCAST_MAC) {
      this.neighbors[packet.transmitterAddress] = true;
      continue;
    }

    // Select random destination
    var others = Object.keys(this.neighbors);
    if (others.length) {
      var nextHop = others[Math.floor(Math.random() * others.length)];

      packet.transmitterAddress = this.mac;
      packet.receiverAddress = nextHop;

      this.outgoing.push(packet);
    }
  }
}

// Name displayed under the node
Node.prototype.getNodeName = function () {
  // Find hostname in meta data, display MAC address as fallback
  return findValue(this.meta, 'hostname', this.mac);
}

// Label on top of the node body
Node.prototype.getNodeLabel = function () {
  // Count unicast packets
  var count = 0;
  for (var i in this.outgoing) {
    count += (this.outgoing[i] !== BROADCAST_MAC);
  }
  return count ? count.toString() : '';
}

// Color of the ring around the node body
Node.prototype.getRingColor = function () {
  return isEmpty(this.neighbors) ? '' : '#008000';
}

// Color of the round node body
Node.prototype.getBodyColor = function () {
  return '#fff';
}

// Number of small red circles around the node
// body indicating the number of connected clients
Node.prototype.getClientCount = function () {
  return (this.meta && ('statistics' in this.meta)) ? this.meta.statistics.clients : 0;
}

Node.prototype.reset = function () {
  this.incoming = [];
  this.outgoing = [];
  this.neighbors = {};
}

// For the transition to new implementations
Node.prototype.copyFromOldImplementation = function (oldNode) {
  copyExistingFields(oldNode, this);
};
<|endoftext|>


<commit_before>'use strict';
/*
	effects.js

	Contains the functionality for the scrolling fixed menu
	and the popup menu toggle

*/
$(document).ready(function(){

	/* Menu Pop up Toggle */
	$('#popmenu').click( function(){
		$('#popup-menu').toggle('hide');
	});

	/* Smooth Scrolling */
	$(function() {
          $('a[href*="#"]:not([href="#"])').click(function() {
            if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
              var target = $(this.hash);
              target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
              if (target.length) {
                $('html, body').animate({
                  scrollTop: target.offset().top
                }, 1000);
                return false;
              }
            }
        });
    });

	/* Scroll Effect - can elements at different positions */
	$(window).on("scroll", function() {
    //if (window.matchMedia("(min-width: 400px)").matches) {
        if($(window).scrollTop() > 35) {
            $('header').css('background-color', '#fff');
        } else {
            $('header').css('background-color', 'transparent');
        }
    //} else {
            //do nothing
    //}

	});

});

<commit_msg>Improve visibility of nav bar text on page scroll<commit_after>'use strict';
/*
	effects.js

	Contains the functionality for the scrolling fixed menu
	and the popup menu toggle

*/
$(document).ready(function(){

	/* Menu Pop up Toggle */
	$('#popmenu').click( function(){
		$('#popup-menu').toggle('hide');
	});

	/* Smooth Scrolling */
	$(function() {
          $('a[href*="#"]:not([href="#"])').click(function() {
            if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
              var target = $(this.hash);
              target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
              if (target.length) {
                $('html, body').animate({
                  scrollTop: target.offset().top
                }, 1000);
                return false;
              }
            }
        });
    });

	/* Scroll Effect - can elements at different positions */
	$(window).on("scroll", function() {
	    if ($(window).scrollTop() > 35) {
	        $('#site-header').addClass('top-bar--opaque');
	    } else {
            $('#site-header').removeClass('top-bar--opaque');
	    }
	});

});
<|endoftext|>