<commit_before>// Copyright 2014 SAP SE.
//
// 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.

/**
 * @fileoverview Check for correct line endings
 * @author Christoph Kraemer <chr.kraemer@sap.com>
 */
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function (context) {

	var config = {
		ending: "\\n"
	};

	if (context.options[0]) {
		config.ending = context.options[0];
	}

	return {

		"Program": function checkLineEndings(node) {
			// Get the whole source code, not for node only.
			var src = context.getSource(), re;

			switch (config.ending) {
				case "\\r\\n":
					re = /[^\r]\n|\r(?!\n)/;
					break;
				case "\\r":
					re = /\n/;
					break;
				default:
					re = /\r/;
			}

			if (re.test(src)) {
				context.report(node, 0, "Invalid line endings.");
			}
		}

	};

};
<commit_msg>Update line-endings.js<commit_after>// Copyright 2014 SAP SE.
//
// 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.

/**
 * @fileoverview Check for correct line endings
 * @author Christoph Kraemer <chr.kraemer@sap.com>
 */
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function (context) {

	var config = {
		ending: "\\n"
	};

	if (context.options[0]) {
		config.ending = context.options[0];
	}

	return {

		"Program": function checkLineEndings(node) {
			// Get the whole source code, not for node only.
			var src = context.getSource(), re;

			switch (config.ending) {
				case "\\r\\n":
					re = /[^\r]\n|\r(?!\n)/;
					break;
				case "\\r":
					re = /\n/;
					break;
				default:
					re = /\r/;
			}

			if (re.test(src)) {
				context.report(node, 1, "Invalid line endings.");
			}
		}

	};

};
<|endoftext|>


<commit_before>import eventOptionsKey from './eventOptionsKey';

export default class TargetEventHandlers {
  constructor(target) {
    this.target = target;
    this.events = {};
  }

  getEventHandlers(eventName, options) {
    const key = `${eventName} ${eventOptionsKey(options)}`;

    if (!this.events[key]) {
      this.events[key] = {
        handlers: [],
        handleEvent: undefined,
      };
    }

    return this.events[key];
  }

  handleEvent(eventName, options, event) {
    const { handlers } = this.getEventHandlers(eventName, options);
    handlers.forEach((handler) => {
      if (handler) {
        // We need to check for presence here because a handler function may
        // cause later handlers to get removed. This can happen if you for
        // instance have a waypoint that unmounts another waypoint as part of an
        // onEnter/onLeave handler.
        handler(event);
      }
    });
  }

  add(eventName, listener, options) {
    // options has already been normalized at this point.
    const eventHandlers = this.getEventHandlers(eventName, options);

    if (eventHandlers.handlers.length === 0) {
      eventHandlers.handleEvent = this.handleEvent.bind(this, eventName, options);

      this.target.addEventListener(
        eventName,
        eventHandlers.handleEvent,
        options,
      );
    }

    eventHandlers.handlers.push(listener);

    let isSubscribed = true;
    const unsubscribe = () => {
      if (!isSubscribed) {
        return;
      }

      isSubscribed = false;

      const index = eventHandlers.handlers.indexOf(listener);
      eventHandlers.handlers.splice(index, 1);

      if (eventHandlers.handlers.length === 0) {
        // All event handlers have been removed, so we want to remove the event
        // listener from the target node.

        if (this.target) {
          // There can be a race condition where the target may no longer exist
          // when this function is called, e.g. when a React component is
          // unmounting. Guarding against this prevents the following error:
          //
          //   Cannot read property 'removeEventListener' of undefined
          this.target.removeEventListener(
            eventName,
            eventHandlers.handleEvent,
            options,
          );
        }

        eventHandlers.handleEvent = undefined;
      }
    };
    return unsubscribe;
  }
}
<commit_msg>Prevent event handlers from mutating current iteration<commit_after>import eventOptionsKey from './eventOptionsKey';

export default class TargetEventHandlers {
  constructor(target) {
    this.target = target;
    this.events = {};
  }

  getEventHandlers(eventName, options) {
    const key = `${eventName} ${eventOptionsKey(options)}`;

    if (!this.events[key]) {
      this.events[key] = {
        handlers: [],
        handleEvent: undefined,
      };
      this.events[key].nextHandlers = this.events[key].handlers;
    }

    return this.events[key];
  }

  ensureCanMutateNextEventHandlers(eventName, options) {
    const eventHandlers = this.getEventHandlers(eventName, options);
    if (eventHandlers.handlers === eventHandlers.nextHandlers) {
      eventHandlers.nextHandlers = eventHandlers.handlers.slice();
    }
  }

  handleEvent(eventName, options, event) {
    const eventHandlers = this.getEventHandlers(eventName, options);
    eventHandlers.handlers = eventHandlers.nextHandlers;
    eventHandlers.handlers.forEach((handler) => {
      if (handler) {
        // We need to check for presence here because a handler function may
        // cause later handlers to get removed. This can happen if you for
        // instance have a waypoint that unmounts another waypoint as part of an
        // onEnter/onLeave handler.
        handler(event);
      }
    });
  }

  add(eventName, listener, options) {
    // options has already been normalized at this point.
    const eventHandlers = this.getEventHandlers(eventName, options);

    this.ensureCanMutateNextEventHandlers(eventName, options);

    if (eventHandlers.nextHandlers.length === 0) {
      eventHandlers.handleEvent = this.handleEvent.bind(this, eventName, options);

      this.target.addEventListener(
        eventName,
        eventHandlers.handleEvent,
        options,
      );
    }

    eventHandlers.nextHandlers.push(listener);

    let isSubscribed = true;
    const unsubscribe = () => {
      if (!isSubscribed) {
        return;
      }

      isSubscribed = false;

      this.ensureCanMutateNextEventHandlers(eventName, options);
      const index = eventHandlers.nextHandlers.indexOf(listener);
      eventHandlers.nextHandlers.splice(index, 1);

      if (eventHandlers.nextHandlers.length === 0) {
        // All event handlers have been removed, so we want to remove the event
        // listener from the target node.

        if (this.target) {
          // There can be a race condition where the target may no longer exist
          // when this function is called, e.g. when a React component is
          // unmounting. Guarding against this prevents the following error:
          //
          //   Cannot read property 'removeEventListener' of undefined
          this.target.removeEventListener(
            eventName,
            eventHandlers.handleEvent,
            options,
          );
        }

        eventHandlers.handleEvent = undefined;
      }
    };
    return unsubscribe;
  }
}
<|endoftext|>


<commit_before>try {
  module.exports = require('./robotskirt');
} catch (e) {
  module.exports = require('./marked');
}
<commit_msg>for test coverage<commit_after>if (process.env.NICO_COVERAGE=1) {
  module.exports = require('./marked');
} else if (process.env.NICO_COVERAGE=2) {
  module.exports = require('./robotskirt');
} else {
  try {
    module.exports = require('./robotskirt');
  } catch (e) {
    module.exports = require('./marked');
  }
}
<|endoftext|>


<commit_before>module.exports = {
	name: "frappe-html",
	setup(build) {
		let path = require("path");
		let fs = require("fs/promises");

		build.onResolve({ filter: /\.html$/ }, (args) => {
			return {
				path: path.join(args.resolveDir, args.path),
				namespace: "frappe-html",
			};
		});

		build.onLoad({ filter: /.*/, namespace: "frappe-html" }, (args) => {
			let filepath = args.path;
			let filename = path.basename(filepath).split(".")[0];

			return fs
				.readFile(filepath, "utf-8")
				.then((content) => {
					content = scrub_html_template(content);
					return {
						contents: `\n\tfrappe.templates['${filename}'] = \`${content}\`;\n`,
						watchFiles: [filepath],
					};
				})
				.catch(() => {
					return {
						contents: "",
						warnings: [
							{
								text: `There was an error importing ${filepath}`,
							},
						],
					};
				});
		});
	},
};

