<commit_before>'use strict';

module.exports = function (grunt) {

  require('time-grunt')(grunt);
  grunt.file.expand('../node_modules/grunt-*/tasks').forEach(grunt.loadTasks);

  function mountFolder (connect, dir, maxage) {
    return connect.static(require('path').resolve(grunt.template.process(dir)), { maxAge: maxage||0 });
  }

  grunt.initConfig({

    // Project settings
    yeoman: {
      // configurable paths
      app: require('./bower.json').appPath || 'app',
      dist: 'dist'
    },

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      options: {
        nospawn: true,
        livereload: '<%= connect.options.livereload %>'
      },
      js: {
        files: ['{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js'],
        tasks: ['newer:jshint:all']
      },
      css: {
        files: ['{.tmp,<%= yeoman.app %>}/styles/{,*/}*.css'],
        tasks: ['stylus']
      },
      stylus: {
        files: ['<%= yeoman.app %>/styles/{,*/}*.styl'],
        tasks: ['stylus', 'autoprefixer']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        options: {
          livereload: true
        },
        files: [
          '<%= yeoman.app %>/{,*/}*.html',
          '.tmp/styles/{,*/}*.css',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
        ]
      }
    },

    // The actual grunt server settings
    connect: {
      options: {
        hostname: 'localhost',
        livereload: 35729
      },
      livereload: {
        options: {
          debug: false,
          open: true,
          port: 9000,
          middleware: function (connect) {
            return [
              mountFolder(connect, 'test', 86400000),
              mountFolder(connect, '.tmp', 86400000),
              mountFolder(connect, '<%= yeoman.app %>', 86400000)
            ];
          }
        }
      },
      test: {
        options: {
          port: 9000,
          middleware: function (connect) {
            return [
              mountFolder(connect, 'test', 86400000),
              mountFolder(connect, '<%= yeoman.dist %>', 86400000)
            ];
          }
        }
      },
      dist: {
        options: {
          base: '<%= yeoman.dist %>'
        }
      }
    },

    // Make sure code styles are up to par and there are no obvious mistakes
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: [
        'Gruntfile.js',
        '<%= yeoman.app %>/scripts/{,*/}*.js'
      ],
      test: {
        options: {
          jshintrc: 'test/.jshintrc'
        },
        src: ['test/spec/{,*/}*.js']
      }
    },

    // Empties folders to start fresh
    clean: {
      dist: {
        files: [
          {
            dot: true,
            src: [
              '.tmp',
              '<%= yeoman.dist %>/*',
              '!<%= yeoman.dist %>/.git*'
            ]
          }
        ]
      },
      server: '.tmp'
    },

    // Add vendor prefixed styles
    autoprefixer: {
      options: {
        browsers: ['last 1 version']
      },
      dist: {
        files: [
          {
            expand: true,
            cwd: '.tmp/styles/',
            src: '{,*/}*.css',
            dest: '.tmp/styles/'
          }
        ]
      }
    },

    stylus: {
      compile: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/styles',
          src: [ '**/*.styl' ],
          dest: '.tmp/styles',
          ext: '.css'
        }]
      }
    },

    rev: {
      dist: {
        files: {
          src: [
            '<%= yeoman.dist %>/scripts/{,*/}*.js',
            '<%= yeoman.dist %>/styles/{,*/}*.css',
            '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
            '<%= yeoman.dist %>/styles/fonts/*'
          ]
        }
      }
    },

    // Reads HTML for usemin blocks to enable smart builds that automatically
    // concat, minify and revision files. Creates configurations in memory so
    // additional tasks can operate on them
    useminPrepare: {
      html: ['<%= yeoman.app %>/index.html', '<%= yeoman.app %>/settings.html'],
      options: {
        dest: '<%= yeoman.dist %>'
      }
    },

    // Performs rewrites based on rev and the useminPrepare configuration
    usemin: {
      html: ['<%= yeoman.dist %>/{,*/}*.html'],
      css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
      options: {
        assetsDirs: ['<%= yeoman.dist %>']
      }
    },

    // The following *-min tasks produce minified files in the dist folder
    htmlmin: {
      dist: {
        options: {
          // Optional configurations that you can uncomment to use
          // removeCommentsFromCDATA: true,
          // collapseBooleanAttributes: true,
          // removeAttributeQuotes: true,
          // removeRedundantAttributes: true,
          // useShortDoctype: true,
          // removeEmptyAttributes: true,
          // removeOptionalTags: true*/
        },
        files: [
          {
            expand: true,
            cwd: '<%= yeoman.app %>',
            src: ['*.html', 'views/*.html'],
            dest: '<%= yeoman.dist %>'
          }
        ]
      }
    },

    // Allow the use of non-minsafe AngularJS files. Automatically makes it
    // minsafe compatible so Uglify does not destroy the ng references
    ngmin: {
      dist: {
        files: [
          {
            expand: true,
            cwd: '.tmp/concat/scripts',
            src: '*.js',
            dest: '.tmp/concat/scripts'
          }
        ]
      }
    },

    // Replace Google CDN references
    cdnify: {
      dist: {
        html: ['<%= yeoman.dist %>/*.html']
      }
    },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [
          {
            expand: true,
            dot: true,
            cwd: '<%= yeoman.app %>',
            dest: '<%= yeoman.dist %>',
            src: [
              '*.html', 'views/**/*.html',
              '*.{ico,png,txt}',
              '.htaccess',
              'bower_components/**/*',
              'images/{,*/}*.{webp,ico,png,jpg,jpeg,gif,svg}',
              'fonts/*',
              'translations/*'
            ]
          },
          {
            expand: true,
            cwd: '.tmp/images',
            dest: '<%= yeoman.dist %>/images',
            src: [
              'generated/*'
            ]
          }
        ]
      },

      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },

    bower: {
      install: {
        options: {
          targetDir: 'app/bower_components',
          install: true,
          verbose: false,
          cleanTargetDir: false,
          cleanBowerDir: false
        }
      }
    },

    // Test settings
    karma: {
      unit: {
        configFile: 'test/karma.conf.js',
        singleRun: false
      },
      e2e: {
        proxies: { '/': 'http://localhost:9000/' },
        configFile: 'test/karma-e2e.conf.js',
        browsers: ['Chrome'],
        autoWatch: true,
        singleRun: false
      }
    }
  });

  grunt.registerTask('serve', function (target) {
    grunt.task.run([
      'clean:server',
      'stylus',
      'autoprefixer',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('test', function (target) {
    grunt.task.run([
      'clean:server',
      'stylus',
      'autoprefixer',
      'connect:test',
      'karma:unit'
    ]);
  });

  grunt.registerTask('build', [
    'clean:dist',
    'bower:install',
    'useminPrepare',
    'stylus',
    'autoprefixer',
    'concat',
    'ngmin',
    'copy:dist',
    'cdnify',
    'cssmin',
    'uglify',
    'rev',
    'usemin'
  ]);
};
<commit_msg>chore(build): copy and autoprefix css files<commit_after>'use strict';

module.exports = function (grunt) {

  require('time-grunt')(grunt);
  grunt.file.expand('../node_modules/grunt-*/tasks').forEach(grunt.loadTasks);

  function mountFolder (connect, dir, maxage) {
    return connect.static(require('path').resolve(grunt.template.process(dir)), { maxAge: maxage||0 });
  }

  grunt.initConfig({

    // Project settings
    yeoman: {
      // configurable paths
      app: require('./bower.json').appPath || 'app',
      dist: 'dist'
    },

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      options: {
        nospawn: true,
        livereload: '<%= connect.options.livereload %>'
      },
      js: {
        files: ['{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js'],
        tasks: ['newer:jshint:all']
      },
      css: {
        files: ['{.tmp,<%= yeoman.app %>}/styles/{,*/}*.css'],
        tasks: ['autoprefixer']
      },
      stylus: {
        files: ['<%= yeoman.app %>/styles/{,*/}*.styl'],
        tasks: ['stylus', 'autoprefixer']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        options: {
          livereload: true
        },
        files: [
          '<%= yeoman.app %>/{,*/}*.html',
          '.tmp/styles/{,*/}*.css',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
        ]
      }
    },

    // The actual grunt server settings
    connect: {
      options: {
        hostname: 'localhost',
        livereload: 35729
      },
      livereload: {
        options: {
          debug: false,
          open: true,
          port: 9000,
          middleware: function (connect) {
            return [
              mountFolder(connect, 'test', 86400000),
              mountFolder(connect, '.tmp', 86400000),
              mountFolder(connect, '<%= yeoman.app %>', 86400000)
            ];
          }
        }
      },
      test: {
        options: {
          port: 9000,
          middleware: function (connect) {
            return [
              mountFolder(connect, 'test', 86400000),
              mountFolder(connect, '<%= yeoman.dist %>', 86400000)
            ];
          }
        }
      },
      dist: {
        options: {
          base: '<%= yeoman.dist %>'
        }
      }
    },

    // Make sure code styles are up to par and there are no obvious mistakes
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: [
        'Gruntfile.js',
        '<%= yeoman.app %>/scripts/{,*/}*.js'
      ],
      test: {
        options: {
          jshintrc: 'test/.jshintrc'
        },
        src: ['test/spec/{,*/}*.js']
      }
    },

    // Empties folders to start fresh
    clean: {
      dist: {
        files: [
          {
            dot: true,
            src: [
              '.tmp',
              '<%= yeoman.dist %>/*',
              '!<%= yeoman.dist %>/.git*'
            ]
          }
        ]
      },
      server: '.tmp'
    },

    // Add vendor prefixed styles
    autoprefixer: {
      options: {
        browsers: ['> 1%']
      },
      dist: {
        files: [
          {
            expand: true,
            cwd: '.tmp/styles/',
            src: '{,*/}*.css',
            dest: '.tmp/styles/'
          }
        ]
      }
    },

    stylus: {
      compile: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/styles',
          src: [ '**/*.styl' ],
          dest: '.tmp/styles',
          ext: '.css'
        }]
      }
    },

    rev: {
      dist: {
        files: {
          src: [
            '<%= yeoman.dist %>/scripts/{,*/}*.js',
            '<%= yeoman.dist %>/styles/{,*/}*.css',
            '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
            '<%= yeoman.dist %>/styles/fonts/*'
          ]
        }
      }
    },

    // Reads HTML for usemin blocks to enable smart builds that automatically
    // concat, minify and revision files. Creates configurations in memory so
    // additional tasks can operate on them
    useminPrepare: {
      html: ['<%= yeoman.app %>/index.html', '<%= yeoman.app %>/settings.html'],
      options: {
        dest: '<%= yeoman.dist %>'
      }
    },

    // Performs rewrites based on rev and the useminPrepare configuration
    usemin: {
      html: ['<%= yeoman.dist %>/{,*/}*.html'],
      css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
      options: {
        assetsDirs: ['<%= yeoman.dist %>']
      }
    },

    // The following *-min tasks produce minified files in the dist folder
    htmlmin: {
      dist: {
        options: {
          // Optional configurations that you can uncomment to use
          // removeCommentsFromCDATA: true,
          // collapseBooleanAttributes: true,
          // removeAttributeQuotes: true,
          // removeRedundantAttributes: true,
          // useShortDoctype: true,
          // removeEmptyAttributes: true,
          // removeOptionalTags: true*/
        },
        files: [
          {
            expand: true,
            cwd: '<%= yeoman.app %>',
            src: ['*.html', 'views/*.html'],
            dest: '<%= yeoman.dist %>'
          }
        ]
      }
    },

    // Allow the use of non-minsafe AngularJS files. Automatically makes it
    // minsafe compatible so Uglify does not destroy the ng references
    ngmin: {
      dist: {
        files: [
          {
            expand: true,
            cwd: '.tmp/concat/scripts',
            src: '*.js',
            dest: '.tmp/concat/scripts'
          }
        ]
      }
    },

    // Replace Google CDN references
    cdnify: {
      dist: {
        html: ['<%= yeoman.dist %>/*.html']
      }
    },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [
          {
            expand: true,
            dot: true,
            cwd: '<%= yeoman.app %>',
            dest: '<%= yeoman.dist %>',
            src: [
              '*.html', 'views/**/*.html',
              '*.{ico,png,txt}',
              '.htaccess',
              'bower_components/**/*',
              'images/{,*/}*.{webp,ico,png,jpg,jpeg,gif,svg}',
              'fonts/*',
              'translations/*'
            ]
          },
          {
            expand: true,
            cwd: '.tmp/images',
            dest: '<%= yeoman.dist %>/images',
            src: [
              'generated/*'
            ]
          }
        ]
      },
      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },

    bower: {
      install: {
        options: {
          targetDir: 'app/bower_components',
          install: true,
          verbose: false,
          cleanTargetDir: false,
          cleanBowerDir: false
        }
      }
    },

    // Test settings
    karma: {
      unit: {
        configFile: 'test/karma.conf.js',
        singleRun: false
      },
      e2e: {
        proxies: { '/': 'http://localhost:9000/' },
        configFile: 'test/karma-e2e.conf.js',
        browsers: ['Chrome'],
        autoWatch: true,
        singleRun: false
      }
    }
  });

  grunt.registerTask('serve', function (target) {
    grunt.task.run([
      'clean:server',
      'copy:styles',
      'stylus',
      'autoprefixer',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('test', function (target) {
    grunt.task.run([
      'clean:server',
      'copy:styles',
      'stylus',
      'autoprefixer',
      'connect:test',
      'karma:unit'
    ]);
  });

  grunt.registerTask('build', [
    'clean:dist',
    'bower:install',
    'useminPrepare',
    'stylus',
    'autoprefixer',
    'concat',
    'ngmin',
    'copy:dist',
    'cdnify',
    'cssmin',
    'uglify',
    'rev',
    'usemin'
  ]);
};
<|endoftext|>


<commit_before>"use strict";

var WebGMEGlobal = { 'version': 'DEMO - 12/16/2013',
    'SUPPORTS_TOUCH': 'ontouchstart' in window || navigator.msMaxTouchPoints }; //touch device detection}

// let require load all the toplevel needed script and call us on domReady
define(['logManager',
    'bin/getconfig',
    'js/client',
    'clientUtil',
    'js/Utils/GMEConcepts',
    'js/LayoutManager/LayoutManager',
    'js/Decorators/DecoratorManager',
    'js/KeyboardManager/KeyboardManager',
    'js/PanelManager/PanelManager',
    './WebGME.History',
    'js/Utils/METAAspectHelper',
    'js/ConstraintManager/ConstraintManager'], function (logManager,
                                            CONFIG,
                                            Client,
                                            util,
                                            GMEConcepts,
                                            LayoutManager,
                                            DecoratorManager,
                                            KeyboardManager,
                                            PanelManager,
                                            WebGMEHistory,
                                            METAAspectHelper,
                                            ConstraintManager) {

    var _webGMEStart = function () {
        var lm,
            client,
            loadPanels,
            layoutToLoad = util.getURLParameterByName('layout') || 'DefaultLayout',
            commitToLoad = util.getURLParameterByName('commit').toLowerCase(),
            projectToLoad = util.getURLParameterByName('project'),
            objectToLoad = util.getURLParameterByName('obj').toLowerCase(),
            logger = logManager.create('WebGME'),
            selectObject;

        lm = new LayoutManager();
        lm.loadLayout(layoutToLoad, function () {
            var panels = [],
                layoutPanels = lm._currentLayout.panels,
                len = layoutPanels ? layoutPanels.length : 0,
                i;

            client = new Client(CONFIG);

            WebGMEGlobal.ConstraintManager = new ConstraintManager(client);

            WebGMEHistory.setClient(client);

            GMEConcepts.initialize(client);

            METAAspectHelper.initialize(client);

            //hook up branch changed to set read-only mode on panels
            client.addEventListener(client.events.BRANCH_CHANGED, function (__project, branchName) {
                var readOnly = branchName === null || branchName === undefined;
                lm.setPanelReadOnly(readOnly);
            });

            client.decoratorManager = new DecoratorManager();

            for (i = 0; i < len; i += 1) {
                panels.push({'panel': layoutPanels[i].panel,
                    'container': layoutPanels[i].container,
                    'control': layoutPanels[i].control,
                    'params' : {'client': client}});
            }

            //load the panels
            loadPanels(panels);

            //as of now it's a global variable just to make access to it easier
            //TODO: might need to be changed
            WebGMEGlobal.KeyboardManager = KeyboardManager;
            WebGMEGlobal.KeyboardManager.setEnabled(true);
            WebGMEGlobal.PanelManager = new PanelManager();
        });

        loadPanels = function (panels) {
            var p = panels.splice(0, 1)[0];

            lm.loadPanel(p, function () {
                if (panels.length > 0) {
                    loadPanels(panels);
                } else {
                    client.connectToDatabaseAsync({'open': true,
                                                    'project': projectToLoad || CONFIG.project}, function (err) {
                        if (err) {
                            logger.error(err);
                        } else {
                            if (commitToLoad && commitToLoad !== "") {
                                client.selectCommitAsync(commitToLoad, function (err) {
                                    if (err) {
                                        logger.error(err);
                                    } else {
                                        selectObject();
                                    }
                                });
                            } else {
                                selectObject();
                            }
                        }
                    });
                }
            });
        };

        selectObject = function () {
            if (objectToLoad && objectToLoad !== "") {
                setTimeout(function () {
                    client.setSelectedObjectId(objectToLoad);
                }, 1000);
            }
        };
    };

    return {
        start : _webGMEStart
    };
});<commit_msg>version upadte<commit_after>"use strict";

var WebGMEGlobal = { 'version': '0.1.0',
    'SUPPORTS_TOUCH': 'ontouchstart' in window || navigator.msMaxTouchPoints }; //touch device detection}

// let require load all the toplevel needed script and call us on domReady
define(['logManager',
    'bin/getconfig',
    'js/client',
    'clientUtil',
    'js/Utils/GMEConcepts',
    'js/LayoutManager/LayoutManager',
    'js/Decorators/DecoratorManager',
    'js/KeyboardManager/KeyboardManager',
    'js/PanelManager/PanelManager',
    './WebGME.History',
    'js/Utils/METAAspectHelper',
    'js/ConstraintManager/ConstraintManager'], function (logManager,
                                            CONFIG,
                                            Client,
                                            util,
                                            GMEConcepts,
                                            LayoutManager,
                                            DecoratorManager,
                                            KeyboardManager,
                                            PanelManager,
                                            WebGMEHistory,
                                            METAAspectHelper,
                                            ConstraintManager) {

    var _webGMEStart = function () {
        var lm,
            client,
            loadPanels,
            layoutToLoad = util.getURLParameterByName('layout') || 'DefaultLayout',
            commitToLoad = util.getURLParameterByName('commit').toLowerCase(),
            projectToLoad = util.getURLParameterByName('project'),
            objectToLoad = util.getURLParameterByName('obj').toLowerCase(),
            logger = logManager.create('WebGME'),
            selectObject;

        lm = new LayoutManager();
        lm.loadLayout(layoutToLoad, function () {
            var panels = [],
                layoutPanels = lm._currentLayout.panels,
                len = layoutPanels ? layoutPanels.length : 0,
                i;

            client = new Client(CONFIG);

            WebGMEGlobal.ConstraintManager = new ConstraintManager(client);

            WebGMEHistory.setClient(client);

            GMEConcepts.initialize(client);

            METAAspectHelper.initialize(client);

            //hook up branch changed to set read-only mode on panels
            client.addEventListener(client.events.BRANCH_CHANGED, function (__project, branchName) {
                var readOnly = branchName === null || branchName === undefined;
                lm.setPanelReadOnly(readOnly);
            });

            client.decoratorManager = new DecoratorManager();

            for (i = 0; i < len; i += 1) {
                panels.push({'panel': layoutPanels[i].panel,
                    'container': layoutPanels[i].container,
                    'control': layoutPanels[i].control,
                    'params' : {'client': client}});
            }

            //load the panels
            loadPanels(panels);

            //as of now it's a global variable just to make access to it easier
            //TODO: might need to be changed
            WebGMEGlobal.KeyboardManager = KeyboardManager;
            WebGMEGlobal.KeyboardManager.setEnabled(true);
            WebGMEGlobal.PanelManager = new PanelManager();
        });

        loadPanels = function (panels) {
            var p = panels.splice(0, 1)[0];

            lm.loadPanel(p, function () {
                if (panels.length > 0) {
                    loadPanels(panels);
                } else {
                    client.connectToDatabaseAsync({'open': true,
                                                    'project': projectToLoad || CONFIG.project}, function (err) {
                        if (err) {
                            logger.error(err);
                        } else {
                            if (commitToLoad && commitToLoad !== "") {
                                client.selectCommitAsync(commitToLoad, function (err) {
                                    if (err) {
                                        logger.error(err);
                                    } else {
                                        selectObject();
                                    }
                                });
                            } else {
                                selectObject();
                            }
                        }
                    });
                }
            });
        };

        selectObject = function () {
            if (objectToLoad && objectToLoad !== "") {
                setTimeout(function () {
                    client.setSelectedObjectId(objectToLoad);
                }, 1000);
            }
        };
    };

    return {
        start : _webGMEStart
    };
});<|endoftext|>


<commit_before>import React, { Component } from 'react';
import Button from 'material-ui/Button';

import 'typeface-roboto';

import CategoryView from './CategoryView/CategoryView.js';

class App extends Component {
  constructor(props) {
    super(props);
    // Will have one state per top-level view:
    //     - default    : welcome page
    //     - categories : categories list
    //     - daily      : entries for a given date
    //     - search     : search / filter entries
    this.state = {
      view: 'default',
    };
    this.handleCategoriesBtnClick = this.handleCategoriesBtnClick.bind(this)
  }

  handleCategoriesBtnClick(e) {
    this.setState({
      view: 'categories'
    });
  }

  render() {
    let view = null;
    if (this.state.view == 'categories') {
      view = (
        <CategoryView></CategoryView>
      )
    }

    return (

        <Button type="button"
          onClick={this.handleCategoriesBtnClick}
          color="primary"
          raised>
            Send GET /categories
        </Button>
        {view}

    );
  }
}

export default App;
<commit_msg>using Reboot component<commit_after>import React, { Component } from 'react';
import Button from 'material-ui/Button';
import Reboot from 'material-ui/Reboot';

import 'typeface-roboto';

import CategoryView from './CategoryView/CategoryView.js';

class App extends Component {
  constructor(props) {
    super(props);
    // Will have one state per top-level view:
    //     - default    : welcome page
    //     - categories : categories list
    //     - daily      : entries for a given date
    //     - search     : search / filter entries
    this.state = {
      view: 'default',
    };
    this.handleCategoriesBtnClick = this.handleCategoriesBtnClick.bind(this)
  }

  handleCategoriesBtnClick(e) {
    this.setState({
      view: 'categories'
    });
  }

  render() {
    let view = null;
    if (this.state.view === 'categories') {
      view = (
        <CategoryView></CategoryView>
      )
    }

    return (

        <Reboot />
        <Button type="button"
          onClick={this.handleCategoriesBtnClick}
          color="primary"
          raised>
            Send GET /categories
        </Button>
        {view}

    );
  }
}

export default App;
<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Component.extend({
    classNames: ['content-wrapper'],
    mapmarkers: {},
    displayMarker: {},

    actions: {
        markerclick: function(marker){
            var self = this;
            var lat = marker.latitude;
            var lon = marker.longitude;
            console.log(marker);

            var data = new Ember.RSVP.Promise(function(resolve){
    			$.get('http://nominatim.openstreetmap.org/reverse', 'format=json&lat=' + lat +'&lon=' + lon + '&zoom=18&addressdetails=1', function(data){
    				resolve(data);
    			}, 'json');
    		});

            data.then(function(data){
                console.log(data);
                marker.address = data.display_name;
                self.set('displayMarker', marker);
            });

			$('.marker-desc-wrapper').show();
		},

        new_marker: function(latlng){
            this.sendAction('new_marker', latlng);
        },
        save_marker: function(label){
			this.sendAction('save_marker', label);
		},

        change_rating: function(value){
            var markerId = this.get('displayMarker').id;
            var data = new Ember.RSVP.Promise(function(resolve){
                $.ajax({
                    type: "POST",
                    contentType: "application/json",
                    url: '/api/v1/markers/' + markerId + '/rate',
                    data: {
                        'score': value
                    },
                    dataType: "json",
                    success: function(data){
                        resolve(data);
                    }
                });
    		});

            data.then(function(data){
                var marker = this.get('displayMarker');
                marker.positiveCount = data.positiveCount;
                marker.negativeCount = data.negativeCount;
            });
        }
    }
});
<commit_msg>Atualizando marcadores após rating<commit_after>import Ember from 'ember';

export default Ember.Component.extend({
    classNames: ['content-wrapper'],
    mapmarkers: {},
    displayMarker: {},

    clone: function(marker){
        return {
            "id": marker.id,
            "latitude": marker.latitude,
            "longitude": marker.longitude,
            "label": marker.label,
            "positiveCount": marker.positiveCount,
            "negativeCount": marker.negativeCount,
            "address": marker.address
        };
    },

    actions: {
        markerclick: function(marker){
            var self = this;
            var lat = marker.latitude;
            var lon = marker.longitude;

            var data = new Ember.RSVP.Promise(function(resolve){
    			$.get('http://nominatim.openstreetmap.org/reverse', 'format=json&lat=' + lat +'&lon=' + lon + '&zoom=18&addressdetails=1', function(data){
    				resolve(data);
    			}, 'json');
    		});

            data.then(function(data){
                console.log(data);
                marker.address = data.display_name;
                self.set('displayMarker', marker);
            });

			$('.marker-desc-wrapper').show();
		},

        new_marker: function(latlng){
            this.sendAction('new_marker', latlng);
        },
        save_marker: function(label){
			this.sendAction('save_marker', label);
		},

        change_rating: function(value){
            var markerId = this.get('displayMarker').id;
            var data = new Ember.RSVP.Promise(function(resolve){
                $.ajax({
                    type: "POST",
                    contentType: "application/json",
                    url: '/api/v1/markers/' + markerId + '/rate',
                    data: JSON.stringify({
                        'score': value
                    }),
                    dataType: "json",
                    success: function(data){
                        resolve(data);
                    }
                });
    		});

            var self = this;

            data.then(function(data){
                var marker = self.get('displayMarker');
                marker.positiveCount = data.positiveCount;
                marker.negativeCount = data.negativeCount;

                var clone = self.clone(marker);
                self.set('displayMarker', clone);

                console.log(self.get('displayMarker'));
                self.sendAction('reload');
            });
        }
    }
});
<|endoftext|>


<commit_before>/**
 * Created by ldp on 2015/2/7.
 */

/*
 归并排序

 归并(Merging) ：是指将两个或两个以上的有序序列合并成一个有序序列。若采用线性表(无论是那种存储结构)易于实现，其时间复杂度为O(m+n) 。
 归并思想实例：两堆扑克牌，都已从小到大排好序，要将两堆合并为一堆且要求从小到大排序。
 ◆  将两堆最上面的抽出(设为C1，C2)比较大小，将小者置于一边作为新的一堆(不妨设C1<C2)；再从第一堆中抽出一张继续与C2进行比较，将较小的放置在新堆的最下面；
 ◆ 重复上述过程，直到某一堆已抽完，然后将剩下一堆中的所有牌转移到新堆中。

 1   排序思想
 ①  初始时，将每个记录看成一个单独的有序序列，则n个待排序记录就是n个长度为1的有序子序列；
 ②  对所有有序子序列进行两两归并，得到n/2个长度为2或1的有序子序列——一趟归并；
 ③  重复② ，直到得到长度为n的有序序列为止。

 上述排序过程中，子序列总是两两归并，称为2-路归并排序。其核心是如何将相邻的两个子序列归并成一个子序列。设相邻的两个子序列分别为：
 {R[k], R[k+1], …, R[m]}和{R[m+1], R[m+2],…, R[h]}，将它们归并为一个有序的子序列：
 {DR[l], DR[l+1], …, DR[m], DR[m+1], …, DR[h] }

 例：设有9个待排序的记录，关键字分别为23, 38, 22, 45, 23, 67, 31, 15, 41，归并排序的过程。
 初始关键字: [23]   [38]   [22]   [45]   [23]   [67]   [31]   [15]   [41]
              |      |      |      |      |      |      |      |
              --------      --------      --------      --------
 一趟归并后: [23    38]    [22     45]    [23     67]    [15     31]   [41]
                 |              |             |              |
                 ---------------               ---------------
 二趟归并后: [22     23      38     45]    [15     23     31     67]    [41]
                        |                              |
                        --------------------------------
 三趟归并后: [15     22      23     23     31     38     45     67]    [41]
                                       |                                |
                                       ----------------------------------
 四趟归并后: [15     22      23     23     31     38     41     45     67

 2  一趟归并排序
 一趟归并排序都是从前到后，依次将相邻的两个有序子序列归并为一个，且除最后一个子序列外，其余每个子序列的长度都相同。设这些子序列的长度为d，则一趟归并排序的过程是：
 从j=0开始，依次将相邻的两个有序子序列
 R[j…j+d-1]和R[j+d…j+2d-1]进行归并；每次归并两个子序列后，j后移动2d个位置，即
 j=j+2d；若剩下的元素不足两个子序列时，分以下两种情况处理：
 ①  剩下的元素个数>d：再调用一次上述过程，将一个长度为d的子序列和不足d的子序列进行归并；
 ②  剩下的元素个数≤d：将剩下的元素依次复制到归并后的序列中。

 3.算法分析
具有n个待排序记录的归并次数是㏒2n，而一趟归并的时间复杂度为O(n)，则整个归并排序的时间复杂度无论是最好还是最坏情况均为O(n㏒2n)。在排序过程中，使用了辅助向量DR，大小与待排序记录空间相同，则空间复杂度为O(n)。归并排序是稳定的。

 */

var nCount = 0;
var nonRecursiveCount = 0;
var recursiveCount = 0;

/**
 * 将有序的sr[s1..e1]和sr[s2..e2]归并为有序的tr[s1..e2]
 * @param sr
 * @param s1
 * @param e1
 * @param e2
 */
function merge(sr, s1, e1, e2){
    var temp = [];
    var i = s1;
    var j = e1 + 1;
    var k = 0;

    while(i <= e1 && j <= e2){
        if(sr[i] < sr[j]) temp[k++] = sr[i++];
        else temp[k++] = sr[j++];
    }
    while(i <= e1) temp[k++] = sr[i++];
    while(j <= e2) temp[k++] = sr[j++];

    // 复制回去
    for(i = s1, k = 0; i <= e2; ++i, ++k) sr[i] = temp[k];
}

/**
 * 2-路归并排序递归算法
 * @param {Array} sr
 * @param {Number} s
 * @param {Number} t
 */
function mergeSortRecursive(sr, s, t){
    if(s == null) s = 0;
    if(t == null) t = sr.length - 1;

    if(s >= t) return;

    // 将sr[s..t]平分为sr[s..m]和sr[m+1..t]
    var m = (s + t) >> 1;
    // 递归地将sr[s..m]归并为有序的sr[s..m]
    mergeSortRecursive(sr, s, m);
    // 递归地将sr[m+1..t]归并为有序的sr[m+1..t]
    mergeSortRecursive(sr, m + 1, t);
    // 将sr[s..m]和sr[m+1..t]归并到sr[s..t];
    merge(sr, s, m, t);
}
exports.mergeSortRecursive = mergeSortRecursive;

console.log('\n\nmergeSortRecursive:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
mergeSortRecursive(arr);
console.log(arr + '');

function mergeSortNonRecursive(sr){
    var j, k;
    for(var d = 1, n = sr.length - 1; d < n; d *= 2) {
        // 一趟归并排序算法
        j = 0;

        // 子序列两两归并
        while((k = (j + 2 * d - 1)) < n){
            merge(sr, j,  j + d - 1, k);
            j = k + 1;
        }

        // 剩余元素个数超过一个子序列长度
        if(j + d - 1 < n) merge(sr, j, j + d - 1, n);
        // 剩余子序列复制
        else merge(sr, j, n, n);
    }
}
exports.mergeSortNonRecursive = mergeSortNonRecursive;

console.log('\nmergeSortNonRecursive:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
mergeSortNonRecursive(arr);
console.log(arr + '');

// 自然合并排序
// http://www.cnblogs.com/liushang0419/archive/2011/09/19/2181476.html
// http://www.cnblogs.com/lanke/archive/2013/01/15/2860487.html
/*
自然归并是归并排序的一个变形，效率更高一些，可以在归并排序非递归实现的基础上进行修改.对于已经一个已经给定数组a,通常存在多个长度大于1的已经自然排好的子数组段,因此用一次对数组a的线性扫描就可以找出所有这些排好序的子数组段,然后再对这些子数组段俩俩合并.
 */

// 扫描得到子串的函数
function pass(sqList, rec){
    var num = 0;
    rec[num++] = 0;

    for(var i = 1, len = sqList.length; i < len; ++i){
        if(sqList[i] > sqList[i + 1]) rec[num++] = i + 1;
    }
    rec[num++] = len;

    return num;
}

function natureMergeSort(sqList){
    var rec = [];

    //num=2说明已经排好序了
    //每循环一次，进行一次pass()操作
    for(var num = pass(sqList, rec); num !== 2; num = pass(sqList, rec)){
        for(var i = 0; i + 2 < num; i += 2) {
            merge(sqList, rec[i], rec[i + 1] - 1, rec[i + 2] - 1);
        }
    }
}

exports.natureMergeSort = natureMergeSort;

console.log('\nnatureMergeSort:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
natureMergeSort(arr);
console.log(arr + '');

console.log(recursiveCount);
console.log(nonRecursiveCount);
console.log(nCount);

// 双向自然合并排序算法
/*
双向自然合并排序是根据欲排序数据局部不是升序就是降序的自然有序特点,先线性扫描出自然有序的子数组段,再进行合并排序.扫描时的有序数段长度越长,段数越少,对应合并树的层数就会越少,算法的效率越高.
 */
var naturalMergeSort = (function(){
    return naturalMergeSort;

    function naturalMergeSort(a){
        var b = [];
        var n = a.length;
        while(!mergeRuns(a, b, n) && !mergeRuns(b, a, n));
    }

    function mergeRuns(a, b, n){
        var i = 0;
        var k = 0;
        var asc = true;
        var x;

        while(i < n){
            k = i;
            // 找到最后一个递增序列元素
            do x = a[i++]; while(i < n && x <= a[i]);
            // 找到最后一个递减序列元素
            while(i < n && x >= a[i]) x = a[i++];
            // 归并递增序列和递减序列，结果可能递增或递减
            merge(a, b, k, i - 1, asc);
            asc = !asc;
        }

        // 当k等于0时代表a已经排好序了
        return k === 0;
    }

    function merge(a, b, low, high, asc){
        var k = asc ? low : high;
        var c = asc ? 1 : -1;
        var i = low;
        var j = high;

        while(i <= j){
            if(a[i] <= a[j]) b[k] = a[i++];
            else b[k] = a[j--];
            k += c;
        }
        for(i = k = low, j = high; i <= j; ++i, ++k) a[i] = b[k];
    }
})();

exports.naturalMergeSort = naturalMergeSort;

console.log('\nnaturalMergeSort:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
naturalMergeSort(arr);
console.log(arr + '');<commit_msg>modified<commit_after>/**
 * Created by ldp on 2015/2/7.
 */

/*
 归并排序

 归并(Merging) ：是指将两个或两个以上的有序序列合并成一个有序序列。若采用线性表(无论是那种存储结构)易于实现，其时间复杂度为O(m+n) 。
 归并思想实例：两堆扑克牌，都已从小到大排好序，要将两堆合并为一堆且要求从小到大排序。
 ◆  将两堆最上面的抽出(设为C1，C2)比较大小，将小者置于一边作为新的一堆(不妨设C1<C2)；再从第一堆中抽出一张继续与C2进行比较，将较小的放置在新堆的最下面；
 ◆ 重复上述过程，直到某一堆已抽完，然后将剩下一堆中的所有牌转移到新堆中。

 1   排序思想
 ①  初始时，将每个记录看成一个单独的有序序列，则n个待排序记录就是n个长度为1的有序子序列；
 ②  对所有有序子序列进行两两归并，得到n/2个长度为2或1的有序子序列——一趟归并；
 ③  重复② ，直到得到长度为n的有序序列为止。

 上述排序过程中，子序列总是两两归并，称为2-路归并排序。其核心是如何将相邻的两个子序列归并成一个子序列。设相邻的两个子序列分别为：
 {R[k], R[k+1], …, R[m]}和{R[m+1], R[m+2],…, R[h]}，将它们归并为一个有序的子序列：
 {DR[l], DR[l+1], …, DR[m], DR[m+1], …, DR[h] }

 例：设有9个待排序的记录，关键字分别为23, 38, 22, 45, 23, 67, 31, 15, 41，归并排序的过程。
 初始关键字: [23]   [38]   [22]   [45]   [23]   [67]   [31]   [15]   [41]
              |      |      |      |      |      |      |      |
              --------      --------      --------      --------
 一趟归并后: [23    38]    [22     45]    [23     67]    [15     31]   [41]
                 |              |             |              |
                 ---------------               ---------------
 二趟归并后: [22     23      38     45]    [15     23     31     67]    [41]
                        |                              |
                        --------------------------------
 三趟归并后: [15     22      23     23     31     38     45     67]    [41]
                                       |                                |
                                       ----------------------------------
 四趟归并后: [15     22      23     23     31     38     41     45     67

 2  一趟归并排序
 一趟归并排序都是从前到后，依次将相邻的两个有序子序列归并为一个，且除最后一个子序列外，其余每个子序列的长度都相同。设这些子序列的长度为d，则一趟归并排序的过程是：
 从j=0开始，依次将相邻的两个有序子序列
 R[j…j+d-1]和R[j+d…j+2d-1]进行归并；每次归并两个子序列后，j后移动2d个位置，即
 j=j+2d；若剩下的元素不足两个子序列时，分以下两种情况处理：
 ①  剩下的元素个数>d：再调用一次上述过程，将一个长度为d的子序列和不足d的子序列进行归并；
 ②  剩下的元素个数≤d：将剩下的元素依次复制到归并后的序列中。

 3.算法分析
具有n个待排序记录的归并次数是㏒2n，而一趟归并的时间复杂度为O(n)，则整个归并排序的时间复杂度无论是最好还是最坏情况均为O(n㏒2n)。在排序过程中，使用了辅助向量DR，大小与待排序记录空间相同，则空间复杂度为O(n)。归并排序是稳定的。

 */

var nCount = 0;
var nonRecursiveCount = 0;
var recursiveCount = 0;

/**
 * 将有序的sr[s1..e1]和sr[s2..e2]归并为有序的tr[s1..e2]
 * @param sr
 * @param s1
 * @param e1
 * @param e2
 */
function merge(sr, s1, e1, e2){
    var temp = [];
    var i = s1;
    var j = e1 + 1;
    var k = 0;

    while(i <= e1 && j <= e2){
        if(sr[i] < sr[j]) temp[k++] = sr[i++];
        else temp[k++] = sr[j++];
    }
    while(i <= e1) temp[k++] = sr[i++];
    while(j <= e2) temp[k++] = sr[j++];

    // 复制回去
    for(i = s1, k = 0; i <= e2; ++i, ++k) sr[i] = temp[k];
}

/**
 * 2-路归并排序递归算法
 * @param {Array} sr
 * @param {Number} s
 * @param {Number} t
 */
function mergeSortRecursive(sr, s, t){
    if(s == null) s = 0;
    if(t == null) t = sr.length - 1;

    if(s >= t) return;

    // 将sr[s..t]平分为sr[s..m]和sr[m+1..t]
    var m = (s + t) >> 1;
    // 递归地将sr[s..m]归并为有序的sr[s..m]
    mergeSortRecursive(sr, s, m);
    // 递归地将sr[m+1..t]归并为有序的sr[m+1..t]
    mergeSortRecursive(sr, m + 1, t);
    // 将sr[s..m]和sr[m+1..t]归并到sr[s..t];
    merge(sr, s, m, t);
}
exports.mergeSortRecursive = mergeSortRecursive;

console.log('\n\nmergeSortRecursive:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
mergeSortRecursive(arr);
console.log(arr + '');

function mergeSortNonRecursive(sr){
    var j, k;
    for(var d = 1, n = sr.length - 1; d < n; d *= 2) {
        // 一趟归并排序算法
        j = 0;

        // 子序列两两归并
        while((k = (j + 2 * d - 1)) < n){
            merge(sr, j,  j + d - 1, k);
            j = k + 1;
        }

        // 剩余元素个数超过一个子序列长度
        if(j + d - 1 < n) merge(sr, j, j + d - 1, n);
        // 剩余子序列复制
        else merge(sr, j, n, n);
    }
}
exports.mergeSortNonRecursive = mergeSortNonRecursive;

console.log('\nmergeSortNonRecursive:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
mergeSortNonRecursive(arr);
console.log(arr + '');

// 自然合并排序
// http://www.cnblogs.com/liushang0419/archive/2011/09/19/2181476.html
// http://www.cnblogs.com/lanke/archive/2013/01/15/2860487.html
/*
自然归并是归并排序的一个变形，效率更高一些，可以在归并排序非递归实现的基础上进行修改.对于已经一个已经给定数组a,通常存在多个长度大于1的已经自然排好的子数组段,因此用一次对数组a的线性扫描就可以找出所有这些排好序的子数组段,然后再对这些子数组段俩俩合并.
 */

// 扫描得到子串的函数
function pass(sqList, rec){
    var num = 0;
    rec[num++] = 0;

    for(var i = 1, len = sqList.length; i < len; ++i){
        if(sqList[i] > sqList[i + 1]) rec[num++] = i + 1;
    }
    rec[num++] = len;

    return num;
}

function natureMergeSort(sqList){
    var rec = [];

    //num=2说明已经排好序了
    //每循环一次，进行一次pass()操作
    for(var num = pass(sqList, rec); num !== 2; num = pass(sqList, rec)){
        for(var i = 0; i + 2 < num; i += 2) {
            merge(sqList, rec[i], rec[i + 1] - 1, rec[i + 2] - 1);
        }
    }
}

exports.natureMergeSort = natureMergeSort;

console.log('\nnatureMergeSort:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
natureMergeSort(arr);
console.log(arr + '');

console.log(recursiveCount);
console.log(nonRecursiveCount);
console.log(nCount);

// 双向自然合并排序算法
/*
双向自然合并排序是根据欲排序数据局部不是升序就是降序的自然有序特点,先线性扫描出自然有序的子数组段,再进行合并排序.扫描时的有序数段长度越长,段数越少,对应合并树的层数就会越少,算法的效率越高.
 */
var naturalMergeSort = (function(){
    return naturalMergeSort;

    function naturalMergeSort(a){
        var b = [];
        var n = a.length;
        while(!mergeRuns(a, b, n)/* && !mergeRuns(b, a, n)*/);
    }

    function mergeRuns(a, b, n){
        var i = 0;
        var k = 0;
        var asc = true;
        var x;

        while(i < n){
            k = i;
            // 找到最后一个递增序列元素
            do x = a[i++]; while(i < n && x <= a[i]);
            // 找到最后一个递减序列元素
            while(i < n && x >= a[i]) x = a[i++];
            // 归并递增序列和递减序列，结果可能递增或递减
            merge(a, b, k, i - 1, asc);
            asc = !asc;
        }

        // 当k等于0时代表a已经排好序了
        return k === 0;
    }

    function merge(a, b, low, high, asc){
        var k = asc ? low : high;
        var c = asc ? 1 : -1;
        var i = low;
        var j = high;

        while(i <= j){
            if(a[i] <= a[j]) b[k] = a[i++];
            else b[k] = a[j--];
            k += c;
        }
        for(i = k = low, j = high; i <= j; ++i, ++k) a[i] = b[k];
    }
})();

exports.naturalMergeSort = naturalMergeSort;

console.log('\nnaturalMergeSort:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
naturalMergeSort(arr);
console.log(arr + '');<|endoftext|>


<commit_before>
/*
 Copyright 2013 Simon Paulger <spaulger@codezen.co.uk>

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

(function() {
    'use strict';

    /**
     * Chrome Storage Backbone storage adapter
     *
     * @param keyNamespace storage namespace prefix
     * @param storageArea Storage area to use
     * @constructor
     */
    Backbone.ChromeStorage = function(keyNamespace, storageArea)
    {
        if (typeof keyNamespace == 'string' && keyNamespace != '') {
            this._keyNamespace = keyNamespace;
        } else {
            throw new TypeError('Invalid key namespace.');
        }

        // Apply storage area
        if (storageArea == 'local' || storageArea == null) {
            this._chromeStorage = chrome.storage.local;
        } else if (storageArea == 'sync') {
            this._chromeStorage = chrome.storage.sync;
        } else {
            throw new TypeError('Invalid storage area declaration.');
        }
    };

    /**
     * Enum for StorageArea type. Should be when declaring
     * the storage area when constructing the storage adapter
     */
    Backbone.ChromeStorage.StorageArea =
    {
        SYNC: 'sync',
        LOCAL: 'local'
    };

    Backbone.ChromeStorage.prototype =
    {
        _keyNamespace: null,
        _chromeStorage: null,
        _recordIndex: [],

        /**
         * Get the Chrome storage namespace pointer
         *
         * @returns {Object} Chrome storage namespace object
         * @private
         */
        _getChromeStorage: function()
        {
            return this._chromeStorage;
        },

        /**
         * Generate a unique UUID for use as a key
         *
         * @returns {string} Unique UUID
         * @private
         */
        _generateUuid: function()
        {
            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
                return v.toString(16);
            });
        },

        /**
         * Add or update an existing key/value pair in storage
         *
         * @param model Model of data to update
         * @param options Storage options
         * @private
         */
        _updateRecord: function(model, options)
        {
            // Get or generate an Id
            var id = model.id || this._generateUuid();

            function apiCallback() {
                // Notify callbacks if defined
                if (chrome.runtime.lastError == null) {
                    var attributes = model.attributes;
                    attributes.id = id;
                    options.success(attributes);
                } else if (chrome.runtime.lastError != null && options.error != null) {
                    options.error(model, chrome.runtime.lastError);
                }
            }

            // Update record index with new id if not found
            if ($.inArray(id, this._recordIndex) == -1) {
                this._recordIndex.push(id);
            }

            // Update index if adding, and add/update record
            var data = {};
            data[this._keyNamespace] = this._recordIndex;
            data[id] = model.attributes;

            // Trigger request event
            model.trigger('request', model, data, options);

            // Set data
            this._getChromeStorage().set(data, apiCallback);
        },

        /**
         * Remove the modelOrCollection from storage
         *
         * @param model Model of data to remove
         * @param options Storage options
         * @private
         */
        _deleteRecord: function(model, options)
        {
            var callbackCount = 0;
            var success = true;
            var errors = [];

            function apiCallback() {
                callbackCount++;

                // Check if an error occurred
                if (chrome.runtime.lastError != null) {
                    success = false;
                    errors.push(chrome.runtime.lastError);
                }

                // Notify callbacks if defined
                if (callbackCount == 2 && success) {
                    // Success
                    options.success({});
                } else if (callbackCount == 2 && !success && options.error != null) {
                    // Error
                    options.error(model, errors);
                }
            }

            // If the model has an id, attempt to remove it from storage
            if (!model.isNew()) {
                // Find record index position and remove
                var recordPosition = $.inArray(model.id, this._recordIndex);
                if (recordPosition != -1) {
                    this._recordIndex.splice(recordPosition, 1);
                }

                // Trigger request event
                model.trigger('request', model, model.id, options);

                // Update record index with item removed in storage
                var data = {};
                data[this._keyNamespace] = this._recordIndex;
                this._getChromeStorage().set(data, apiCallback);

                // Remove item from storage
                this._getChromeStorage().remove([model.id], apiCallback);
            } else if (options.error != null) {
                // Nothing to remove, notify error callback if defined
                options.error(model, 'Model id is not defined');
            }
        },

        /**
         * Read modelOrCollection from storage
         *
         * @param modelOrCollection Model with id to read
         * @param options Storage options
         * @private
         */
        _readRecord: function(modelOrCollection, options)
        {
            var that = this;

            function recordReadCallback(items) {
                if (chrome.runtime.lastError == null) {
                    // Format items into object to pass to success
                    // and reply to success callback with resp
                    var resp = [];

                    for (var key in items) {
                        resp.push(items[key]);
                    }

                    options.success(resp);
                } else if (options.error != null) {
                    options.error(modelOrCollection, chrome.runtime.lastError);
                }
            }

            function recordIndexReadCallback(items) {
                if (chrome.runtime.lastError == null) {
                    // Attempt to read all records for all id's in the record index
                    var recordIndex = items[that._keyNamespace] || null;

                    // Trigger request event
                    modelOrCollection.trigger('request', modelOrCollection, [recordIndex], options);

                    // Get data
                    that._getChromeStorage().get([recordIndex], recordReadCallback);
                } else if (options.error != null) {
                    options.error(modelOrCollection, chrome.runtime.lastError);
                }
            }

            if (modelOrCollection instanceof Backbone.Collection) {
                // Update record index with item removed in storage
                this._getChromeStorage().get([this._keyNamespace], recordIndexReadCallback);
            } else {
                // Trigger request event
                modelOrCollection.trigger('request', modelOrCollection, [this._keyNamespace], options);

                // Get data
                this._getChromeStorage().get([modelOrCollection.id], recordReadCallback);
            }
        },

        /**
         * Implement Backbone.sync function signature.
         *
         * @param method Sync method
         * @param modelOrCollection Backbone model or collection
         * @param options Options
         */
        sync: function(method, modelOrCollection, options)
        {
            switch (method) {
                case 'update':  return this._updateRecord(modelOrCollection, options);
                case 'create':  return this._updateRecord(modelOrCollection, options);
                case 'read':    return this._readRecord(modelOrCollection, options);
                case 'delete':  return this._deleteRecord(modelOrCollection, options);
            }

            throw new TypeError('Unknown method ' + method + ' in sync');
        }
    };
})();
<commit_msg>fix error callback parameters<commit_after>
/*
 Copyright 2013 Simon Paulger <spaulger@codezen.co.uk>

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

(function() {
    'use strict';

    /**
     * Chrome Storage Backbone storage adapter
     *
     * @param keyNamespace storage namespace prefix
     * @param storageArea Storage area to use
     * @constructor
     */
    Backbone.ChromeStorage = function(keyNamespace, storageArea)
    {
        if (typeof keyNamespace == 'string' && keyNamespace != '') {
            this._keyNamespace = keyNamespace;
        } else {
            throw new TypeError('Invalid key namespace.');
        }

        // Apply storage area
        if (storageArea == 'local' || storageArea == null) {
            this._chromeStorage = chrome.storage.local;
        } else if (storageArea == 'sync') {
            this._chromeStorage = chrome.storage.sync;
        } else {
            throw new TypeError('Invalid storage area declaration.');
        }
    };

    /**
     * Enum for StorageArea type. Should be when declaring
     * the storage area when constructing the storage adapter
     */
    Backbone.ChromeStorage.StorageArea =
    {
        SYNC: 'sync',
        LOCAL: 'local'
    };

    Backbone.ChromeStorage.prototype =
    {
        _keyNamespace: null,
        _chromeStorage: null,
        _recordIndex: [],

        /**
         * Get the Chrome storage namespace pointer
         *
         * @returns {Object} Chrome storage namespace object
         * @private
         */
        _getChromeStorage: function()
        {
            return this._chromeStorage;
        },

        /**
         * Generate a unique UUID for use as a key
         *
         * @returns {string} Unique UUID
         * @private
         */
        _generateUuid: function()
        {
            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
                return v.toString(16);
            });
        },

        /**
         * Add or update an existing key/value pair in storage
         *
         * @param model Model of data to update
         * @param options Storage options
         * @private
         */
        _updateRecord: function(model, options)
        {
            // Get or generate an Id
            var id = model.id || this._generateUuid();

            function apiCallback() {
                // Notify callbacks if defined
                if (chrome.runtime.lastError == null) {
                    var attributes = model.attributes;
                    attributes.id = id;
                    options.success(attributes);
                } else {
                    options.error(chrome.runtime.lastError);
                }
            }

            // Update record index with new id if not found
            if ($.inArray(id, this._recordIndex) == -1) {
                this._recordIndex.push(id);
            }

            // Update index if adding, and add/update record
            var data = {};
            data[this._keyNamespace] = this._recordIndex;
            data[id] = model.attributes;

            // Trigger request event
            model.trigger('request', model, data, options);

            // Set data
            this._getChromeStorage().set(data, apiCallback);
        },

        /**
         * Remove the modelOrCollection from storage
         *
         * @param model Model of data to remove
         * @param options Storage options
         * @private
         */
        _deleteRecord: function(model, options)
        {
            var callbackCount = 0;
            var success = true;
            var errors = [];

            function apiCallback() {
                callbackCount++;

                // Check if an error occurred
                if (chrome.runtime.lastError != null) {
                    success = false;
                    errors.push(chrome.runtime.lastError);
                }

                // Notify callbacks if defined
                if (callbackCount == 2 && success) {
                    // Success
                    options.success({});
                } else if (callbackCount == 2 && !success) {
                    // Error
                    options.error(errors);
                }
            }

            // If the model has an id, attempt to remove it from storage
            if (!model.isNew()) {
                // Find record index position and remove
                var recordPosition = $.inArray(model.id, this._recordIndex);
                if (recordPosition != -1) {
                    this._recordIndex.splice(recordPosition, 1);
                }

                // Trigger request event
                model.trigger('request', model, model.id, options);

                // Update record index with item removed in storage
                var data = {};
                data[this._keyNamespace] = this._recordIndex;
                this._getChromeStorage().set(data, apiCallback);

                // Remove item from storage
                this._getChromeStorage().remove([model.id], apiCallback);
            } else {
                // Nothing to remove, notify error callback if defined
                options.error('Model id is not defined');
            }
        },

        /**
         * Read modelOrCollection from storage
         *
         * @param modelOrCollection Model with id to read
         * @param options Storage options
         * @private
         */
        _readRecord: function(modelOrCollection, options)
        {
            var that = this;

            function recordReadCallback(items) {
                if (chrome.runtime.lastError == null) {
                    // Format items into object to pass to success
                    // and reply to success callback with resp
                    var resp = [];

                    for (var key in items) {
                        resp.push(items[key]);
                    }

                    options.success(resp);
                } else {
                    options.error(chrome.runtime.lastError);
                }
            }

            function recordIndexReadCallback(items) {
                if (chrome.runtime.lastError == null) {
                    // Attempt to read all records for all id's in the record index
                    var recordIndex = items[that._keyNamespace] || null;

                    // Trigger request event
                    modelOrCollection.trigger('request', modelOrCollection, [recordIndex], options);

                    // Get data
                    that._getChromeStorage().get([recordIndex], recordReadCallback);
                } else {
                    options.error(chrome.runtime.lastError);
                }
            }

            if (modelOrCollection instanceof Backbone.Collection) {
                // Update record index with item removed in storage
                this._getChromeStorage().get([this._keyNamespace], recordIndexReadCallback);
            } else {
                // Trigger request event
                modelOrCollection.trigger('request', modelOrCollection, [this._keyNamespace], options);

                // Get data
                this._getChromeStorage().get([modelOrCollection.id], recordReadCallback);
            }
        },

        /**
         * Implement Backbone.sync function signature.
         *
         * @param method Sync method
         * @param modelOrCollection Backbone model or collection
         * @param options Options
         */
        sync: function(method, modelOrCollection, options)
        {
            switch (method) {
                case 'update':  return this._updateRecord(modelOrCollection, options);
                case 'create':  return this._updateRecord(modelOrCollection, options);
                case 'read':    return this._readRecord(modelOrCollection, options);
                case 'delete':  return this._deleteRecord(modelOrCollection, options);
            }

            throw new TypeError('Unknown method ' + method + ' in sync');
        }
    };
})();
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Grid, Row, Col, ResponsiveEmbed, Button, Glyphicon, Image } from 'react-bootstrap';
import captureVideoFrame from 'capture-video-frame';

const mediaConstraints = {
    audio: false,
    video: true
};

class Camera extends Component {

    constructor(props) {
        super(props);

        this.state = {
            streaming: false,
            streamURL: null,
            image: null,
            thumbnail: null
        }

        this.startMediaStream = this.startMediaStream.bind(this);
        this.stopMediaStream = this.stopMediaStream.bind(this);
        this.onMediaSuccess = this.onMediaSuccess.bind(this);
        this.onMediaFailure = this.onMediaFailure.bind(this);
        this.shutter = this.shutter.bind(this);
        this.save = this.save.bind(this);
        this.discard = this.discard.bind(this);
        this.onMediaFailure = this.onMediaFailure.bind(this);

    }

    componentWillMount() {
        this.startMediaStream();
    }

    componentWillUnmount() {
        this.stopMediaStream();
    }

    startMediaStream(){
        // First get a hold of getUserMedia, if present
		const getUserMedia = (navigator.getUserMedia ||
				navigator.webkitGetUserMedia ||
				navigator.mozGetUserMedia ||
				navigator.msGetUserMedia);

        if (!getUserMedia) {
            this.setState({ mediaFailure: {name: 'getUserMediaUnsupported'}});
            return;
        }

        getUserMedia.call(navigator, mediaConstraints, this.onMediaSuccess, this.onMediaFailure);
    }

    onMediaSuccess(stream) {

        this.setState({
            streaming: true,
            streamURL: URL.createObjectURL(stream)
        });
    }

    onMediaFailure(error) {
        this.props.onFailure(error);
    }

    stopMediaStream(){
        this.state.mediaRecorder.stream.getTracks().map((track) => track.stop());
    }

    shutter() {
        const image = captureVideoFrame(this._viewfinder, 'png');
        this.setState({
            image: image,
            thumbnail: image
        });
    }

    save() {
        // Pass the blobs up
        this.props.save({
            image: this.state.image.blob,
            imageThumbnail: this.state.thumbnail.blob
        });
    }

    discard() {
        this.setState({
            image: null,
            thumbnail: null
        })
    }

    render() {
        return (
            <Grid>
                <Row>
                    <Col xs={3}/>
                    <Col xs={6}>

                            { this.state.streaming &&
                                <ResponsiveEmbed a4by3>
                                    <video
                                        ref={(ref) => { this._viewfinder = ref; }}
                                        src={this.state.streamURL}
                                        muted
                                        autoPlay
                                        />
                                </ResponsiveEmbed>
                            }
                            { this.state.thumbnail &&

                                    <div style={{
                                            position: 'absolute',
                                            top: 0,
                                            left: 0,
                                            right: 0,
                                            bottom: 0,
                                            margin: 'auto',
                                            width: '60%',
                                            height: '60%'
                                        }}>
                                        <ResponsiveEmbed a4by3>
                                            <Image
                                                src={this.state.thumbnail.dataUri}
                                                alt="The photo you just took"
                                                />
                                        </ResponsiveEmbed>

                            }

                    </Col>
                    <Col xs={3}/>
                </Row>
                <Row>
                    <Col xs={3}/>
                    <Col xs={6}>
                        { (this.state.streaming) &&
                            <Button bsStyle="primary" bsSize="large" block
                              onClick={this.shutter}>
                              <Glyphicon glyph="record" /> Take Picture
                            </Button>
                        }
                        { (this.state.image) &&
                              <Button bsStyle="primary" bsSize="large" block
                                onClick={this.save}>
                                <Glyphicon glyph="save"/> Save
                              </Button>
                        }
                        { this.state.image &&
                              <Button bsStyle="primary" bsSize="large" block
                                onClick={this.discard}>
                                <Glyphicon glyph="trash"/> Delete
                              </Button>
                        }
                    </Col>
                    <Col xs={3}/>
                </Row>
            </Grid>
        );
    }
}

Camera.propTypes = {
    save: React.PropTypes.func.isRequired,
    onFailure: React.PropTypes.func.isRequired
};
Camera.defaultProps = {};
/**
 * Expose a test for media capabilities for use by other components
 */
Camera.mediaCheck = function(){
    return new Promise(function(resolve, reject){
        function mediaOK (stream) {
            stream.getTracks().map((track) => track.stop());
            resolve();
        }

        function mediaFail (error) {
            reject(error);
        }

        // First get a hold of getUserMedia, if present
    	const getUserMedia = (navigator.getUserMedia ||
    			navigator.webkitGetUserMedia ||
    			navigator.mozGetUserMedia ||
    			navigator.msGetUserMedia);

        if (!getUserMedia) {
            reject({name: 'getUserMediaUnsupported'});
        } else {
            getUserMedia.call(navigator, mediaConstraints, mediaOK, mediaFail);// First get a hold of getUserMedia, if present
        }

    });
};

export default Camera;
<commit_msg>Close media stream on camera unmount<commit_after>import React, { Component } from 'react';
import { Grid, Row, Col, ResponsiveEmbed, Button, Glyphicon, Image } from 'react-bootstrap';
import captureVideoFrame from 'capture-video-frame';

const mediaConstraints = {
    audio: false,
    video: true
};

class Camera extends Component {

    constructor(props) {
        super(props);

        this.state = {
            streaming: false,
            stream: null,
            streamURL: null,
            image: null,
            thumbnail: null
        }

        this.startMediaStream = this.startMediaStream.bind(this);
        this.stopMediaStream = this.stopMediaStream.bind(this);
        this.onMediaSuccess = this.onMediaSuccess.bind(this);
        this.onMediaFailure = this.onMediaFailure.bind(this);
        this.shutter = this.shutter.bind(this);
        this.save = this.save.bind(this);
        this.discard = this.discard.bind(this);
        this.onMediaFailure = this.onMediaFailure.bind(this);

    }

    componentWillMount() {
        this.startMediaStream();
    }

    componentWillUnmount() {
        this.stopMediaStream();
    }

    startMediaStream(){
        // First get a hold of getUserMedia, if present
		const getUserMedia = (navigator.getUserMedia ||
				navigator.webkitGetUserMedia ||
				navigator.mozGetUserMedia ||
				navigator.msGetUserMedia);

        if (!getUserMedia) {
            this.setState({ mediaFailure: {name: 'getUserMediaUnsupported'}});
            return;
        }

        getUserMedia.call(navigator, mediaConstraints, this.onMediaSuccess, this.onMediaFailure);
    }

    onMediaSuccess(stream) {

        this.setState({
            streaming: true,
            streamURL: URL.createObjectURL(stream),
            stream: stream
        });
    }

    onMediaFailure(error) {
        this.props.onFailure(error);
    }

    stopMediaStream(){
        this.state.stream.getTracks().map((track) => track.stop());
    }

    shutter() {
        const image = captureVideoFrame(this._viewfinder, 'png');
        this.setState({
            image: image,
            thumbnail: image
        });
    }

    save() {
        // Pass the blobs up
        this.props.save({
            image: this.state.image.blob,
            imageThumbnail: this.state.thumbnail.blob
        });
    }

    discard() {
        this.setState({
            image: null,
            thumbnail: null
        })
    }

    render() {
        return (
            <Grid>
                <Row>
                    <Col xs={3}/>
                    <Col xs={6}>

                            { this.state.streaming &&
                                <ResponsiveEmbed a4by3>
                                    <video
                                        ref={(ref) => { this._viewfinder = ref; }}
                                        src={this.state.streamURL}
                                        muted
                                        autoPlay
                                        />
                                </ResponsiveEmbed>
                            }
                            { this.state.thumbnail &&

                                    <div style={{
                                            position: 'absolute',
                                            top: 0,
                                            left: 0,
                                            right: 0,
                                            bottom: 0,
                                            margin: 'auto',
                                            width: '60%',
                                            height: '60%'
                                        }}>
                                        <ResponsiveEmbed a4by3>
                                            <Image
                                                src={this.state.thumbnail.dataUri}
                                                alt="The photo you just took"
                                                />
                                        </ResponsiveEmbed>

                            }

                    </Col>
                    <Col xs={3}/>
                </Row>
                <Row>
                    <Col xs={3}/>
                    <Col xs={6}>
                        { (this.state.streaming) &&
                            <Button bsStyle="primary" bsSize="large" block
                              onClick={this.shutter}>
                              <Glyphicon glyph="record" /> Take Picture
                            </Button>
                        }
                        { (this.state.image) &&
                              <Button bsStyle="primary" bsSize="large" block
                                onClick={this.save}>
                                <Glyphicon glyph="save"/> Save
                              </Button>
                        }
                        { this.state.image &&
                              <Button bsStyle="primary" bsSize="large" block
                                onClick={this.discard}>
                                <Glyphicon glyph="trash"/> Delete
                              </Button>
                        }
                    </Col>
                    <Col xs={3}/>
                </Row>
            </Grid>
        );
    }
}

Camera.propTypes = {
    save: React.PropTypes.func.isRequired,
    onFailure: React.PropTypes.func.isRequired
};
Camera.defaultProps = {};
/**
 * Expose a test for media capabilities for use by other components
 */
Camera.mediaCheck = function(){
    return new Promise(function(resolve, reject){
        function mediaOK (stream) {
            stream.getTracks().map((track) => track.stop());
            resolve();
        }

        function mediaFail (error) {
            reject(error);
        }

        // First get a hold of getUserMedia, if present
    	const getUserMedia = (navigator.getUserMedia ||
    			navigator.webkitGetUserMedia ||
    			navigator.mozGetUserMedia ||
    			navigator.msGetUserMedia);

        if (!getUserMedia) {
            reject({name: 'getUserMediaUnsupported'});
        } else {
            getUserMedia.call(navigator, mediaConstraints, mediaOK, mediaFail);// First get a hold of getUserMedia, if present
        }

    });
};

export default Camera;
<|endoftext|>


<commit_before>import R from 'ramda'

const ElectronStore = require('electron-store')

export class ShipDB {
  constructor () {
    let datasource = require('../../data/expected.json')
    datasource.data = R.pickBy((key, val) => !R.isEmpty(val), datasource.data)

    this.db = new ElectronStore({
      defaults: datasource,
      name: 'chistr-ships'
    })

    if (datasource.time > this.db.get('time')) {
      console.log('Updating expected values...')
      R.forEach(datasource.data, (shipId, data) => {
        this.set(shipId, data)
      })
      this.db.set('time', datasource.time)
    }
  }

  clear () {
    this.db.clear()
    let datasource = require('../../data/expected.json')
    datasource.data = R.pickBy((key, val) => !R.isEmpty(val), datasource.data)
    this.db.store = datasource
  }

  has (shipId) {
    return this.db.has(`data.${shipId.toString()}`)
  }

  hasName (shipId) {
    return this.has(shipId) &&
      this.get(shipId).hasOwnProperty('name') &&
      // refresh ship names after some time
      this.get(shipId).timestamp > Date.now() - (1000 * 60 * 60 * 24 * 7)
  }

  get (shipId) {
    return this.db.get(`data.${shipId.toString()}`)
  }

  getName (shipId) {
    if (this.hasName(shipId)) {
      return this.get(shipId).name
    } else {
      return undefined
    }
  }

  set (shipId, dataObj) {
    const _shipId = shipId.toString()
    if (this.has(_shipId)) {
      this.db.set(`data.${_shipId}`, {...this.db.get(`data.${_shipId}`), ...dataObj})
    } else {
      this.db.set(`data.${_shipId}`, dataObj)
    }
  }

  setName (shipId, name) {
    this.set(shipId, { name: name, timestamp: Date.now() })
  }

  delete (shipId) {
    this.db.delete(shipId.toString())
  }
}
<commit_msg>Fix expected value updating<commit_after>import R from 'ramda'

const ElectronStore = require('electron-store')

export class ShipDB {
  constructor () {
    let datasource = require('../../data/expected.json')
    datasource.data = R.pickBy((key, val) => !R.isEmpty(val), datasource.data)

    this.db = new ElectronStore({
      defaults: datasource,
      name: 'chistr-ships'
    })

    if (datasource.time > this.db.get('time')) {
      console.log('Updating expected values...')
      R.forEach((shipId, data) => {
        this.set(shipId, data)
      })(datasource.data)
      this.db.set('time', datasource.time)
    }
  }

  clear () {
    this.db.clear()
    let datasource = require('../../data/expected.json')
    datasource.data = R.pickBy((key, val) => !R.isEmpty(val), datasource.data)
    this.db.store = datasource
  }

  has (shipId) {
    return this.db.has(`data.${shipId.toString()}`)
  }

  hasName (shipId) {
    return this.has(shipId) &&
      this.get(shipId).hasOwnProperty('name') &&
      // refresh ship names after some time
      this.get(shipId).timestamp > Date.now() - (1000 * 60 * 60 * 24 * 7)
  }

  get (shipId) {
    return this.db.get(`data.${shipId.toString()}`)
  }

  getName (shipId) {
    if (this.hasName(shipId)) {
      return this.get(shipId).name
    } else {
      return undefined
    }
  }

  set (shipId, dataObj) {
    const _shipId = shipId.toString()
    if (this.has(_shipId)) {
      this.db.set(`data.${_shipId}`, {...this.db.get(`data.${_shipId}`), ...dataObj})
    } else {
      this.db.set(`data.${_shipId}`, dataObj)
    }
  }

  setName (shipId, name) {
    this.set(shipId, { name: name, timestamp: Date.now() })
  }

  delete (shipId) {
    this.db.delete(shipId.toString())
  }
}
<|endoftext|>


<commit_before>module.exports = function (text) {
    if (!text) {
        return {
            mappings: [],
            replacements: []
        };
    }

    var config = JSON.parse(text);
    if (config.version !== 1) {
        throw new Error("Unsupported config version: " + config.version);
    }

    return {
        mappings: config.mappings.map(function (mapping) {
            var match = parseValue(mapping.match);
            var path = parseValue(mapping.path);

            return function (url) {
                if (url.search(match) !== -1) {
                    return url.replace(match, path);
                }
            };
        }),
        replacements: config.replacements.map(function (replacement) {
            var match = parseValue(replacement.match);
            // by default `replace` doesn't globally replace plain string,
            // so wrap it in a regex with the global flag set
            if (typeof match === "string") {
                match = new RegExp(escapeStringForRegExp(match), "g");
            }
            var isMatchFn = typeof match == "function";
            var replace = parseValue(replacement.replace);
            var isReplaceFn = typeof replace == "function";

            return function (content, context) {
                var _match = isMatchFn ? match(context) : match;
                var _replace = isReplaceFn ? replace(context) : replace;
                return content.replace(_match, _replace);
            };
        })
    };
};

function parseValue(value) {
    if (typeof value === "object") {
        if (value.regex) {
            // global regex by default
            return new RegExp(value.regex, value.flags || "g");
        } else if (value.var) {
            var path = value.var;
            return function (context) {
                return getPath(context, path);
            };
        }
    } else {
        return value;
    }
}

var headDotTail = /^([^\.]+)(\.(.*))?$/;
function getPath(context, path) {
    if (!context) {
        return undefined;
    }

    var parts = headDotTail.exec(path);
    var head = parts[1];
    var tail = parts[3];
    if (!tail) {
        return context[head];
    } else if (context[head]) {
        return getPath(context[head], tail);
    }
    return undefined;
}

// from http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
function escapeStringForRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}<commit_msg>Don’t fail when getPath isn’t given a path<commit_after>module.exports = function (text) {
    if (!text) {
        return {
            mappings: [],
            replacements: []
        };
    }

    var config = JSON.parse(text);
    if (config.version !== 1) {
        throw new Error("Unsupported config version: " + config.version);
    }

    return {
        mappings: config.mappings.map(function (mapping) {
            var match = parseValue(mapping.match);
            var path = parseValue(mapping.path);

            return function (url) {
                if (url.search(match) !== -1) {
                    return url.replace(match, path);
                }
            };
        }),
        replacements: config.replacements.map(function (replacement) {
            var match = parseValue(replacement.match);
            // by default `replace` doesn't globally replace plain string,
            // so wrap it in a regex with the global flag set
            if (typeof match === "string") {
                match = new RegExp(escapeStringForRegExp(match), "g");
            }
            var isMatchFn = typeof match == "function";
            var replace = parseValue(replacement.replace);
            var isReplaceFn = typeof replace == "function";

            return function (content, context) {
                var _match = isMatchFn ? match(context) : match;
                var _replace = isReplaceFn ? replace(context) : replace;
                return content.replace(_match, _replace);
            };
        })
    };
};

function parseValue(value) {
    if (typeof value === "object") {
        if (value.regex) {
            // global regex by default
            return new RegExp(value.regex, value.flags || "g");
        } else if (value.var) {
            var path = value.var;
            return function (context) {
                return getPath(context, path);
            };
        }
    } else {
        return value;
    }
}

var headDotTail = /^([^\.]+)(\.(.*))?$/;
function getPath(context, path) {
    if (!context || !path) {
        return undefined;
    }

    var parts = headDotTail.exec(path);
    var head = parts[1];
    var tail = parts[3];
    if (!tail) {
        return context[head];
    } else if (context[head]) {
        return getPath(context[head], tail);
    }
    return undefined;
}

// from http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
function escapeStringForRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}<|endoftext|>