function scrub_html_template(content) {
	content = content.replace(/`/g, "\\`");
	return content;
}
<commit_msg>fix: allow backtick in HTML templates as well<commit_after>module.exports = {
	name: "frappe-html",
	setup(build) {
		let path = require("path");
		let fs = require("fs/promises");

		build.onResolve({ filter: /\.html$/ }, (args) => {
			return {
				path: path.join(args.resolveDir, args.path),
				namespace: "frappe-html",
			};
		});

		build.onLoad({ filter: /.*/, namespace: "frappe-html" }, (args) => {
			let filepath = args.path;
			let filename = path.basename(filepath).split(".")[0];

			return fs
				.readFile(filepath, "utf-8")
				.then((content) => {
					content = JSON.stringify(scrub_html_template(content));
					return {
						contents: `\n\tfrappe.templates['${filename}'] = ${content};\n`,
						watchFiles: [filepath],
					};
				})
				.catch(() => {
					return {
						contents: "",
						warnings: [
							{
								text: `There was an error importing ${filepath}`,
							},
						],
					};
				});
		});
	},
};

function scrub_html_template(content) {
	content = content.replace(/`/g, "\\`");
	return content;
}
<|endoftext|>


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

export default class AudioPlayer extends Component {

    static propTypes = {
        url: PropTypes.string,
        playing: PropTypes.bool,
        volume: PropTypes.number,
        hidden: PropTypes.bool,
        attributes: PropTypes.object,
        progressFrequency: PropTypes.number,
        onPlay: PropTypes.func,
        onPause: PropTypes.func,
        onEnded: PropTypes.func,
        onError: PropTypes.func,
        onProgress: PropTypes.func,
        onDuration: PropTypes.func
    };

    static defaultProps = {
        playing: false,
        volume: 0.8,
        hidden: false,
        attributes: {},
        progressFrequency: 1000,
        onPlay: function() {},
        onPause: function() {},
        onEnded: function() {},
        onError: function() {},
        onProgress: function() {},
        onDuration: function() {}
    };

    /* this instance variables have no effect on the rendering of the component ( no state needed )*/
    isReady = false;

    componentDidMount() {

        this.player.addEventListener('canplay', this.onReady);
        this.player.addEventListener('play', this.onPlay);
        this.player.addEventListener('pause', this.onPause);
        this.player.addEventListener('ended', this.onEnded);
        this.player.addEventListener('error', this.onError);
        this.player.setAttribute('webkit-playsinline', '');

        const { url } = this.props;
        if (url) {
            this.load(url);
        }
        this.progress();
    }

    componentWillUnmount() {

        this.player.removeEventListener('canplay', this.onReady);
        this.player.removeEventListener('play', this.onPlay);
        this.player.removeEventListener('pause', this.onPause);
        this.player.removeEventListener('ended', this.onEnded);
        this.player.removeEventListener('error', this.onError);

        this.stop();
        clearTimeout(this.progressTimeout);
    }

    componentWillReceiveProps (nextProps) {
        const { url, playing, volume} = this.props;
        // Invoke player methods based on incoming props
        if (url !== nextProps.url && nextProps.url) {
            this.load(nextProps.url);
        } else if (url && !nextProps.url) {
            this.load('');
            this.seekTo(0);
            this.stop();
        }
        if (!playing && nextProps.playing) {
            this.play();
        } else if (playing && !nextProps.playing) {
            this.pause();
        }
        if (volume !== nextProps.volume) {
            this.setVolume(nextProps.volume);
        }
    }

    /* this changing props has no effect on the rendering of the component */
    shouldComponentUpdate(nextProps) {
        return false;
    }

    onReady = () => {
        this.player.play();
        this.isReady = true;
        const duration = this.getDuration();
        if (duration) {
            this.props.onDuration(duration);
        }
    };

    onPlay = () => {
        this.props.onPlay();
    };

    onPause = () => {
        this.props.onPause();
    };

    onEnded = () => {
        this.props.onEnded();
    };

    onError = () => {
        this.props.onError();
    };

    load (url) {
        this.player.src = url;
        this.isReady = false;
    }

    play () {
        if(this.isReady) {
            this.player.play();
        }
    }

    pause () {
        this.player.pause();
    }

    stop () {
        this.player.removeAttribute('src');
    }

    setVolume (fraction) {
        this.player.volume = fraction;
    }

    getDuration () {
        return this.player.duration;
    }

    getFractionPlayed () {
        if (!this.isReady) return null;
        return this.player.currentTime / this.getDuration();
    }

    getFractionLoaded () {
        if (!this.isReady || this.player.buffered.length === 0) return null;
        return this.player.buffered.end(0) / this.getDuration();
    }

    seekTo = fraction => {
        if(this.isReady) {
            // When seeking before player is ready, store value and seek later
            const currentTime = this.getDuration() * fraction;
            this.player.currentTime = currentTime;
        }
    };

    progress = () => {
        if (this.props.url && this.player) {
            const loaded = this.getFractionLoaded() || 0;
            const played = this.getFractionPlayed() || 0;
            const progress = {};
            if (loaded !== this.prevLoaded) {
                progress.loaded = loaded;
            }
            if (played !== this.prevPlayed) {
                progress.played = played;
            }
            if (progress.loaded || progress.played) {
                this.props.onProgress(progress);
            }
            this.prevLoaded = loaded;
            this.prevPlayed = played;
        }
        this.progressTimeout = setTimeout(this.progress, this.props.progressFrequency);
    };

    render () {
        const { url, attributes, hidden, className, style } = this.props;

        const mediaStyle = {
            width: '100%',
            height: '100%',
            display: url ? 'block' : 'none'
        };

        return (

                <audio
                    ref={ player => this.player = player}
                    style={ mediaStyle }
                    preload='auto'
                    { ...attributes }
                /> : null;

        );
    }
}<commit_msg>adds method to query audio element<commit_after>import React, { Component, PropTypes } from 'react';

export default class AudioPlayer extends Component {

    static propTypes = {
        url: PropTypes.string,
        playing: PropTypes.bool,
        volume: PropTypes.number,
        hidden: PropTypes.bool,
        attributes: PropTypes.object,
        progressFrequency: PropTypes.number,
        onPlay: PropTypes.func,
        onPause: PropTypes.func,
        onEnded: PropTypes.func,
        onError: PropTypes.func,
        onProgress: PropTypes.func,
        onDuration: PropTypes.func
    };

    static defaultProps = {
        playing: false,
        volume: 0.8,
        hidden: false,
        attributes: {},
        progressFrequency: 1000,
        onPlay: function() {},
        onPause: function() {},
        onEnded: function() {},
        onError: function() {},
        onProgress: function() {},
        onDuration: function() {}
    };

    /* this instance variables have no effect on the rendering of the component ( no state needed )*/
    isReady = false;

    componentDidMount() {

        this.player.addEventListener('canplay', this.onReady);
        this.player.addEventListener('play', this.onPlay);
        this.player.addEventListener('pause', this.onPause);
        this.player.addEventListener('ended', this.onEnded);
        this.player.addEventListener('error', this.onError);
        this.player.setAttribute('webkit-playsinline', '');

        const { url } = this.props;
        if (url) {
            this.load(url);
        }
        this.progress();
    }

    componentWillUnmount() {

        this.player.removeEventListener('canplay', this.onReady);
        this.player.removeEventListener('play', this.onPlay);
        this.player.removeEventListener('pause', this.onPause);
        this.player.removeEventListener('ended', this.onEnded);
        this.player.removeEventListener('error', this.onError);

        this.stop();
        clearTimeout(this.progressTimeout);
    }

    componentWillReceiveProps (nextProps) {
        const { url, playing, volume} = this.props;
        // Invoke player methods based on incoming props
        if (url !== nextProps.url && nextProps.url) {
            this.load(nextProps.url);
        } else if (url && !nextProps.url) {
            this.load('');
            this.seekTo(0);
            this.stop();
        }
        if (!playing && nextProps.playing) {
            this.play();
        } else if (playing && !nextProps.playing) {
            this.pause();
        }
        if (volume !== nextProps.volume) {
            this.setVolume(nextProps.volume);
        }
    }

    /* this changing props has no effect on the rendering of the component */
    shouldComponentUpdate(nextProps) {
        return false;
    }

    onReady = () => {
        this.player.play();
        this.isReady = true;
        const duration = this.getDuration();
        if (duration) {
            this.props.onDuration(duration);
        }
    };

    onPlay = () => {
        this.props.onPlay();
    };

    onPause = () => {
        this.props.onPause();
    };

    onEnded = () => {
        this.props.onEnded();
    };

    onError = () => {
        this.props.onError();
    };

    load (url) {
        this.player.src = url;
        this.isReady = false;
    }

    play () {
        if(this.isReady) {
            this.player.play();
        }
    }

    pause () {
        this.player.pause();
    }

    stop () {
        this.player.removeAttribute('src');
    }

    setVolume (fraction) {
        this.player.volume = fraction;
    }

    getDuration () {
        return this.player.duration;
    }

    getFractionPlayed () {
        if (!this.isReady) return null;
        return this.player.currentTime / this.getDuration();
    }

    getFractionLoaded () {
        if (!this.isReady || this.player.buffered.length === 0) return null;
        return this.player.buffered.end(0) / this.getDuration();
    }

    seekTo = fraction => {
        if(this.isReady) {
            // When seeking before player is ready, store value and seek later
            const currentTime = this.getDuration() * fraction;
            this.player.currentTime = currentTime;
        }
    };

    getAudio() {
        return this.player;
    }

    progress = () => {
        if (this.props.url && this.player) {
            const loaded = this.getFractionLoaded() || 0;
            const played = this.getFractionPlayed() || 0;
            const progress = {};
            if (loaded !== this.prevLoaded) {
                progress.loaded = loaded;
            }
            if (played !== this.prevPlayed) {
                progress.played = played;
            }
            if (progress.loaded || progress.played) {
                this.props.onProgress(progress);
            }
            this.prevLoaded = loaded;
            this.prevPlayed = played;
        }
        this.progressTimeout = setTimeout(this.progress, this.props.progressFrequency);
    };

    render () {
        const { url, attributes, hidden, className, style } = this.props;

        const mediaStyle = {
            width: '100%',
            height: '100%',
            display: url ? 'block' : 'none'
        };
        return (

                <audio
                    ref={ player => this.player = player}
                    style={ mediaStyle }
                    preload='auto'
                    { ...attributes }
                />

        );
    }
}<|endoftext|>


<commit_before>module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('web/mySampleProject.json'),
    env : {
      options : {
       //Shared Options Hash
      },
      configCDN : {
        AZURE_STORAGE_ACCOUNT : 'azure storage account name to use',
        AZURE_STORAGE_ACCESS_KEY : 'your-ssh-access-key-string would go here'
      }
    },
    'azureblob': {
      options: { // global options applied to each task
        containerName: 'assets',
        containerDelete: false, //do not apply true here, container would be deleted at each task
        metadata: {cacheControl: 'public, max-age=31556926'}, // max-age 1 year for all entries
        gzip: true,
        copySimulation: false  // set true: only dry-run what copy would look like
      },
      css: {
          files: [{
            expand: true,
            cwd: 'web/Content/',
            dest: '<%= pkg.version %>/css/',
            src: ['**/*', '!themes/**/*']
          }]
      },
      js: {
        files: [{
          expand: true,
          cwd: 'web/scripts',
          dest: '<%= pkg.version %>/js/',
          src: ['*.js']
        }]
      }
    }
  });

  // Load the plugin that provides all the pirate magic
  grunt.loadNpmTasks('grunt-env'); // https://npmjs.org/package/grunt-env
  grunt.loadNpmTasks('grunt-azureblob');

  // Default task(s).
  grunt.registerTask('default', ['env:configCDN', 'azureblob']);

  grunt.event.on('qunit.spawn', function (url) {
    grunt.log.ok("Running test: " + url);
  });
  grunt.event.on('qunit.moduleStart', function (name) {
    grunt.log.ok("Starting module: " + name);
  });
};<commit_msg>in sample - change copySimulation : true<commit_after>module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('web/mySampleProject.json'),
    env : {
      options : {
       //Shared Options Hash
      },
      configCDN : {
        AZURE_STORAGE_ACCOUNT : 'azure storage account name to use',
        AZURE_STORAGE_ACCESS_KEY : 'your-ssh-access-key-string would go here'
      }
    },
    'azureblob': {
      options: { // global options applied to each task
        containerName: 'assets',
        containerDelete: false, //do not apply true here, container would be deleted at each task
        metadata: {cacheControl: 'public, max-age=31556926'}, // max-age 1 year for all entries
        gzip: true,
        copySimulation: true  // set true: only dry-run what copy would look like
      },
      css: {
          files: [{
            expand: true,
            cwd: 'web/Content/',
            dest: '<%= pkg.version %>/css/',
            src: ['**/*', '!themes/**/*']
          }]
      },
      js: {
        files: [{
          expand: true,
          cwd: 'web/scripts',
          dest: '<%= pkg.version %>/js/',
          src: ['*.js']
        }]
      }
    }
  });

  // Load the plugin that provides all the pirate magic
  grunt.loadNpmTasks('grunt-env'); // https://npmjs.org/package/grunt-env
  grunt.loadNpmTasks('grunt-azureblob');

  // Default task(s).
  grunt.registerTask('default', ['env:configCDN', 'azureblob']);

  grunt.event.on('qunit.spawn', function (url) {
    grunt.log.ok("Running test: " + url);
  });
  grunt.event.on('qunit.moduleStart', function (name) {
    grunt.log.ok("Starting module: " + name);
  });
};<|endoftext|>


<commit_before>define(function () {
	var current = {

		initialize: function () {
			_('table').on('click', '.update', function() {
				// Update the plug-in
				current.installNext(_('table').dataTable().fnGetData($(this).closest('tr')[0]).plugin.artifact, 0);
			}).dataTable({
				ajax: REST_PATH + 'plugin',
				dataSrc: '',
				sAjaxDataProp: '',
				dom: '<"row"<"col-sm-6"B><"col-sm-6"f>r>t',
				pageLength: -1,
				destroy: true,
				order: [[1, 'asc']],
				columns: [
					{
						data: null,
						orderable: false,
						render: function(data) {
							return data.plugin.type === 'feature' ? '' : current.$main.toIcon(data.node);
						}
					}, {
						data: 'id'
					}, {
						data: 'name'
					}, {
						data: 'vendor',
						className: 'hidden-xs hidden-sm'
					}, {
						data: 'plugin.version',
						className: 'truncate',
						render : function(version, _m, plugin) {
							var result = version;
							if (plugin.newVersion) {
								// Upgrade is available
								result += '  ' + plugin.newVersion + '';
							}
							return result;
						}
					}, {
						data: 'plugin.type',
						className: 'hidden-xs hidden-sm'
					}, {
						data: 'nodes',
						className: 'icon',
						render: function(nb, _i, plugin) {
							return plugin.plugin.type === 'feature' ? '' : nb;
						}
					}, {
						data: 'subscriptions',
						className: 'icon',
						render: function(nb, _i, plugin) {
							return plugin.plugin.type === 'feature' ? '' : nb;
						}
					}
				],
				buttons: [
					{
						extend: 'create',
						text: 'install',
						action: function () {
							_('search').select2('val','');
							_('popup').modal('show');
						}
					}, {
						text: current.$messages.restart,
						className : 'btn-danger',
						action: function () {
							current.restart();
						}
					}
				]
			});

			_('search').select2({
				placeholder: current.$messages.plugin,
				allowClear: true,
				minimumInputLength: 1,
				multiple:true,
				escapeMarkup: function (m) {
					return m;
				},
				ajax: {
					url: REST_PATH + 'plugin/search',
					dataType: 'json',
					quietMillis: 250,
					data: function (term) {
						return { 'q': term };
					},
					results: function (data) {
						return {
							more: false,
							results: $(data).map(function () {
								return {
									id: this.a,
									data: this,
									text: this.a + ' ' + this.latestVersion + ''
								};
							})
						};
					}
				}
			});

			_('save').click(function(){
				current.install(_('search').select2('val'));
				_('popup').modal('hide');
			});
		},

		/**
		 * Install the requested plug-ins.
		 * @param pluginsAsString The plug-in identifiers (comma separated) or null. When null, a prompt is displayed.
		 */
		install : function(plugins) {
			if (plugins) {
				current.installNext(plugins, 0);
			}
		},

		/**
		 * Install a the plug-ins from the one at the specified index, and then the next ones.
		 * There is one AJAX call by plug-in, and stops at any error.
		 * @param {string[]|string} plugins The plug-in identifiers array to install. Accept a sole plugin string too.
		 * @param {number} index The starting plug-in index within the given array. When undefined, is 0.
		 */
		installNext : function(plugins, index) {
			plugins = typeof plugins === 'array' ? plugins : [plugins];
			index = index || 0;
			if (index >= plugins.length) {
				// All plug-ins are installed
				current.table && current.table.api().ajax.reload();
				return;
			}

			// Install this plug-in
			var plugin = plugins[index].trim();
			if (plugin) {
				$.ajax({
					type: 'POST',
					url: REST_PATH + 'plugin/' + encodeURIComponent(plugin),
					dataType: 'text',
					contentType: 'application/json',
					success: function () {
						var next = index < plugins.length - 1;
						notifyManager.notify(Handlebars.compile(current.$messages['downloaded' + (next ? '-continue' : '')])([plugin, (index + 1), plugins.length]));

						// Install the next plug-in
						next & current.installNext(plugins, index + 1);
					}
				});
			} else {
				// The token was empty, install the next real plug-in
				current.installNext(plugins, index + 1);
			}
		},

		/**
		 * Request a restart of the API container.
		 */
		restart : function() {
			$.ajax({
				type: 'PUT',
				url: REST_PATH + 'plugin/restart',
				dataType: 'text',
				contentType: 'application/json',
				success: function () {
					notifyManager.notify(current.$messages['restart-requested']);
				}
			});
		}
	};
	return current;
});
<commit_msg>Auto-focus the plugin search input<commit_after>define(function () {
	var current = {

		initialize: function () {
			_('table').on('click', '.update', function() {
				// Update the plug-in
				current.installNext(_('table').dataTable().fnGetData($(this).closest('tr')[0]).plugin.artifact, 0);
			}).dataTable({
				ajax: REST_PATH + 'plugin',
				dataSrc: '',
				sAjaxDataProp: '',
				dom: '<"row"<"col-sm-6"B><"col-sm-6"f>r>t',
				pageLength: -1,
				destroy: true,
				order: [[1, 'asc']],
				columns: [
					{
						data: null,
						orderable: false,
						render: function(data) {
							return data.plugin.type === 'feature' ? '' : current.$main.toIcon(data.node);
						}
					}, {
						data: 'id'
					}, {
						data: 'name'
					}, {
						data: 'vendor',
						className: 'hidden-xs hidden-sm'
					}, {
						data: 'plugin.version',
						className: 'truncate',
						render : function(version, _m, plugin) {
							var result = version;
							if (plugin.newVersion) {
								// Upgrade is available
								result += '  ' + plugin.newVersion + '';
							}
							return result;
						}
					}, {
						data: 'plugin.type',
						className: 'hidden-xs hidden-sm'
					}, {
						data: 'nodes',
						className: 'icon',
						render: function(nb, _i, plugin) {
							return plugin.plugin.type === 'feature' ? '' : nb;
						}
					}, {
						data: 'subscriptions',
						className: 'icon',
						render: function(nb, _i, plugin) {
							return plugin.plugin.type === 'feature' ? '' : nb;
						}
					}
				],
				buttons: [
					{
						extend: 'create',
						text: 'install',
						action: function () {
							_('popup').modal('show');
						}
					}, {
						text: current.$messages.restart,
						className : 'btn-danger',
						action: function () {
							current.restart();
						}
					}
				]
			});

			_('search').select2({
				placeholder: current.$messages.plugin,
				allowClear: true,
				minimumInputLength: 1,
				multiple:true,
				escapeMarkup: function (m) {
					return m;
				},
				ajax: {
					url: REST_PATH + 'plugin/search',
					dataType: 'json',
					quietMillis: 250,
					data: function (term) {
						return { 'q': term };
					},
					results: function (data) {
						return {
							more: false,
							results: $(data).map(function () {
								return {
									id: this.a,
									data: this,
									text: this.a + ' ' + this.latestVersion + ''
								};
							})
						};
					}
				}
			});

			_('save').click(function(){
				current.install(_('search').select2('val'));
				_('popup').modal('hide');
			});
			_('popup').on('show.bs.modal', function() {
				_('search').select2('data', null);
			}).on('shown.bs.modal', function() {
				_('search').select2('focus');
			});
		},

		/**
		 * Install the requested plug-ins.
		 * @param pluginsAsString The plug-in identifiers (comma separated) or null. When null, a prompt is displayed.
		 */
		install : function(plugins) {
			if (plugins) {
				current.installNext(plugins, 0);
			}
		},

		/**
		 * Install a the plug-ins from the one at the specified index, and then the next ones.
		 * There is one AJAX call by plug-in, and stops at any error.
		 * @param {string[]|string} plugins The plug-in identifiers array to install. Accept a sole plugin string too.
		 * @param {number} index The starting plug-in index within the given array. When undefined, is 0.
		 */
		installNext : function(plugins, index) {
			plugins = $.isArray(plugins) ? plugins : [plugins];
			index = index || 0;
			if (index >= plugins.length) {
				// All plug-ins are installed
				current.table && current.table.api().ajax.reload();
				return;
			}

			// Install this plug-in
			var plugin = plugins[index].trim();
			if (plugin) {
				$.ajax({
					type: 'POST',
					url: REST_PATH + 'plugin/' + encodeURIComponent(plugin),
					dataType: 'text',
					contentType: 'application/json',
					success: function () {
						var next = index < plugins.length - 1;
						notifyManager.notify(Handlebars.compile(current.$messages['downloaded' + (next ? '-continue' : '')])([plugin, (index + 1), plugins.length]));

						// Install the next plug-in
						next & current.installNext(plugins, index + 1);
					}
				});
			} else {
				// The token was empty, install the next real plug-in
				current.installNext(plugins, index + 1);
			}
		},

		/**
		 * Request a restart of the API container.
		 */
		restart : function() {
			$.ajax({
				type: 'PUT',
				url: REST_PATH + 'plugin/restart',
				dataType: 'text',
				contentType: 'application/json',
				success: function () {
					notifyManager.notify(current.$messages['restart-requested']);
				}
			});
		}
	};
	return current;
});
<|endoftext|>