<commit_before>/**
 * Created by ldp on 2015/2/7.
 */

/*
 归并排序

 归并(Merging) ：是指将两个或两个以上的有序序列合并成一个有序序列。若采用线性表(无论是那种存储结构)易于实现，其时间复杂度为O(m+n) 。
 归并思想实例：两堆扑克牌，都已从小到大排好序，要将两堆合并为一堆且要求从小到大排序。
 ◆  将两堆最上面的抽出(设为C1，C2)比较大小，将小者置于一边作为新的一堆(不妨设C1<C2)；再从第一堆中抽出一张继续与C2进行比较，将较小的放置在新堆的最下面；
 ◆ 重复上述过程，直到某一堆已抽完，然后将剩下一堆中的所有牌转移到新堆中。

 1   排序思想
 ①  初始时，将每个记录看成一个单独的有序序列，则n个待排序记录就是n个长度为1的有序子序列；
 ②  对所有有序子序列进行两两归并，得到n/2个长度为2或1的有序子序列——一趟归并；
 ③  重复② ，直到得到长度为n的有序序列为止。

 上述排序过程中，子序列总是两两归并，称为2-路归并排序。其核心是如何将相邻的两个子序列归并成一个子序列。设相邻的两个子序列分别为：
 {R[k], R[k+1], …, R[m]}和{R[m+1], R[m+2],…, R[h]}，将它们归并为一个有序的子序列：
 {DR[l], DR[l+1], …, DR[m], DR[m+1], …, DR[h] }

 例：设有9个待排序的记录，关键字分别为23, 38, 22, 45, 23, 67, 31, 15, 41，归并排序的过程。
 初始关键字: [23]   [38]   [22]   [45]   [23]   [67]   [31]   [15]   [41]
              |      |      |      |      |      |      |      |
              --------      --------      --------      --------
 一趟归并后: [23    38]    [22     45]    [23     67]    [15     31]   [41]
                 |              |             |              |
                 ---------------               ---------------
 二趟归并后: [22     23      38     45]    [15     23     31     67]    [41]
                        |                              |
                        --------------------------------
 三趟归并后: [15     22      23     23     31     38     45     67]    [41]
                                       |                                |
                                       ----------------------------------
 四趟归并后: [15     22      23     23     31     38     41     45     67

2.算法分析
具有n个待排序记录的归并次数是㏒2n，而一趟归并的时间复杂度为O(n)，则整个归并排序的时间复杂度无论是最好还是最坏情况均为O(n㏒2n)。在排序过程中，使用了辅助向量DR，大小与待排序记录空间相同，则空间复杂度为O(n)。归并排序是稳定的。

 */

/**
 * 将有序的sr[s1..e1]和sr[s2..e2]归并为有序的tr[s1..e2]
 * @param sr
 * @param s1
 * @param e1
 * @param s2
 * @param e2
 */
function merge(sr, s1, e1, s2, e2){
    var temp = [];
    var i = s1;
    var j = s2;
    var k = 0;

    while(i <= e1 && j <= e2){
        if(sr[i] < sr[j]) temp[k++] = sr[i++];
        else temp[k++] = sr[j++];
    }
    while(i <= e1) temp[k++] = sr[i++];
    while(j <= e2) temp[k++] = sr[j++];

    // 复制回去
    for(i = s1, k = 0; i <= e2; ++i, ++k) sr[i] = temp[k];
}

/**
 * 2-路归并排序递归算法
 * @param {Array} sr
 * @param {Number} s
 * @param {Number} t
 */
function mergeSortRecursive(sr, s, t){
    s = s != null ? s : 0;
    t = t != null ? t : sr.length - 1;

    if(s >= t) return;

    // 将sr[s..t]平分为sr[s..m]和sr[m+1..t]
    var m = (s + t) >> 1;
    // 递归地将sr[s..m]归并为有序的sr[s..m]
    mergeSortRecursive(sr, s, m);
    // 递归地将sr[m+1..t]归并为有序的sr[m+1..t]
    mergeSortRecursive(sr, m + 1, t);
    // 将sr[s..m]和sr[m+1..t]归并到sr[s..t];
    merge(sr, s, m, m + 1, t);
}
exports.mergeSortRecursive = mergeSortRecursive;