<commit_before>var lastTimestamp = 0;
var pollRate = 1000;
var alertTimeoutId = null;
var focused = true;
var title = document.title;
var maxDisplayed = 100;

window.onfocus = function () {
    if (alertTimeoutId != null) {
        clearInterval(alertTimeoutId);
        alertTimeoutId = null;
    }

    document.title = title;
    focused = true;
}

window.onblur = function() {
    focused = false;
}

function doNewMessageAlert() {
    var msg = "New Message";
    var timeoutId;
    var blink = function() { document.title = document.title == msg ? title : msg; };
    if (!alertTimeoutId && !focused) {
        alertTimeoutId = setInterval(blink, 1000);
    }
}

function updateChatTimes() {
    //run though all the chat messages in the DOM and
    //update the "posted X hrs/days/etc ago" labels
    $(".chat-body .post-date span").each(function(index, elem) {
        var date = moment($(elem).attr('data-date'), 'x');
        var posted = moment.duration(date.diff(moment())).humanize();

        $(elem).html(posted);
    });
}

function pruneOldMessages() {
    //run though all the chat messages in the DOM and
    //prune old messages that are at the top
    var len = $(".chatmessage").length;
    var toRemove = len - maxDisplayed;

    if (toRemove > 0) {
        $(".chatmessage").each(function(index, elem) {
            if (toRemove-- > 0) {
                elem.remove();
                return true;
            } else {
                return false;
            }
        });
    }

}

function showProfileImage(image) {
    bootbox.alert("", function() {
    });
}

function showMediaImage(image) {
    bootbox.alert("", function() {
    });
}

function addToChatBox(messages) {
    var tzoff = new Date().getTimezoneOffset();

    for (var i = 0, len=messages.length; i < len; i++) {
        var msg = messages[i];

        var liClass = 'left';
        var spanClass = 'pull-left';
        var smallClass = 'pull-right';
        var strongClass = '';

        if (msg.userId == userid) {
            liClass = 'right';
            spanClass = 'pull-right';
            smallClass = '';
            strongClass = 'pull-right ';
        }

        var localTimePostedOn = moment(msg.timestamp).zone(tzoff);
        var posted = moment.duration(localTimePostedOn.diff(moment())).humanize();

        var pimage;

        if (msg.user.profileImage != null) {
            pimage = msg.user.profileImage.slice(0, -4) + "-t.jpg";
        } else {
            pimage = "/images/blank.png";
        }

        var id = conversationId + msg.timestamp.toString() + msg.userId;

        var body;
        if (msg.media != null) {
            var mimage = msg.media.slice(0, -4) + "-t.jpg";
            body = '';
        } else {
            body = '
' + html_sanitize(msg.message) + '
';
        }

        $("ul.chat").append(
            '
' +
                '' +
                    '' +
                        '' +
                    '' +
                '' +
                '
' +
                    '
' +
                        '' +
                            msg.user.username +
                        '' +
                        '' +
                            '' + posted + ' ago' +
                        '' +
                    '
' +
                        body +
                '
' +
            '
'
        );

        (function (pimage) {
            $("#" + id + " > span.chat-img > a").click(function (evt) {
                if (pimage != null) {
                    showProfileImage(pimage);
                }
                evt.preventDefault();
            });
        })(msg.user.profileImage);

        if (msg.media) {
            (function (mimage) {
                $("#" + id + " > div.chat-body > a.media").click(function (evt) {
                    if (pimage != null) {
                        showMediaImage(mimage);
                    }
                    evt.preventDefault();
                });
            })(msg.media);
        }

        lastTimestamp = msg.timestamp;
    }

    if (messages.length > 0) {
        //something was added, scroll to the bottom
        document.getElementById('chat-body').scrollTop = 99999;
        //also alert
        doNewMessageAlert();
    }

}

function getChatSinceLastCheck(completedCallback) {
    var cid = conversationId;

    $.ajax({
        type: "GET",
        dataType: "json",
        url: "/chat/since/" + cid + "/" + lastTimestamp +"?timestamp="+$.now(),
        contentType: "application/json",

        success:
            function(data) {
                addToChatBox(data);
            },

        complete:
            function(xhr, status) {
                completedCallback();
            }
    });
}

function sendChat() {
    var text = $("#btn-input").val();
    if (text.trim() == '') return;

    $("#btn-input").val('');
    var cid = conversationId;

    $.ajax({
        type: "POST",
        dataType: "json",
        url: "/chat/add",
        contentType: "application/json",
        data: JSON.stringify({"chatText": text, "conversationId": cid}),
        success:
        function(data) {
        }
    });
}

function chatRefresh(callback) {
    getChatSinceLastCheck(function() {
        pruneOldMessages();
        updateChatTimes();

        callback();
    });
}

function chatTimer() {
    chatRefresh(function() {
        setTimeout(chatTimer, pollRate);
    });
}

function leaveChat() {
    var cid = conversationId;

    $.ajax({
        type: "POST",
        dataType: "json",
        url: "/chat/leave",
        contentType: "application/json",
        data: JSON.stringify({"conversationId": cid}),
        success:
        function(data) {
            window.location = "/";
        }
    });
}

function chatClear() {
    //run though all the chat messages in the DOM and
    //remove them all
    $(".chatmessage").each(function(index, elem) {
        elem.remove();
    });
}

$(document).ready(function() {
    var cid = conversationId;

    //grab the most recent chat messages
    $.ajax({
        type: "GET",
        dataType: "json",
        url: "/chat/recent/" + cid,
        contentType: "application/json",
        success:
        function(data) {
            addToChatBox(data);
        }
    });

    $("#btn-chat").click(function(evt) {
        sendChat();
    });

    $("#btn-input").keypress(function (e) {
        var key = e.which;
        if(key == 13)  { //enter key
            sendChat();
            return false;
        }
    });

    $("#chat-clear").click(function (e) {
        chatClear();
        e.preventDefault();
    });

    $("#chat-leave").click(function (e) {
        leaveChat();
        e.preventDefault();
    });

    $("#btn-media").click(function(e) {
        $("#addMediaModal").modal();
    });

    $("#media-cancel").click(function(e) {
        $("#imagefile").val('');
        submissionDropzone.removeAllFiles();
    });

    $("#media-send").click(function(e) {
        var file = $("#imagefile").val();
        $("#imagefile").val('');

        submissionDropzone.removeAllFiles();

        $.ajax({
            type: "POST",
            dataType: "json",
            url: "/chat/add",
            contentType: "application/json",
            data: JSON.stringify({"media": file, "conversationId": cid}),
            success:
            function(data) {
            }
        });
    });

    setTimeout(chatTimer, pollRate);
});
<commit_msg>Set the ajax poll timeout to 10 seconds<commit_after>var lastTimestamp = 0;
var pollRate = 1000;
var alertTimeoutId = null;
var focused = true;
var title = document.title;
var maxDisplayed = 100;

window.onfocus = function () {
    if (alertTimeoutId != null) {
        clearInterval(alertTimeoutId);
        alertTimeoutId = null;
    }

    document.title = title;
    focused = true;
}

window.onblur = function() {
    focused = false;
}

function doNewMessageAlert() {
    var msg = "New Message";
    var timeoutId;
    var blink = function() { document.title = document.title == msg ? title : msg; };
    if (!alertTimeoutId && !focused) {
        alertTimeoutId = setInterval(blink, 1000);
    }
}

function updateChatTimes() {
    //run though all the chat messages in the DOM and
    //update the "posted X hrs/days/etc ago" labels
    $(".chat-body .post-date span").each(function(index, elem) {
        var date = moment($(elem).attr('data-date'), 'x');
        var posted = moment.duration(date.diff(moment())).humanize();

        $(elem).html(posted);
    });
}

function pruneOldMessages() {
    //run though all the chat messages in the DOM and
    //prune old messages that are at the top
    var len = $(".chatmessage").length;
    var toRemove = len - maxDisplayed;

    if (toRemove > 0) {
        $(".chatmessage").each(function(index, elem) {
            if (toRemove-- > 0) {
                elem.remove();
                return true;
            } else {
                return false;
            }
        });
    }

}

function showProfileImage(image) {
    bootbox.alert("", function() {
    });
}

function showMediaImage(image) {
    bootbox.alert("", function() {
    });
}

function addToChatBox(messages) {
    var tzoff = new Date().getTimezoneOffset();

    for (var i = 0, len=messages.length; i < len; i++) {
        var msg = messages[i];

        var liClass = 'left';
        var spanClass = 'pull-left';
        var smallClass = 'pull-right';
        var strongClass = '';

        if (msg.userId == userid) {
            liClass = 'right';
            spanClass = 'pull-right';
            smallClass = '';
            strongClass = 'pull-right ';
        }

        var localTimePostedOn = moment(msg.timestamp).zone(tzoff);
        var posted = moment.duration(localTimePostedOn.diff(moment())).humanize();

        var pimage;

        if (msg.user.profileImage != null) {
            pimage = msg.user.profileImage.slice(0, -4) + "-t.jpg";
        } else {
            pimage = "/images/blank.png";
        }

        var id = conversationId + msg.timestamp.toString() + msg.userId;

        var body;
        if (msg.media != null) {
            var mimage = msg.media.slice(0, -4) + "-t.jpg";
            body = '';
        } else {
            body = '
' + html_sanitize(msg.message) + '
';
        }

        $("ul.chat").append(
            '
' +
                '' +
                    '' +
                        '' +
                    '' +
                '' +
                '
' +
                    '
' +
                        '' +
                            msg.user.username +
                        '' +
                        '' +
                            '' + posted + ' ago' +
                        '' +
                    '
' +
                        body +
                '
' +
            '
'
        );

        (function (pimage) {
            $("#" + id + " > span.chat-img > a").click(function (evt) {
                if (pimage != null) {
                    showProfileImage(pimage);
                }
                evt.preventDefault();
            });
        })(msg.user.profileImage);

        if (msg.media) {
            (function (mimage) {
                $("#" + id + " > div.chat-body > a.media").click(function (evt) {
                    if (pimage != null) {
                        showMediaImage(mimage);
                    }
                    evt.preventDefault();
                });
            })(msg.media);
        }

        lastTimestamp = msg.timestamp;
    }

    if (messages.length > 0) {
        //something was added, scroll to the bottom
        document.getElementById('chat-body').scrollTop = 99999;
        //also alert
        doNewMessageAlert();
    }

}

function getChatSinceLastCheck(completedCallback) {
    var cid = conversationId;

    $.ajax({
        type: "GET",
        dataType: "json",
        url: "/chat/since/" + cid + "/" + lastTimestamp +"?timestamp="+$.now(),
        contentType: "application/json",
        timeout: 10000,
        success:
            function(data) {
                addToChatBox(data);
            },

        complete:
            function(xhr, status) {
                completedCallback();
            }
    });
}

function sendChat() {
    var text = $("#btn-input").val();
    if (text.trim() == '') return;

    $("#btn-input").val('');
    var cid = conversationId;

    $.ajax({
        type: "POST",
        dataType: "json",
        url: "/chat/add",
        contentType: "application/json",
        data: JSON.stringify({"chatText": text, "conversationId": cid}),
        success:
        function(data) {
        }
    });
}

function chatRefresh(callback) {
    getChatSinceLastCheck(function() {
        pruneOldMessages();
        updateChatTimes();

        callback();
    });
}

function chatTimer() {
    chatRefresh(function() {
        setTimeout(chatTimer, pollRate);
    });
}

function leaveChat() {
    var cid = conversationId;

    $.ajax({
        type: "POST",
        dataType: "json",
        url: "/chat/leave",
        contentType: "application/json",
        data: JSON.stringify({"conversationId": cid}),
        success:
        function(data) {
            window.location = "/";
        }
    });
}

function chatClear() {
    //run though all the chat messages in the DOM and
    //remove them all
    $(".chatmessage").each(function(index, elem) {
        elem.remove();
    });
}

$(document).ready(function() {
    var cid = conversationId;

    //grab the most recent chat messages
    $.ajax({
        type: "GET",
        dataType: "json",
        url: "/chat/recent/" + cid,
        contentType: "application/json",
        success:
        function(data) {
            addToChatBox(data);
        }
    });

    $("#btn-chat").click(function(evt) {
        sendChat();
    });

    $("#btn-input").keypress(function (e) {
        var key = e.which;
        if(key == 13)  { //enter key
            sendChat();
            return false;
        }
    });

    $("#chat-clear").click(function (e) {
        chatClear();
        e.preventDefault();
    });

    $("#chat-leave").click(function (e) {
        leaveChat();
        e.preventDefault();
    });

    $("#btn-media").click(function(e) {
        $("#addMediaModal").modal();
    });

    $("#media-cancel").click(function(e) {
        $("#imagefile").val('');
        submissionDropzone.removeAllFiles();
    });

    $("#media-send").click(function(e) {
        var file = $("#imagefile").val();
        $("#imagefile").val('');

        submissionDropzone.removeAllFiles();

        $.ajax({
            type: "POST",
            dataType: "json",
            url: "/chat/add",
            contentType: "application/json",
            data: JSON.stringify({"media": file, "conversationId": cid}),
            success:
            function(data) {
            }
        });
    });

    setTimeout(chatTimer, pollRate);
});
<|endoftext|>


<commit_before>'use strict';

const { kebabCase } = require('lodash');
const url = require('url');
const Generator = require('../../lib/generator');
const j = require('../../lib/transform');