console.log('\n\nmergeSortRecursive:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
mergeSortRecursive(arr);
console.log(arr + '');

// 一趟归并排序算法
function mergePass(sr, d, n){
    var j = 0;
    var k;

    // 子序列两两归并
    while((k = (j + 2 * d - 1)) <= n){
        merge(sr, j, j + d - 1, j + d, k);
        j = k + 1;
    }

    // 剩余元素个数超过一个子序列长度
    if(j + d - 1 < n) merge(sr, j, j + d - 1, j + d, n);
    // 剩余子序列复制
    else merge(sr, j, n, n, n);
}

function mergeSortNonRecursive(sr){
    for(var d = 1, len = sr.length; d < len; d *= 2)
        mergePass(sr, d, len - 1);
}
exports.mergeSortNonRecursive = mergeSortNonRecursive;

console.log('\nmergeSortNonRecursive:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
mergeSortNonRecursive(arr);
console.log(arr + '');

// todo 自然合并排序
// http://www.cnblogs.com/liushang0419/archive/2011/09/19/2181476.html<commit_msg>refact code<commit_after>/**
 * Created by ldp on 2015/2/7.
 */

/*
 归并排序

 归并(Merging) ：是指将两个或两个以上的有序序列合并成一个有序序列。若采用线性表(无论是那种存储结构)易于实现，其时间复杂度为O(m+n) 。
 归并思想实例：两堆扑克牌，都已从小到大排好序，要将两堆合并为一堆且要求从小到大排序。
 ◆  将两堆最上面的抽出(设为C1，C2)比较大小，将小者置于一边作为新的一堆(不妨设C1<C2)；再从第一堆中抽出一张继续与C2进行比较，将较小的放置在新堆的最下面；
 ◆ 重复上述过程，直到某一堆已抽完，然后将剩下一堆中的所有牌转移到新堆中。

 1   排序思想
 ①  初始时，将每个记录看成一个单独的有序序列，则n个待排序记录就是n个长度为1的有序子序列；
 ②  对所有有序子序列进行两两归并，得到n/2个长度为2或1的有序子序列——一趟归并；
 ③  重复② ，直到得到长度为n的有序序列为止。

 上述排序过程中，子序列总是两两归并，称为2-路归并排序。其核心是如何将相邻的两个子序列归并成一个子序列。设相邻的两个子序列分别为：
 {R[k], R[k+1], …, R[m]}和{R[m+1], R[m+2],…, R[h]}，将它们归并为一个有序的子序列：
 {DR[l], DR[l+1], …, DR[m], DR[m+1], …, DR[h] }

 例：设有9个待排序的记录，关键字分别为23, 38, 22, 45, 23, 67, 31, 15, 41，归并排序的过程。
 初始关键字: [23]   [38]   [22]   [45]   [23]   [67]   [31]   [15]   [41]
              |      |      |      |      |      |      |      |
              --------      --------      --------      --------
 一趟归并后: [23    38]    [22     45]    [23     67]    [15     31]   [41]
                 |              |             |              |
                 ---------------               ---------------
 二趟归并后: [22     23      38     45]    [15     23     31     67]    [41]
                        |                              |
                        --------------------------------
 三趟归并后: [15     22      23     23     31     38     45     67]    [41]
                                       |                                |
                                       ----------------------------------
 四趟归并后: [15     22      23     23     31     38     41     45     67

 2  一趟归并排序
 一趟归并排序都是从前到后，依次将相邻的两个有序子序列归并为一个，且除最后一个子序列外，其余每个子序列的长度都相同。设这些子序列的长度为d，则一趟归并排序的过程是：
 从j=0开始，依次将相邻的两个有序子序列
 R[j…j+d-1]和R[j+d…j+2d-1]进行归并；每次归并两个子序列后，j后移动2d个位置，即
 j=j+2d；若剩下的元素不足两个子序列时，分以下两种情况处理：
 ①  剩下的元素个数>d：再调用一次上述过程，将一个长度为d的子序列和不足d的子序列进行归并；
 ②  剩下的元素个数≤d：将剩下的元素依次复制到归并后的序列中。

 3.算法分析
具有n个待排序记录的归并次数是㏒2n，而一趟归并的时间复杂度为O(n)，则整个归并排序的时间复杂度无论是最好还是最坏情况均为O(n㏒2n)。在排序过程中，使用了辅助向量DR，大小与待排序记录空间相同，则空间复杂度为O(n)。归并排序是稳定的。

 */

/**
 * 将有序的sr[s1..e1]和sr[s2..e2]归并为有序的tr[s1..e2]
 * @param sr
 * @param s1
 * @param e1
 * @param e2
 */
function merge(sr, s1, e1, e2){
    var temp = [];
    var i = s1;
    var s2 = e1 + 1;
    var j = s2;
    var k = 0;

    while(i <= e1 && j <= e2){
        if(sr[i] < sr[j]) temp[k++] = sr[i++];
        else temp[k++] = sr[j++];
    }
    while(i <= e1) temp[k++] = sr[i++];
    while(j <= e2) temp[k++] = sr[j++];

    // 复制回去
    for(i = s1, k = 0; i <= e2; ++i, ++k) sr[i] = temp[k];
}

/**
 * 2-路归并排序递归算法
 * @param {Array} sr
 * @param {Number} s
 * @param {Number} t
 */
function mergeSortRecursive(sr, s, t){
    s = s != null ? s : 0;
    t = t != null ? t : sr.length - 1;

    if(s >= t) return;

    // 将sr[s..t]平分为sr[s..m]和sr[m+1..t]
    var m = (s + t) >> 1;
    // 递归地将sr[s..m]归并为有序的sr[s..m]
    mergeSortRecursive(sr, s, m);
    // 递归地将sr[m+1..t]归并为有序的sr[m+1..t]
    mergeSortRecursive(sr, m + 1, t);
    // 将sr[s..m]和sr[m+1..t]归并到sr[s..t];
    merge(sr, s, m, t);
}
exports.mergeSortRecursive = mergeSortRecursive;

console.log('\n\nmergeSortRecursive:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
mergeSortRecursive(arr);
console.log(arr + '');

// 一趟归并排序算法
function mergePass(sr, d, n){
    var j = 0;
    var k;

    // 子序列两两归并
    while((k = (j + 2 * d - 1)) <= n){
        merge(sr, j, j + d - 1, k);
        j = k + 1;
    }

    // 剩余元素个数超过一个子序列长度
    if(j + d - 1 < n) merge(sr, j, j + d - 1, n);
    // 剩余子序列复制
    else merge(sr, j, n, n);
}

function mergeSortNonRecursive(sr){
    for(var d = 1, len = sr.length; d < len; d *= 2)
        mergePass(sr, d, len - 1);
}
exports.mergeSortNonRecursive = mergeSortNonRecursive;

console.log('\nmergeSortNonRecursive:');
var arr = [49, 38, 65, 97, 76, 13, 27, 49, 55, 4];
mergeSortNonRecursive(arr);
console.log(arr + '');

// todo 自然合并排序
// http://www.cnblogs.com/liushang0419/archive/2011/09/19/2181476.html<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';

class CmsApp extends React.Component {
  constructor(props) {
    super(props);
    this.props.actions.addEntity = this.props.actions.addEntity.bind(this);
    this.save = this.save.bind(this);
    this.mapEntity = this.mapEntity.bind(this);
  }
  save() {
    console.log(this.props.cmsAppState);
    this.props.actions.addEntity(this.props.cmsAppState);
  }
  toggle() {
    this.props.actions.toggleEntity(this.props.cmsAppState);
  }
  mapEntity(entity, index) {
    return <form key={index}><input type="text" value={entity.text} onChange={this.save} /><input type="submit" onClick={this.save} /></form>;
  }

  render() {
    return (

        {this.props.cmsAppState.map(this.mapEntity)}

    );
  }
}

CmsApp.propTypes = {
  actions: PropTypes.object.isRequired,
  cmsAppState: PropTypes.array.isRequired
};

export default CmsApp;
<commit_msg>Separate create fields from edit fields<commit_after>import React, {PropTypes} from 'react';

class CmsApp extends React.Component {
  constructor(props) {
    super(props);
    this.props.actions.addEntity = this.props.actions.addEntity.bind(this);
    this.save = this.save.bind(this);
    this.mapEntity = this.mapEntity.bind(this);
  }
  save() {
    this.props.actions.addEntity(this.props.cmsAppState);
  }
  toggle() {
    this.props.actions.toggleEntity(this.props.cmsAppState);
  }
  mapEntity(entity, index) {
    return (
<input type="text" value={entity.text} readOnly/><input type="submit" value="Save" onClick={this.save} />
);
  }

  render() {
    return (

        {this.props.cmsAppState.map(this.mapEntity)}

<input type="text" /><input type="submit" value="Save" onClick={this.save} />

    );
  }
}

CmsApp.propTypes = {
  actions: PropTypes.object.isRequired,
  cmsAppState: PropTypes.array.isRequired
};

export default CmsApp;
<|endoftext|>