module.exports = class ConnectionGenerator extends Generator {
  constructor(args, opts) {
    super(args, opts);

    this.dependencies = [];
  }

  _transformCode(code) {
    const { database } = this.props;

    const ast = j(code);
    const appDeclaration = ast.findDeclaration('app');
    const configureHooks = ast.findConfigure('hooks');
    const requireCall = `const ${database} = require('./${database}');`;

    if (appDeclaration.length === 0) {
      throw new Error('Could not find \'app\' variable declaration in app.js to insert database configuration. Did you modify app.js?');
    }

    if (configureHooks.length === 0) {
      throw new Error('Could not find .configure(hooks()) call in app.js after which to insert database configuration. Did you modify app.js?');
    }

    appDeclaration.insertBefore(requireCall);
    configureHooks.insertAfter(`app.configure(${database});`);

    return ast.toSource();
  }

  _getConfiguration() {
    const sqlPackages = {
      mariadb: 'mysql',
      mysql: 'mysql',
      mssql: 'tedious',
      postgres: 'pg',
      sqlite: 'sqlite3'
      // oracle: 'oracle'
    };

    const { connectionString, database, adapter } = this.props;
    const parsed = url.parse(connectionString);

    switch(database) {
    case 'nedb':
      this.dependencies.push('nedb');
      return connectionString.substring(7, connectionString.length);

    case 'rethinkdb':
      this.dependencies.push('rethinkdbdash');
      return {
        db: parsed.path.substring(1, parsed.path.length),
        servers: [
          {
            host: parsed.hostname,
            port: parsed.port
          }
        ]
      };

    case 'memory':
      return null;

    case 'mongodb':
      this.dependencies.push(adapter);
      return connectionString;

    case 'mariadb':
    case 'mysql':
    case 'mssql':
    // case oracle:
    case 'postgres': // eslint-disable-line no-fallthrough
    case 'sqlite':
      this.dependencies.push(adapter);

      if (sqlPackages[database]) {
        this.dependencies.push(sqlPackages[database]);
      }

      if (adapter === 'sequelize') {
        return connectionString;
      }

      return {
        client: sqlPackages[database],
        connection: database === 'sqlite' ? {
          filename: connectionString.substring(9, connectionString.length)
        } : connectionString
      };

    default:
      throw new Error(`Invalid database '${database}'. Cannot assemble configuration.`);
    }
  }

  _writeConfiguration() {
    const { database } = this.props;
    const config = Object.assign({}, this.defaultConfig);

    config[database] = this._getConfiguration();

    this.conflicter.force = true;
    this.fs.writeJSON(
      this.destinationPath('config', 'default.json'),
      config
    );
  }

  prompting() {
    this.checkPackage();

    const databaseName = kebabCase(this.pkg.name);
    const { defaultConfig } = this;

    const getProps = answers => Object.assign({}, this.props, answers);
    const setProps = props => Object.assign(this.props, props);

    const prompts = [
      {
        type: 'list',
        name: 'database',
        message: 'Which database are you connecting to?',
        default: 'nedb',
        choices: [
          { name: 'MariaDB', value: 'mariadb' },
          { name: 'Memory', value: 'memory' },
          { name: 'MongoDB', value: 'mongodb' },
          { name: 'MySQL', value: 'mysql' },
          { name: 'NeDB', value: 'nedb' },
          // { name: 'Oracle', value: 'oracle' },
          { name: 'PostgreSQL', value: 'postgres' },
          { name: 'RethinkDB', value: 'rethinkdb' },
          { name: 'SQLite', value: 'sqlite' },
          { name: 'SQL Server', value: 'mssql' }
        ],
        when(current) {
          const answers = getProps(current);
          const { database, adapter } = answers;

          if (database) {
            return false;
          }

          switch(adapter) {
          case 'nedb':
          case 'rethinkdb':
          case 'memory':
          case 'mongodb':
            setProps({ database: adapter });
            return false;
          case 'mongoose':
            setProps({ database: 'mongodb' });
            return false;
          }

          return true;
        }
      },
      {
        type: 'list',
        name: 'adapter',
        message: 'Which database adapter would you like to use?',
        default(current) {
          const answers = getProps(current);
          const { database } = answers;

          if (database === 'mongodb') {
            return 'mongoose';
          }

          return 'sequelize';
        },
        choices(current) {
          const answers = getProps(current);
          const { database } = answers;
          const mongoOptions = [
            { name: 'MongoDB Native', value: 'mongodb' },
            { name: 'Mongoose', value: 'mongoose' }
          ];
          const sqlOptions = [
            { name: 'Sequelize', value: 'sequelize' },
            { name: 'KnexJS', value: 'knex' }
          ];

          if (database === 'mongodb') {
            return mongoOptions;
          }

          // It's an SQL DB
          return sqlOptions;
        },
        when(current) {
          const answers = getProps(current);
          const { database, adapter } = answers;

          if (adapter) {
            return false;
          }

          switch(database) {
          case 'nedb':
          case 'rethinkdb':
          case 'memory':
            return false;
          }

          return true;
        }
      },
      {
        name: 'connectionString',
        message: 'What is the database connection string?',
        default(current) {
          const answers = getProps(current);
          const { database } = answers;
          const defaultConnectionStrings = {
            mariadb: `mariadb://root:@localhost:3306/${databaseName}`,
            mongodb: `mongodb://localhost:27017/${databaseName}`,
            mysql: `mysql://root:@localhost:3306/${databaseName}`,
            nedb: 'nedb://../data',
            // oracle: `oracle://root:password@localhost:1521/${databaseName}`,
            postgres: `postgres://postgres:@localhost:5432/${databaseName}`,
            rethinkdb: `rethinkdb://localhost:28015/${databaseName}`,
            sqlite: `sqlite://${databaseName}.sqlite`,
            mssql: `mssql://root:password@localhost:1433/${databaseName}`
          };

          return defaultConnectionStrings[database];
        },
        when(current) {
          const answers = getProps(current);
          const { database } = answers;
          const connectionString = defaultConfig[database];

          if (typeof connectionString === 'string') {
            setProps({ connectionString });
            return false;
          }

          return database !== 'memory';
        }
      }
    ];

    return this.prompt(prompts).then(props => {
      this.props = Object.assign(this.props, props);
    });
  }

  writing() {
    let template;
    const { database, adapter } = this.props;
    const context = Object.assign({}, this.props);

    if (database === 'rethinkdb') {
      template = 'rethinkdb.js';
    }
    else if (adapter && adapter !== 'nedb') {
      template = database === 'mssql' ? `${adapter}-mssql.js` : `${adapter}.js`;
    }

    if (template) {
      const dbFile = `${database}.js`;

      // If the file doesn't exist yet, add it to the app.js
      if (!this.fs.exists(this.destinationPath(this.libDirectory, dbFile))) {
        const appjs = this.destinationPath(this.libDirectory, 'app.js');

        this.conflicter.force = true;
        this.fs.write(appjs, this._transformCode(
          this.fs.read(appjs).toString()
        ));
      }

      this.fs.copyTpl(
        this.templatePath(template),
        this.destinationPath(this.libDirectory, dbFile),
        context
      );
    }

    this._writeConfiguration();

    this._packagerInstall(this.dependencies, {
      save: true
    });
  }

  end() {
    const { database, connectionString } = this.props;

    // NOTE (EK): If this is the first time we set this up
    // show this nice message.
    if (connectionString) {
      const databaseName = kebabCase(this.pkg.name);
      this.log();
      this.log(`Woot! We've set up your ${database} database connection!`);

      switch(database) {
      case 'mariadb':
      case 'mongodb':
      case 'mssql':
      case 'mysql':
      // case 'oracle':
      case 'postgres': // eslint-disable-line no-fallthrough
      case 'rethinkdb':
        this.log(`Make sure that your ${database} database is running, the username/role is correct, and the database "${databaseName}" has been created.`);
        this.log('Your configuration can be found in the projects config/ folder.');
        break;
      }
    }
  }
};
<commit_msg>Suggest valid RethinkDB database name and prevent overwriting configuration settings (#175)<commit_after>'use strict';

const { kebabCase, snakeCase } = require('lodash');
const url = require('url');
const Generator = require('../../lib/generator');
const j = require('../../lib/transform');

module.exports = class ConnectionGenerator extends Generator {
  constructor(args, opts) {
    super(args, opts);

    this.dependencies = [];
  }

  _transformCode(code) {
    const { database } = this.props;

    const ast = j(code);
    const appDeclaration = ast.findDeclaration('app');
    const configureHooks = ast.findConfigure('hooks');
    const requireCall = `const ${database} = require('./${database}');`;

    if (appDeclaration.length === 0) {
      throw new Error('Could not find \'app\' variable declaration in app.js to insert database configuration. Did you modify app.js?');
    }

    if (configureHooks.length === 0) {
      throw new Error('Could not find .configure(hooks()) call in app.js after which to insert database configuration. Did you modify app.js?');
    }

    appDeclaration.insertBefore(requireCall);
    configureHooks.insertAfter(`app.configure(${database});`);

    return ast.toSource();
  }

  _getConfiguration() {
    const sqlPackages = {
      mariadb: 'mysql',
      mysql: 'mysql',
      mssql: 'tedious',
      postgres: 'pg',
      sqlite: 'sqlite3'
      // oracle: 'oracle'
    };

    const { connectionString, database, adapter } = this.props;
    const parsed = url.parse(connectionString);

    switch(database) {
    case 'nedb':
      this.dependencies.push('nedb');
      return connectionString.substring(7, connectionString.length);

    case 'rethinkdb':
      this.dependencies.push('rethinkdbdash');
      return {
        db: parsed.path.substring(1, parsed.path.length),
        servers: [
          {
            host: parsed.hostname,
            port: parsed.port
          }
        ]
      };

    case 'memory':
      return null;

    case 'mongodb':
      this.dependencies.push(adapter);
      return connectionString;

    case 'mariadb':
    case 'mysql':
    case 'mssql':
    // case oracle:
    case 'postgres': // eslint-disable-line no-fallthrough
    case 'sqlite':
      this.dependencies.push(adapter);

      if (sqlPackages[database]) {
        this.dependencies.push(sqlPackages[database]);
      }

      if (adapter === 'sequelize') {
        return connectionString;
      }

      return {
        client: sqlPackages[database],
        connection: database === 'sqlite' ? {
          filename: connectionString.substring(9, connectionString.length)
        } : connectionString
      };

    default:
      throw new Error(`Invalid database '${database}'. Cannot assemble configuration.`);
    }
  }

  _writeConfiguration() {
    const { database } = this.props;
    const config = Object.assign({}, this.defaultConfig);

    config[database] = this._getConfiguration();

    this.conflicter.force = true;
    this.fs.writeJSON(
      this.destinationPath('config', 'default.json'),
      config
    );
  }

  prompting() {
    this.checkPackage();

    const databaseName = kebabCase(this.pkg.name);
    const snakeDatabaseName = snakeCase(this.pkg.name);
    const { defaultConfig } = this;

    const getProps = answers => Object.assign({}, this.props, answers);
    const setProps = props => Object.assign(this.props, props);

    const prompts = [
      {
        type: 'list',
        name: 'database',
        message: 'Which database are you connecting to?',
        default: 'nedb',
        choices: [
          { name: 'MariaDB', value: 'mariadb' },
          { name: 'Memory', value: 'memory' },
          { name: 'MongoDB', value: 'mongodb' },
          { name: 'MySQL', value: 'mysql' },
          { name: 'NeDB', value: 'nedb' },
          // { name: 'Oracle', value: 'oracle' },
          { name: 'PostgreSQL', value: 'postgres' },
          { name: 'RethinkDB', value: 'rethinkdb' },
          { name: 'SQLite', value: 'sqlite' },
          { name: 'SQL Server', value: 'mssql' }
        ],
        when(current) {
          const answers = getProps(current);
          const { database, adapter } = answers;

          if (database) {
            return false;
          }

          switch(adapter) {
          case 'nedb':
          case 'rethinkdb':
          case 'memory':
          case 'mongodb':
            setProps({ database: adapter });
            return false;
          case 'mongoose':
            setProps({ database: 'mongodb' });
            return false;
          }

          return true;
        }
      },
      {
        type: 'list',
        name: 'adapter',
        message: 'Which database adapter would you like to use?',
        default(current) {
          const answers = getProps(current);
          const { database } = answers;

          if (database === 'mongodb') {
            return 'mongoose';
          }

          return 'sequelize';
        },
        choices(current) {
          const answers = getProps(current);
          const { database } = answers;
          const mongoOptions = [
            { name: 'MongoDB Native', value: 'mongodb' },
            { name: 'Mongoose', value: 'mongoose' }
          ];
          const sqlOptions = [
            { name: 'Sequelize', value: 'sequelize' },
            { name: 'KnexJS', value: 'knex' }
          ];

          if (database === 'mongodb') {
            return mongoOptions;
          }

          // It's an SQL DB
          return sqlOptions;
        },
        when(current) {
          const answers = getProps(current);
          const { database, adapter } = answers;

          if (adapter) {
            return false;
          }

          switch(database) {
          case 'nedb':
          case 'rethinkdb':
          case 'memory':
            return false;
          }

          return true;
        }
      },
      {
        name: 'connectionString',
        message: 'What is the database connection string?',
        default(current) {
          const answers = getProps(current);
          const { database } = answers;
          const defaultConnectionStrings = {
            mariadb: `mariadb://root:@localhost:3306/${databaseName}`,
            mongodb: `mongodb://localhost:27017/${databaseName}`,
            mysql: `mysql://root:@localhost:3306/${databaseName}`,
            nedb: 'nedb://../data',
            // oracle: `oracle://root:password@localhost:1521/${databaseName}`,
            postgres: `postgres://postgres:@localhost:5432/${databaseName}`,
            rethinkdb: `rethinkdb://localhost:28015/${snakeDatabaseName}`,
            sqlite: `sqlite://${databaseName}.sqlite`,
            mssql: `mssql://root:password@localhost:1433/${databaseName}`
          };

          return defaultConnectionStrings[database];
        },
        when(current) {
          const answers = getProps(current);
          const { database } = answers;
          const connectionString = defaultConfig[database];

          if (typeof connectionString === 'string') {
            setProps({ connectionString });
            return false;
          }

          if(typeof connectionString === 'object' && database === 'rethinkdb') {
            // Assign the database connection variables by destructuring the current connection object
            const {
              db: databaseName = snakeDatabaseName,
              servers: [{
                host: databaseHost = 'localhost',
                port: databasePort = '28015'
              }]
            } = connectionString;

            setProps({ connectionString: `rethinkdb://${databaseHost}:${databasePort}/${databaseName}` });
            return false;
          }

          return database !== 'memory';
        }
      }
    ];

    return this.prompt(prompts).then(props => {
      this.props = Object.assign(this.props, props);
    });
  }

  writing() {
    let template;
    const { database, adapter } = this.props;
    const context = Object.assign({}, this.props);

    if (database === 'rethinkdb') {
      template = 'rethinkdb.js';
    }
    else if (adapter && adapter !== 'nedb') {
      template = database === 'mssql' ? `${adapter}-mssql.js` : `${adapter}.js`;
    }

    if (template) {
      const dbFile = `${database}.js`;

      // If the file doesn't exist yet, add it to the app.js
      if (!this.fs.exists(this.destinationPath(this.libDirectory, dbFile))) {
        const appjs = this.destinationPath(this.libDirectory, 'app.js');

        this.conflicter.force = true;
        this.fs.write(appjs, this._transformCode(
          this.fs.read(appjs).toString()
        ));
      }

      this.fs.copyTpl(
        this.templatePath(template),
        this.destinationPath(this.libDirectory, dbFile),
        context
      );
    }

    this._writeConfiguration();

    this._packagerInstall(this.dependencies, {
      save: true
    });
  }

  end() {
    const { database, connectionString } = this.props;

    // NOTE (EK): If this is the first time we set this up
    // show this nice message.
    if (connectionString) {
      const databaseName = database === 'rethinkdb' ? snakeCase(this.pkg.name) : kebabCase(this.pkg.name);
      this.log();
      this.log(`Woot! We've set up your ${database} database connection!`);

      switch(database) {
      case 'mariadb':
      case 'mongodb':
      case 'mssql':
      case 'mysql':
      // case 'oracle':
      case 'postgres': // eslint-disable-line no-fallthrough
      case 'rethinkdb':
        this.log(`Make sure that your ${database} database is running, the username/role is correct, and the database "${databaseName}" has been created.`);
        this.log('Your configuration can be found in the projects config/ folder.');
        break;
      }
    }
  }
};
<|endoftext|>


<commit_before>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Model for a toggle button that sticks when pushed down and pops up when
 * pushed a second time.
 *
 * @author Sam Reid
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var ButtonModel = require( 'SUN/experimental/buttons/ButtonModel' );

  /**
   *
   * @param valueA {Object} one value for the toggle
   * @param valueB {Object} other value for the toggle
   * @param valueProperty {Property<Object>} axon property that can be either valueA or valueB.  Would have preferred to call this `property` but it would clash with the property function name.
   * @constructor
   */
  function StickyToggleButtonModel( valueA, valueB, valueProperty ) {
    var thisModel = this;

    this.valueA = valueA;
    this.valueB = valueB;
    this.valueProperty = valueProperty;

    ButtonModel.call( this );

    // When the user releases the toggle button, it should only fire a
    // toggle event if it is not during the same action in which they
    // pressed the button.  Track the state to see if they have already
    // pushed the button.
    // Note: Does this need to be reset when the simulation does "reset
    // all"?  I (sreid) can't find any negative consequences in the user
    // interface of not resetting it, but maybe I missed something. Or maybe
    // it would be safe to reset it anyway.
    this.addProperty( 'readyToToggleUp', false );

    // If the button is untoggled and the user presses it, show it pressed and
    // toggle the state right away.  When the button is released, untoggle the
    // state (unless it was part of the same action that toggled the button
    // down in the first place).
    this.property( 'down' ).link( function( down ) {
      if ( thisModel.enabled && thisModel.over ) {
        if ( down && valueProperty.value === valueA ) {
          thisModel.toggle();
          thisModel.readyToToggleUp = false;
        }
        if ( !down && valueProperty.value === valueB ) {
          if ( thisModel.readyToToggleUp ) {
            thisModel.toggle();
          }
          else {
            thisModel.readyToToggleUp = true;
          }
        }
      }

      //Handle the case where the pointer moved out then up over a toggle button, so it will respond to the next press
      if ( !down && !thisModel.over ) {
        thisModel.readyToToggleUp = true;
      }
    } );

    //Make the button ready to toggle when enabled
    this.property( 'enabled' ).onValue( true, function() {
      thisModel.readyToToggleUp = true;
    } );
  }

  return inherit( ButtonModel, StickyToggleButtonModel, {
    toggle: function() {
      assert && assert( this.valueProperty.value === this.valueA || this.valueProperty.value === this.valueB );
      if ( this.valueProperty.value === this.valueA ) {
        this.valueProperty.value = this.valueB;
      }
      else {
        this.valueProperty.value = this.valueA;
      }
    }
  } );
} );<commit_msg>Added docs to clarify toggling, see #70<commit_after>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Model for a toggle button that sticks when pushed down ("toggles") and pops up when
 * pushed a second time ("untoggles").
 *
 * @author Sam Reid
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var ButtonModel = require( 'SUN/experimental/buttons/ButtonModel' );

  /**
   *
   * @param valueA {Object} one value for the toggle
   * @param valueB {Object} other value for the toggle
   * @param valueProperty {Property<Object>} axon property that can be either valueA or valueB.  Would have preferred to call this `property` but it would clash with the property function name.
   * @constructor
   */
  function StickyToggleButtonModel( valueA, valueB, valueProperty ) {
    var thisModel = this;

    this.valueA = valueA;
    this.valueB = valueB;
    this.valueProperty = valueProperty;

    ButtonModel.call( this );

    // When the user releases the toggle button, it should only fire a
    // toggle event if it is not during the same action in which they
    // pressed the button.  Track the state to see if they have already
    // pushed the button.
    // Note: Does this need to be reset when the simulation does "reset
    // all"?  I (sreid) can't find any negative consequences in the user
    // interface of not resetting it, but maybe I missed something. Or maybe
    // it would be safe to reset it anyway.
    this.addProperty( 'readyToToggleUp', false );

    // If the button is untoggled and the user presses it, show it pressed and
    // toggle the state right away.  When the button is released, untoggle the
    // state (unless it was part of the same action that toggled the button
    // down in the first place).
    this.property( 'down' ).link( function( down ) {
      if ( thisModel.enabled && thisModel.over ) {
        if ( down && valueProperty.value === valueA ) {
          thisModel.toggle();
          thisModel.readyToToggleUp = false;
        }
        if ( !down && valueProperty.value === valueB ) {
          if ( thisModel.readyToToggleUp ) {
            thisModel.toggle();
          }
          else {
            thisModel.readyToToggleUp = true;
          }
        }
      }

      //Handle the case where the pointer moved out then up over a toggle button, so it will respond to the next press
      if ( !down && !thisModel.over ) {
        thisModel.readyToToggleUp = true;
      }
    } );

    //Make the button ready to toggle when enabled
    this.property( 'enabled' ).onValue( true, function() {
      thisModel.readyToToggleUp = true;
    } );
  }

  return inherit( ButtonModel, StickyToggleButtonModel, {
    toggle: function() {
      assert && assert( this.valueProperty.value === this.valueA || this.valueProperty.value === this.valueB );
      if ( this.valueProperty.value === this.valueA ) {
        this.valueProperty.value = this.valueB;
      }
      else {
        this.valueProperty.value = this.valueA;
      }
    }
  } );
} );<|endoftext|>


<commit_before>/**
 * Created by Shawn Liu on 15-5-15.
 */

var Promise = require("bluebird");
var logger = require("node-config-logger").getLogger("components/crawler/retailer.js");
var _ = require("lodash");
var urlParser = require("url");
var retailerSelectors = require("./retailer_selectors");
var validSubdomain = {
    "en_gb": {
        "groceries.asda.com": true,
        "direct.asda.com": true
    }
}
exports.getSelector = function (productURL, locale, retailer) {
    var url = "";
    try {
        url = productURL ? urlParser.parse(productURL) : null;
        if (url) {
            var domain = retailer || url.hostname.toLowerCase();
            var comps = domain.split(".");
            var tld = comps[comps.length - 1];
            var nc = 2; // number of useful domain components
            switch (tld) {
                case "uk" :
                    if (!locale) locale = "en_gb";
                    nc = 3;
                    break;

                case "us" :
                case "com" :
                    if (!locale) locale = "en_us";
                    break;

                case "au" :
                    if (!locale) locale = "en_au";
                    nc = 3;
                    break;

                case "de" :
                    if (!locale) locale = "de_de";
                    break;

                case "fr" :
                    if (!locale) locale = "fr_fr";
                    break;

                case "es" :
                    if (!locale) locale = "es_es";
                    break;

                default:
                    if (!locale) locale = tld;
            }

            if (!retailer) {
                // some retailer sub domains are actually meaningful
                domain = comps.slice(-(nc + 1)).join(".");
                if (!validSubdomain[locale] || !validSubdomain[locale][domain]) {
                    domain = comps.slice(-nc).join(".");
                }
            }

            var section = url.pathname.split("/")[1];
            switch (domain) {
                case "tesco.com" :
                    section = (section === "direct") ? section : "groceries";
                    section = section + "." + domain;
                    domain = section;
                    break;

                case "sainsburys.co.uk" :
                    // todo more precise comparison based on parsed url path
                    if (productURL.indexOf("groceries") !== -1 || productURL.indexOf("webapp/wcs/stores/servlet/SearchDisplayView") !== -1) {
                        section = "groceries." + domain;
                    }
                    domain = section;
                    break;

                default:

            }
            //resolve(domain);
            var localeConfig = _.find(retailerSelectors, {"locale": locale});
            if (!localeConfig) {
                //reject("unknown locale '%s'", locale);
                return Promise.reject({
                    status: false,
                    url: productURL,
                    message: "unknown locale '" + locale + "'"
                })
            } else {
                var retailer = _.find(localeConfig.retailers, {"id": domain});
                if (!retailer) {
                    // reject("unknown retailer '%s'", domain);
                    return Promise.reject({
                        status: false,
                        url: productURL,
                        message: "unknown retailer '" + domain + "'"
                    })
                } else {
                    //resolve(_.cloneDeep(retailer));
                    retailer.status = true;
                    return Promise.resolve(_.cloneDeep(retailer))
                }
            }
        } else {
            logger.error("Product URL could not be parsed: " + productURL);
            return Promise.reject({
                status: false,
                url: productURL,
                message: "Product URL could not be parsed: " + productURL
            });
        }
    } catch (e) {
        logger.error("Failure while getting selectors for " + productURL + " : " + e);
        return Promise.reject({
            status: false,
            url: productURL,
            message: e
        });
    }
}
<commit_msg>try to ensure retaielr obj inherit from parent<commit_after>/**
 * Created by Shawn Liu on 15-5-15.
 */

var Promise = require("bluebird");
var logger = require("node-config-logger").getLogger("components/crawler/retailer.js");
var _ = require("lodash");
var urlParser = require("url");
var retailerSelectors = require("./retailer_selectors");
var Path = require("path");
var fs = require("fs");
var validSubdomain = {
    "en_gb": {
        "groceries.asda.com": true,
        "direct.asda.com": true
    }
}
exports.getSelector = function (productURL, locale, retailer) {
    var url = "";
    try {
        url = productURL ? urlParser.parse(productURL) : null;
        if (url) {
            var domain = retailer || url.hostname.toLowerCase();
            var comps = domain.split(".");
            var tld = comps[comps.length - 1];
            var nc = 2; // number of useful domain components
            switch (tld) {
                case "uk" :
                    if (!locale) locale = "en_gb";
                    nc = 3;
                    break;

                case "us" :
                case "com" :
                    if (!locale) locale = "en_us";
                    break;

                case "au" :
                    if (!locale) locale = "en_au";
                    nc = 3;
                    break;

                case "de" :
                    if (!locale) locale = "de_de";
                    break;

                case "fr" :
                    if (!locale) locale = "fr_fr";
                    break;

                case "es" :
                    if (!locale) locale = "es_es";
                    break;

                default:
                    if (!locale) locale = tld;
            }

            if (!retailer) {
                // some retailer sub domains are actually meaningful
                domain = comps.slice(-(nc + 1)).join(".");
                if (!validSubdomain[locale] || !validSubdomain[locale][domain]) {
                    domain = comps.slice(-nc).join(".");
                }
            }

            var section = url.pathname.split("/")[1];
            switch (domain) {
                case "tesco.com" :
                    section = (section === "direct") ? section : "groceries";
                    section = section + "." + domain;
                    domain = section;
                    break;

                case "sainsburys.co.uk" :
                    // todo more precise comparison based on parsed url path
                    if (productURL.indexOf("groceries") !== -1 || productURL.indexOf("webapp/wcs/stores/servlet/SearchDisplayView") !== -1) {
                        section = "groceries." + domain;
                    }
                    domain = section;
                    break;

                default:

            }
            //resolve(domain);
            var localeConfig = _.find(retailerSelectors, {"locale": locale});
            if (!localeConfig) {
                //reject("unknown locale '%s'", locale);
                return Promise.reject({
                    status: false,
                    url: productURL,
                    message: "unknown locale '" + locale + "'"
                })
            } else {
                var retailer = _.find(localeConfig.retailers, {"id": domain});
                if (!retailer) {
                    // reject("unknown retailer '%s'", domain);
                    return Promise.reject({
                        status: false,
                        url: productURL,
                        message: "unknown retailer '" + domain + "'"
                    })
                } else {
                    //resolve(_.cloneDeep(retailer));
                    retailer.status = true;
                    return Promise.resolve(_.cloneDeep(retailer))
                }
            }
        } else {
            logger.error("Product URL could not be parsed: " + productURL);
            return Promise.reject({
                status: false,
                url: productURL,
                message: "Product URL could not be parsed: " + productURL
            });
        }
    } catch (e) {
        logger.error("Failure while getting selectors for " + productURL + " : " + e);
        return Promise.reject({
            status: false,
            url: productURL,
            message: e
        });
    }
}

function _extractInfo(productURL, locale, retailer) {
    var url = "";
    var path = [__dirname, "sites"];
    try {
        url = productURL ? urlParser.parse(productURL) : null;
        if (url) {
            var domain = retailer || url.hostname.toLowerCase();
            var comps = domain.split(".");
            var tld = comps[comps.length - 1];
            var nc = 2; // number of useful domain components
            switch (tld) {
                case "uk" :
                    if (!locale) locale = "en_gb";
                    nc = 3;
                    break;

                case "us" :
                case "com" :
                    if (!locale) locale = "en_us";
                    break;

                case "au" :
                    if (!locale) locale = "en_au";
                    nc = 3;
                    break;

                case "de" :
                    if (!locale) locale = "de_de";
                    break;

                case "fr" :
                    if (!locale) locale = "fr_fr";
                    break;

                case "es" :
                    if (!locale) locale = "es_es";
                    break;

                default:
                    if (!locale) locale = tld;
            }
            path.push(locale);
            if (!retailer) {
                // some retailer sub domains are actually meaningful
                domain = comps.slice(-(nc + 1)).join(".");
                if (!validSubdomain[locale] || !validSubdomain[locale][domain]) {
                    domain = comps.slice(-nc).join(".");
                }
            }

            var section = url.pathname.split("/")[1];
            switch (domain) {
                case "tesco.com" :
                    section = (section === "direct") ? section : "groceries";
                    section = section + "." + domain;
                    path.push.apply(path, [domain, (section + ".js")]);
                    domain = section;
                    break;

                case "sainsburys.co.uk" :
                    // todo more precise comparison based on parsed url path
                    if (productURL.indexOf("groceries") !== -1 || productURL.indexOf("webapp/wcs/stores/servlet/SearchDisplayView") !== -1) {
                        section = "groceries." + domain;
                    }
                    path.push.apply(path, (section.match("groceries")) ? [domain, (section + ".js")] : [domain + ".js"]);
                    domain = section;
                    break;

                default:

            }

            return new Promise(function (resolve, reject) {
                var filePath = Path.join.apply(null, path);
                fs.exists(filePath, function (exists) {
                    if (exists) {
                        //logger.debug("loaded retailer script " + filePath);
                        resolve({
                            status: true,
                            url: productURL,
                            retailerFile: filePath,
                            selectorId: domain
                        });

                    } else {
                        // disable reject, so that the promise can go on even there exist some retailer scripts not implemented.
                        resolve({
                            status: true,
                            url: productURL,
                            selectorId: domain
                        });
                    }
                });
            });
        }
    } catch (e) {
        return Promise.reject({
            status: false,
            message: e.message || e
        });
    }
}

function RetailerObject(productURL, locale, retailer) {
    this.productURL = productURL;
    this.locale = locale;
    this.retailer = retailer;
}

RetailerObject.prototype.getSelector = function () {
    return _extractInfo(this.productURL, this.locale, this.retailer)
        .then(function (result) {
            var localeConfig = _.find(retailerSelectors, {"locale": this.locale});
            if (!localeConfig) {
                //reject("unknown locale '%s'", locale);
                return Promise.reject({
                    status: false,
                    url: this.productURL,
                    message: "unknown locale '" + this.locale + "'"
                })
            } else {
                var retailer = _.find(localeConfig.retailers, {"id": result.selectorId});
                if (!retailer) {
                    // reject("unknown retailer '%s'", domain);
                    return Promise.reject({
                        status: false,
                        url: this.productURL,
                        message: "unknown retailer '" + result.selectorId + "'"
                    })
                } else {
                    //resolve(_.cloneDeep(retailer));
                    retailer.status = true;
                    return Promise.resolve(_.cloneDeep(retailer))
                }
            }
        })
}

RetailerObject.prototype.format = function (jsonObject) {
    return _extractInfo(this.productURL, this.locale, this.retailer)
        .then(function (result) {

        })
}

module.exports = RetailerObject;<|endoftext|>


<commit_before>import React, {PropTypes} from 'react'
import Ink from 'react-ink'
import styles from 'part:@sanity/components/buttons/default-style'
import Spinner from 'part:@sanity/components/loading/spinner'

export default class DefaultButton extends React.Component {
  static propTypes = {
    kind: PropTypes.oneOf(['secondary', 'simple']),
    color: PropTypes.oneOf(['primary', 'success', 'danger']),
    onClick: PropTypes.func,
    children: PropTypes.node,
    inverted: PropTypes.bool,
    icon: PropTypes.func,
    loading: PropTypes.bool,
    ripple: PropTypes.bool,
    className: PropTypes.string,
    disabled: PropTypes.bool
  }

  static defaultProps = {
    ripple: true,
    icon: null,
    onClick() {}
  }

  constructor(...args) {
    super(...args)

    this.handleClick = this.handleClick.bind(this)
  }

  handleClick(event) {
    this.props.onClick(event)
  }

  render() {

    const {kind, ripple, disabled, inverted, color, icon, loading, className, children, ...rest} = this.props

    const Icon = icon

    if (!styles[kind] && kind) {
      console.error(`There is no ${kind} button`) // eslint-disable-line no-console
    }

    const style = `
      ${styles[kind] || (inverted && styles.inverted) || styles.default}
      ${color && styles[`color__${color}`]}
      ${Icon && styles.hasIcon}
      ${className}
      ${disabled && styles.disabled}
    `

    return (
      <button
        {...rest}
        className={style}
        type="button"
        onClick={this.handleClick}
        disabled={disabled}
      >
        {
          loading && <Spinner />
        }
        {
          Icon && <Icon className={styles.icon} />
        }
        {
          children && {children}
        }
        {
          ripple && !disabled && <Ink duration={200} opacity={0.10} radius={200} />
        }
      </button>
    )
  }
}
<commit_msg>Remove noisy console.error<commit_after>import React, {PropTypes} from 'react'
import Ink from 'react-ink'
import styles from 'part:@sanity/components/buttons/default-style'
import Spinner from 'part:@sanity/components/loading/spinner'

export default class DefaultButton extends React.Component {
  static propTypes = {
    kind: PropTypes.oneOf(Object.keys(styles)),
    color: PropTypes.oneOf(['primary', 'success', 'danger']),
    onClick: PropTypes.func,
    children: PropTypes.node,
    inverted: PropTypes.bool,
    icon: PropTypes.func,
    loading: PropTypes.bool,
    ripple: PropTypes.bool,
    className: PropTypes.string,
    disabled: PropTypes.bool
  }

  static defaultProps = {
    ripple: true,
    icon: null,
    onClick() {}
  }

  constructor(...args) {
    super(...args)

    this.handleClick = this.handleClick.bind(this)
  }

  handleClick(event) {
    this.props.onClick(event)
  }

  render() {

    const {kind, ripple, disabled, inverted, color, icon, loading, className, children, ...rest} = this.props

    const Icon = icon

    const style = `
      ${styles[kind] || (inverted && styles.inverted) || styles.default}
      ${color && styles[`color__${color}`]}
      ${Icon && styles.hasIcon}
      ${className}
      ${disabled && styles.disabled}
    `

    return (
      <button
        {...rest}
        className={style}
        type="button"
        onClick={this.handleClick}
        disabled={disabled}
      >
        {
          loading && <Spinner />
        }
        {
          Icon && <Icon className={styles.icon} />
        }
        {
          children && {children}
        }
        {
          ripple && !disabled && <Ink duration={200} opacity={0.10} radius={200} />
        }
      </button>
    )
  }
}
<|endoftext|>